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

Commit 8103c82

Browse files
committed
Merge branch 'release/v0.36.3'
2 parents b21bdd0 + 582b95b commit 8103c82

File tree

37 files changed

+1360
-1100
lines changed

37 files changed

+1360
-1100
lines changed

.circleci/config.yml

Lines changed: 35 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -15,45 +15,63 @@ jobs:
1515
- run: npm run prod-webapp
1616
test-e2e-login:
1717
docker:
18-
- image: circleci/node:10.15.1
19-
environment:
20-
TEST_E2E_GREP: login-to-hello-blockstack-app
18+
- image: circleci/node:10.15.1-browsers
2119
working_directory: ~/repo
2220
steps:
2321
- checkout
24-
- run: npm install
25-
- run: npm run test-e2e:browserstack
22+
- run:
23+
name: Repo Check 1
24+
command: |
25+
if [ "$CIRCLE_REPOSITORY_URL" == "[email protected]:blockstack/blockstack-browser.git" ]; then
26+
export TEST_E2E_GREP=login-to-hello-blockstack-app
27+
npm install && npm run test-e2e:browserstack
28+
else
29+
export TEST_E2E_GREP=login-to-hello-blockstack-app
30+
npm install && npm run test-e2e:localBuild
31+
fi
2632
- store_artifacts:
2733
path: /tmp/test-errors
2834
test-e2e-account-creation:
2935
docker:
30-
- image: circleci/node:10.15.1
31-
environment:
32-
TEST_E2E_GREP: account-creation
36+
- image: circleci/node:10.15.1-browsers
3337
working_directory: ~/repo
3438
steps:
3539
- checkout
36-
- run: npm install
37-
- run: npm run test-e2e:browserstack
40+
- run:
41+
name: Repo Check 2
42+
command: |
43+
if [ "$CIRCLE_REPOSITORY_URL" == "[email protected]:blockstack/blockstack-browser.git" ]; then
44+
export TEST_E2E_GREP=account-creation
45+
npm install && npm run test-e2e:browserstack
46+
else
47+
export TEST_E2E_GREP=account-creation
48+
npm install && npm run test-e2e:localBuild
49+
fi
3850
- store_artifacts:
3951
path: /tmp/test-errors
4052
test-e2e-account-recovery:
4153
docker:
42-
- image: circleci/node:10.15.1
43-
environment:
44-
TEST_E2E_GREP: account-recovery
54+
- image: circleci/node:10.15.1-browsers
4555
working_directory: ~/repo
4656
steps:
4757
- checkout
48-
- run: npm install
49-
- run: npm run test-e2e:browserstack
58+
- run:
59+
name: Repo Check 3
60+
command: |
61+
if [ "$CIRCLE_REPOSITORY_URL" == "[email protected]:tim/blockstack-browser.git" ]; then
62+
export TEST_E2E_GREP=account-recovery
63+
npm install && npm run test-e2e:browserstack
64+
else
65+
export TEST_E2E_GREP=account-recovery
66+
npm install && npm run test-e2e:localBuild
67+
fi
5068
- store_artifacts:
5169
path: /tmp/test-errors
5270
workflows:
5371
version: 2
54-
build_and_test-e2e:
72+
build_and_test_e2e_local_or_remote-e2e:
5573
jobs:
5674
- build
5775
- test-e2e-login
5876
- test-e2e-account-creation
59-
- test-e2e-account-recovery
77+
- test-e2e-account-recovery

app/js/account/utils/blockstack-inc.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ export function redirectToConnectToGaiaHub() {
1111
window.top.location.href = `http://${host}:${port}/account/storage#gaiahub`
1212
}
1313

14-
const connectToGaiaHub = (hubUrl: string, key: string) => bsConnectToGaiaHub(hubUrl, key)
14+
const connectToGaiaHub = (hubUrl: string, key: string, associationToken?: string) =>
15+
bsConnectToGaiaHub(hubUrl, key, associationToken)
1516

1617
export { connectToGaiaHub, GaiaHubConfig, uploadToGaiaHub }

app/js/auth/index.js

