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

Commit fd4c1f5

Browse files
authored
Merge pull request #1723 from blockstack/feature/user-selectable-gaia-hub
Add developer-optional Gaia hub choice during onboarding
2 parents 02d195f + 6865e8f commit fd4c1f5

13 files changed

Lines changed: 487 additions & 23 deletions

File tree

app/js/account/store/settings/actions.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ function resetApi(api) {
6363
}
6464
}
6565

66-
function connectStorage() {
66+
function connectStorage(customGaiaUrl) {
6767
return async (dispatch, getState) => {
6868
logger.info('connectStorage')
6969
const state = getState()
@@ -75,9 +75,12 @@ function connectStorage() {
7575
return Promise.reject()
7676
}
7777

78-
return connectToGaiaHub(api.gaiaHubUrl, idKeypairs[0].key).then(gaiaHubConfig => {
78+
const gaiaHubUrl = customGaiaUrl || api.gaiaHubUrl
79+
80+
return connectToGaiaHub(gaiaHubUrl, idKeypairs[0].key).then(gaiaHubConfig => {
7981
const newApi = Object.assign({}, api, {
8082
gaiaHubConfig,
83+
gaiaHubUrl,
8184
hostedDataLocation: BLOCKSTACK_INC
8285
})
8386
dispatch(updateApi(newApi))

app/js/auth/index.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,8 @@ class AuthPage extends React.Component {
271271
profile.apps = apps
272272
const signedProfileTokenData = signProfileForUpload(
273273
profile,
274-
nextProps.identityKeypairs[identityIndex]
274+
nextProps.identityKeypairs[identityIndex],
275+
this.props.api
275276
)
276277
logger.debug(
277278
'componentWillReceiveProps: uploading updated profile with new apps array'

app/js/components/styled/onboarding/index.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -433,6 +433,20 @@ const Loading = styled.div`
433433
}
434434
`
435435

436+
const RecommendedHubPlaceholder = styled.div`
437+
background: #ececec;
438+
text-align: center;
439+
font-weight: 500;
440+
padding: 10px;
441+
margin-bottom: 2em;
442+
`
443+
444+
const Hr = styled.hr`
445+
border-top: 1px solid #ececec;
446+
width: 100%;
447+
margin-bottom: 2em;
448+
`
449+
436450
const PanelCard = ({ children, ...rest }) => (
437451
<Card {...rest}>
438452
<PlaceholderStyles />
@@ -458,5 +472,7 @@ Panel.Card.ErrorMessage.Icon = Icon
458472
Panel.Progress = Progress
459473
Panel.Progress.Dot = Dot
460474
Panel.Loading = Loading
475+
Panel.RecommendedHubPlaceholder = RecommendedHubPlaceholder
476+
Panel.Hr = Hr
461477

462478
export default Panel

app/js/profiles/store/identity/actions.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,10 @@ function createNewProfile(
271271
function refreshIdentities(
272272
api: {
273273
bitcoinAddressLookupUrl: string,
274-
nameLookupUrl: string
274+
nameLookupUrl: string,
275+
gaiaHubConfig: {
276+
url_prefix: string,
277+
},
275278
},
276279
ownerAddresses: Array<string>
277280
) {
@@ -292,7 +295,7 @@ function refreshIdentities(
292295
)
293296
const gaiaBucketAddress = ownerAddresses[0]
294297
return fetchProfileLocations(
295-
'https://gaia.blockstack.org/hub',
298+
api.gaiaHubConfig.url_prefix,
296299
address,
297300
gaiaBucketAddress,
298301
index

app/js/profiles/store/registration/actions.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ function registerName(api, domainName, identity, identityIndex,
147147
return dispatch => {
148148
logger.debug(`Signing a new profile for ${domainName}`)
149149
const profile = identity.profile || DEFAULT_PROFILE
150-
const signedProfileTokenData = signProfileForUpload(profile, keypair)
150+
const signedProfileTokenData = signProfileForUpload(profile, keypair, api)
151151

152152
dispatch(profileUploading())
153153
logger.info(`Uploading ${domainName} profile...`)

app/js/sign-in/index.js

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,14 @@ class SignIn extends React.Component {
206206
this.props.api,
207207
this.props.identityAddresses
208208
)
209+
const identity = this.props.localIdentities[0]
210+
if (identity && identity.profile && identity.profile.api) {
211+
const newApi = {
212+
...this.props.api,
213+
...identity.profile.api
214+
}
215+
this.props.updateApi(newApi)
216+
}
209217
logger.debug('refreshIdentities complete')
210218
updateEmail(this.state.email)
211219
logger.debug('updated email')
@@ -427,7 +435,8 @@ SignIn.propTypes = {
427435
refreshIdentities: PropTypes.func.isRequired,
428436
localIdentities: PropTypes.array.isRequired,
429437
encryptedBackupPhrase: PropTypes.string,
430-
connectStorage: PropTypes.func.isRequired
438+
connectStorage: PropTypes.func.isRequired,
439+
updateApi: PropTypes.func.isRequired
431440
}
432441

433442
export default withRouter(

app/js/sign-up/index.js

Lines changed: 142 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import React from 'react'
22
import PropTypes from 'prop-types'
33
import { browserHistory, withRouter } from 'react-router'
4+
import { decodeToken } from 'jsontokens'
45
import App from '../App'
56
import {
67
selectConnectedStorageAtLeastOnce,
@@ -47,7 +48,10 @@ import {
4748
Password,
4849
Success,
4950
Username,
50-
RecoveryInformationScreen
51+
RecoveryInformationScreen,
52+
GaiaHubSelect,
53+
CustomGaiaHub,
54+
RecommendedGaiaHub
5155
} from './views'
5256
import { notify } from 'reapop'
5357

@@ -62,23 +66,32 @@ const views = [
6266
Initial,
6367
Username,
6468
Password,
69+
GaiaHubSelect,
70+
CustomGaiaHub,
6571
Email,
6672
RecoveryInformationScreen,
67-
Success
73+
Success,
74+
RecommendedGaiaHub
6875
]
6976
const VIEWS = {
7077
INITIAL: 0,
7178
USERNAME: 1,
7279
PASSWORD: 2,
73-
EMAIL: 3,
74-
INFO: 4,
75-
HOORAY: 5
80+
GAIA: 3,
81+
RECOMMENDED_GAIA_HUB: 8,
82+
CUSTOMHUB: 4,
83+
EMAIL: 5,
84+
INFO: 6,
85+
HOORAY: 7
7686
}
7787
const VIEW_EVENTS = {
7888
[VIEWS.INITIAL]: 'Onboarding - Initial',
7989
[VIEWS.EMAIL]: 'Onboarding - Email',
8090
[VIEWS.PASSWORD]: 'Onboarding - Password',
8191
[VIEWS.USERNAME]: 'Onboarding - Username',
92+
[VIEWS.RECOMMENDED_GAIA_HUB]: 'Onboarding - Recommended Gaia Hub',
93+
[VIEWS.GAIA]: 'Onboarding - Gaia Hub Select',
94+
[VIEWS.CUSTOMHUB]: 'Onboarding - Custom Gaia Hub',
8295
[VIEWS.INFO]: 'Onboarding - Info',
8396
[VIEWS.HOORAY]: 'Onboarding - Complete'
8497
}
@@ -132,7 +145,10 @@ class Onboarding extends React.Component {
132145
restoreEmailError: null,
133146
loading: false,
134147
view: VIEWS.INITIAL,
135-
usernameRegistrationInProgress: false
148+
usernameRegistrationInProgress: false,
149+
hubURL: '',
150+
decodedAuthToken: null,
151+
customHubError: null
136152
}
137153
updateValue = (key, value) => {
138154
this.setState({ [key]: value })
@@ -169,12 +185,61 @@ class Onboarding extends React.Component {
169185
* Submit our password
170186
*/
171187
submitPassword = async () => {
188+
const decodedAuthRequest = this.getDecodedAuthRequest()
189+
if (decodedAuthRequest && (decodedAuthRequest.solicitGaiaHubUrl || decodedAuthRequest.recommendedGaiaHub)) {
190+
if (decodedAuthRequest.recommendedGaiaHubUrl) {
191+
this.updateView(VIEWS.RECOMMENDED_GAIA_HUB)
192+
} else {
193+
this.updateView(VIEWS.GAIA)
194+
}
195+
} else {
196+
this.setState({
197+
loading: true
198+
})
199+
await this.createAccount()
200+
this.updateView(VIEWS.EMAIL)
201+
}
202+
}
203+
204+
/**
205+
* Set gaia hub
206+
*/
207+
defaultGaiaHub = async () => {
172208
this.setState({
173209
loading: true
174210
})
175211
await this.createAccount()
176212
this.updateView(VIEWS.EMAIL)
177213
}
214+
215+
/**
216+
* Set a custom gaia hub
217+
*/
218+
customGaiaHub = async () => {
219+
this.setState({
220+
loading: true
221+
})
222+
const success = await this.validateGaiaURL()
223+
if (success) {
224+
await this.createAccount()
225+
this.updateView(VIEWS.EMAIL)
226+
}
227+
}
228+
229+
submitRecommendedGaiaHub = async () => {
230+
const decodedAuthRequest = this.getDecodedAuthRequest()
231+
this.setState({
232+
loading: true,
233+
hubURL: decodedAuthRequest.recommendedGaiaHubUrl
234+
}, async () => {
235+
const success = await this.validateGaiaURL()
236+
if (success) {
237+
await this.createAccount()
238+
this.updateView(VIEWS.EMAIL)
239+
}
240+
})
241+
}
242+
178243
/**
179244
* Submit Username
180245
* This will create our account and then register a name and connect storage
@@ -203,7 +268,7 @@ class Onboarding extends React.Component {
203268
// Create new ID and owner address and then set to default
204269
await this.createNewIdAndSetDefault()
205270
// Connect our default storage
206-
await this.props.connectStorage()
271+
await this.props.connectStorage(this.state.hubURL)
207272
// Register the username
208273
await this.registerUsername()
209274
}
@@ -357,6 +422,33 @@ class Onboarding extends React.Component {
357422
})
358423
}
359424

425+
async validateGaiaURL() {
426+
const { hubURL } = this.state
427+
if (!/^https:\/\//.test(hubURL)) {
428+
this.setState({
429+
loading: false,
430+
customHubError: 'A Gaia Hub URL must use SSL.'
431+
})
432+
return false
433+
}
434+
435+
try {
436+
await fetch(`${hubURL}/hub_info`)
437+
} catch (error) {
438+
this.setState({
439+
loading: false,
440+
customHubError: 'Your Gaia URL does not appear to be a valid Gaia hub.'
441+
})
442+
return false
443+
}
444+
445+
this.setState({
446+
customHubError: null
447+
})
448+
449+
return true
450+
}
451+
360452
/**
361453
* Decode and save auth request
362454
*
@@ -380,6 +472,13 @@ class Onboarding extends React.Component {
380472
}
381473
}
382474

475+
getDecodedAuthRequest() {
476+
const authRequest = this.props.authRequest || this.state.authRequest
477+
if (!authRequest) return null
478+
const decodedAuthRequest = decodeToken(authRequest).payload
479+
return decodedAuthRequest
480+
}
481+
383482
/**
384483
* Check for Auth Request
385484
* this returns the authRequest query param if one exists
@@ -489,11 +588,13 @@ class Onboarding extends React.Component {
489588
// If we were waiting on an appManifest, we haven't tracked yet.
490589
this.trackViewEvent(this.state.view, nextProps.appManifest)
491590
}
591+
const decodedAuthRequest = this.getDecodedAuthRequest()
592+
this.setState({ decodedAuthRequest })
492593
}
493594

494595
render() {
495596
const { appManifest } = this.props
496-
const { email, password, username, emailSubmitted, view } = this.state
597+
const { email, password, username, emailSubmitted, view, decodedAuthRequest } = this.state
497598

498599
const app = formatAppManifest(appManifest)
499600

@@ -525,6 +626,24 @@ class Onboarding extends React.Component {
525626
updateValue: this.updateValue
526627
}
527628
},
629+
{
630+
show: VIEWS.GAIA,
631+
props: {
632+
loading: this.state.loading,
633+
next: this.defaultGaiaHub,
634+
customHub: () => this.updateView(VIEWS.CUSTOMHUB)
635+
}
636+
},
637+
{
638+
show: VIEWS.CUSTOMHUB,
639+
props: {
640+
loading: this.state.loading,
641+
hubURL: this.state.hubURL,
642+
next: this.customGaiaHub,
643+
updateValue: this.updateValue,
644+
customHubError: this.state.customHubError
645+
}
646+
},
528647
{
529648
show: VIEWS.EMAIL,
530649
props: {
@@ -561,6 +680,19 @@ class Onboarding extends React.Component {
561680
goToRecovery: this.goToBackup,
562681
finish: () => this.finish()
563682
}
683+
},
684+
{
685+
show: VIEWS.RECOMMENDED_GAIA_HUB,
686+
props: {
687+
recommendedGaiaHubUrl: decodedAuthRequest && decodedAuthRequest.recommendedGaiaHubUrl,
688+
updateValue: this.updateValue,
689+
next: () => this.submitRecommendedGaiaHub(),
690+
customHub: () => this.updateView(VIEWS.CUSTOMHUB),
691+
defaultHub: this.defaultGaiaHub,
692+
loading: this.state.loading,
693+
customHubError: this.state.customHubError,
694+
app
695+
}
564696
}
565697
]
566698

@@ -613,7 +745,8 @@ Onboarding.propTypes = {
613745
verifyAuthRequestAndLoadManifest: PropTypes.func.isRequired,
614746
encryptedBackupPhrase: PropTypes.string,
615747
notify: PropTypes.func.isRequired,
616-
connectStorage: PropTypes.func.isRequired
748+
connectStorage: PropTypes.func.isRequired,
749+
authRequest: PropTypes.string
617750
}
618751

619752
export default withRouter(

0 commit comments

Comments
 (0)