Skip to content

Commit

Permalink
POC: Configure two Web Wallet applications (Root Document & Main Proc…
Browse files Browse the repository at this point in the history
…ess) to coexist.
  • Loading branch information
Empowerful committed Apr 25, 2019
1 parent a708ee6 commit 0412030
Show file tree
Hide file tree
Showing 78 changed files with 2,486 additions and 571 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -84,10 +84,11 @@
},
"dependencies": {
"@blockchain-com/components": "5.1.1",
"@ledgerhq/hw-app-eth": "4.26.0-beta.ebeb3540",
"@ledgerhq/hw-app-btc": "4.30.0",
"@ledgerhq/hw-app-eth": "4.26.0-beta.ebeb3540",
"@ledgerhq/hw-app-str": "4.26.0-beta.ebeb3540",
"@ledgerhq/hw-transport-u2f": "4.31.0",
"@nodeguy/channel": "0.6.5",
"awesome-phonenumber": "2.2.6",
"base-64": "0.1.0",
"bignumber.js": "8.0.1",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import * as router from 'connected-react-router'
import * as R from 'ramda'

import * as coreTypes from 'blockchain-wallet-v4/src/redux/actionTypes'
import * as types from '../data/actionTypes'

const alreadyForwarded = ({ meta }) => meta && meta.forwarded

const dispatchToBoth = ({ rootDocumentDispatch, next }, action) => {
if (!alreadyForwarded(action)) {
rootDocumentDispatch(action)
}

next(action)
}

const dispatchToRootDocument = ({ rootDocumentDispatch }, action) => {
rootDocumentDispatch(action)
}

const tag = action => ({
...action,
meta: { ...action.meta, forwarded: true }
})

const handlers = {
// This requires the GUID.
[coreTypes.data.misc.FETCH_LOGS]: dispatchToRootDocument,

// This requires the GUID.
[coreTypes.settings.FETCH_SETTINGS]: dispatchToRootDocument,

// Tell the Root Document to merge our wrapper with its own.
[coreTypes.wallet.MERGE_WRAPPER]: dispatchToRootDocument,

// Inform the root document about routing changes so that it can switch which
// application is displayed.
[router.LOCATION_CHANGE]: dispatchToBoth,

// Tell the root document to reload itself when we do.
[types.auth.LOGOUT]: dispatchToBoth,

// This requires the GUID.
[types.modules.settings.UPDATE_LANGUAGE]: dispatchToRootDocument
}

export default ({ actionsChannel, rootDocumentDispatch }) => store => {
// Now that we have access to the store, dispatch stored actions from the Root
// Document to it.
actionsChannel.forEach(store.dispatch)

return next => action => {
const { type } = action

const context = {
rootDocumentDispatch: R.pipe(
tag,
rootDocumentDispatch
),
next,
store
}

if (type in handlers) {
return handlers[type](context, action)
} else {
return next(action)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import Channel from '@nodeguy/channel'

import { serializer } from 'blockchain-wallet-v4/src/types'
import Middleware from './Middleware'
import * as kernel from '../../../web-microkernel/src'

export default async ({ input, output, outputOrigin }) => {
// We need to export a function for dispatching actions from the Root
// Document before the store is created so use a channel to save them until
// the store is ready.
const actionsChannel = Channel()

const connection = await kernel.RealmConnection({
exports: { dispatch: actionsChannel.push },
input,
output,
outputOrigin,
reviver: serializer.reviver
})

return {
connection,

middleware: Middleware({
actionsChannel,
rootDocumentDispatch: connection.imports.dispatch
})
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export const DEAUTHORIZE_BROWSER = 'DEAUTHORIZE_BROWSER'
export const LOGIN = 'LOGIN'
export const LOGIN_FAILURE = 'LOGIN_FAILURE'
export const LOGIN_LOADING = 'LOGIN_LOADING'
export const LOGIN_ROUTINE = 'LOGIN_ROUTINE'
export const LOGIN_SUCCESS = 'LOGIN_SUCCESS'
export const LOGOUT = 'LOGOUT'
export const LOGOUT_CLEAR_REDUX_STORE = 'LOGOUT_CLEAR_REDUX_STORE'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ export const login = (guid, password, code, sharedKey, mobileLogin) => ({
payload: { guid, password, code, sharedKey, mobileLogin }
})
export const loginLoading = () => ({ type: AT.LOGIN_LOADING })

export const loginRoutine = (mobileLogin = false, firstLogin = false) => ({
type: AT.LOGIN_ROUTINE,
payload: { firstLogin, mobileLogin }
})

export const loginSuccess = () => ({ type: AT.LOGIN_SUCCESS, payload: {} })
export const loginFailure = err => ({
type: AT.LOGIN_FAILURE,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@ import { takeLatest } from 'redux-saga/effects'
import * as AT from './actionTypes'
import sagas from './sagas'

export default ({ api, coreSagas }) => {
const authSagas = sagas({ api, coreSagas })
export default (...args) => {
const authSagas = sagas(...args)

return function* authSaga () {
yield takeLatest(AT.DEAUTHORIZE_BROWSER, authSagas.deauthorizeBrowser)
yield takeLatest(AT.LOGIN, authSagas.login)
yield takeLatest(AT.LOGIN_ROUTINE, authSagas.loginRoutineSaga)
yield takeLatest(AT.LOGOUT, authSagas.logout)
yield takeLatest(
AT.LOGOUT_CLEAR_REDUX_STORE,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export const emailMismatch2faErrorMessage =
export const wrongCaptcha2faErrorMessage = 'Error: Captcha Code Incorrect'
export const wrongAuthCodeErrorMessage = 'Authentication code is incorrect'

export default ({ api, coreSagas }) => {
export default ({ api, coreSagas, rootDocument }) => {
const upgradeWallet = function*() {
try {
let password = yield call(promptForSecondPassword)
Expand Down Expand Up @@ -92,15 +92,18 @@ export default ({ api, coreSagas }) => {
if (userFlowSupported) yield put(actions.modules.profile.signIn())
}

const loginRoutineSaga = function*(mobileLogin, firstLogin) {
const loginRoutineSaga = function*({ payload: { mobileLogin, firstLogin } }) {
try {
// If needed, the user should upgrade its wallet before being able to open the wallet
const isHdWallet = yield select(selectors.core.wallet.isHdWallet)
if (!isHdWallet) {
yield call(upgradeWalletSaga)
}
yield put(actions.auth.authenticate())
yield call(coreSagas.kvStore.root.fetchRoot, askSecondPasswordEnhancer)

yield call(coreSagas.kvStore.root.fetchRoot, {
askSecondPasswordEnhancer
})

// If there was no ethereum metadata kv store entry, we need to create one and that requires the second password.
yield call(
coreSagas.kvStore.ethereum.fetchMetadataEthereum,
Expand All @@ -118,19 +121,13 @@ export default ({ api, coreSagas }) => {
yield put(actions.middleware.webSocket.eth.startSocket())
yield put(actions.middleware.webSocket.xlm.startStreams())
yield put(actions.router.push('/home'))
yield call(coreSagas.settings.fetchSettings)
yield put(actions.core.settings.fetchSettings())
yield call(coreSagas.data.xlm.fetchLedgerDetails)
yield call(coreSagas.data.xlm.fetchData)
yield call(authNabu)
yield call(upgradeAddressLabelsSaga)
yield put(actions.auth.loginSuccess())
yield put(actions.auth.startLogoutTimer())
// store guid in cache for future logins
const guid = yield select(selectors.core.wallet.getGuid)
yield put(actions.cache.guidEntered(guid))
// reset auth type and clear previous login form state
yield put(actions.auth.setAuthType(0))
yield put(actions.form.destroy('login'))
// set payload language to settings language
const language = yield select(selectors.preferences.getLanguage)
yield put(actions.modules.settings.updateLanguage(language))
Expand Down Expand Up @@ -222,7 +219,7 @@ export default ({ api, coreSagas }) => {
password,
code
})
yield call(loginRoutineSaga, mobileLogin)
yield put(actions.auth.loginRoutine(mobileLogin))
} catch (error) {
const initialError = prop('initial_error', error)
const authRequired = prop('authorization_required', error)
Expand All @@ -245,7 +242,7 @@ export default ({ api, coreSagas }) => {
session,
password
})
yield call(loginRoutineSaga, mobileLogin)
yield put(actions.auth.loginRoutine(mobileLogin))
} catch (error) {
if (error && error.auth_type > 0) {
yield put(actions.auth.setAuthType(error.auth_type))
Expand Down Expand Up @@ -334,7 +331,7 @@ export default ({ api, coreSagas }) => {
yield put(actions.alerts.displayInfo(C.CREATE_WALLET_INFO))
yield call(coreSagas.wallet.createWalletSaga, action.payload)
yield put(actions.alerts.displaySuccess(C.REGISTER_SUCCESS))
yield call(loginRoutineSaga, false, true)
yield put(actions.auth.loginRoutine(false, true))
yield put(actions.auth.registerSuccess())
} catch (e) {
yield put(actions.auth.registerFailure())
Expand All @@ -349,7 +346,7 @@ export default ({ api, coreSagas }) => {
yield put(actions.alerts.displayInfo(C.RESTORE_WALLET_INFO))
yield call(coreSagas.wallet.restoreWalletSaga, action.payload)
yield put(actions.alerts.displaySuccess(C.RESTORE_SUCCESS))
yield call(loginRoutineSaga, false, true)
yield put(actions.auth.loginRoutine(false, true))
yield put(actions.auth.restoreSuccess())
} catch (e) {
yield put(actions.auth.restoreFailure())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,11 +93,11 @@ describe('authSagas', () => {
})
})

it('should call login routine', () => {
it('should put login routine', () => {
const { mobileLogin } = payload
saga
.next()
.call(loginRoutineSaga, mobileLogin)
.put(actions.auth.loginRoutineSaga(mobileLogin))
.next()
.isDone()
})
Expand Down Expand Up @@ -185,9 +185,9 @@ describe('authSagas', () => {
})
})

it('should call login routine', () => {
it('should put login routine', () => {
const { mobileLogin } = payload
saga.next().call(loginRoutineSaga, mobileLogin)
saga.next().put(actions.auth.loginRoutineSaga(mobileLogin))
})

it('should follow 2FA flow on auth error', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const logger = (state = INITIAL_STATE, action) => {

switch (type) {
case AT.LOG_ERROR_MSG: {
console.error(payload)
return insert(0, createLog('ERROR', payload), state)
}
case AT.LOG_INFO_MSG: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,23 +59,30 @@ export default function* rootSaga ({
btcSocket,
ethSocket,
ratesSocket,
rootDocument,
networks,
options
}) {
const coreSagas = coreSagasFactory({ api, networks, options })

const coreSagas = coreSagasFactory({
api,
networks,
options,
rootDocument
})

yield all([
call(welcomeSaga),
fork(alerts),
fork(analytics({ api })),
fork(auth({ api, coreSagas })),
fork(auth({ api, coreSagas, rootDocument })),
fork(components({ api, coreSagas, networks, options })),
fork(modules({ api, coreSagas, networks })),
fork(preferences()),
fork(goals({ api })),
fork(wallet({ coreSagas })),
fork(middleware({ api, bchSocket, btcSocket, ethSocket, ratesSocket })),
fork(coreRootSagaFactory({ api, networks, options })),
fork(coreRootSagaFactory({ api, networks, options, rootDocument })),
fork(router()),
call(languageInitSaga)
])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,8 @@ import { FormattedMessage } from 'react-intl'
import { Banner, Text } from 'blockchain-info-components'

import About from './About'
import PairingCode from './PairingCode'
import PrivacyPolicy from './PrivacyPolicy'
import TermsOfService from './TermsOfService'
import WalletId from './WalletId'

const Wrapper = styled.section`
padding: 30px;
Expand All @@ -32,8 +30,6 @@ const General = () => {
/>
</Text>
</Banner>
<WalletId />
<PairingCode />
<PrivacyPolicy />
<TermsOfService />
<About />
Expand Down
Loading

0 comments on commit 0412030

Please sign in to comment.