UNPKG

@blockv/sdk

Version:

Allows web apps to display and interact with vatoms.

425 lines (372 loc) 13.6 kB
// // BlockV AG. Copyright (c) 2018, all rights reserved. // // Licensed under the BlockV SDK License (the "License"); you may not use this file or // the BlockV SDK except in compliance with the License accompanying it. Unless // required by applicable law or agreed to in writing, the BlockV SDK distributed under // the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF // ANY KIND, either express or implied. See the License for the specific language // governing permissions and limitations under the License. // import urlParse from 'url-parse' import User from '../../../../model/User' export default class UserApi { constructor (bv) { this.Blockv = bv this.client = bv.client this.store = bv.store this.dataPool = bv.dataPool } /** * Registers a user on the Blockv platform. * * @param registration contains properties of the user. * Only the properties to be registered should be set. * @return new Observable<User> instance */ getAccessToken () { return this.store.token } setAccessToken (token) { this.store.token = '' this.store.token = token } getRefreshToken () { return this.store.refreshToken } setRefreshToken (token) { this.store.token = '' this.store.refreshToken = token } register (registration) { return this.client.request('POST', '/v1/users', registration, false) .then( (data) => { this.store.token = data.access_token.token this.store.refreshToken = data.refresh_token.token this.store.assetProvider = data.asset_provider this.store.userID = data.user.id this.dataPool.setSessionInfo({ userID: data.user.id }) return data } ).then(data => new User(data.user)) } /** * Logs a user into the Blockv platform. Accepts a user token (phone or email). * * @param token the user's phone(E.164) or email * @param tokenType the type of the token (phone or email) * @param password the user's password. * @return JSON Object */ login (token, tokenType, password) { const payload = { token, token_type: tokenType, auth_data: { password } } return this.client.request('POST', '/v1/user/login', payload, false).then( (data) => { if (!password) { const error = new Error('Login Failed, Password Reset') error.code = 'PASSWORD_RESET' throw error } else { this.store.token = data.access_token.token this.store.refreshToken = data.refresh_token.token this.store.assetProvider = data.asset_provider this.store.userID = data.user.id this.dataPool.setSessionInfo({ userID: data.user.id, client: this.client }) return data } } ).then(data => new User(data.user)) } /** * Logs a user into the Blockv platform. Accepts a guest id * * @param guestId the user's guest id. * @return JSON Object */ loginGuest (guestId) { const payload = { token: guestId, token_type: 'guest_id' } return this.client.request('POST', '/v1/user/login', payload, false).then( (data) => { this.store.token = data.access_token.token this.store.refreshToken = data.refresh_token.token this.store.assetProvider = data.asset_provider this.dataPool.setSessionInfo({ userID: data.user.id }) return data } ).then(data => new User(data.user)) } uploadAvatar (request) { // get file // change to formData return this.client.request('POST', '/v1/user/avatar', request, true) } /** * Fetches the current user's profile information from the Blockv platform. * * @return JSON Object */ getCurrentUser (payload) { // get the current authenticated in user return this.client.request('GET', '/v1/user', payload, true).then(data => new User(data)) } /** * Updates the current user's profile on the Blockv platform. * @param update holds the properties of the user, e.g. their first name. * Only the properties to be updated should be set. * @return JSON Object */ updateUser (update) { return this.client.request('PATCH', '/v1/user', update, true) } /** * Gets a list of the current users tokens * @return JSON Object */ getUserTokens () { return this.client.request('GET', '/v1/user/tokens', '', true) } /** * Verifies ownership of a token by submitting the verification code to the Blockv platform. * @param token the user's phone(E.164) or email * @param tokenType the type of the token (phone or email) * @param code the verification code send to the user's token (phone or email). * @return JSON Object */ verifyUserToken (verification) { return this.client.request('POST', '/v1/user/verify_token', verification, true) } /** * Sends a One-Time-Pin (OTP) to the user's token (phone or email). * This OTP may be used in place of a password to login. * @param token the user's phone(E.164) or email * @param tokenType the type of the token (phone or email) * @return JSON Object */ resetPassword (token, tokenType) { const payload = { token, token_type: tokenType } return this.client.request('POST', '/v1/user/reset_token', payload, false) } /** * Sends a verification code to the user's token (phone or email). * This verification code should be used to verifiy the user's ownership * of the token (phone or email). * @param token the user's phone(E.164) or email * @param tokenType the type of the token (phone or email) * @return JSON Object */ sendTokenVerification (token, tokenType) { const payload = { token, token_type: tokenType } return this.client.request('POST', '/v1/user/reset_token_verification', payload, false) } /** * Returns a server generated guest id * @return Object payload containing a guest user generated by the server */ getGuestToken () { return this.client.request('POST', '/v1/user/guest', '', false).then(data => data.properties.guest_id) } /** * Log out the current user. * The current user will not longer be authorized to perform user * scoped requests on the Blockv platfrom. * @return new JSON */ logout (params) { return this.client.request('POST', '/v1/user/logout', params, true).then(() => { this.store.token = '' this.store.refreshToken = '' this.dataPool.setSessionInfo(null) }).catch((err) => { console.warn(err) this.store.token = '' this.store.refreshToken = '' this.DataPool.setSessionInfo(null) throw err }) } static mapString (o) { return Object.keys(o).map(key => `${key}=${o[key]}`).join('&') } encodeAssetProvider (url) { const aP = this.store.assetProvider const aPlen = aP.length const compare = urlParse(url) for (let i = 0; i < aPlen; i += 1) { const comparethis = urlParse(aP[i].uri) if (compare.hostname === comparethis.hostname) { // same uri so get the policy signature and key and append const queryString = UserApi.mapString(aP[i].descriptor) return `${url}?${queryString}` } } return url } addUserToken (payload) { /** * payload is * { * "token": "another.email@domain.com", * "token_type": "email", * "is_primary": false * } */ return this.client.request('POST', '/v1/user/tokens', payload, true) } setDefaultToken (tokenId) { return this.client.request('PUT', `/v1/user/tokens/${tokenId}/default`, null, true) } /** * Deletes a Users Token * @param {String} tokenId * @return {Promise<Object>} returns a success */ deleteUserToken (tokenId) { return this.client.request('DELETE', `/v1/user/tokens/${tokenId}`, null, true) } /** * Adds a redeemable the users account * @param {Object} payload Object containing the redeemable information * @return {Promise<Object>} returns a Object containing the new redeemable */ async addRedeemable (payload) { const { userID } = this.store return this.client.request('POST', `/v1/users/${userID}/redeemables`, payload, true) } async getPublicUserProfile (userID) { return this.client.request('GET', `/v1/users/${userID}`, '', true) } /** * Logs the user in via OAuth in a browser popup window. * NOTE: This is a private method, subject to change once more OAuth flows have been fully implemented on the backend. * @private * @returns {Promise<boolean>} `true` if login completed, or `false` if login was cancelled by the user. */ async loginOAuthPopup () { // Ensure SDK has been initialized if (!this.store.appID) throw new Error('Please initialize the SDK and set your App ID first.') // Generate random state ID const stateID = Math.random().toString(36).substr(2) // Generate the oauth URL const redirectURI = 'https://login.blockv.io/send-event.html' const uri = `https://login.blockv.io/?response_type=code&client_id=${this.store.appID}&redirect_uri=${encodeURIComponent(redirectURI)}&scope=all&state=${stateID}` // Create popup window const newWindow = window.open(uri, '_blank', 'left=200,top=200,width=360,height=480,chrome,centerscreen') if (!newWindow) { throw new Error('Unable to login, popups have been blocked') } // Create pending promise let promiseResolved = false let promiseSuccess = null let promiseFail = null const promise = new Promise((resolve, reject) => { promiseSuccess = resolve promiseFail = reject }) // Create window close checker const closeChecker = setInterval(() => { // Check if window was closed if (!newWindow.closed) return false // It was, cancel timer clearInterval(closeChecker) // If promise was never resolved, the user must have closed the popup before logging in. Resolve the promise. if (!promiseResolved) promiseSuccess(false) }, 250) // Create message listener const messageListener = async (e) => { // Ensure it's from the correct origin if (e.origin !== 'https://login.blockv.io') return false // Ensure the state matches if (e.data.state !== stateID) return false // Ensure the action matches if (e.data.action !== 'oauth-response') return false console.log(e.data) // Check response type if (e.data.code) { let oauthObj = { 'grant_type': 'authorization_code', 'client_id': this.Blockv.store.appID, 'code': e.data.code, 'redirect_uri': redirectURI } let oa = await this.Blockv.client.request('POST', 'v1/oauth/token', oauthObj, false) // We have our user data, store it this.setRefreshToken(oa.refresh_token.token) this.store.token = oa.access_token.token // Get user info and set the store properties const profile = await this.getCurrentUser() this.store.userID = profile.id // Get asset provider info and store it const assetProviders = await this.client.request('GET', 'v1/user/asset_providers', null, true) this.store.assetProvider = assetProviders.asset_provider // Inform data pool that the current user changed this.dataPool.setSessionInfo({ userID: profile.id }) // Done promiseResolved = true promiseSuccess(true) } else { // Login failed, return error const err = new Error(e.data.error_text || 'Unable to login.') err.code = e.data.error promiseResolved = true promiseFail(err) } // Cleanup, remove event listener newWindow.close() window.removeEventListener('message', messageListener) clearInterval(closeChecker) return true } // Attach message listener window.addEventListener('message', messageListener) // Done, return promise return promise } // Used for manual OAuth Login flow async loginOauthCode (redirectURI, code) { let oauthObj = { 'grant_type': 'authorization_code', 'client_id': this.store.appID, 'code': code, 'redirect_uri': redirectURI } let oa = await this.Blockv.client.request('POST', 'v1/oauth/token', oauthObj, false) // We have our user data, store it this.setRefreshToken(oa.refresh_token.token) this.store.token = oa.access_token.token // Get user info and set the store properties const profile = await this.getCurrentUser() this.store.userID = profile.id // Get asset provider info and store it const assetProviders = await this.client.request('GET', 'v1/user/asset_providers', null, true) this.store.assetProvider = assetProviders.asset_provider // Inform data pool that the current user changed this.dataPool.setSessionInfo({ userID: profile.id }) } }