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

Commit

Permalink
Merge branch 'release/v0.36.3'
Browse files Browse the repository at this point in the history
  • Loading branch information
yknl committed Jun 19, 2019
2 parents b21bdd0 + 582b95b commit 8103c82
Show file tree
Hide file tree
Showing 37 changed files with 1,360 additions and 1,100 deletions.
52 changes: 35 additions & 17 deletions .circleci/config.yml
Expand Up @@ -15,45 +15,63 @@ jobs:
- run: npm run prod-webapp
test-e2e-login:
docker:
- image: circleci/node:10.15.1
environment:
TEST_E2E_GREP: login-to-hello-blockstack-app
- image: circleci/node:10.15.1-browsers
working_directory: ~/repo
steps:
- checkout
- run: npm install
- run: npm run test-e2e:browserstack
- run:
name: Repo Check 1
command: |
if [ "$CIRCLE_REPOSITORY_URL" == "git@github.com:blockstack/blockstack-browser.git" ]; then
export TEST_E2E_GREP=login-to-hello-blockstack-app
npm install && npm run test-e2e:browserstack
else
export TEST_E2E_GREP=login-to-hello-blockstack-app
npm install && npm run test-e2e:localBuild
fi
- store_artifacts:
path: /tmp/test-errors
test-e2e-account-creation:
docker:
- image: circleci/node:10.15.1
environment:
TEST_E2E_GREP: account-creation
- image: circleci/node:10.15.1-browsers
working_directory: ~/repo
steps:
- checkout
- run: npm install
- run: npm run test-e2e:browserstack
- run:
name: Repo Check 2
command: |
if [ "$CIRCLE_REPOSITORY_URL" == "git@github.com:blockstack/blockstack-browser.git" ]; then
export TEST_E2E_GREP=account-creation
npm install && npm run test-e2e:browserstack
else
export TEST_E2E_GREP=account-creation
npm install && npm run test-e2e:localBuild
fi
- store_artifacts:
path: /tmp/test-errors
test-e2e-account-recovery:
docker:
- image: circleci/node:10.15.1
environment:
TEST_E2E_GREP: account-recovery
- image: circleci/node:10.15.1-browsers
working_directory: ~/repo
steps:
- checkout
- run: npm install
- run: npm run test-e2e:browserstack
- run:
name: Repo Check 3
command: |
if [ "$CIRCLE_REPOSITORY_URL" == "git@github.com:tim/blockstack-browser.git" ]; then
export TEST_E2E_GREP=account-recovery
npm install && npm run test-e2e:browserstack
else
export TEST_E2E_GREP=account-recovery
npm install && npm run test-e2e:localBuild
fi
- store_artifacts:
path: /tmp/test-errors
workflows:
version: 2
build_and_test-e2e:
build_and_test_e2e_local_or_remote-e2e:
jobs:
- build
- test-e2e-login
- test-e2e-account-creation
- test-e2e-account-recovery
- test-e2e-account-recovery
3 changes: 2 additions & 1 deletion app/js/account/utils/blockstack-inc.js
Expand Up @@ -11,6 +11,7 @@ export function redirectToConnectToGaiaHub() {
window.top.location.href = `http://${host}:${port}/account/storage#gaiahub`
}

const connectToGaiaHub = (hubUrl: string, key: string) => bsConnectToGaiaHub(hubUrl, key)
const connectToGaiaHub = (hubUrl: string, key: string, associationToken?: string) =>
bsConnectToGaiaHub(hubUrl, key, associationToken)

