Skip to content

Commit

Permalink
feat(sso): add payload decode from mobile auth message
Browse files Browse the repository at this point in the history
  • Loading branch information
schnogz committed Nov 12, 2021
1 parent 9eae3ec commit 1f40006
Show file tree
Hide file tree
Showing 2 changed files with 10 additions and 77 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { hasPath, pathOr } from 'ramda'
import { END, eventChannel } from 'redux-saga'
import { call, put, select, take } from 'redux-saga/effects'

Expand All @@ -16,24 +15,18 @@ import {

import { LOGIN_FORM } from './model'

// TODO: remove all console logs after dev debugging phase

let messageListener

// global function for mobile clients to call to pass message
// this must be exposed on window
window.receiveMessageFromMobile = (message) => {
// eslint-disable-next-line
console.log('SSO mobile message: ', message)
messageListener(message)
}

// returns eventChannel to calling generator function that will in turn propagate (emit) future message from mobile
// this function must be always be called first before we are able to detect messages since it will expose the
// emitter on messageListener so receiveMessageFromMobile func can emit the actual message
const pollForMessageFromMobile = () => {
// eslint-disable-next-line
console.log('SSO message polling started')
return eventChannel((emitter) => {
messageListener = emitter
return () => emitter(END)
Expand All @@ -47,35 +40,12 @@ const sendMessageToMobile = (
) => {
// messages must be passed as strings to mobile clients
const messageStringified = JSON.stringify(message)
console.log('sendMessageToMobile start')
console.log('sendMessageToMobile platform:', platform)
console.log('sendMessageToMobile webkit defined:', hasPath(['webkit'], window))
console.log('sendMessageToMobile BCAndroidSSI defined:', hasPath(['BCAndroidSSI'], window))
switch (true) {
// ios
case platform === PlatformTypes.IOS:
console.log('sendMessageToMobile ios detected')
try {
console.log(
'sendMessageToMobile webkit.messageHandlers exists?: ',
hasPath(['webkit', 'messageHandlers'], window)
)
try {
console.log(window.webkit.messageHandlers)
} catch (e) {
console.log('messageHandlers missing')
}
console.log(
'sendMessageToMobile connectionStatusHandler exists?: ',
hasPath(['webkit', 'messageHandlers', 'connectionStatusHandler'], window)
)
console.log(
'sendMessageToMobile credentialsHandler exists?: ',
hasPath(['webkit', 'messageHandlers', 'credentialsHandler'], window)
)
// ios has two different message handlers
if ((message as MobileAuthConnectedMessage).status) {
console.log('sendMessageToMobile inside connectionStatusHandler')
window.webkit.messageHandlers.connectionStatusHandler.postMessage(messageStringified)
} else {
window.webkit.messageHandlers.credentialsHandler.postMessage(messageStringified)
Expand All @@ -86,26 +56,21 @@ const sendMessageToMobile = (
break
// android
case platform === PlatformTypes.ANDROID:
console.log('sendMessageToMobile android detected')
try {
console.log(
'sendMessageToMobile postMessage exists?: ',
hasPath(['BCAndroidSSI', 'postMessage'], window)
)
window.BCAndroidSSI.postMessage(messageStringified)
} catch (e) {
throw new Error('Failed to send message to Android')
}
break
default:
console.log('sendMessageToMobile no mobile window detected')
throw new Error('Unable to send message. Missing platform type or window function')
}
}

// initiates contact with mobile apps and returns the auth payload
export const initMobileAuthFlow = function* () {
let mobileMessageChannel
let authPayloadFromMobile
let authPayloadFromMobileEncoded

// get auth metadata about product and platform stored in initial auth saga
const { platform, product } = yield select(selectors.auth.getProductAuthMetadata)
Expand All @@ -114,60 +79,30 @@ export const initMobileAuthFlow = function* () {
try {
// start event listener for message from mobile
mobileMessageChannel = yield call(pollForMessageFromMobile)
console.log('calling sendMessageToMobile')
// let mobile know webview has finished loading
sendMessageToMobile(platform, { status: 'connected' })
// eslint-disable-next-line
console.log('SSO sent connected message to mobile')
// wait for auth payload message from mobile
while (true) {
authPayloadFromMobile = yield take(mobileMessageChannel)
if (authPayloadFromMobile) {
// eslint-disable-next-line
console.log('SSO auth payload message:', authPayloadFromMobile)
authPayloadFromMobileEncoded = yield take(mobileMessageChannel)
if (authPayloadFromMobileEncoded) {
break
}
}
} catch (e) {
mobileMessageChannel.end()
}
// TEST DATA
// authPayloadFromMobile = {
// exchange: {
// email: 'leora+235+1002@blockchain.com',
// user_id: 'ed005bec-1ced-4fc0-95ea-0d6f75ecae10'
// },
// wallet: {
// guid: '543e134b-e022-4fd6-9185-700b5e90908a',
// email: 'leora+235+1002@blockchain.com',
// two_fa_type: 0,
// email_code:
// 'G4XNGu7Pg5yI3qDTyMXTduTFdDZaT40MREr3/yYwwo6vC+aRfqeZqTZlMStgWmsg/9Qq5sLW6LtFS5k/7J+bT2nPs6v2YDz+ud666sodqmTwtsRfEGSVAyW1XX5EUG+tNpA8Jk90coxQtGUL94XV99Yt64W6i9rdDEeDn4UCUhP/KZ4w3iK/og7bLSNFqPIf',
// is_mobile_setup: false,
// has_cloud_backup: false,
// nabu: {
// user_id: '85d02fd0-c74d-4cc5-878e-a77bddb988a3',
// recovery_token: 'e728e8e6-a709-4768-bd51-b08b2796d853'
// }
// },
// user_type: 'EXCHANGE',
// upgradeable: null,
// mergeable: true,
// unified: null,
// product: 'EXCHANGE'
// }

// TODO: mobile will send us an encoded string version of the auth payload,
// need to parse before storing in redux

// decode from base64
const authPayloadDecoded = JSON.parse(atob(authPayloadFromMobileEncoded))
// store payload to redux state so we can use later
yield put(actions.auth.setMagicLinkInfo(authPayloadFromMobile))
yield put(actions.auth.setMagicLinkInfo(authPayloadDecoded))

const {
exchange: exchangeData,
mergeable,
upgradeable,
wallet: walletData
}: WalletDataFromMagicLink = authPayloadFromMobile
}: WalletDataFromMagicLink = authPayloadDecoded

// determine correct flow then setup forms and next step
switch (true) {
Expand Down Expand Up @@ -200,7 +135,7 @@ export const initMobileAuthFlow = function* () {
)
yield put(actions.form.change(LOGIN_FORM, 'step', LoginSteps.ENTER_PASSWORD_EXCHANGE))
break
// no sso flow require, continue to auth
// no sso flow required, continue to auth
default:
break
}
Expand Down
2 changes: 0 additions & 2 deletions packages/blockchain-wallet-v4-frontend/src/data/auth/sagas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -531,8 +531,6 @@ export default ({ api, coreSagas, networks }) => {
switch (true) {
// mobile webview auth flow
case platform !== PlatformTypes.WEB:
// eslint-disable-next-line
console.log('SSO mobile flow detected: ', platform, product)
yield call(initMobileAuthFlow)
break
// no guid on path, use cached/stored guid if exists
Expand Down

0 comments on commit 1f40006

Please sign in to comment.