edge-core-js
Version:
Edge account & wallet management library
130 lines (98 loc) • 4.31 kB
JavaScript
function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }import { buildReducer, memoizeReducer } from 'redux-keto'
import { verifyData } from '../../util/crypto/verify'
import { base58 } from '../../util/encoding'
import { searchTree } from './login'
import { findDuressStash, } from './login-stash'
import { findPin2Stash } from './pin2'
export const login = buildReducer({
apiKey(state = '', action) {
return action.type === 'INIT' ? action.payload.apiKey : state
},
apiSecret(state = null, action) {
return action.type === 'INIT' ? _nullishCoalesce(action.payload.apiSecret, () => ( null)) : state
},
contextAppId(state = '', action) {
return action.type === 'INIT' ? action.payload.appId : state
},
deviceDescription(state = null, action) {
return action.type === 'INIT' ? action.payload.deviceDescription : state
},
localUsers: memoizeReducer(
(next) => next.login.contextAppId,
(next) => next.login.stashes,
(next) => next.clientInfo,
(appId, stashes, clientInfo) => {
function processStash(stashTree) {
const { lastLogin, loginId, recovery2Key, username } = stashTree
const stash = searchTree(stashTree, stash => stash.appId === appId)
const keyLoginEnabled =
stash != null &&
(stash.passwordAuthBox != null || stash.loginAuthBox != null)
// Only look at the duress stash if we're in duress mode:
const duressStash = clientInfo.duressEnabled
? findDuressStash(stashTree, appId)
: undefined
// Only fake pin disabled if the duress stash is present and has a
// pin2Key:
const fakePinDisabled =
_optionalChain([duressStash, 'optionalAccess', _ => _.pin2Key]) != null && _optionalChain([duressStash, 'optionalAccess', _2 => _2.fakePinDisabled]) === true
const pin2Stash = findPin2Stash(stashTree, appId)
// Disable PIN login if we're faking it from the duress stash, or we
// don't have a pin2Key on the account's pin2Stash:
const pinLoginEnabled = !fakePinDisabled && _optionalChain([pin2Stash, 'optionalAccess', _3 => _3.pin2Key]) != null
return {
keyLoginEnabled,
lastLogin,
loginId: base58.stringify(loginId),
pinLoginEnabled,
recovery2Key:
recovery2Key != null ? base58.stringify(recovery2Key) : undefined,
username,
voucherId: stash != null ? stash.voucherId : undefined
}
}
return stashes.map(processStash)
}
),
loginServers(state = [], action) {
return action.type === 'INIT' ? action.payload.loginServers : state
},
stashes(state = [], action) {
switch (action.type) {
case 'INIT': {
return action.payload.stashes
}
case 'LOGIN_STASH_DELETED': {
const loginId = action.payload
return state.filter(
stashTree => !verifyData(stashTree.loginId, loginId)
)
}
case 'LOGIN_STASH_SAVED': {
const newStashTree = action.payload
const out = state.filter(
stashTree => !verifyData(stashTree.loginId, newStashTree.loginId)
)
out.unshift(newStashTree)
return out
}
}
return state
},
walletInfos(state, action, next) {
// Optimize the common case:
if (next.accountIds.length === 1) {
const id = next.accountIds[0]
return next.accounts[id].walletInfos
}
const out = {}
for (const accountId of next.accountIds) {
const account = next.accounts[accountId]
for (const id of Object.keys(account.walletInfos)) {
const info = account.walletInfos[id]
out[id] = info
}
}
return out
}
})