From d0a6a4185775e120d1e2d6a66045af91afa420fd Mon Sep 17 00:00:00 2001 From: Larry Salibra Date: Mon, 8 Jan 2018 21:48:37 +0800 Subject: [PATCH 01/24] verify app origin and display app origin to user #1147 --- app/js/auth/components/AuthModal.js | 7 ++++--- app/js/auth/store/auth.js | 15 ++++++++++----- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/app/js/auth/components/AuthModal.js b/app/js/auth/components/AuthModal.js index 54f0190ee..d2ca7e803 100644 --- a/app/js/auth/components/AuthModal.js +++ b/app/js/auth/components/AuthModal.js @@ -61,7 +61,7 @@ class AuthModal extends Component { static propTypes = { defaultIdentity: PropTypes.number.isRequired, localIdentities: PropTypes.array.isRequired, - loadAppManifest: PropTypes.func.isRequired, + verifyAuthRequestAndLoadManifest: PropTypes.func.isRequired, clearSessionToken: PropTypes.func.isRequired, getCoreSessionToken: PropTypes.func.isRequired, coreAPIPassword: PropTypes.string.isRequired, @@ -126,7 +126,7 @@ class AuthModal extends Component { invalidScopes }) - this.props.loadAppManifest(authRequest) + this.props.verifyAuthRequestAndLoadManifest(authRequest) } componentWillReceiveProps(nextProps) { @@ -436,7 +436,8 @@ class AuthModal extends Component { :

- The app "{appManifest.name}" wants to access your basic info + The app "{appManifest.name}" located at {decodedToken.payload.domain_name} +  wants to access your basic info {requestingEmail ? and email address : null}

