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/0.21.6'
Browse files Browse the repository at this point in the history
  • Loading branch information
larrysalibra committed Dec 27, 2017
2 parents b5668bf + 58d2217 commit 839f2a6
Show file tree
Hide file tree
Showing 9 changed files with 253 additions and 272 deletions.
59 changes: 17 additions & 42 deletions app/js/HomeScreenPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@ import React, { Component, PropTypes } from 'react'
import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'
import Navbar from './components/Navbar'
import ToolTip from './components/ToolTip'
import { AppsActions } from './store/apps'
import appList from './data/apps'
import { isWebAppBuild, isCoreEndpointDisabled } from './utils/window-utils'
import { isWebAppBuild } from './utils/window-utils'

function mapStateToProps(state) {
return {
Expand All @@ -21,48 +20,24 @@ function mapDispatchToProps(dispatch) {
return bindActionCreators(Object.assign({}, AppsActions), dispatch)
}

const AppIcon = (props) => {
const disabledForCore = isCoreEndpointDisabled() && props.storageRequired
return (
<div className="container-fluid app-box-wrap">
<ToolTip id="coreDisabled">
<div>
<div>
This app requires Gaia storage, which is not supported in the webapp build.
Feature coming soon!
</div>
</div>
</ToolTip>
{disabledForCore ?
<div
className="app-box"
data-tip
data-for="coreDisabled"
>
<img
src={`/images/${props.iconImage}`}
alt={props.displayName}
/>
</div>
:
<a
href={props.launchLink}
className="app-box-container"
>
<div className="app-box">
<img
src={`/images/${props.iconImage}`}
alt={props.displayName}
/>
</div>
</a>
}
<div className="app-text-container">
<h3>{props.displayName}</h3>
const AppIcon = (props) => (
<div className="container-fluid app-box-wrap">
<a
href={props.launchLink}
className="app-box-container"
>
<div className="app-box">
<img
src={`/images/${props.iconImage}`}
alt={props.displayName}
/>
</div>
</a>
<div className="app-text-container">
<h3>{props.displayName}</h3>
</div>
)
}
</div>
)

const disclaimerWeb = `The Blockstack Tokens are a crypto asset that is currently being
developed by Blockstack Token LLC, a Delaware limited liability
Expand Down
62 changes: 7 additions & 55 deletions app/js/account/utils/blockstack-inc.js
Original file line number Diff line number Diff line change
@@ -1,74 +1,23 @@
// @flow
import log4js from 'log4js'
import bitcoin from 'bitcoinjs-lib'
import bigi from 'bigi'
const logger = log4js.getLogger('account/utils/blockstack-inc.js')

export type GaiaHubConfig = {
address: string,
token: string,
server: string
}
import { uploadToGaiaHub, connectToGaiaHub, GaiaHubConfig } from 'blockstack'

function uploadToGaiaHub(hubConfig: GaiaHubConfig, filename: string, contents: any,
contentType: string = 'application/octet-stream'): Promise<*> {
return new Promise((resolve) => {
logger.debug(`uploadToGaiaHub: uploading ${filename} to ${hubConfig.server}`)
return fetch(`${hubConfig.server}/store/${hubConfig.address}/${filename}`,
{ method: 'POST',
headers: {
'Content-Type': contentType,
Authorization: `bearer ${hubConfig.token}`
},
body: contents })
.then((response) => response.text())
.then((responseText) => JSON.parse(responseText))
.then((responseJSON) => {
resolve(responseJSON.publicURL)
})
})
}
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(hubConfig, filename, photoFile)
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(hubConfig, filename, signedProfileTokenData, 'application/json')
}

export function connectToGaiaHub(gaiaHubUrl: string, challengeSignerHex: string): Promise<*> {
logger.debug(`connectToGaiaHub: ${gaiaHubUrl}/hub_info`)
const challengeSigner = new bitcoin.ECPair(
bigi.fromHex(challengeSignerHex))
return new Promise((resolve) => {
fetch(`${gaiaHubUrl}/hub_info`)
.then((response) => response.text())
.then((responseText) => JSON.parse(responseText))
.then((responseJSON) => {
const readURL = responseJSON.read_url_prefix
const challenge = responseJSON.challenge_text
const digest = bitcoin.crypto.sha256(challenge)
const signature = challengeSigner.sign(digest)
.toDER().toString('hex')
const publickey = challengeSigner.getPublicKeyBuffer()
.toString('hex')
const token = new Buffer(JSON.stringify(
{ publickey, signature })).toString('base64')
const address = challengeSigner.getAddress()
resolve({ url_prefix: readURL,
address,
token,
server: gaiaHubUrl }
) }) })
return uploadToGaiaHub(filename, signedProfileTokenData, hubConfig, 'application/json')
}

export function redirectToConnectToGaiaHub() {
Expand All @@ -77,3 +26,6 @@ export function redirectToConnectToGaiaHub() {
const host = location.hostname
window.top.location.href = `http://${host}:${port}/account/storage#gaiahub`
}

export { connectToGaiaHub, GaiaHubConfig }

73 changes: 46 additions & 27 deletions app/js/auth/components/AuthModal.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,16 @@ import { AuthActions } from '../store/auth'
import { Link } from 'react-router'
import { decodeToken } from 'jsontokens'
import {
makeAuthResponse, getAuthRequestFromURL, Person, redirectUserToApp
makeAuthResponse, getAuthRequestFromURL, Person, redirectUserToApp,
isLaterVersion
} from 'blockstack'
import Image from '../../components/Image'
import { AppsNode } from '../../utils/account-utils'
import { setCoreStorageConfig } from '../../utils/api-utils'
import { isCoreEndpointDisabled, isWindowsBuild } from '../../utils/window-utils'
import { getTokenFileUrlFromZoneFile } from '../../utils/zone-utils'
import { HDNode } from 'bitcoinjs-lib'
import { validateScopes } from '../utils'
import { validateScopes, appRequestSupportsDirectHub } from '../utils'
import log4js from 'log4js'

const logger = log4js.getLogger('auth/components/AuthModal.js')
Expand Down Expand Up @@ -90,7 +91,7 @@ class AuthModal extends Component {
invalidScopes: false,
sendEmail: false,
blockchainId: null,
noStorage: false,
noCoreStorage: false,
responseSent: false,
requestingEmail: false
}
Expand Down Expand Up @@ -139,7 +140,7 @@ class AuthModal extends Component {
const localIdentities = nextProps.localIdentities
const identityKeypairs = nextProps.identityKeypairs
if ((!appDomain || !nextProps.coreSessionTokens[appDomain])) {
if (this.state.noStorage) {
if (this.state.noCoreStorage) {
logger.debug('componentWillReceiveProps: no core session token expected')
} else {
logger.debug('componentWillReceiveProps: no app domain or no core session token')
Expand All @@ -151,7 +152,7 @@ class AuthModal extends Component {

const coreSessionToken = nextProps.coreSessionTokens[appDomain]
let decodedCoreSessionToken = null
if (!this.state.noStorage) {
if (!this.state.noCoreStorage) {
logger.debug('componentWillReceiveProps: received coreSessionToken')
decodedCoreSessionToken = decodeToken(coreSessionToken)
} else {
Expand Down Expand Up @@ -206,9 +207,6 @@ class AuthModal extends Component {
}

// TODO: what if the token is expired?
// TODO: use a semver check -- or pass payload version to
// makeAuthResponse
let authResponse

let profileResponseData
if (this.state.decodedToken.payload.do_not_include_profile) {
Expand All @@ -217,19 +215,22 @@ class AuthModal extends Component {
profileResponseData = profile
}

if (this.state.decodedToken.payload.version === '1.1.0' &&
this.state.decodedToken.payload.public_keys.length > 0) {
const transitPublicKey = this.state.decodedToken.payload.public_keys[0]
let transitPublicKey = undefined
let hubUrl = undefined

authResponse = makeAuthResponse(privateKey, profileResponseData, blockchainId,
metadata,
coreSessionToken, appPrivateKey,
undefined, transitPublicKey)
} else {
authResponse = makeAuthResponse(privateKey, profileResponseData, blockchainId,
metadata,
coreSessionToken, appPrivateKey)
const requestVersion = this.state.decodedToken.payload.version
if (isLaterVersion(requestVersion, '1.1.0') &&
this.state.decodedToken.payload.public_keys.length > 0) {
transitPublicKey = this.state.decodedToken.payload.public_keys[0]
}
if (appRequestSupportsDirectHub(this.state.decodedToken.payload)) {
hubUrl = this.props.api.gaiaHubConfig.server
}

const authResponse = makeAuthResponse(privateKey, profileResponseData, blockchainId,
metadata, coreSessionToken, appPrivateKey,
undefined, transitPublicKey, hubUrl)


this.props.clearSessionToken(appDomain)

Expand Down Expand Up @@ -304,6 +305,7 @@ class AuthModal extends Component {
const appsNode = new AppsNode(HDNode.fromBase58(appsNodeKey), salt)
const appPrivateKey = appsNode.getAppNode(appDomain).getAppPrivateKey()
const blockchainId = (hasUsername ? identity.username : null)
const needsCoreStorage = !appRequestSupportsDirectHub(this.state.decodedToken.payload)

const scopesJSONString = JSON.stringify(scopes)

Expand All @@ -320,7 +322,7 @@ class AuthModal extends Component {
sendEmail: !!scopes.includes('email')
})
const requestingStoreWrite = !!scopes.includes('store_write')
if (requestingStoreWrite) {
if (requestingStoreWrite && needsCoreStorage) {
logger.trace('login(): Calling setCoreStorageConfig()...')
setCoreStorageConfig(this.props.api, identityIndex, identity.ownerAddress,
identity.profile, profileSigningKeypair)
Expand All @@ -331,10 +333,16 @@ class AuthModal extends Component {
this.props.corePort, this.props.coreAPIPassword, appPrivateKey,
appDomain, this.state.authRequest, blockchainId)
})
} else if (requestingStoreWrite && !needsCoreStorage) {
logger.trace('login(): app can communicate directly with gaiahub, not setting up core.')
this.setState({
noCoreStorage: true
})
this.props.noCoreSessionToken(appDomain)
} else {
logger.trace('login(): No storage access requested.')
this.setState({
noStorage: true
noCoreStorage: true
})
this.props.noCoreSessionToken(appDomain)
}
Expand All @@ -347,14 +355,15 @@ class AuthModal extends Component {
const processing = this.state.processing
const invalidScopes = this.state.invalidScopes
const decodedToken = this.state.decodedToken
const noStorage = (decodedToken
&& decodedToken.payload.scopes
&& !decodedToken.payload.scopes.includes('store_write'))
const noCoreStorage = (decodedToken
&& decodedToken.payload.scopes
&& (!decodedToken.payload.scopes.includes('store_write')
|| appRequestSupportsDirectHub(decodedToken.payload)))

const coreShortCircuit = (!appManifestLoading
&& appManifest !== null
&& !invalidScopes
&& !noStorage
&& !noCoreStorage
&& isCoreEndpointDisabled())
if (coreShortCircuit) {
let appText
Expand All @@ -377,9 +386,19 @@ class AuthModal extends Component {
>
<h3>Sign In Request</h3>
<div>
{appManifest.hasOwnProperty('icons') ?
<p>
<Image
src={appManifest.icons[0].src}
style={{ width: '128px', height: '128px' }}
fallbackSrc="/images/app-icon-hello-blockstack.png"
/>
</p>
: null}
<p>
This application requires using Gaia storage, which is not supported yet
in our {appText}. Feature coming soon!
This application uses an older Gaia storage library, which is not supported
in our {appText}. Once the application updates its library, you will be
able to use it.
</p>
</div>
</Modal>
Expand Down
14 changes: 14 additions & 0 deletions app/js/auth/utils.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// @flow

import log4js from 'log4js'
import { isLaterVersion } from 'blockstack'

const logger = log4js.getLogger('auth/components/util.js')

Expand All @@ -10,6 +11,19 @@ const VALID_SCOPES = {
email: true
}

export function appRequestSupportsDirectHub(requestPayload: Object): boolean {
let version = '0'
let supportsHubUrl = false
if (requestPayload.hasOwnProperty('version')) {
version = requestPayload.version
}
if (requestPayload.hasOwnProperty('supports_hub_url')) {
supportsHubUrl = requestPayload.supports_hub_url
}

return isLaterVersion(version, '1.2.0') || !!supportsHubUrl
}

export function validateScopes(scopes: Array<string>): boolean {
logger.trace('validateScopes')

Expand Down
2 changes: 1 addition & 1 deletion docs/release-checklist.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Browser release checklist

- [ ] `git flow release start 0.14.0` where 0.14.0 is the version of the release
- [ ] `git flow release start 0.14.0` where 0.14.0 is the version of the release (make sure the version prefix `v` is set for git flow)
- [ ] `git flow release publish` (optional, shares release branch)
- [ ] update version in `/package.json`
- [ ] update version and build number in xcode
Expand Down
4 changes: 2 additions & 2 deletions native/macos/Blockstack/Blockstack/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>0.21.5</string>
<string>0.21.6</string>
<key>CFBundleURLTypes</key>
<array>
<dict>
Expand All @@ -30,7 +30,7 @@
</dict>
</array>
<key>CFBundleVersion</key>
<string>80</string>
<string>81</string>
<key>LSApplicationCategoryType</key>
<string>public.app-category.utilities</string>
<key>LSMinimumSystemVersion</key>
Expand Down
Loading

0 comments on commit 839f2a6

Please sign in to comment.