export { connectToGaiaHub, GaiaHubConfig, uploadToGaiaHub }
97 changes: 75 additions & 22 deletions app/js/auth/index.js
Expand Up @@ -4,9 +4,10 @@ import { ShellParent, AppHomeWrapper } from '@blockstack/ui'
import { Initial, LegacyGaia } from './views'
import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'
import { randomBytes } from 'crypto'
import { AuthActions } from './store/auth'
import { IdentityActions } from '../profiles/store/identity'
import { decodeToken } from 'jsontokens'
import { decodeToken, TokenSigner } from 'jsontokens'
import { parseZoneFile } from 'zone-file'
import queryString from 'query-string'
import {
Expand All @@ -15,7 +16,8 @@ import {
redirectUserToApp,
getAppBucketUrl,
isLaterVersion,
updateQueryStringParameter
updateQueryStringParameter,
getPublicKeyFromPrivate
} from 'blockstack'
import { AppsNode } from '@utils/account-utils'
import {
Expand All @@ -27,7 +29,10 @@ import { HDNode } from 'bitcoinjs-lib'
import log4js from 'log4js'
import { uploadProfile } from '../account/utils'
import { signProfileForUpload } from '@utils'
import { validateScopes, appRequestSupportsDirectHub } from './utils'
import {
validateScopes,
appRequestSupportsDirectHub
} from './utils'
import {
selectApi,
selectCoreHost,
Expand All @@ -53,6 +58,7 @@ import {
} from '@common/store/selectors/account'
import { formatAppManifest } from '@common'
import Modal from 'react-modal'
import url from 'url'

const views = [Initial, LegacyGaia]

Expand Down Expand Up @@ -86,6 +92,21 @@ function mapDispatchToProps(dispatch) {
return bindActionCreators(actions, dispatch)
}

function makeGaiaAssociationToken(secretKeyHex: string, childPublicKeyHex: string) {
const LIFETIME_SECONDS = 365 * 24 * 3600
const signerKeyHex = secretKeyHex.slice(0, 64)
const compressedPublicKeyHex = getPublicKeyFromPrivate(signerKeyHex)
const salt = randomBytes(16).toString('hex')
const payload = { childToAssociate: childPublicKeyHex,
iss: compressedPublicKeyHex,
exp: LIFETIME_SECONDS + (new Date()/1000),
iat: Date.now()/1000,
salt }

const token = new TokenSigner('ES256K', signerKeyHex).sign(payload)
return token
}

class AuthPage extends React.Component {
static contextTypes = {
router: PropTypes.object
Expand Down Expand Up @@ -171,24 +192,34 @@ class AuthPage extends React.Component {
if (redirectURI) {
// Get the current localhost authentication url that the app will redirect back to,
// and remove the 'echo' param from it.
const authContinuationURI = updateQueryStringParameter(window.location.href, 'echo', '')
redirectURI = updateQueryStringParameter(redirectURI, 'echoReply', this.state.echoRequestId)
redirectURI = updateQueryStringParameter(redirectURI, 'authContinuation', encodeURIComponent(authContinuationURI))
const authContinuationURI = updateQueryStringParameter(
window.location.href,
'echo',
''
)
redirectURI = updateQueryStringParameter(
redirectURI,
'echoReply',
this.state.echoRequestId
)
redirectURI = updateQueryStringParameter(
redirectURI,
'authContinuation',
encodeURIComponent(authContinuationURI)
)
} else {
throw new Error('Invalid redirect echo reply URI')
}
this.setState({ responseSent: true })
window.location = redirectURI
}

componentWillReceiveProps(nextProps) {

componentWillReceiveProps(nextProps) {
if (!this.state.responseSent) {

if (this.state.echoRequestId) {
this.redirectUserToEchoReply()
return
}
}

const storageConnected = this.props.api.storageConnected
this.setState({
Expand Down Expand Up @@ -251,9 +282,7 @@ class AuthPage extends React.Component {

if (identity.zoneFile && identity.zoneFile.length > 0) {
const zoneFileJson = parseZoneFile(identity.zoneFile)
const profileUrlFromZonefile = getTokenFileUrlFromZoneFile(
zoneFileJson
)
const profileUrlFromZonefile = getTokenFileUrlFromZoneFile(zoneFileJson)
if (
profileUrlFromZonefile !== null &&
profileUrlFromZonefile !== undefined
Expand All @@ -267,6 +296,7 @@ class AuthPage extends React.Component {
const gaiaUrlBase = nextProps.api.gaiaHubConfig.url_prefix

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

getFreshIdentities = async () => {
await this.props.refreshIdentities(
this.props.api,
this.props.addresses
)
await this.props.refreshIdentities(this.props.api, this.props.addresses)
this.setState({ refreshingIdentities: false })
}

Expand Down Expand Up @@ -392,6 +419,8 @@ class AuthPage extends React.Component {

let transitPublicKey = undefined
let hubUrl = undefined
let blockstackAPIUrl = undefined
let associationToken = undefined

let requestVersion = '0'
if (this.state.decodedToken.payload.hasOwnProperty('version')) {
Expand All @@ -407,6 +436,13 @@ class AuthPage extends React.Component {
if (appRequestSupportsDirectHub(this.state.decodedToken.payload)) {
hubUrl = this.props.api.gaiaHubUrl
}
if (isLaterVersion(requestVersion, '1.3.0')) {
const compressedAppPublicKey = getPublicKeyFromPrivate(appPrivateKey.slice(0,64))
const parsedCoreUrl = url.parse(this.props.api.nameLookupUrl)

blockstackAPIUrl = `${parsedCoreUrl.protocol}//${parsedCoreUrl.host}`
associationToken = makeGaiaAssociationToken(privateKey, compressedAppPublicKey)
}

const authResponse = makeAuthResponse(
privateKey,
Expand All @@ -417,14 +453,17 @@ class AuthPage extends React.Component {
appPrivateKey,
undefined,
transitPublicKey,
hubUrl
hubUrl,
blockstackAPIUrl,
associationToken
)

this.props.clearSessionToken(appDomain)

logger.info(
`login(): id index ${this.state.currentIdentityIndex} is logging in`
)

this.setState({ responseSent: true })
redirectUserToApp(this.state.authRequest, authResponse)
}
Expand Down Expand Up @@ -541,7 +580,11 @@ class AuthPage extends React.Component {
}

render() {
const { appManifest, appManifestLoading, appManifestLoadingError } = this.props
const {
appManifest,
appManifestLoading,
appManifestLoadingError
} = this.props

if (appManifestLoadingError) {
return (
Expand Down Expand Up @@ -596,11 +639,18 @@ class AuthPage extends React.Component {
)
},
deny: () => console.log('go back to app'),
backLabel: 'Cancel',
backView: () => {
if (document.referrer === '') {
window.close()
} else {
history.back()
}
},
accounts: this.props.localIdentities,
processing: this.state.processing,
refreshingIdentities: this.state.refreshingIdentities,
selectedIndex: this.state.currentIdentityIndex,
disableBackOnView: 0
selectedIndex: this.state.currentIdentityIndex
}
},
{
Expand Down Expand Up @@ -630,4 +680,7 @@ class AuthPage extends React.Component {
}
}

export default connect(mapStateToProps, mapDispatchToProps)(AuthPage)
export default connect(
mapStateToProps,
mapDispatchToProps
)(AuthPage)
1 change: 0 additions & 1 deletion app/js/auth/utils.js
Expand Up @@ -5,7 +5,6 @@ import { isLaterVersion } from 'blockstack'

const logger = log4js.getLogger(__filename)


const VALID_SCOPES = {
store_write: true,
email: true,
Expand Down
17 changes: 7 additions & 10 deletions app/js/auth/views/initial.js
Expand Up @@ -6,7 +6,13 @@ const basicInfo = 'read your basic info'
const readEmail = 'read your email address'
const publishData = 'publish data stored for this app'

const Accounts = ({ list, handleClick, processing, refreshingIdentities, selectedIndex }) => {
const Accounts = ({
list,
handleClick,
processing,
refreshingIdentities,
selectedIndex
}) => {
let loadingMessage = null
if (processing) {
loadingMessage = 'Signing in...'
Expand Down Expand Up @@ -121,15 +127,6 @@ const InitialScreen = ({
</Buttons>
</>
)
},
actions: {
items: [
{
label: 'Deny',
to: '/',
negative: true
}
]
}
}
return <ShellScreen {...rest} {...props} />
Expand Down

0 comments on commit 8103c82

Please sign in to comment.