{appManifest.hasOwnProperty('icons') ? diff --git a/app/js/auth/store/auth.js b/app/js/auth/store/auth.js index 18bafc63d..9bb9fce0c 100644 --- a/app/js/auth/store/auth.js +++ b/app/js/auth/store/auth.js @@ -1,4 +1,5 @@ -import { getCoreSession, fetchAppManifest } from 'blockstack' +import { getCoreSession, + verifyAuthRequestAndLoadManifest as bskVerifyAuthRequestAndLoadManifest } from 'blockstack' import log4js from 'log4js' const logger = log4js.getLogger('auth/store/auth.js') @@ -78,13 +79,17 @@ function noCoreSessionToken(appDomain) { } } -function loadAppManifest(authRequest) { +function verifyAuthRequestAndLoadManifest(authRequest) { return dispatch => { dispatch(appManifestLoading()) - fetchAppManifest(authRequest).then(appManifest => { + bskVerifyAuthRequestAndLoadManifest(authRequest) + .then(appManifest => { dispatch(appManifestLoaded(appManifest)) + }, () => { + logger.error('verifyAuthRequestAndLoadManifest: invalid authentication request') + dispatch(appManifestLoadingError('Invalid authentication request.')) }).catch((e) => { - logger.error('loadAppManifest: error', e) + logger.error('verifyAuthRequestAndLoadManifest: error', e) dispatch(appManifestLoadingError(e)) }) } @@ -136,6 +141,6 @@ export const AuthActions = { clearSessionToken, getCoreSessionToken, noCoreSessionToken, - loadAppManifest, + verifyAuthRequestAndLoadManifest, loginToApp } From 8fd3069a726e700bca8e4a5f086fa250b5934fa4 Mon Sep 17 00:00:00 2001 From: Aaron Blankstein Date: Mon, 8 Jan 2018 15:54:00 -0500 Subject: [PATCH 02/24] first bug discovery --- app/js/profiles/store/identity/actions.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/js/profiles/store/identity/actions.js b/app/js/profiles/store/identity/actions.js index 052860516..1ae54ca8d 100644 --- a/app/js/profiles/store/identity/actions.js +++ b/app/js/profiles/store/identity/actions.js @@ -196,6 +196,9 @@ function createNewProfile(encryptedBackupPhrase: string, getIdentityOwnerAddressNode(identityPrivateKeychainNode, index) const newIdentityKeypair = deriveIdentityKeyPair(identityOwnerAddressNode) logger.debug(`createNewProfile: new identity: ${newIdentityKeypair.address}`) + // aaron: the following lines will double increment + // so we get indexes like: + // 0, 1, 3, 5, 7, 9, 11 ... dispatch(AccountActions.newIdentityAddress(newIdentityKeypair)) dispatch(AccountActions.usedIdentityAddress()) const ownerAddress = newIdentityKeypair.address From 3aa36e1690a2bb94784244e7dabc0a21b6b18ca6 Mon Sep 17 00:00:00 2001 From: Aaron Blankstein Date: Mon, 8 Jan 2018 18:15:18 -0500 Subject: [PATCH 03/24] fix the double increment of the identity index --- app/js/profiles/store/identity/actions.js | 1 - 1 file changed, 1 deletion(-) diff --git a/app/js/profiles/store/identity/actions.js b/app/js/profiles/store/identity/actions.js index 1ae54ca8d..76e269994 100644 --- a/app/js/profiles/store/identity/actions.js +++ b/app/js/profiles/store/identity/actions.js @@ -200,7 +200,6 @@ function createNewProfile(encryptedBackupPhrase: string, // so we get indexes like: // 0, 1, 3, 5, 7, 9, 11 ... dispatch(AccountActions.newIdentityAddress(newIdentityKeypair)) - dispatch(AccountActions.usedIdentityAddress()) const ownerAddress = newIdentityKeypair.address // $FlowFixMe dispatch(createNewIdentityWithOwnerAddress(index, ownerAddress)) From 88c8bd5d04f2c7cec8f2cfdc7af5dfb78c472e0c Mon Sep 17 00:00:00 2001 From: Aaron Blankstein Date: Mon, 8 Jan 2018 18:15:58 -0500 Subject: [PATCH 04/24] remove my comment identifying the culprit lines --- app/js/profiles/store/identity/actions.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/app/js/profiles/store/identity/actions.js b/app/js/profiles/store/identity/actions.js index 76e269994..79e9c6e06 100644 --- a/app/js/profiles/store/identity/actions.js +++ b/app/js/profiles/store/identity/actions.js @@ -196,9 +196,6 @@ function createNewProfile(encryptedBackupPhrase: string, getIdentityOwnerAddressNode(identityPrivateKeychainNode, index) const newIdentityKeypair = deriveIdentityKeyPair(identityOwnerAddressNode) logger.debug(`createNewProfile: new identity: ${newIdentityKeypair.address}`) - // aaron: the following lines will double increment - // so we get indexes like: - // 0, 1, 3, 5, 7, 9, 11 ... dispatch(AccountActions.newIdentityAddress(newIdentityKeypair)) const ownerAddress = newIdentityKeypair.address // $FlowFixMe From 3faf7d08b6b9fc6d3d413b4ba6ba9e1d07ec801a Mon Sep 17 00:00:00 2001 From: Aaron Blankstein Date: Mon, 8 Jan 2018 18:30:08 -0500 Subject: [PATCH 05/24] update test case so that it only has 1 increment-identity-address-index action --- tests/profiles/store/identity/actions/async.test.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/profiles/store/identity/actions/async.test.js b/tests/profiles/store/identity/actions/async.test.js index cd75b63a7..afa39d8a0 100644 --- a/tests/profiles/store/identity/actions/async.test.js +++ b/tests/profiles/store/identity/actions/async.test.js @@ -48,9 +48,6 @@ describe('Identity Store: Async Actions', () => { }, "type": "NEW_IDENTITY_ADDRESS" }, - { - "type": "INCREMENT_IDENTITY_ADDRESS_INDEX" - }, { "index": 0, "ownerAddress": "13ssnrZTn4TJzQkwFZHajfeZXrGe6fQtrZ", From ca0e4a283eec1c97396771cbeb9de60344616d0a Mon Sep 17 00:00:00 2001 From: Aaron Blankstein Date: Fri, 12 Jan 2018 16:58:10 -0500 Subject: [PATCH 06/24] begin work on correcting profile uploads --- app/js/account/utils/blockstack-inc.js | 18 +--- app/js/account/utils/index.js | 118 ++++++++++++++++++------- 2 files changed, 87 insertions(+), 49 deletions(-) diff --git a/app/js/account/utils/blockstack-inc.js b/app/js/account/utils/blockstack-inc.js index 7684ffbc4..31ebaba66 100644 --- a/app/js/account/utils/blockstack-inc.js +++ b/app/js/account/utils/blockstack-inc.js @@ -1,25 +1,9 @@ // @flow import log4js from 'log4js' -import { uploadToGaiaHub, connectToGaiaHub, GaiaHubConfig } from 'blockstack' +import { connectToGaiaHub, GaiaHubConfig } from 'blockstack' const logger = log4js.getLogger('account/utils/blockstack-inc.js') -export function uploadPhotoToGaiaHub(api: {gaiaHubConfig: GaiaHubConfig }, - identityIndex: number, identityAddress: string, photoFile: any, photoIndex: number) { - logger.trace('uploadPhotoToGaiaHub') - const hubConfig = api.gaiaHubConfig - const filename = `${identityIndex}/avatar-${photoIndex}` - return uploadToGaiaHub(filename, photoFile, hubConfig) -} - -export function uploadProfileToGaiaHub(api: {gaiaHubConfig: GaiaHubConfig}, - identityIndex: number, identityAddress: string, signedProfileTokenData: string) { - logger.trace('uploadProfileToGaiaHub') - const hubConfig = api.gaiaHubConfig - const filename = `${identityIndex}/profile.json` - return uploadToGaiaHub(filename, signedProfileTokenData, hubConfig, 'application/json') -} - export function redirectToConnectToGaiaHub() { logger.trace('redirectToConnectToGaiaHub') const port = location.port === '' ? 80 : location.port diff --git a/app/js/account/utils/index.js b/app/js/account/utils/index.js index 43ab8599c..de3b35162 100644 --- a/app/js/account/utils/index.js +++ b/app/js/account/utils/index.js @@ -1,7 +1,11 @@ // @flow -import { uploadPhotoToDropbox, uploadProfileToDropbox } from './dropbox' -import { uploadPhotoToGaiaHub, uploadProfileToGaiaHub } from './blockstack-inc' -import type { GaiaHubConfig } from './blockstack-inc' +import { parseZoneFile } from 'zone-file' + +import type { GaiaHubConfig } from 'blockstack' +import { getFullReadUrl, connectToGaiaHub, uploadToGaiaHub } from 'blockstack' + +import { getTokenFileUrlFromZoneFile } from '../../utils/zone-utils' + import log4js from 'log4js' const logger = log4js.getLogger('account/utils/index.js') @@ -9,14 +13,6 @@ const logger = log4js.getLogger('account/utils/index.js') export const BLOCKSTACK_INC = 'gaia-hub' export const DROPBOX = 'dropbox' -function getStorageMethod(api: {dropboxAccessToken: string}) { - if (api.hostedDataLocation === DROPBOX && - api.dropboxAccessToken.length > 0) { - return DROPBOX - } - return BLOCKSTACK_INC -} - function checkIdentityInputs(identityIndex: number, identityAddress: string) { if (!identityIndex && identityIndex !== 0) { const message = 'checkIdentityInputs: No identity index provided' @@ -31,32 +27,90 @@ function checkIdentityInputs(identityIndex: number, identityAddress: string) { } } -export function uploadPhoto(api: {dropboxAccessToken: string, gaiaHubConfig: GaiaHubConfig}, - identityIndex: number, identityAddress: string, photoFile: string, photoIndex: number) { - const storageMethod = getStorageMethod(api) - logger.debug(`uploadPhoto: id index: ${identityIndex} id address ${identityAddress}`) - switch (storageMethod) { - case DROPBOX: - return uploadPhotoToDropbox(api, identityIndex, identityAddress, photoFile, photoIndex) - default: - return uploadPhotoToGaiaHub(api, identityIndex, identityAddress, photoFile, photoIndex) +function getProfileUploadLocation(identity: any, hubConfig: GaiaHubConfig) { + if (identity.zoneFile) { + const zoneFileJson = parseZoneFile(identity.zoneFile) + return getTokenFileUrlFromZoneFile(zoneFileJson) + } else { + return getFullReadUrl('profile.json', hubConfig) + } +} + +// aaron: this should be moved into blockstack.js +function canWriteUrl(url: string, + hubConfig: GaiaHubConfig): ?string { + const readPrefix = `${hubConfig.url_prefix}${hubConfig.address}/` + if (url.startsWith(readPrefix)) { + return url.substring(readPrefix.length) + } else { + return null + } +} + +function tryUpload(urlToWrite: string, data: string, + hubConfig: GaiaHubConfig, mimeType: ?string = undefined) { + const filenameWrite = canWriteUrl(urlToWrite, hubConfig) + if (filenameWrite === null) { + return null } + return uploadToGaiaHub(filenameWrite, data, hubConfig, mimeType) } -export function uploadProfile(api: {dropboxAccessToken: string, gaiaHubConfig: GaiaHubConfig }, - identityIndex: number, identityAddress: string, signedProfileTokenData: string, - firstUpload: boolean = false) { +export function uploadPhoto( + api: {dropboxAccessToken: string, gaiaHubConfig: GaiaHubConfig}, + identity: any, + identityIndex: number, identityAddress: string, photoFile: string, photoIndex: number) { checkIdentityInputs(identityIndex, identityAddress) - const storageMethod = getStorageMethod(api) + return connectToGaiaHub('') + .then((identityHubConfig) => { + const globalHubConfig = api.gaiaHubConfig - switch (storageMethod) { - case DROPBOX: - return uploadProfileToDropbox(api, identityIndex, identityAddress, - signedProfileTokenData, firstUpload) + let uploadPrefix = getProfileUploadLocation(identity, identityHubConfig) + if (uploadPrefix.endsWith('profile.json')) { + uploadPrefix = uploadPrefix.substring(0, uploadPrefix.length - 'profile.json'.length) + } else { + throw new Error(`Cannot determine photo location based on profile location ${uploadPrefix}`) + } + const urlToWrite = `${uploadPrefix}/avatar-${photoIndex}` + let uploadAttempt = tryUpload(urlToWrite, photoFile, identityHubConfig, undefined) + if (uploadAttempt === null) { + uploadAttempt = tryUpload(urlToWrite, photoFile, globalHubConfig, undefined) + } - default: - return uploadProfileToGaiaHub(api, identityIndex, identityAddress, - signedProfileTokenData) - } + // if still null, we don't know the write gaia-hub-config to write the file. + if (uploadAttempt === null) { + throw new Error(`Wanted to write to ${urlToWrite} but I don't know how.`) + } + + return uploadAttempt + }) +} + +export function uploadProfile( + api: {dropboxAccessToken: string, gaiaHubConfig: GaiaHubConfig }, + identity: any, + identityIndex: number, identityAddress: string, signedProfileTokenData: string) { + checkIdentityInputs(identityIndex, identityAddress) + + return connectToGaiaHub('') + .then((identityHubConfig) => { + const globalHubConfig = api.gaiaHubConfig + + const urlToWrite = getProfileUploadLocation(identity, identityHubConfig) + + let uploadAttempt = tryUpload(urlToWrite, signedProfileTokenData, + identityHubConfig, 'application/json') + if (uploadAttempt === null) { + uploadAttempt = tryUpload(urlToWrite, signedProfileTokenData, + globalHubConfig, 'application/json') + } + + // if still null, we don't know the write gaia-hub-config to write the file. + if (uploadAttempt === null) { + throw new Error(`Wanted to write to ${urlToWrite} but I don't know how.`) + } + + return uploadAttempt + }) } From 96b54e5dfde15ab8713ff44ffccd3bf1ee2cb58a Mon Sep 17 00:00:00 2001 From: Aaron Blankstein Date: Tue, 16 Jan 2018 17:09:36 -0500 Subject: [PATCH 07/24] update uploadProfile/uploadPhoto callers to pass the correct args, update tests --- app/js/account/utils/index.js | 46 ++++++------------- app/js/profiles/DefaultProfilePage.js | 12 ++--- app/js/profiles/EditProfilePage.js | 11 ++--- .../registration/RegistrationSelectView.js | 6 ++- app/js/profiles/store/registration/actions.js | 5 +- .../store/registration/actions/async.test.js | 30 +++++++++--- 6 files changed, 55 insertions(+), 55 deletions(-) diff --git a/app/js/account/utils/index.js b/app/js/account/utils/index.js index de3b35162..4d7a0265b 100644 --- a/app/js/account/utils/index.js +++ b/app/js/account/utils/index.js @@ -2,41 +2,25 @@ import { parseZoneFile } from 'zone-file' import type { GaiaHubConfig } from 'blockstack' -import { getFullReadUrl, connectToGaiaHub, uploadToGaiaHub } from 'blockstack' +import { connectToGaiaHub, uploadToGaiaHub } from 'blockstack' import { getTokenFileUrlFromZoneFile } from '../../utils/zone-utils' -import log4js from 'log4js' - -const logger = log4js.getLogger('account/utils/index.js') - export const BLOCKSTACK_INC = 'gaia-hub' export const DROPBOX = 'dropbox' -function checkIdentityInputs(identityIndex: number, identityAddress: string) { - if (!identityIndex && identityIndex !== 0) { - const message = 'checkIdentityInputs: No identity index provided' - logger.error(message) - throw new Error(message) - } - - if (!identityAddress) { - const message = 'checkIdentityInputs: No identity address provided' - logger.error(message) - throw new Error(message) - } -} - function getProfileUploadLocation(identity: any, hubConfig: GaiaHubConfig) { if (identity.zoneFile) { const zoneFileJson = parseZoneFile(identity.zoneFile) return getTokenFileUrlFromZoneFile(zoneFileJson) } else { - return getFullReadUrl('profile.json', hubConfig) + // aaron-debt: this should call a function in blockstack.js to get + // the read url + return `${hubConfig.url_prefix}${hubConfig.address}/profile.json` } } -// aaron: this should be moved into blockstack.js +// aaron-debt: this should be moved into blockstack.js function canWriteUrl(url: string, hubConfig: GaiaHubConfig): ?string { const readPrefix = `${hubConfig.url_prefix}${hubConfig.address}/` @@ -57,12 +41,10 @@ function tryUpload(urlToWrite: string, data: string, } export function uploadPhoto( - api: {dropboxAccessToken: string, gaiaHubConfig: GaiaHubConfig}, - identity: any, - identityIndex: number, identityAddress: string, photoFile: string, photoIndex: number) { - checkIdentityInputs(identityIndex, identityAddress) - - return connectToGaiaHub('') + api: {gaiaHubConfig: GaiaHubConfig, gaiaHubUrl: string}, + identity: any, identityKeyPair: {key: string}, + photoFile: string, photoIndex: number) { + return connectToGaiaHub(api.gaiaHubUrl, identityKeyPair.key) .then((identityHubConfig) => { const globalHubConfig = api.gaiaHubConfig @@ -88,12 +70,10 @@ export function uploadPhoto( } export function uploadProfile( - api: {dropboxAccessToken: string, gaiaHubConfig: GaiaHubConfig }, - identity: any, - identityIndex: number, identityAddress: string, signedProfileTokenData: string) { - checkIdentityInputs(identityIndex, identityAddress) - - return connectToGaiaHub('') + api: {gaiaHubConfig: GaiaHubConfig, gaiaHubUrl: string}, + identity: any, identityKeyPair: {key: string}, + signedProfileTokenData: string) { + return connectToGaiaHub(api.gaiaHubUrl, identityKeyPair.key) .then((identityHubConfig) => { const globalHubConfig = api.gaiaHubConfig diff --git a/app/js/profiles/DefaultProfilePage.js b/app/js/profiles/DefaultProfilePage.js index f4675cf42..7e903f85c 100644 --- a/app/js/profiles/DefaultProfilePage.js +++ b/app/js/profiles/DefaultProfilePage.js @@ -391,17 +391,17 @@ class DefaultProfilePage extends Component { const identityIndex = this.props.defaultIdentity const identity = this.props.localIdentities[identityIndex] const verifications = identity.verifications - const identityAddress = identity.ownerAddress const trustLevel = identity.trustLevel this.props.updateProfile(this.props.defaultIdentity, newProfile, verifications, trustLevel) logger.trace('saveProfile: Preparing to upload profile') logger.debug(`saveProfile: signing with key index ${identityIndex}`) - const signedProfileTokenData = signProfileForUpload(this.state.profile, - this.props.identityKeypairs[identityIndex]) + + const identitySigner = this.props.identityKeypairs[identityIndex] + const signedProfileTokenData = signProfileForUpload(this.state.profile, identitySigner) if (this.props.storageConnected) { - uploadProfile(this.props.api, identityIndex, identityAddress, signedProfileTokenData) + uploadProfile(this.props.api, identity, identitySigner, signedProfileTokenData) .catch((err) => { logger.error('saveProfile: profile not uploaded', err) }) @@ -423,13 +423,13 @@ class DefaultProfilePage extends Component { uploadProfilePhoto = (e) => { const identityIndex = this.props.defaultIdentity const identity = this.props.localIdentities[identityIndex] - const ownerAddress = identity.ownerAddress + const identitySigner = this.props.identityKeypairs[identityIndex] const profile = this.state.profile const photoIndex = 0 logger.debug('uploadProfilePhoto: trying to upload...') if (this.props.storageConnected) { - uploadPhoto(this.props.api, identityIndex, ownerAddress, e.target.files[0], photoIndex) + uploadPhoto(this.props.api, identity, identitySigner, e.target.files[0], photoIndex) .then((avatarUrl) => { logger.debug(`uploadProfilePhoto: uploaded photo: ${avatarUrl}`) profile.image = [] diff --git a/app/js/profiles/EditProfilePage.js b/app/js/profiles/EditProfilePage.js index 771ff9f57..152a4b2e3 100644 --- a/app/js/profiles/EditProfilePage.js +++ b/app/js/profiles/EditProfilePage.js @@ -263,17 +263,16 @@ class EditProfilePage extends Component { const identityIndex = this.props.routeParams.index const identity = this.props.localIdentities[identityIndex] const verifications = identity.verifications - const identityAddress = identity.ownerAddress const trustLevel = identity.trustLevel this.props.updateProfile(this.props.routeParams.index, newProfile, verifications, trustLevel) logger.trace('saveProfile: Preparing to upload profile') logger.debug(`saveProfile: signing with key index ${identityIndex}`) - const signedProfileTokenData = signProfileForUpload(this.state.profile, - this.props.identityKeypairs[identityIndex]) + const identitySigner = this.props.identityKeypairs[identityIndex] + const signedProfileTokenData = signProfileForUpload(this.state.profile, identitySigner) if (this.props.storageConnected) { - uploadProfile(this.props.api, identityIndex, identityAddress, signedProfileTokenData) + uploadProfile(this.props.api, identity, identitySigner, signedProfileTokenData) .catch((err) => { logger.error('saveProfile: profile not uploaded', err) }) @@ -284,13 +283,13 @@ class EditProfilePage extends Component { uploadProfilePhoto(e) { const identityIndex = this.state.index + const identitySigner = this.props.identityKeypairs[identityIndex] const identity = this.props.localIdentities[identityIndex] - const ownerAddress = identity.ownerAddress const profile = this.state.profile const photoIndex = 0 logger.debug('uploadProfilePhoto: trying to upload...') if (this.props.storageConnected) { - uploadPhoto(this.props.api, identityIndex, ownerAddress, e.target.files[0], photoIndex) + uploadPhoto(this.props.api, identity, identitySigner, e.target.files[0], photoIndex) .then((avatarUrl) => { logger.debug(`uploadProfilePhoto: uploaded photo: ${avatarUrl}`) profile.image = [] diff --git a/app/js/profiles/components/registration/RegistrationSelectView.js b/app/js/profiles/components/registration/RegistrationSelectView.js index 7cd5ff4f8..338fe3954 100644 --- a/app/js/profiles/components/registration/RegistrationSelectView.js +++ b/app/js/profiles/components/registration/RegistrationSelectView.js @@ -203,13 +203,15 @@ class AddUsernameSelectPage extends Component { logger.debug(`register: is ${name} a subdomain? ${nameIsSubdomain}`) if (nameIsSubdomain) { - this.props.registerName(this.props.api, name, index, address, keypair) + this.props.registerName(this.props.api, name, identity, + index, address, keypair) } else { const password = this.state.password const encryptedBackupPhrase = this.props.encryptedBackupPhrase decryptBitcoinPrivateKey(password, encryptedBackupPhrase) .then((paymentKey) => { - this.props.registerName(this.props.api, name, index, address, keypair, paymentKey) + this.props.registerName(this.props.api, name, identity, + index, address, keypair, paymentKey) }) .catch((error) => { this.setState({ diff --git a/app/js/profiles/store/registration/actions.js b/app/js/profiles/store/registration/actions.js index 80fd9cb1b..1b59227d4 100644 --- a/app/js/profiles/store/registration/actions.js +++ b/app/js/profiles/store/registration/actions.js @@ -87,7 +87,8 @@ function setOwnerKey(setOwnerKeyUrl, requestHeaders, keypair, nameIsSubdomain) { }) } -function registerName(api, domainName, identityIndex, ownerAddress, keypair, paymentKey = null) { +function registerName(api, domainName, identity, identityIndex, + ownerAddress, keypair, paymentKey = null) { logger.trace(`registerName: domainName: ${domainName}`) return dispatch => { logger.debug(`Signing a blank default profile for ${domainName}`) @@ -95,7 +96,7 @@ function registerName(api, domainName, identityIndex, ownerAddress, keypair, pay dispatch(profileUploading()) logger.trace(`Uploading ${domainName} profile...`) - return uploadProfile(api, identityIndex, ownerAddress, signedProfileTokenData) + return uploadProfile(api, identity, keypair, signedProfileTokenData) .then((profileUrl) => { logger.trace(`Uploading ${domainName} profiled succeeded.`) const tokenFileUrl = profileUrl diff --git a/tests/profiles/store/registration/actions/async.test.js b/tests/profiles/store/registration/actions/async.test.js index 20688b2e4..918d72a5b 100644 --- a/tests/profiles/store/registration/actions/async.test.js +++ b/tests/profiles/store/registration/actions/async.test.js @@ -128,10 +128,18 @@ describe('Registration Store: Async Actions', () => { unsafe: true, payment_key: `${paymentUncompressedPrivateKey}01`} + const mockHubInfoResponse = { "challenge_text": + "[\"gaiahub\",\"2018\",\"storage.blockstack.org\",\"blockstack_storage_please_sign\"]", + "read_url_prefix": + "https://gaia.blockstack.org/hub/" } + nock('https://hub.blockstack.org') + .get('/hub_info') + .reply(200, mockHubInfoResponse) + const mockResponseBody = {"publicURL":`https://gaia.blockstack.org/hub/1GnrEexgXvHCZobXDVdhpto6QPXKthN99n/0/profile.json`} // mock gaia hub nock('https://hub.blockstack.org') - .post(`/store/${BitcoinKeyPairs.test1.address}/0/profile.json`) + .post(`/store/${BitcoinKeyPairs.test1.address}/profile.json`) .reply(200, mockResponseBody) const mockGaiaConfig = { @@ -160,11 +168,12 @@ describe('Registration Store: Async Actions', () => { const mockAPI = Object.assign({}, DEFAULT_API, { hostedDataLocation: 'gaia-hub', - gaiaHubConfig: mockGaiaConfig.gaiaHubConfig + gaiaHubConfig: mockGaiaConfig.gaiaHubConfig, + gaiaHubUrl: 'https://hub.blockstack.org' }) return store.dispatch(RegistrationActions.registerName(mockAPI, - 'satoshi.id', 0, BitcoinKeyPairs.test1.address, keypair, paymentUncompressedPrivateKey)) + 'satoshi.id', {}, 0, BitcoinKeyPairs.test1.address, keypair, paymentUncompressedPrivateKey)) .then(() => { const expectedActions = [ { type: 'PROFILE_UPLOADING' }, @@ -242,10 +251,18 @@ describe('Registration Store: Async Actions', () => { const mockResponseBody = {"publicURL":`https://gaia.blockstack.org/hub/${BitcoinKeyPairs.test1.address}/0/profile.json`} // mock gaia hub nock('https://hub.blockstack.org') - .post(`/store/${BitcoinKeyPairs.test1.address}/0/profile.json`) + .post(`/store/${BitcoinKeyPairs.test1.address}/profile.json`) .reply(200, mockResponseBody) + const mockHubInfoResponse = { "challenge_text": + "[\"gaiahub\",\"2018\",\"storage.blockstack.org\",\"blockstack_storage_please_sign\"]", + "read_url_prefix": + "https://gaia.blockstack.org/hub/" } + nock('https://hub.blockstack.org') + .get('/hub_info') + .reply(200, mockHubInfoResponse) + const store = mockStore({ lastNameEntered: 'satoshi.id', names: {} @@ -262,11 +279,12 @@ describe('Registration Store: Async Actions', () => { const mockAPI = Object.assign({}, DEFAULT_API, { hostedDataLocation: 'gaia-hub', - gaiaHubConfig: mockGaiaConfig.gaiaHubConfig + gaiaHubConfig: mockGaiaConfig.gaiaHubConfig, + gaiaHubUrl: 'https://hub.blockstack.org' }) return store.dispatch(RegistrationActions.registerName(mockAPI, - 'satoshi.id', 0, BitcoinKeyPairs.test1.address, keypair)) + 'satoshi.id', {}, 0, BitcoinKeyPairs.test1.address, keypair)) .then(() => { assert(0, 'This promise is supposed to be rejected.') }) From 999081e098111eb95c9917f1d2ab5676e53a80ee Mon Sep 17 00:00:00 2001 From: Aaron Blankstein Date: Wed, 17 Jan 2018 11:52:26 -0500 Subject: [PATCH 08/24] intelligent reads. this passes tests, but that is misleading, because there should be more test-coverage in this spot --- app/js/profiles/store/identity/actions.js | 111 +++++++++++++++------- 1 file changed, 75 insertions(+), 36 deletions(-) diff --git a/app/js/profiles/store/identity/actions.js b/app/js/profiles/store/identity/actions.js index 052860516..375bb8310 100644 --- a/app/js/profiles/store/identity/actions.js +++ b/app/js/profiles/store/identity/actions.js @@ -208,6 +208,61 @@ function createNewProfile(encryptedBackupPhrase: string, } } +/** + * Try to fetch and verify a profile from the historic set of default locations, + * in order of recency. If all of them return 404s, or fail to validate, return null + */ +function fetchProfileLocations(gaiaUrlBase: string, + ownerAddress: string, + firstAddress: string, + ownerIndex: number) { + function recursiveTryFetch(locations) { + if (locations.length === 0) { + return Promise.resolve(null) + } + const location = locations[0] + return fetch(location) + .then(response => { + if (response.ok) { + return response.json() + .then(tokenRecords => getProfileFromTokens(tokenRecords, ownerAddress)) + .then(profile => { + if (profile) { + logger.debug(`Found valid profile at ${location}`) + return profile + } else { + logger.debug(`Failed to verify profile at ${location}... trying others`) + return recursiveTryFetch(locations.slice(1)) + } + }) + } else { + logger.debug(`Failed to find profile at ${location}... trying others`) + return recursiveTryFetch(locations.slice(1)) + } + }) + } + + const urls = [] + // the new default + urls.push(`${gaiaUrlBase}/${ownerAddress}/profile.json`) + + // the 'indexed' URL -- + // this is gaia/:firstAddress/:index/profile.json + // however, the index is _not_ equal to the current index. + // indexes were mapped from + // correct: [0, 1, 3, 5, 7, 9...] + // incorrect: [0, 1, 2, 3, 4, 5...] + + if (ownerIndex < 2) { + urls.push(`${gaiaUrlBase}/${firstAddress}/${ownerIndex}/profile.json`) + } else if (ownerIndex % 2 === 1) { + const buggedIndex = 1 + Math.floor(ownerIndex / 2) + urls.push(`${gaiaUrlBase}/${firstAddress}/${buggedIndex}/profile.json`) + } + + return recursiveTryFetch(urls) +} + /** * Checks each owner address to see if it owns a name, if it owns a name, * it resolves the profile and updates the state with the owner address's @@ -230,47 +285,31 @@ function refreshIdentities(api: {bitcoinAddressLookupUrl: string, .then((responseText) => JSON.parse(responseText)) .then((responseJson) => { if (responseJson.names.length === 0) { - logger.debug(`refreshIdentities: ${address} owns no names`) + logger.debug(`refreshIdentities: ${address} owns no names, checking default locations.`) const gaiaBucketAddress = ownerAddresses[0] - const profileUrlBase = `https://gaia.blockstack.org/hub/${gaiaBucketAddress}` - const profileUrl = `${profileUrlBase}/${index}/profile.json` - logger.debug(`refreshIdentities: check default storage for profile: ${profileUrl}`) - return fetch(profileUrl) - .then(response => { - if (response.ok) { - response.text() - .then(responseText => JSON.parse(responseText)) - .then((responseJsonProfile) => { - const tokenRecords = responseJsonProfile - const profile = getProfileFromTokens(tokenRecords, address) - if (profile) { - logger.debug(`refreshIdentities: found profile at ${profileUrl}`) - const zoneFile = '' - dispatch(updateProfile(index, profile, zoneFile)) - let verifications = [] - let trustLevel = 0 - logger.debug(`refreshIdentities: validating address proofs for ${address}`) - return validateProofsService(profile, address).then((proofs) => { - verifications = proofs - trustLevel = calculateTrustLevel(verifications) - dispatch(updateSocialProofVerifications(index, verifications, trustLevel)) - }) + return fetchProfileLocations('https://gaia.blockstack.org/hub', + address, gaiaBucketAddress, index) + .then(profile => { + if (profile) { + const zoneFile = '' + dispatch(updateProfile(index, profile, zoneFile)) + let verifications = [] + let trustLevel = 0 + logger.debug(`refreshIdentities: validating address proofs for ${address}`) + return validateProofsService(profile, address).then((proofs) => { + verifications = proofs + trustLevel = calculateTrustLevel(verifications) + dispatch(updateSocialProofVerifications(index, verifications, trustLevel)) + }) .catch((error) => { logger.error(`refreshIdentities: ${address} validateProofs: error`, error) return Promise.resolve() }) - } else { - resolve() - return Promise.resolve() - } - }) - return Promise.resolve() - } else { - logger.debug(`refreshIdentities: nothing found in default storage at ${profileUrl}`) - resolve() - return Promise.resolve() - } - }) + } else { + resolve() + return Promise.resolve() + } + }) } else { if (responseJson.names.length === 1) { logger.debug(`refreshIdentities: ${address} has 1 name}`) From 39d0c7b9e61ec61645c4fde018547166e9b4e1e6 Mon Sep 17 00:00:00 2001 From: Aaron Blankstein Date: Wed, 17 Jan 2018 14:25:21 -0500 Subject: [PATCH 09/24] update getProfileFromTokens to (optionally) fail on verification error, use that in the profile reading logic. add tests for profile reading --- app/js/profiles/store/identity/actions.js | 29 +-- app/js/utils/profile-utils.js | 8 +- .../store/identity/actions/async.test.js | 206 +++++++++++++++++- 3 files changed, 226 insertions(+), 17 deletions(-) diff --git a/app/js/profiles/store/identity/actions.js b/app/js/profiles/store/identity/actions.js index 375bb8310..c49322cd3 100644 --- a/app/js/profiles/store/identity/actions.js +++ b/app/js/profiles/store/identity/actions.js @@ -225,15 +225,14 @@ function fetchProfileLocations(gaiaUrlBase: string, .then(response => { if (response.ok) { return response.json() - .then(tokenRecords => getProfileFromTokens(tokenRecords, ownerAddress)) + .then(tokenRecords => getProfileFromTokens(tokenRecords, ownerAddress, false)) .then(profile => { - if (profile) { - logger.debug(`Found valid profile at ${location}`) - return profile - } else { - logger.debug(`Failed to verify profile at ${location}... trying others`) - return recursiveTryFetch(locations.slice(1)) - } + logger.debug(`Found valid profile at ${location}`) + return profile + }) + .catch(() => { + logger.debug(`Failed to verify profile at ${location}... trying others`) + return recursiveTryFetch(locations.slice(1)) }) } else { logger.debug(`Failed to find profile at ${location}... trying others`) @@ -296,14 +295,16 @@ function refreshIdentities(api: {bitcoinAddressLookupUrl: string, let verifications = [] let trustLevel = 0 logger.debug(`refreshIdentities: validating address proofs for ${address}`) - return validateProofsService(profile, address).then((proofs) => { - verifications = proofs - trustLevel = calculateTrustLevel(verifications) - dispatch(updateSocialProofVerifications(index, verifications, trustLevel)) - }) + return validateProofsService(profile, address) + .then((proofs) => { + verifications = proofs + trustLevel = calculateTrustLevel(verifications) + dispatch(updateSocialProofVerifications(index, verifications, trustLevel)) + resolve() + }) .catch((error) => { logger.error(`refreshIdentities: ${address} validateProofs: error`, error) - return Promise.resolve() + resolve() }) } else { resolve() diff --git a/app/js/utils/profile-utils.js b/app/js/utils/profile-utils.js index 20281c544..5d083f398 100644 --- a/app/js/utils/profile-utils.js +++ b/app/js/utils/profile-utils.js @@ -73,7 +73,7 @@ export function verifyTokenRecord(tokenRecord, publicKeyOrAddress) { return decodedToken } -export function getProfileFromTokens(tokenRecords, publicKeychain) { +export function getProfileFromTokens(tokenRecords, publicKeychain, silentVerify = true) { let profile = {} tokenRecords.map((tokenRecord) => { @@ -84,7 +84,11 @@ export function getProfileFromTokens(tokenRecords, publicKeychain) { decodedToken = decodeToken(tokenRecord.token) decodedToken = verifyTokenRecord(tokenRecord, publicKeychain) } catch (error) { - console.warn(error) + if (!silentVerify) { + throw error + } else { + console.warn(error) + } } if (decodedToken !== null) { diff --git a/tests/profiles/store/identity/actions/async.test.js b/tests/profiles/store/identity/actions/async.test.js index cd75b63a7..f66b91bd5 100644 --- a/tests/profiles/store/identity/actions/async.test.js +++ b/tests/profiles/store/identity/actions/async.test.js @@ -4,7 +4,8 @@ import nock from 'nock' import { IdentityActions } from '../../../../../app/js/profiles/store/identity' import DEFAULT_API from '../../../../../app/js/account/store/settings/default' import { NameLookups, TokenFileLookups } from '../../../../fixtures/profiles' - +import { DEFAULT_PROFILE, signProfileForUpload } from '../../../../../app/js/utils/profile-utils' +import { ECPair } from 'bitcoinjs-lib' const middlewares = [thunk] @@ -135,6 +136,209 @@ describe('Identity Store: Async Actions', () => { }) }) + it('checks default storage for profile if address owns no names, selects first if valid', () => { + // mock core + + const keypairs = [{ key: 'a29c3e73dba79ab0f84cb792bafd65ec71f243ebe67a7ebd842ef5cdce3b21eb', + keyID: '03e93ae65d6675061a167c34b8321bef87594468e9b2dd19c05a67a7b4caefa017', + address: '1JeTQ5cQjsD57YGcsVFhwT7iuQUXJR6BSk', + appsNodeKey: 'xprvA1y4zBndD83n6PWgVH6ivkTpNQ2WU1UGPg9hWa2q8sCANa7YrYMZFHWMhrbpsarxXMuQRa4jtaT2YXugwsKrjFgn765tUHu9XjyiDFEjB7f', + salt: 'c15619adafe7e75a195a1a2b5788ca42e585a3fd181ae2ff009c6089de54ed9e' }] + + const address = keypairs[0].address + nock(`https://gaia.blockstack.org`) + .get(`/hub/${address}/profile.json`) + .reply(200, signProfileForUpload(DEFAULT_PROFILE, keypairs[0])) + + nock(`https://gaia.blockstack.org`) + .get(`/hub/${address}/0/profile.json`) + .reply(200, signProfileForUpload( + { + "@context": "http://schema.org", + "@type": "Person", + "name":"Second" + }, + keypairs[0])) + + nock('http://localhost:6270') + .get(`/v1/addresses/bitcoin/${address}`) + .reply(200, { names: [] }, + { 'Content-Type': 'application/json' }) + + const store = mockStore(initialState) + + const mockAPI = Object.assign({}, DEFAULT_API, { + + }) + + const addresses = [address] + + return store.dispatch(IdentityActions.refreshIdentities(mockAPI, + addresses)) + .then(() => { + const expectedActions = [ + { + "index": 0, + "profile": DEFAULT_PROFILE, + "type": "UPDATE_PROFILE", + "zoneFile": "" + }, + { + "index": 0, + "trustLevel": 0, + "type": "UPDATE_SOCIAL_PROOF_VERIFICATIONS", + "verifications": [] + } + ] + + assert.deepEqual(store.getActions(), expectedActions) + }) + }) + + it('checks default storage for profile if address owns no names, ensures first is valid', () => { + // mock core + + const keypair = { key: 'a29c3e73dba79ab0f84cb792bafd65ec71f243ebe67a7ebd842ef5cdce3b21eb', + keyID: '03e93ae65d6675061a167c34b8321bef87594468e9b2dd19c05a67a7b4caefa017', + address: '1JeTQ5cQjsD57YGcsVFhwT7iuQUXJR6BSk', + appsNodeKey: 'xprvA1y4zBndD83n6PWgVH6ivkTpNQ2WU1UGPg9hWa2q8sCANa7YrYMZFHWMhrbpsarxXMuQRa4jtaT2YXugwsKrjFgn765tUHu9XjyiDFEjB7f', + salt: 'c15619adafe7e75a195a1a2b5788ca42e585a3fd181ae2ff009c6089de54ed9e' } + + // bad pair: + const ecPair = ECPair.makeRandom() + const badpair = { + address: ecPair.getAddress(), + key: ecPair.d.toBuffer(32).toString('hex'), + keyID: ecPair.getPublicKeyBuffer().toString('hex') + } + + const address = keypair.address + const secondProfile = { + "@context": "http://schema.org", + "@type": "Person", + "name":"Second" + } + nock(`https://gaia.blockstack.org`) + .get(`/hub/${address}/profile.json`) + .reply(200, signProfileForUpload(DEFAULT_PROFILE, badpair)) + + nock(`https://gaia.blockstack.org`) + .get(`/hub/${address}/0/profile.json`) + .reply(200, signProfileForUpload( + secondProfile, + keypair)) + + nock('http://localhost:6270') + .get(`/v1/addresses/bitcoin/${address}`) + .reply(200, { names: [] }, + { 'Content-Type': 'application/json' }) + + const store = mockStore(initialState) + + const mockAPI = Object.assign({}, DEFAULT_API, { + + }) + + const addresses = [address] + + return store.dispatch(IdentityActions.refreshIdentities(mockAPI, + addresses)) + .then(() => { + const expectedActions = [ + { + "index": 0, + "profile": secondProfile, + "type": "UPDATE_PROFILE", + "zoneFile": "" + }, + { + "index": 0, + "trustLevel": 0, + "type": "UPDATE_SOCIAL_PROOF_VERIFICATIONS", + "verifications": [] + } + ] + + assert.deepEqual(store.getActions(), expectedActions) + }) + }) + + + it('checks default storage for profile if address owns no names, uses 2nd if first not found, and uses correct old index.', () => { + // mock core + + const keypair = { key: 'a29c3e73dba79ab0f84cb792bafd65ec71f243ebe67a7ebd842ef5cdce3b21eb', + keyID: '03e93ae65d6675061a167c34b8321bef87594468e9b2dd19c05a67a7b4caefa017', + address: '1JeTQ5cQjsD57YGcsVFhwT7iuQUXJR6BSk', + appsNodeKey: 'xprvA1y4zBndD83n6PWgVH6ivkTpNQ2WU1UGPg9hWa2q8sCANa7YrYMZFHWMhrbpsarxXMuQRa4jtaT2YXugwsKrjFgn765tUHu9XjyiDFEjB7f', + salt: 'c15619adafe7e75a195a1a2b5788ca42e585a3fd181ae2ff009c6089de54ed9e' } + + // bad pair: + const ecPair = ECPair.makeRandom() + const badpair = { + address: ecPair.getAddress(), + key: ecPair.d.toBuffer(32).toString('hex'), + keyID: ecPair.getPublicKeyBuffer().toString('hex') + } + + const dummyAddress = '18AJ31xprVk8u2KqT18NvbmUgkYo9MPYD6' + const address = keypair.address + + const secondProfile = { + "@context": "http://schema.org", + "@type": "Person", + "name":"Second" + } + nock(`https://gaia.blockstack.org`) + .get(`/hub/${address}/profile.json`) + .reply(404, 'Not found') + + // the _tested_ index is 3, which should map to /2/ + nock(`https://gaia.blockstack.org`) + .get(`/hub/${dummyAddress}/2/profile.json`) + .reply(200, signProfileForUpload( + secondProfile, + keypair)) + + nock('http://localhost:6270') + .get(`/v1/addresses/bitcoin/${address}`) + .reply(200, { names: [] }, + { 'Content-Type': 'application/json' }) + + nock('http://localhost:6270') + .get(`/v1/addresses/bitcoin/${dummyAddress}`) + .reply(200, { names: [] }, + { 'Content-Type': 'application/json' }) + + const store = mockStore(initialState) + + const mockAPI = Object.assign({}, DEFAULT_API, { + + }) + + const addresses = [dummyAddress, dummyAddress, dummyAddress, address] + + return store.dispatch(IdentityActions.refreshIdentities(mockAPI, + addresses)) + .then(() => { + const expectedActions = [ + { + "index": 3, + "profile": secondProfile, + "type": "UPDATE_PROFILE", + "zoneFile": "" + }, + { + "index": 3, + "trustLevel": 0, + "type": "UPDATE_SOCIAL_PROOF_VERIFICATIONS", + "verifications": [] + } + ] + + assert.deepEqual(store.getActions(), expectedActions) + }) + }) describe('fetchPublicIdentity', () => { it('fetches profile & validates proof of given identity from the public network', () => { From ef9b27fcfe247f6e0b3244606b0c2a4f093438bc Mon Sep 17 00:00:00 2001 From: Aaron Blankstein Date: Wed, 17 Jan 2018 15:57:57 -0500 Subject: [PATCH 10/24] fix parameters passed to updateProfile: this was corrupting the .zoneFile entry in the component props -- only materialized as a bug in this branch because we use the zoneFile to determine where to write --- app/js/profiles/DefaultProfilePage.js | 4 +--- app/js/profiles/EditProfilePage.js | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/app/js/profiles/DefaultProfilePage.js b/app/js/profiles/DefaultProfilePage.js index 7e903f85c..c7ff5fbfc 100644 --- a/app/js/profiles/DefaultProfilePage.js +++ b/app/js/profiles/DefaultProfilePage.js @@ -390,10 +390,8 @@ class DefaultProfilePage extends Component { const identityIndex = this.props.defaultIdentity const identity = this.props.localIdentities[identityIndex] - const verifications = identity.verifications - const trustLevel = identity.trustLevel - this.props.updateProfile(this.props.defaultIdentity, newProfile, verifications, trustLevel) + this.props.updateProfile(this.props.defaultIdentity, newProfile, identity.zoneFile) logger.trace('saveProfile: Preparing to upload profile') logger.debug(`saveProfile: signing with key index ${identityIndex}`) diff --git a/app/js/profiles/EditProfilePage.js b/app/js/profiles/EditProfilePage.js index 152a4b2e3..552e38e94 100644 --- a/app/js/profiles/EditProfilePage.js +++ b/app/js/profiles/EditProfilePage.js @@ -262,10 +262,8 @@ class EditProfilePage extends Component { const identityIndex = this.props.routeParams.index const identity = this.props.localIdentities[identityIndex] - const verifications = identity.verifications - const trustLevel = identity.trustLevel - this.props.updateProfile(this.props.routeParams.index, newProfile, verifications, trustLevel) + this.props.updateProfile(this.props.routeParams.index, newProfile, identity.zoneFile) logger.trace('saveProfile: Preparing to upload profile') logger.debug(`saveProfile: signing with key index ${identityIndex}`) From 25c37807f2afecf7ccf3d26156e5adc49f70ba7b Mon Sep 17 00:00:00 2001 From: Aaron Blankstein Date: Wed, 17 Jan 2018 16:46:11 -0500 Subject: [PATCH 11/24] tests for writing profiles to the zonefile location, the default location, and error case --- tests/account/utils.test.js | 106 ++++++++++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 tests/account/utils.test.js diff --git a/tests/account/utils.test.js b/tests/account/utils.test.js new file mode 100644 index 000000000..19e694817 --- /dev/null +++ b/tests/account/utils.test.js @@ -0,0 +1,106 @@ +import { + uploadPhoto, uploadProfile + } from '../../app/js/account/utils' +import { ECPair } from 'bitcoinjs-lib' +import { BitcoinKeyPairs } from '../fixtures/bitcoin' +import nock from 'nock' + +const mockHubInfoResponse = { "challenge_text": + "[\"gaiahub\",\"2018\",\"storage.blockstack.org\",\"blockstack_storage_please_sign\"]", + "read_url_prefix": + "https://gaia.blockstack.org/hub/" } + +const globalAPIConfig = { + gaiaHubConfig: { + address: '15GAGiT2j2F1EzZrvjk3B8vBCfwVEzQaZx', + server: 'https://hub.blockstack.org', + token: 'dummy-token', + url_prefix: 'https://gaia.blockstack.org/hub/' + }, + gaiaHubUrl: 'https://hub.blockstack.org' +} + +describe('upload-profile', () => { + beforeEach(() => { + nock('https://hub.blockstack.org') + .get('/hub_info') + .reply(200, mockHubInfoResponse) + + }) + + afterEach(() => { + }) + + describe('uploadProfile', () => { + it('should upload to the zonefile entry location, using the global uploader if necessary', () => { + const ecPair = ECPair.fromWIF(BitcoinKeyPairs.test1.wif) + const address = ecPair.getAddress() + const key = ecPair.d.toBuffer(32).toString('hex') + const keyPair = { + address, + key + } + + const hubAddress = globalAPIConfig.gaiaHubConfig.address + + const mockResponseBody = {"publicURL":`https://gaia.blockstack.org/hub/${hubAddress}/foo-profile.json`} + // mock gaia hub + nock('https://hub.blockstack.org') + .post(`/store/${hubAddress}/foo-profile.json`) + .reply(200, mockResponseBody) + + const zoneFile = `$ORIGIN satoshi.id\n$TTL 3600\n_http._tcp\tIN\tURI\t10\t1\t"https://gaia.blockstack.org/hub/${hubAddress}/foo-profile.json"\n\n` + + const identity = { zoneFile } + + uploadProfile(globalAPIConfig, identity, keyPair, 'test-data') + .then(x => assert.equal( + 'https://gaia.blockstack.org/hub/15GAGiT2j2F1EzZrvjk3B8vBCfwVEzQaZx/foo-profile.json', x)) + .catch(() => assert.fail()) + }) + + it('should upload to the default entry location if no zonefile', () => { + const ecPair = ECPair.fromWIF(BitcoinKeyPairs.test1.wif) + const address = ecPair.getAddress() + const key = ecPair.d.toBuffer(32).toString('hex') + const keyPair = { + address, + key + } + + const mockResponseBody = {"publicURL":`https://gaia.blockstack.org/hub/${address}/profile.json`} + // mock gaia hub + nock('https://hub.blockstack.org') + .post(`/store/${address}/profile.json`) + .reply(200, mockResponseBody) + + const identity = {} + + uploadProfile(globalAPIConfig, identity, keyPair, 'test-data') + .then(x => assert.equal( + `https://gaia.blockstack.org/hub/${address}/profile.json`, x)) + .catch(() => assert.fail()) + }) + + it('should error if it cannot write to where the zonefile points', () => { + const ecPair = ECPair.fromWIF(BitcoinKeyPairs.test1.wif) + const address = ecPair.getAddress() + const key = ecPair.d.toBuffer(32).toString('hex') + const keyPair = { + address, + key + } + + const zoneFile = `$ORIGIN satoshi.id\n$TTL 3600\n_http._tcp\tIN\tURI\t10\t1\t"https://potato.blockstack.org/hub/${address}/foo-profile.json"\n\n` + + const identity = { zoneFile } + + uploadProfile(globalAPIConfig, identity, keyPair, 'test-data') + .then(x => assert.equal( + `https://gaia.blockstack.org/hub/${address}/profile.json`, x)) + .catch(() => assert.fail()) + }) + + }) + +}) From 2984b773cb794be1b73d1115b28a014984f6ac59 Mon Sep 17 00:00:00 2001 From: Aaron Blankstein Date: Wed, 17 Jan 2018 18:07:33 -0500 Subject: [PATCH 12/24] catch errors in profile reads + a little less talking from nock misses in tests --- app/js/profiles/store/identity/actions.js | 4 ++++ .../store/identity/actions/async.test.js | 23 ++++++++++++++++--- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/app/js/profiles/store/identity/actions.js b/app/js/profiles/store/identity/actions.js index c49322cd3..819fe70b8 100644 --- a/app/js/profiles/store/identity/actions.js +++ b/app/js/profiles/store/identity/actions.js @@ -239,6 +239,10 @@ function fetchProfileLocations(gaiaUrlBase: string, return recursiveTryFetch(locations.slice(1)) } }) + .catch(() => { + logger.debug(`Error in fetching profile at ${location}... trying others`) + return recursiveTryFetch(locations.slice(1)) + }) } const urls = [] diff --git a/tests/profiles/store/identity/actions/async.test.js b/tests/profiles/store/identity/actions/async.test.js index f66b91bd5..b2dd6562a 100644 --- a/tests/profiles/store/identity/actions/async.test.js +++ b/tests/profiles/store/identity/actions/async.test.js @@ -73,9 +73,10 @@ describe('Identity Store: Async Actions', () => { .get('/v1/addresses/bitcoin/18AJ31xprVk8u2KqT18NvbmUgkYo9MPYD6') .reply(200, { names: ['guylepage.id'] }, { 'Content-Type': 'application/json' }) - // .get('/v1/names/guylepage.id') - // .reply(200, NameLookups['guylepage.id'], - // { 'Content-Type': 'application/json' }) + + nock('http://localhost:6270') + .get('/v1/names/guylepage.id') + .reply(404, '') // const nockAWS = nock('https://blockstack.s3.amazonaws.com') // .get('/guylepage.id') @@ -289,10 +290,16 @@ describe('Identity Store: Async Actions', () => { "@type": "Person", "name":"Second" } + nock(`https://gaia.blockstack.org`) .get(`/hub/${address}/profile.json`) .reply(404, 'Not found') + nock(`https://gaia.blockstack.org`) + .get(`/hub/${dummyAddress}/profile.json`) + .times(3) + .reply(404, 'Not found') + // the _tested_ index is 3, which should map to /2/ nock(`https://gaia.blockstack.org`) .get(`/hub/${dummyAddress}/2/profile.json`) @@ -307,6 +314,7 @@ describe('Identity Store: Async Actions', () => { nock('http://localhost:6270') .get(`/v1/addresses/bitcoin/${dummyAddress}`) + .times(3) .reply(200, { names: [] }, { 'Content-Type': 'application/json' }) @@ -345,6 +353,7 @@ describe('Identity Store: Async Actions', () => { // mock core nock('http://localhost:6270') + .persist() .get('/v1/names/guylepage.id') .reply(200, NameLookups['guylepage.id'], { 'Content-Type': 'application/json' }) @@ -364,6 +373,10 @@ describe('Identity Store: Async Actions', () => { .get('/g3lepage/posts/10154179855498760') .reply(200, 'verifying that guylepage.id is my blockstack id') + nock('https://www.facebook.com') + .get('/g3lepage/posts/undefined') + .reply(404, '') + nock('https://www.facebook.com') .persist() .get('/plugins/post.php?href=https%3A%2F%2Fwww.facebook.com%2Fg3lepage%2Fposts%2F10154179855498760') @@ -373,6 +386,10 @@ describe('Identity Store: Async Actions', () => { .get('/guylepage3/48777a21a70d322b0fa4c1fcc53f4477') .reply(200, 'verifying that guylepage.id is my blockstack id') + nock('https://gist.github.com') + .get('/guylepage3/48777a21a70d322b0fa4c1fcc53f4477/raw') + .reply(404, '') + const store = mockStore(initialState) const mockAPI = Object.assign({}, DEFAULT_API, { From 06d6f702309cebc79fcc6dd52b935848e83b978a Mon Sep 17 00:00:00 2001 From: Larry Salibra Date: Mon, 22 Jan 2018 19:13:02 +0800 Subject: [PATCH 13/24] display app origin on a new line #1147 #1148 --- app/js/auth/components/AuthModal.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/js/auth/components/AuthModal.js b/app/js/auth/components/AuthModal.js index 0eeff6b22..3b99cf66f 100644 --- a/app/js/auth/components/AuthModal.js +++ b/app/js/auth/components/AuthModal.js @@ -513,8 +513,9 @@ class AuthModal extends Component {

: null} -

The app "{appManifest.name}" located at - {decodedToken.payload.domain_name} wants to

+

The app "{appManifest.name}" located at
+ {decodedToken.payload.domain_name}
+ wants to:

Read your basic info From 5713763e39755aae0c4cd3ef6f520c74a6d16401 Mon Sep 17 00:00:00 2001 From: Ken Date: Mon, 22 Jan 2018 13:58:43 -0500 Subject: [PATCH 14/24] Fix duplicated profiles when creating new ID. #1040 #1173. --- app/js/profiles/store/identity/reducer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/js/profiles/store/identity/reducer.js b/app/js/profiles/store/identity/reducer.js index a648d2dcb..f2b27afa1 100644 --- a/app/js/profiles/store/identity/reducer.js +++ b/app/js/profiles/store/identity/reducer.js @@ -35,7 +35,7 @@ function IdentityReducer(state = initialState, action) { username: null, usernameOwned: false, usernamePending: false, - profile: DEFAULT_PROFILE, + profile: Object.assign({}, DEFAULT_PROFILE), verifications: [], trustLevel: 0, registered: false, From dbbd98d5efe03ff7e59e9e2115e301d8da79ae17 Mon Sep 17 00:00:00 2001 From: Larry Salibra Date: Wed, 24 Jan 2018 22:08:05 +0800 Subject: [PATCH 15/24] mock profile fetch urls --- tests/profiles/store/identity/actions/async.test.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/profiles/store/identity/actions/async.test.js b/tests/profiles/store/identity/actions/async.test.js index eb36d0bb8..d9f6726d7 100644 --- a/tests/profiles/store/identity/actions/async.test.js +++ b/tests/profiles/store/identity/actions/async.test.js @@ -22,8 +22,13 @@ const initialState = { } describe('Identity Store: Async Actions', () => { + beforeEach(() => { + nock.disableNetConnect() + }) + afterEach(() => { nock.cleanAll() + nock.enableNetConnect() }) describe('createNewProfile', () => { @@ -126,6 +131,14 @@ describe('Identity Store: Async Actions', () => { const localIdentities = {} const namesOwned = [] + nock(`https://gaia.blockstack.org`) + .get(`/hub/${addresses[0]}/profile.json`) + .reply(404) + + nock(`https://gaia.blockstack.org`) + .get(`/hub/${addresses[0]}/0/profile.json`) + .reply(404) + return store.dispatch(IdentityActions.refreshIdentities(mockAPI, addresses, localIdentities, namesOwned)) .then(() => { From 8f9f63619d9eb0f15b784982b2804d0066593ed4 Mon Sep 17 00:00:00 2001 From: Larry Salibra Date: Fri, 26 Jan 2018 15:41:18 +0800 Subject: [PATCH 16/24] remove dropbox sdk --- package-lock.json | 327 ++++------------------------------------------ package.json | 1 - 2 files changed, 29 insertions(+), 299 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3a33feb8e..30ca102b3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "blockstack-browser", - "version": "0.21.6", + "version": "0.22.1", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -103,15 +103,6 @@ "integrity": "sha1-q11PuIP1loFtNRX495HAr0ht1ic=", "dev": true }, - "agent-base": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-2.1.1.tgz", - "integrity": "sha1-1t4Q1a9hMtW9aSQn1G/FOFOQlMc=", - "requires": { - "extend": "3.0.1", - "semver": "5.0.3" - } - }, "ajv": { "version": "4.11.8", "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz", @@ -440,11 +431,6 @@ "integrity": "sha1-E8pRXYYgbaC6xm6DTdOX2HWBCUw=", "dev": true }, - "ast-types": { - "version": "0.9.13", - "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.9.13.tgz", - "integrity": "sha512-72w1vrspLfSP4htDZWMgDya3gz7VFIojiaxWdXfJkpR/KouBvJZ2xoHxG79VwdGr8ZdG/b6zgwqoIG24QtRqCQ==" - }, "astw": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/astw/-/astw-2.2.0.tgz", @@ -4971,7 +4957,8 @@ "component-emitter": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", - "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=" + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", + "dev": true }, "component-inherit": { "version": "0.0.3", @@ -5237,11 +5224,6 @@ "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=", "dev": true }, - "cookiejar": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.1.tgz", - "integrity": "sha1-Qa1XsbVVlR7BcUEqgZQrHoIA00o=" - }, "core-js": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz", @@ -5749,11 +5731,6 @@ "assert-plus": "1.0.0" } }, - "data-uri-to-buffer": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-1.2.0.tgz", - "integrity": "sha512-vKQ9DTQPN1FLYiiEEOQ6IBGFqvjCa5rSK3cWMy/Nespm5d/x3dGFT9UBZnkLxCwua/IXBi2TYnwTEpsOvhC4UQ==" - }, "date-format": { "version": "0.0.0", "resolved": "https://registry.npmjs.org/date-format/-/date-format-0.0.0.tgz", @@ -6411,7 +6388,8 @@ "deep-is": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=" + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true }, "defaults": { "version": "1.0.3", @@ -6437,16 +6415,6 @@ "resolved": "https://registry.npmjs.org/defined/-/defined-0.0.0.tgz", "integrity": "sha1-817qfXBekzuvE7LwOz+D2SFAOz4=" }, - "degenerator": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-1.0.4.tgz", - "integrity": "sha1-/PSQo37OJmRk2cxDGrmMWBnO0JU=", - "requires": { - "ast-types": "0.9.13", - "escodegen": "1.9.0", - "esprima": "3.1.3" - } - }, "del": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz", @@ -6887,51 +6855,6 @@ } } }, - "dropbox": { - "version": "2.5.11", - "resolved": "https://registry.npmjs.org/dropbox/-/dropbox-2.5.11.tgz", - "integrity": "sha1-9i63f7TSvm7CQBXavJHS118/+F4=", - "requires": { - "es6-promise": "4.1.1", - "mime": "2.0.3", - "superagent": "3.6.3", - "superagent-proxy": "1.0.2" - }, - "dependencies": { - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "requires": { - "ms": "2.0.0" - } - }, - "superagent": { - "version": "3.6.3", - "resolved": "https://registry.npmjs.org/superagent/-/superagent-3.6.3.tgz", - "integrity": "sha512-GjsfCFijfjqoz2tRiStSOoTdy7gNZOcK3ar4zONP9D8dXQWE+Qg7cbePHimRpapo06WUvoU3dmgi2e4q+sab5A==", - "requires": { - "component-emitter": "1.2.1", - "cookiejar": "2.1.1", - "debug": "3.1.0", - "extend": "3.0.1", - "form-data": "2.3.1", - "formidable": "1.1.1", - "methods": "1.1.2", - "mime": "1.4.1", - "qs": "6.5.1", - "readable-stream": "2.3.3" - }, - "dependencies": { - "mime": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", - "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==" - } - } - } - } - }, "duplexer2": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz", @@ -7313,14 +7236,6 @@ "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.1.1.tgz", "integrity": "sha512-OaU1hHjgJf+b0NzsxCg7NdIYERD6Hy/PEmFLTjw+b65scuisG3Kt4QoTvJ66BBkPZ581gr0kpoVzKnxniM8nng==" }, - "es6-promisify": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", - "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", - "requires": { - "es6-promise": "4.1.1" - } - }, "es6-set": { "version": "0.1.5", "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.5.tgz", @@ -7417,6 +7332,7 @@ "version": "1.9.0", "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.9.0.tgz", "integrity": "sha512-v0MYvNQ32bzwoG2OSFzWAkuahDQHK92JBN0pTAALJ4RIxEZe766QJPDR8Hqy7XNUy5K3fnVL76OqYAdc4TZEIw==", + "dev": true, "requires": { "esprima": "3.1.3", "estraverse": "4.2.0", @@ -7687,7 +7603,8 @@ "esprima": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz", - "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=" + "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=", + "dev": true }, "esrecurse": { "version": "4.2.0", @@ -7702,12 +7619,14 @@ "estraverse": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", - "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=" + "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", + "dev": true }, "esutils": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", - "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=" + "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", + "dev": true }, "etag": { "version": "1.8.1", @@ -8058,7 +7977,8 @@ "fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=" + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true }, "fastparse": { "version": "1.1.1", @@ -8159,11 +8079,6 @@ "integrity": "sha1-JXoHg4TR24CHvESdEH1SpSZyuek=", "dev": true }, - "file-uri-to-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", - "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==" - }, "filename-regex": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz", @@ -8681,11 +8596,6 @@ "samsam": "1.1.2" } }, - "formidable": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.1.1.tgz", - "integrity": "sha1-lriIb3w8NQi5Mta9cMTTqI818ak=" - }, "forwarded": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", @@ -9661,38 +9571,6 @@ } } }, - "ftp": { - "version": "0.3.10", - "resolved": "https://registry.npmjs.org/ftp/-/ftp-0.3.10.tgz", - "integrity": "sha1-kZfYYa2BQvPmPVqDv+TFn3MwiF0=", - "requires": { - "readable-stream": "1.1.14", - "xregexp": "2.0.0" - }, - "dependencies": { - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" - }, - "readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", - "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "0.0.1", - "string_decoder": "0.10.31" - } - }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" - } - } - }, "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", @@ -9775,19 +9653,6 @@ "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", "dev": true }, - "get-uri": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-2.0.1.tgz", - "integrity": "sha512-7aelVrYqCLuVjq2kEKRTH8fXPTC0xKTkM+G7UlFkEwCXY3sFbSxvY375JoFowOAYbkaU47SrBvOefUlLZZ+6QA==", - "requires": { - "data-uri-to-buffer": "1.2.0", - "debug": "2.6.9", - "extend": "3.0.1", - "file-uri-to-path": "1.0.0", - "ftp": "0.3.10", - "readable-stream": "2.3.3" - } - }, "getpass": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", @@ -11397,16 +11262,6 @@ "requires-port": "1.0.0" } }, - "http-proxy-agent": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-1.0.0.tgz", - "integrity": "sha1-zBzjjkU7+YSg93AtLdWcc9CBKEo=", - "requires": { - "agent-base": "2.1.1", - "debug": "2.6.9", - "extend": "3.0.1" - } - }, "http-signature": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", @@ -11423,16 +11278,6 @@ "integrity": "sha1-P5E2XKvmC3ftDruiS0VOPgnZWoI=", "dev": true }, - "https-proxy-agent": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-1.0.0.tgz", - "integrity": "sha1-NffabEjOTdv6JkiRrFk+5f+GceY=", - "requires": { - "agent-base": "2.1.1", - "debug": "2.6.9", - "extend": "3.0.1" - } - }, "iced-error": { "version": "0.0.12", "resolved": "https://registry.npmjs.org/iced-error/-/iced-error-0.0.12.tgz", @@ -12238,11 +12083,6 @@ "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=", "dev": true }, - "ip": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", - "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=" - }, "ip-regex": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-1.0.3.tgz", @@ -13289,6 +13129,7 @@ "version": "0.3.0", "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dev": true, "requires": { "prelude-ls": "1.1.2", "type-check": "0.3.2" @@ -14398,7 +14239,8 @@ "methods": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", + "dev": true }, "micromatch": { "version": "2.3.11", @@ -14434,7 +14276,8 @@ "mime": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/mime/-/mime-2.0.3.tgz", - "integrity": "sha512-TrpAd/vX3xaLPDgVRm6JkZwLR0KHfukMdU2wTEbqMDdCnY6Yo3mE+mjs9YE6oMNw2QRfXVeBEYpmpO94BIqiug==" + "integrity": "sha512-TrpAd/vX3xaLPDgVRm6JkZwLR0KHfukMdU2wTEbqMDdCnY6Yo3mE+mjs9YE6oMNw2QRfXVeBEYpmpO94BIqiug==", + "dev": true }, "mime-db": { "version": "1.30.0", @@ -14710,11 +14553,6 @@ "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=", "dev": true }, - "netmask": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/netmask/-/netmask-1.0.6.tgz", - "integrity": "sha1-ICl+idhvb2QA8lDZ9Pa0wZRfzTU=" - }, "next-tick": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-0.2.2.tgz", @@ -15301,6 +15139,7 @@ "version": "0.8.2", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", + "dev": true, "requires": { "deep-is": "0.1.3", "fast-levenshtein": "2.0.6", @@ -15492,54 +15331,6 @@ "p-finally": "1.0.0" } }, - "pac-proxy-agent": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-2.0.0.tgz", - "integrity": "sha512-t57UiJpi5mFLTvjheC1SNSwIhml3+ElNOj69iRrydtQXZJr8VIFYSDtyPi/3ZysA62kD2dmww6pDlzk0VaONZg==", - "requires": { - "agent-base": "2.1.1", - "debug": "2.6.9", - "get-uri": "2.0.1", - "http-proxy-agent": "1.0.0", - "https-proxy-agent": "1.0.0", - "pac-resolver": "3.0.0", - "raw-body": "2.3.2", - "socks-proxy-agent": "3.0.1" - }, - "dependencies": { - "socks-proxy-agent": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-3.0.1.tgz", - "integrity": "sha512-ZwEDymm204mTzvdqyUqOdovVr2YRd2NYskrYrF2LXyZ9qDiMAoFESGK8CRphiO7rtbo2Y757k2Nia3x2hGtalA==", - "requires": { - "agent-base": "4.1.1", - "socks": "1.1.10" - }, - "dependencies": { - "agent-base": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.1.1.tgz", - "integrity": "sha512-yWGUUmCZD/33IRjG2It94PzixT8lX+47Uq8fjmd0cgQWITCMrJuXFaVIMnGDmDnZGGKAGdwTx8UGeU8lMR2urA==", - "requires": { - "es6-promisify": "5.0.0" - } - } - } - } - } - }, - "pac-resolver": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-3.0.0.tgz", - "integrity": "sha512-tcc38bsjuE3XZ5+4vP96OfhOugrX+JcnpUbhfuc4LuXBLQhoTthOstZeoQJBDnQUDYzYmdImKsbz0xSl1/9qeA==", - "requires": { - "co": "4.6.0", - "degenerator": "1.0.4", - "ip": "1.1.5", - "netmask": "1.0.6", - "thunkify": "2.1.2" - } - }, "package-json": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/package-json/-/package-json-0.2.0.tgz", @@ -16492,7 +16283,8 @@ "prelude-ls": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=" + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "dev": true }, "prepend-http": { "version": "1.0.4", @@ -16593,28 +16385,6 @@ "ipaddr.js": "1.5.2" } }, - "proxy-agent": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-2.1.0.tgz", - "integrity": "sha512-I23qaUnXmU/ItpXWQcMj9wMcZQTXnJNI7nakSR+q95Iht8H0+w3dCgTJdfnOQqOCX1FZwKLSgurCyEt11LM6OA==", - "requires": { - "agent-base": "2.1.1", - "debug": "2.6.9", - "extend": "3.0.1", - "http-proxy-agent": "1.0.0", - "https-proxy-agent": "1.0.0", - "lru-cache": "2.6.5", - "pac-proxy-agent": "2.0.0", - "socks-proxy-agent": "2.1.1" - }, - "dependencies": { - "lru-cache": { - "version": "2.6.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.6.5.tgz", - "integrity": "sha1-5W1jVBSO3o13B7WNFDIg/QjfD9U=" - } - } - }, "pseudomap": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", @@ -18096,7 +17866,8 @@ "semver": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/semver/-/semver-5.0.3.tgz", - "integrity": "sha1-d0Zt5YnNXTyV8TiqeLxWmjy10no=" + "integrity": "sha1-d0Zt5YnNXTyV8TiqeLxWmjy10no=", + "dev": true }, "semver-diff": { "version": "0.1.0", @@ -18448,11 +18219,6 @@ } } }, - "smart-buffer": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-1.1.15.tgz", - "integrity": "sha1-fxFLW2X6s+KjWqd1uxLw0cZJvxY=" - }, "smart-mixin": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/smart-mixin/-/smart-mixin-2.0.0.tgz", @@ -18617,25 +18383,6 @@ } } }, - "socks": { - "version": "1.1.10", - "resolved": "https://registry.npmjs.org/socks/-/socks-1.1.10.tgz", - "integrity": "sha1-W4t/x8jzQcU+0FbpKbe/Tei6e1o=", - "requires": { - "ip": "1.1.5", - "smart-buffer": "1.1.15" - } - }, - "socks-proxy-agent": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-2.1.1.tgz", - "integrity": "sha512-sFtmYqdUK5dAMh85H0LEVFUCO7OhJJe1/z2x/Z6mxp3s7/QPf1RkZmpZy+BpuU0bEjcV9npqKjq9Y3kwFUjnxw==", - "requires": { - "agent-base": "2.1.1", - "extend": "3.0.1", - "socks": "1.1.10" - } - }, "sort-keys": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz", @@ -18654,7 +18401,8 @@ "source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true }, "source-map-resolve": { "version": "0.3.1", @@ -19333,15 +19081,6 @@ } } }, - "superagent-proxy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/superagent-proxy/-/superagent-proxy-1.0.2.tgz", - "integrity": "sha1-ktNmBXj2GO1DqCz4yseZ/ik4ui0=", - "requires": { - "debug": "2.6.9", - "proxy-agent": "2.1.0" - } - }, "supports-color": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", @@ -19626,11 +19365,6 @@ "xtend": "4.0.1" } }, - "thunkify": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/thunkify/-/thunkify-2.1.2.tgz", - "integrity": "sha1-+qDp0jDFGsyVyhOjYawFyn4EVT0=" - }, "tildify": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/tildify/-/tildify-1.2.0.tgz", @@ -19856,6 +19590,7 @@ "version": "0.3.2", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": true, "requires": { "prelude-ls": "1.1.2" } @@ -20951,7 +20686,8 @@ "wordwrap": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=" + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", + "dev": true }, "wrap-ansi": { "version": "2.1.0", @@ -21075,11 +20811,6 @@ "integrity": "sha1-GFqIjATspGw+QHDZn3tJ3jUomS0=", "dev": true }, - "xregexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-2.0.0.tgz", - "integrity": "sha1-UqY+VsoLhKfzpfPWGHLxJq16WUM=" - }, "xtend": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", diff --git a/package.json b/package.json index 455ffe4f8..66960ea92 100644 --- a/package.json +++ b/package.json @@ -130,7 +130,6 @@ "bootstrap": "^4.0.0-beta", "browser-stdout": "^1.3.0", "currency-formatter": "^1.2.1", - "dropbox": "^2.5.0", "ecurve": "^1.0.4", "hash-handler": "^1.5.1", "hasprop": "0.0.4", From 41967522ac4f9f16b39363cb6f1136362c9c03da Mon Sep 17 00:00:00 2001 From: Larry Salibra Date: Fri, 26 Jan 2018 17:40:32 +0800 Subject: [PATCH 17/24] remove some dropbox legacy code #1184 --- .eslintignore | 1 + app/js/account/StorageProvidersPage.js | 130 +--------------- app/js/account/store/settings/default.js | 4 +- app/js/account/utils/dropbox.js | 142 ------------------ app/js/account/utils/index.js | 1 - app/js/utils/api-utils.js | 41 ++--- app/js/utils/index.js | 1 - app/js/welcome/WelcomeModal.js | 7 - .../welcome/components/ConnectStorageView.js | 16 -- tests/utils/api-utils.test.js | 79 ---------- 10 files changed, 18 insertions(+), 404 deletions(-) delete mode 100644 app/js/account/utils/dropbox.js diff --git a/.eslintignore b/.eslintignore index b54509b61..d2e8e4bba 100644 --- a/.eslintignore +++ b/.eslintignore @@ -28,6 +28,7 @@ app/js/components/* app/js/store/* app/js/utils/* !app/js/utils/account-utils* +!app/js/utils/api-utils* app/js/profiles/store/* app/js/profiles/tabs/* diff --git a/app/js/account/StorageProvidersPage.js b/app/js/account/StorageProvidersPage.js index f6f5380da..0466a1519 100644 --- a/app/js/account/StorageProvidersPage.js +++ b/app/js/account/StorageProvidersPage.js @@ -4,9 +4,7 @@ import { connect } from 'react-redux' import { AccountActions } from '../account/store/account' import { SettingsActions } from '../account/store/settings' -import { DROPBOX, BLOCKSTACK_INC } from './utils/index' -import { getDropboxAccessTokenFromHash, - redirectToConnectToDropbox } from './utils/dropbox' +import { BLOCKSTACK_INC } from './utils/index' import { connectToGaiaHub } from './utils/blockstack-inc' @@ -15,7 +13,6 @@ import log4js from 'log4js' const logger = log4js.getLogger('storage/StorageProvidersPage.js') -const Dropbox = require('dropbox') function mapStateToProps(state) { return { @@ -51,47 +48,18 @@ class StorageProvidersPage extends Component { this.state = { hide: true } - this.connectDropbox = this.connectDropbox.bind(this) - this.disconnectDropbox = this.disconnectDropbox.bind(this) this.updateApi = this.updateApi.bind(this) } componentWillMount() { - const api = this.props.api - const dropboxAccessToken = getDropboxAccessTokenFromHash(window.location.hash) const needToConnectGaiaHub = window.location.hash === '#gaiahub' - const needToConnectDropbox = dropboxAccessToken != null - if (needToConnectDropbox) { - const newApi = Object.assign({}, api, { dropboxAccessToken }) - this.props.updateApi(newApi) - const identityIndex = 0 - const identity = this.props.localIdentities[identityIndex] - const identityAddress = identity.ownerAddress - const profileSigningKeypair = this.props.identityKeypairs[identityIndex] - const profile = identity.profile - - // This is okay selecting storage right now is only done during on-boarding - const firstDropboxUpload = true - - setCoreStorageConfig(newApi, identityIndex, identityAddress, - profile, profileSigningKeypair, firstDropboxUpload) - .then((indexUrl) => { - logger.debug(`componentDidMount: indexUrl: ${indexUrl}`) - // TODO add index URL to token file - logger.debug('componentDidMount: storage initialized') - const newApi2 = Object.assign({}, newApi, { storageConnected: true }) - this.props.updateApi(newApi2) - this.props.storageIsConnected() - logger.debug('componentDidMount: storage configured') - }) - } if (needToConnectGaiaHub) { logger.debug('componentDidMount: trying to connect gaia hub...') this.connectSharedService() } // We can show the page contents since there's not going to be a redirect - if (!(needToConnectGaiaHub || needToConnectDropbox)) { + if (!(needToConnectGaiaHub)) { this.setState({ hide: false }) } } @@ -109,17 +77,6 @@ class StorageProvidersPage extends Component { } } - connectDropbox() { - redirectToConnectToDropbox() - } - - disconnectDropbox() { - const api = this.props.api - const dbx = new Dropbox({ accessToken: api.dropboxAccessToken }) - dbx.authTokenRevoke() - this.props.updateApi(Object.assign({}, api, { dropboxAccessToken: null })) - } - connectSharedService() { const storageProvider = this.props.api.gaiaHubUrl const signer = this.props.identityKeypairs[0].key @@ -204,89 +161,6 @@ class StorageProvidersPage extends Component { Run your own Gaia storage hub

-

- {api.hostedDataLocation !== DROPBOX ? - - : - - } -

-

- -

-

- -

-

- -

-

- -

-

- -

-

- -

-

- -

} diff --git a/app/js/account/store/settings/default.js b/app/js/account/store/settings/default.js index 2999b83a5..093130ad8 100644 --- a/app/js/account/store/settings/default.js +++ b/app/js/account/store/settings/default.js @@ -1,4 +1,4 @@ -import { DROPBOX } from '../../../account/utils/index' +import { BLOCKSTACK_INC } from '../../../account/utils/index' import { isCoreEndpointDisabled } from '../../../utils/window-utils' export const REGTEST_CORE_API_PASSWORD = 'blockstack_integration_test_api_password' @@ -42,7 +42,7 @@ const DEFAULT_API = { } }, browserServerUrl: 'https://blockstack-browser-server.appartisan.com', - hostedDataLocation: DROPBOX, + hostedDataLocation: BLOCKSTACK_INC, coreHost: 'localhost', corePort: 6270, coreAPIPassword: null, diff --git a/app/js/account/utils/dropbox.js b/app/js/account/utils/dropbox.js deleted file mode 100644 index 33f31947f..000000000 --- a/app/js/account/utils/dropbox.js +++ /dev/null @@ -1,142 +0,0 @@ -// @flow -import Dropbox from 'dropbox' -import log4js from 'log4js' - -const logger = log4js.getLogger('account/utils/dropbox.js') - -export const DROPBOX_APP_ID = 'f3l2g7ge4bs68o4' - -export function redirectToConnectToDropbox() { - const dbx = new Dropbox({ clientId: DROPBOX_APP_ID }) - const port = location.port === '' ? 80 : location.port - console.log(port) - window.location = dbx.getAuthenticationUrl( - `http://localhost:${port}/account/storage`) -} - -function getAvatarPath(identityIndex: number, - identityAddress: string, photoIndex: number): string { - const path = `/${identityAddress}/${identityIndex}/avatar-${photoIndex}` - return path -} - -function getProfilePath(identityIndex: number, - identityAddress: string): string { - const path = `/${identityAddress}/${identityIndex}/profile.json` - return path -} - -function deleteProfile(api: {dropboxAccessToken: string}, identityIndex: number, - identityAddress: string): Promise<*> { - const dbx = new Dropbox({ accessToken: api.dropboxAccessToken }) - const path = getProfilePath(identityIndex, identityAddress) - return dbx.filesDelete({ path }) -} - -function uploadProfile(api: {dropboxAccessToken: string}, identityIndex: number, - identityAddress: string, signedProfileTokenData: string, firstUpload: boolean): Promise<*> { - return new Promise((resolve, reject) => { - const dbx = new Dropbox({ accessToken: api.dropboxAccessToken }) - const path = getProfilePath(identityIndex, identityAddress) - return dbx.filesUpload({ path, contents: signedProfileTokenData, mode: 'overwrite' }) - .then((response) => { - if (firstUpload === true) { // we can only create shared link once - logger.debug('uploadProfile: first upload: creating shared link') - return dbx.sharingCreateSharedLinkWithSettings({ path: response.path_lower, settings: {} }) - .then((shareLinkResponse) => { - logger.debug(`uploadProfile: shared link: ${shareLinkResponse}`) - /* Appending dropbox share url with ?dl=1 returns the actual file - instead of dropbox sign up page */ - const profileUrl = `${shareLinkResponse.url.split('=')[0]}=1` - resolve(profileUrl) - }) - .catch((error) => { - logger.error('uploadProfile: error creating shared link', error) - reject(error) - return Promise.reject() - }) - } else { - logger.debug('uploadProfile: not first upload - we won\'t create shared link') - resolve(null) - return Promise.reject() - } - }) - .catch((error) => { - reject(error) - }) - }) -} - - -export function uploadProfileToDropbox(api: {dropboxAccessToken: string}, - identityIndex: number, identityAddress: string, signedProfileTokenData: string, - firstUpload: boolean = false): Promise<*> { - if (firstUpload === true) { // We try to delete any existing profile file - return deleteProfile(api, identityIndex, identityAddress) - .then(() => uploadProfile(api, identityIndex, identityAddress, - signedProfileTokenData, firstUpload)) - // the profile didn't exist - .catch(() => uploadProfile(api, identityIndex, identityAddress, - signedProfileTokenData, firstUpload)) - } else { - return uploadProfile(api, identityIndex, identityAddress, - signedProfileTokenData, firstUpload) - } -} - -function deletePhoto(api: {dropboxAccessToken: string}, identityIndex: number, - identityAddress: string, photoIndex: number): Promise<*> { - const dbx = new Dropbox({ accessToken: api.dropboxAccessToken }) - const path = getAvatarPath(identityIndex, identityAddress, photoIndex) - return dbx.filesDelete({ path }) -} - -function uploadPhoto(api: {dropboxAccessToken: string}, identityIndex: number, - identityAddress: string, photoFile: any, photoIndex: number): Promise<*> { - const dbx = new Dropbox({ accessToken: api.dropboxAccessToken }) - const path = getAvatarPath(identityIndex, identityAddress, photoIndex) - return new Promise((resolve, reject) => dbx.filesUpload({ path, contents: photoFile }) - .then((response) => { - dbx.sharingCreateSharedLinkWithSettings({ path: response.path_lower, settings: {} }) - .then((shareLinkResponse) => { - /* Appending dropbox share url with ?dl=1 returns the actual file - instead of dropbox sign up page */ - const avatarUrl = `${shareLinkResponse.url.split('=')[0]}=1` - - resolve(avatarUrl) - }) - .catch((error) => { - reject(error) - }) - }) - .catch((error) => { - reject(error) - })) -} - -export function uploadPhotoToDropbox(api: {dropboxAccessToken: string}, - identityIndex: number, identityAddress: string, photoFile: any, - photoIndex: number): Promise<*> { - logger.debug(`uploadPhotoToDropbox: id index: ${identityIndex} id address ${identityAddress}`) - // We try to delete any existing photo - return deletePhoto(api, identityIndex, identityAddress, photoIndex).then(() => - uploadPhoto(api, identityIndex, identityAddress, photoFile, photoIndex)) - // the file didn't exist - .catch(() => uploadPhoto(api, identityIndex, identityAddress, photoFile, photoIndex)) -} - - -export function getDropboxAccessTokenFromHash(hash: string) { - let tokens = hash.split('access_token=') - if (tokens.length !== 2) { - return null - } - - tokens = tokens[1].split('&') - - if (tokens[0] === '') { - return null - } - - return tokens[0] -} diff --git a/app/js/account/utils/index.js b/app/js/account/utils/index.js index 4d7a0265b..408eb1e90 100644 --- a/app/js/account/utils/index.js +++ b/app/js/account/utils/index.js @@ -7,7 +7,6 @@ import { connectToGaiaHub, uploadToGaiaHub } from 'blockstack' import { getTokenFileUrlFromZoneFile } from '../../utils/zone-utils' export const BLOCKSTACK_INC = 'gaia-hub' -export const DROPBOX = 'dropbox' function getProfileUploadLocation(identity: any, hubConfig: GaiaHubConfig) { if (identity.zoneFile) { diff --git a/app/js/utils/api-utils.js b/app/js/utils/api-utils.js index 7e0640a89..c9a2ed817 100644 --- a/app/js/utils/api-utils.js +++ b/app/js/utils/api-utils.js @@ -4,25 +4,11 @@ import log4js from 'log4js' const logger = log4js.getLogger('utils/api-utils.js') -import { uploadProfile, DROPBOX, BLOCKSTACK_INC } from '../account/utils' +import { uploadProfile, BLOCKSTACK_INC } from '../account/utils' import { signProfileForUpload } from './index' import { isCoreEndpointDisabled } from './window-utils' -export function getNamesOwned(address, bitcoinAddressLookupUrl, callback) { - const url = bitcoinAddressLookupUrl.replace('{address}', address) - fetch(url) - .then((response) => response.text()) - .then((responseText) => JSON.parse(responseText)) - .then((responseJson) => { - callback([]) - }) - .catch((error) => { - logger.error('getNamesOwned: error', error) - callback([]) - }) -} - export function authorizationHeaderValue(coreAPIPassword) { return `bearer ${coreAPIPassword}` } @@ -157,9 +143,8 @@ function profileInsertStorageRoutingInfo(profile, driverName, indexUrl) { export function setCoreStorageConfig(api, identityIndex = null, identityAddress = null, profile = null, profileSigningKeypair = null, firstDropboxUpload = false) { - if (isCoreEndpointDisabled()) { - return new Promise((resolve, reject) => { + return new Promise((resolve) => { resolve('OK') }) } @@ -171,17 +156,14 @@ export function setCoreStorageConfig(api, const coreAPIPassword = api.coreAPIPassword return new Promise((resolve, reject) => { - var driverName = null; - var requestBody = null; + let driverName = null + let requestBody = null - if (api.hostedDataLocation === DROPBOX) { - driverName = 'dropbox' - requestBody = { driver_config: { token: api.dropboxAccessToken } } - }else if (api.hostedDataLocation === BLOCKSTACK_INC) { + if (api.hostedDataLocation === BLOCKSTACK_INC) { driverName = 'gaia_hub' requestBody = { driver_config: api.gaiaHubConfig } - }else{ - throw new Error('Only support "dropbox" or "blockstack" driver at this time') + } else { + throw new Error('Only support "blockstack" driver at this time') } @@ -218,27 +200,30 @@ export function setCoreStorageConfig(api, if (indexUrl && (identityIndex || identityIndex === 0) && identityAddress && profile && profileSigningKeypair) { - logger.debug(`setCoreStorageConfig: storing index url...`) + logger.debug('setCoreStorageConfig: storing index url...') // insert it into the profile and replicate it. profile = profileInsertStorageRoutingInfo(profile, driverName, indexUrl) const data = signProfileForUpload(profile, profileSigningKeypair) - logger.debug(`setCoreStorageConfig: uploading profile...`) + logger.debug('setCoreStorageConfig: uploading profile...') return uploadProfile(api, identityIndex, identityAddress, data, firstDropboxUpload) .then((result) => { logger.debug('setCoreStorageConfig: saved index url') // saved! resolve(result) + return Promise.resolve(result) }) .catch((error) => { logger.error('setCoreStorageConfig: error saving index url', error) reject(error) + return Promise.reject(error) }) } else { - logger.debug(`setCoreStorageConfig: not saving index url`) + logger.debug('setCoreStorageConfig: not saving index url') // Some drivers won't return an indexUrl // or we'll want to initialize resolve('OK') + return Promise.resolve('OK') } }) }) diff --git a/app/js/utils/index.js b/app/js/utils/index.js index 97eedbe12..4044dd0f0 100644 --- a/app/js/utils/index.js +++ b/app/js/utils/index.js @@ -17,7 +17,6 @@ export { } from './account-utils' export { - getNamesOwned, getIdentities, authorizationHeaderValue } from './api-utils' diff --git a/app/js/welcome/WelcomeModal.js b/app/js/welcome/WelcomeModal.js index 8dcf6a7b7..ee7af92a3 100644 --- a/app/js/welcome/WelcomeModal.js +++ b/app/js/welcome/WelcomeModal.js @@ -7,7 +7,6 @@ import Alert from '../components/Alert' import { AccountActions } from '../account/store/account' import { IdentityActions } from '../profiles/store/identity' import { SettingsActions } from '../account/store/settings' -import { redirectToConnectToDropbox } from '../account/utils/dropbox' import { redirectToConnectToGaiaHub } from '../account/utils/blockstack-inc' import { isWebAppBuild } from '../utils/window-utils' @@ -299,11 +298,6 @@ class WelcomeModal extends Component { this.setPage(this.state.page - 1) } - connectDropbox(event) { - event.preventDefault() - redirectToConnectToDropbox() - } - connectGaiaHub(event) { event.preventDefault() // need to call this again because state gets deleted before this @@ -463,7 +457,6 @@ class WelcomeModal extends Component { page === 8 ? : null diff --git a/app/js/welcome/components/ConnectStorageView.js b/app/js/welcome/components/ConnectStorageView.js index cbf7217e6..8e076b549 100644 --- a/app/js/welcome/components/ConnectStorageView.js +++ b/app/js/welcome/components/ConnectStorageView.js @@ -2,7 +2,6 @@ import React, { Component, PropTypes } from 'react' class ConnectStorageView extends Component { static propTypes = { - connectDropbox: PropTypes.func.isRequired, connectGaiaHub: PropTypes.func.isRequired } @@ -61,21 +60,6 @@ class ConnectStorageView extends Component { > Use default storage - -