Lines changed: 75 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@ import { ShellParent, AppHomeWrapper } from '@blockstack/ui'
44
import { Initial, LegacyGaia } from './views'
55
import { bindActionCreators } from 'redux'
66
import { connect } from 'react-redux'
7+
import { randomBytes } from 'crypto'
78
import { AuthActions } from './store/auth'
89
import { IdentityActions } from '../profiles/store/identity'
9-
import { decodeToken } from 'jsontokens'
10+
import { decodeToken, TokenSigner } from 'jsontokens'
1011
import { parseZoneFile } from 'zone-file'
1112
import queryString from 'query-string'
1213
import {
@@ -15,7 +16,8 @@ import {
1516
redirectUserToApp,
1617
getAppBucketUrl,
1718
isLaterVersion,
18-
updateQueryStringParameter
19+
updateQueryStringParameter,
20+
getPublicKeyFromPrivate
1921
} from 'blockstack'
2022
import { AppsNode } from '@utils/account-utils'
2123
import {
@@ -27,7 +29,10 @@ import { HDNode } from 'bitcoinjs-lib'
2729
import log4js from 'log4js'
2830
import { uploadProfile } from '../account/utils'
2931
import { signProfileForUpload } from '@utils'
30-
import { validateScopes, appRequestSupportsDirectHub } from './utils'
32+
import {
33+
validateScopes,
34+
appRequestSupportsDirectHub
35+
} from './utils'
3136
import {
3237
selectApi,
3338
selectCoreHost,
@@ -53,6 +58,7 @@ import {
5358
} from '@common/store/selectors/account'
5459
import { formatAppManifest } from '@common'
5560
import Modal from 'react-modal'
61+
import url from 'url'
5662

5763
const views = [Initial, LegacyGaia]
5864

@@ -86,6 +92,21 @@ function mapDispatchToProps(dispatch) {
8692
return bindActionCreators(actions, dispatch)
8793
}
8894

95+
function makeGaiaAssociationToken(secretKeyHex: string, childPublicKeyHex: string) {
96+
const LIFETIME_SECONDS = 365 * 24 * 3600
97+
const signerKeyHex = secretKeyHex.slice(0, 64)
98+
const compressedPublicKeyHex = getPublicKeyFromPrivate(signerKeyHex)
99+
const salt = randomBytes(16).toString('hex')
100+
const payload = { childToAssociate: childPublicKeyHex,
101+
iss: compressedPublicKeyHex,
102+
exp: LIFETIME_SECONDS + (new Date()/1000),
103+
iat: Date.now()/1000,
104+
salt }
105+
106+
const token = new TokenSigner('ES256K', signerKeyHex).sign(payload)
107+
return token
108+
}
109+
89110
class AuthPage extends React.Component {
90111
static contextTypes = {
91112
router: PropTypes.object
@@ -171,24 +192,34 @@ class AuthPage extends React.Component {
171192
if (redirectURI) {
172193
// Get the current localhost authentication url that the app will redirect back to,
173194
// and remove the 'echo' param from it.
174-
const authContinuationURI = updateQueryStringParameter(window.location.href, 'echo', '')
175-
redirectURI = updateQueryStringParameter(redirectURI, 'echoReply', this.state.echoRequestId)
176-
redirectURI = updateQueryStringParameter(redirectURI, 'authContinuation', encodeURIComponent(authContinuationURI))
195+
const authContinuationURI = updateQueryStringParameter(
196+
window.location.href,
197+
'echo',
198+
''
199+
)
200+
redirectURI = updateQueryStringParameter(
201+
redirectURI,
202+
'echoReply',
203+
this.state.echoRequestId
204+
)
205+
redirectURI = updateQueryStringParameter(
206+
redirectURI,
207+
'authContinuation',
208+
encodeURIComponent(authContinuationURI)
209+
)
177210
} else {
178211
throw new Error('Invalid redirect echo reply URI')
179212
}
180213
this.setState({ responseSent: true })
181214
window.location = redirectURI
182215
}
183-
184-
componentWillReceiveProps(nextProps) {
185216

217+
componentWillReceiveProps(nextProps) {
186218
if (!this.state.responseSent) {
187-
188219
if (this.state.echoRequestId) {
189220
this.redirectUserToEchoReply()
190221
return
191-
}
222+
}
192223

193224
const storageConnected = this.props.api.storageConnected
194225
this.setState({
@@ -251,9 +282,7 @@ class AuthPage extends React.Component {
251282

252283
if (identity.zoneFile && identity.zoneFile.length > 0) {
253284
const zoneFileJson = parseZoneFile(identity.zoneFile)
254-
const profileUrlFromZonefile = getTokenFileUrlFromZoneFile(
255-
zoneFileJson
256-
)
285+
const profileUrlFromZonefile = getTokenFileUrlFromZoneFile(zoneFileJson)
257286
if (
258287
profileUrlFromZonefile !== null &&
259288
profileUrlFromZonefile !== undefined
@@ -267,6 +296,7 @@ class AuthPage extends React.Component {
267296
const gaiaUrlBase = nextProps.api.gaiaHubConfig.url_prefix
268297

269298
if (!profileUrlPromise) {
299+
// use default Gaia hub if we can't tell from the profile where the profile Gaia hub is
270300
profileUrlPromise = fetchProfileLocations(
271301
gaiaUrlBase,
272302
identityAddress,
@@ -358,10 +388,7 @@ class AuthPage extends React.Component {
358388
}
359389

360390
getFreshIdentities = async () => {
361-
await this.props.refreshIdentities(
362-
this.props.api,
363-
this.props.addresses
364-
)
391+
await this.props.refreshIdentities(this.props.api, this.props.addresses)
365392
this.setState({ refreshingIdentities: false })
366393
}
367394

@@ -392,6 +419,8 @@ class AuthPage extends React.Component {
392419

393420
let transitPublicKey = undefined
394421
let hubUrl = undefined
422+
let blockstackAPIUrl = undefined
423+
let associationToken = undefined
395424

396425
let requestVersion = '0'
397426
if (this.state.decodedToken.payload.hasOwnProperty('version')) {
@@ -407,6 +436,13 @@ class AuthPage extends React.Component {
407436
if (appRequestSupportsDirectHub(this.state.decodedToken.payload)) {
408437
hubUrl = this.props.api.gaiaHubUrl
409438
}
439+
if (isLaterVersion(requestVersion, '1.3.0')) {
440+
const compressedAppPublicKey = getPublicKeyFromPrivate(appPrivateKey.slice(0,64))
441+
const parsedCoreUrl = url.parse(this.props.api.nameLookupUrl)
442+
443+
blockstackAPIUrl = `${parsedCoreUrl.protocol}//${parsedCoreUrl.host}`
444+
associationToken = makeGaiaAssociationToken(privateKey, compressedAppPublicKey)
445+
}
410446

411447
const authResponse = makeAuthResponse(
412448
privateKey,
@@ -417,14 +453,17 @@ class AuthPage extends React.Component {
417453
appPrivateKey,
418454
undefined,
419455
transitPublicKey,
420-
hubUrl
456+
hubUrl,
457+
blockstackAPIUrl,
458+
associationToken
421459
)
422460

423461
this.props.clearSessionToken(appDomain)
424462

425463
logger.info(
426464
`login(): id index ${this.state.currentIdentityIndex} is logging in`
427465
)
466+
428467
this.setState({ responseSent: true })
429468
redirectUserToApp(this.state.authRequest, authResponse)
430469
}
@@ -541,7 +580,11 @@ class AuthPage extends React.Component {
541580
}
542581

543582
render() {
544-
const { appManifest, appManifestLoading, appManifestLoadingError } = this.props
583+
const {
584+
appManifest,
585+
appManifestLoading,
586+
appManifestLoadingError
587+
} = this.props
545588

546589
if (appManifestLoadingError) {
547590
return (
@@ -596,11 +639,18 @@ class AuthPage extends React.Component {
596639
)
597640
},
598641
deny: () => console.log('go back to app'),
642+
backLabel: 'Cancel',
643+
backView: () => {
644+
if (document.referrer === '') {
645+
window.close()
646+
} else {
647+
history.back()
648+
}
649+
},
599650
accounts: this.props.localIdentities,
600651
processing: this.state.processing,
601652
refreshingIdentities: this.state.refreshingIdentities,
602-
selectedIndex: this.state.currentIdentityIndex,
603-
disableBackOnView: 0
653+
selectedIndex: this.state.currentIdentityIndex
604654
}
605655
},
606656
{
@@ -630,4 +680,7 @@ class AuthPage extends React.Component {
630680
}
631681
}
632682

633-
export default connect(mapStateToProps, mapDispatchToProps)(AuthPage)
683+
export default connect(
684+
mapStateToProps,
685+
mapDispatchToProps
686+
)(AuthPage)

app/js/auth/utils.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import { isLaterVersion } from 'blockstack'
55

66
const logger = log4js.getLogger(__filename)
77

8-
98
const VALID_SCOPES = {
109
store_write: true,
1110
email: true,

app/js/auth/views/initial.js

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,13 @@ const basicInfo = 'read your basic info'
66
const readEmail = 'read your email address'
77
const publishData = 'publish data stored for this app'
88

9-
const Accounts = ({ list, handleClick, processing, refreshingIdentities, selectedIndex }) => {
9+
const Accounts = ({
10+
list,
11+
handleClick,
12+
processing,
13+
refreshingIdentities,
14+
selectedIndex
15+
}) => {
1016
let loadingMessage = null
1117
if (processing) {
1218
loadingMessage = 'Signing in...'
@@ -121,15 +127,6 @@ const InitialScreen = ({
121127
</Buttons>
122128
</>
123129
)
124-
},
125-
actions: {
126-
items: [
127-
{
128-
label: 'Deny',
129-
to: '/',
130-
negative: true
131-
}
132-
]
133130
}
134131
}
135132
return <ShellScreen {...rest} {...props} />

0 commit comments

Comments
 (0)