Skip to content
This repository has been archived by the owner on Apr 17, 2023. It is now read-only.

[WIP] Collections support #1940

Open
wants to merge 24 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
bd56e72
Update git ignore.
yknl Jun 24, 2019
8ab4b43
Write and read encrypted settings files for each identity.
yknl Jun 27, 2019
3396a5f
Identity settings initialization.
yknl Jul 9, 2019
b68c96c
Merge branch 'feature/identity-settings' into feature/collections-sup…
yknl Jul 9, 2019
20fec3e
More identity settings initialization.
yknl Jul 10, 2019
b5af7fe
Merge branch 'feature/identity-settings' into feature/collections-sup…
yknl Jul 10, 2019
b0cdbf9
Identity settings refresh on profile page.
yknl Jul 11, 2019
ce1c4a8
Fix tests for DefaultProfilePage
yknl Jul 11, 2019
ceea751
Merge branch 'feature/identity-settings' into feature/collections-sup…
yknl Jul 11, 2019
8a8b14b
Fix import typo.
yknl Jul 11, 2019
7ba822b
Merge branch 'feature/identity-settings' into feature/collections-sup…
yknl Jul 12, 2019
59137b4
Implementation of collection key generation and storage.
yknl Jul 18, 2019
09861fc
Clean up auth processing and collection settings code.
yknl Aug 12, 2019
db4c701
Collections utility functions.
yknl Aug 12, 2019
ae7c2eb
Fix lint.
yknl Aug 12, 2019
7937c54
Fix tests.
yknl Aug 13, 2019
08071e0
Change collections gaia auth token scope to ArchivalPrefix.
yknl Aug 26, 2019
c4bb7dc
Fix issue with Gaia hub url property in api settings being undefined.
yknl Sep 4, 2019
2c97ca9
Merge branch 'develop' into feature/collections-support
yknl Sep 12, 2019
1d23022
Merge branch 'develop' into feature/collections-support
yknl Sep 12, 2019
5d368b7
Fix console warnings
yknl Sep 13, 2019
f2263f9
Use getPublicKeyFromPrivate in collection key generation.
yknl Sep 13, 2019
eb9742f
Fix lint.
yknl Sep 13, 2019
39692ac
Bump version to v0.37.0 alpha 1.
yknl Sep 17, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ native/windows/BlockstackBrowser/Resources/node.exe
native/windows/BlockstackBrowser/Resources/cors-proxy/corsproxy.js
native/windows/BlockstackSetup/obj/
native/windows/BlockstackSetup/bin/
native/windows/BlockstackSetup/*.msi
native/macos/Blockstack/Blockstack/server/corsproxy.js
native/macos/Blockstack/Blockstack/server/blockstackProxy.js
native/macos/Blockstack/Blockstack/server/node
Expand Down
83 changes: 79 additions & 4 deletions app/js/account/store/account/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
} from '@utils'
import { isCoreEndpointDisabled } from '@utils/window-utils'
import { transactions, config, network } from 'blockstack'

import { fetchIdentitySettings } from '../../../account/utils'
import roundTo from 'round-to'
import * as types from './types'
import log4js from 'log4js'
Expand Down Expand Up @@ -41,7 +41,8 @@ function createAccount(
bitcoinPublicKeychain,
firstBitcoinAddress,
identityAddresses,
identityKeypairs
identityKeypairs,
identitySettings
} = getBlockchainIdentities(masterKeychain, identitiesToGenerate)

return {
Expand All @@ -51,7 +52,8 @@ function createAccount(
bitcoinPublicKeychain,
firstBitcoinAddress,
identityAddresses,
identityKeypairs
identityKeypairs,
identitySettings
}
}

Expand Down Expand Up @@ -547,6 +549,74 @@ function usedIdentityAddress() {
}
}

function refreshAllIdentitySettings(
api: { gaiaHubConfig: GaiaHubConfig },
ownerAddresses: Array<string>,
identityKeyPairs: Array<object>
) {
return dispatch => {
const promises: Array<Promise<*>> = ownerAddresses.map((address, index) => {
const promise: Promise<*> = new Promise((resolve, reject) => {
const keyPair = identityKeyPairs[index]
return fetchIdentitySettings(api, address, keyPair)
.then((settings) => {
resolve(settings)
})
.catch(error => reject(error))
})
return promise
})

return Promise.all(promises)
.then(settings => {
return dispatch(updateAllIdentitySettings(settings))
})
.catch((error) => {
logger.error(
'refreshIdentitySettings: error refreshing identity settings',
error
)
return Promise.reject(error)
})
}
}

function refreshIdentitySettings(
api: { gaiaHubConfig: GaiaHubConfig },
identityIndex: int,
ownerAddress: string,
identityKeyPair: { key: string }
) {
return dispatch => fetchIdentitySettings(api, ownerAddress, identityKeyPair)
.then((settings) => {
return dispatch(updateIdentitySettings(identityIndex, settings))
})
}

function updateAllIdentitySettings(settings) {
return {
type: types.UPDATE_ALL_IDENTITY_SETTINGS,
settings
}
}

function updateIdentitySettings(identityIndex, settings) {
return {
type: types.UPDATE_IDENTITY_SETTINGS,
identityIndex,
settings
}
}

function setIdentityCollectionSetting(identityIndex, collectionName, collectionSettings) {
return {
type: types.SET_IDENTITY_COLLECTION_SETTINGS,
identityIndex,
collectionName,
collectionSettings
}
}

const AccountActions = {
createAccount,
updateBackupPhrase,
Expand All @@ -569,7 +639,12 @@ const AccountActions = {
usedIdentityAddress,
displayedRecoveryCode,
newIdentityAddress,
updateEmail
updateEmail,
refreshAllIdentitySettings,
refreshIdentitySettings,
updateAllIdentitySettings,
updateIdentitySettings,
setIdentityCollectionSetting
}

export default AccountActions
35 changes: 33 additions & 2 deletions app/js/account/store/account/reducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ const initialState = {
encryptedBackupPhrase: null, // persist
identityAccount: {
addresses: [],
keypairs: []
keypairs: [],
settings: []
},
bitcoinAccount: {
addresses: [],
Expand Down Expand Up @@ -43,6 +44,7 @@ function AccountReducer(state = initialState, action) {
publicKeychain: action.identityPublicKeychain,
addresses: action.identityAddresses,
keypairs: action.identityKeypairs,
settings: action.identitySettings,
addressIndex: 0
},
bitcoinAccount: {
Expand Down Expand Up @@ -258,13 +260,42 @@ function AccountReducer(state = initialState, action) {
...state.identityAccount.addresses,
action.keypair.address
],
keypairs: [...state.identityAccount.keypairs, action.keypair]
keypairs: [...state.identityAccount.keypairs, action.keypair],
settings: [...state.identityAccount.settings, {}]
})
})
case types.CONNECTED_STORAGE:
return Object.assign({}, state, {
connectedStorageAtLeastOnce: true
})
case types.UPDATE_ALL_IDENTITY_SETTINGS:
return Object.assign({}, state, {
identityAccount: Object.assign({}, state.identityAccount, {
settings: action.settings
})
})
case types.UPDATE_IDENTITY_SETTINGS:
return Object.assign({}, state, {
identityAccount: Object.assign({}, state.identityAccount, {
settings: state.identityAccount.settings.map(
(settingsRow, i) => i === action.identityIndex ? action.settings : settingsRow
)
})
})
case types.SET_IDENTITY_COLLECTION_SETTINGS:
const newIdentitySettings = Object.assign({}, state.identityAccount.settings)

const identitySettingsAtIndex = newIdentitySettings[action.identityIndex]
if (!identitySettingsAtIndex.collections) {
identitySettingsAtIndex.collections = {}
}
identitySettingsAtIndex.collections[action.collectionName] = action.collectionSettings

return Object.assign({}, state, {
identityAccount: Object.assign({}, state.identityAccount, {
settings: newIdentitySettings
})
})
default:
return state
}
Expand Down
3 changes: 3 additions & 0 deletions app/js/account/store/account/types.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,6 @@ export const RECOVERY_CODE_VERIFIED = 'account/RECOVERY_CODE_VERIFIED'
export const INCREMENT_IDENTITY_ADDRESS_INDEX = 'account/INCREMENT_IDENTITY_ADDRESS_INDEX'
export const CONNECTED_STORAGE = 'account/CONNECTED_STORAGE'
export const UPDATE_EMAIL_ADDRESS = 'account/UPDATE_EMAIL_ADDRESS'
export const UPDATE_ALL_IDENTITY_SETTINGS = 'account/UPDATE_ALL_IDENTITY_SETTINGS'
export const UPDATE_IDENTITY_SETTINGS = 'account/UPDATE_IDENTITY_SETTINGS'
export const SET_IDENTITY_COLLECTION_SETTINGS = 'account/SET_IDENTITY_COLLECTION_SETTINGS'
46 changes: 46 additions & 0 deletions app/js/account/utils/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ import { parseZoneFile } from 'zone-file'
import type { GaiaHubConfig } from './blockstack-inc'
import { connectToGaiaHub, uploadToGaiaHub } from './blockstack-inc'

import { encryptContent, decryptContent } from 'blockstack'
import { getTokenFileUrlFromZoneFile } from '@utils/zone-utils'

import log4js from 'log4js'
const logger = log4js.getLogger(__filename)

export const BLOCKSTACK_INC = 'gaia-hub'
const DEFAULT_PROFILE_FILE_NAME = 'profile.json'
const DEFAULT_IDENTITY_SETTINGS_FILE_NAME = 'settings.json'

function getProfileUploadLocation(identity: any, hubConfig: GaiaHubConfig) {
if (identity.zoneFile) {
Expand All @@ -23,6 +25,10 @@ function getProfileUploadLocation(identity: any, hubConfig: GaiaHubConfig) {
}
}

function getSettingsUploadLocation(hubConfig: GaiaHubConfig) {
return `${hubConfig.url_prefix}${hubConfig.address}/${DEFAULT_IDENTITY_SETTINGS_FILE_NAME}`
}

// aaron-debt: this should be moved into blockstack.js
function canWriteUrl(url: string, hubConfig: GaiaHubConfig): ?string {
const readPrefix = `${hubConfig.url_prefix}${hubConfig.address}/`
Expand Down Expand Up @@ -116,3 +122,43 @@ export function uploadProfile(
return uploadAttempt
})
}

export function uploadIdentitySettings(
api: { gaiaHubConfig: GaiaHubConfig, gaiaHubUrl: string},
identityKeyPair: { key: string, keyID: string },
settingsData: string
) {
const publicKey = identityKeyPair.keyID
const encryptedSettingsData = encryptContent(settingsData, { publicKey })
return connectToGaiaHub(api.gaiaHubUrl, identityKeyPair.key).then(identityHubConfig => {
const urlToWrite = getSettingsUploadLocation(identityHubConfig)
return tryUpload(
urlToWrite,
encryptedSettingsData,
identityHubConfig,
'application/json'
)
})
}

export function fetchIdentitySettings(
api: { gaiaHubConfig: GaiaHubConfig },
ownerAddress: string,
identityKeyPair: { key: string }
) {
const privateKey = identityKeyPair.key
const hubConfig = api.gaiaHubConfig
const url = `${hubConfig.url_prefix}${ownerAddress}/${DEFAULT_IDENTITY_SETTINGS_FILE_NAME}`
return fetch(url)
.then(response => {
if (response.ok) {
return response.text()
.then(encryptedSettingsData => decryptContent(encryptedSettingsData, { privateKey }))
.then(decryptedSettingsData => JSON.parse(decryptedSettingsData))
} else if (response.status == 404) {
return {}
} else {
return Promise.reject('Could not fetch identity settings')
}
})
}