Skip to content
This repository was archived by the owner on Jan 22, 2026. It is now read-only.

Commit 70cd193

Browse files
authored
Merge pull request #1669 from blockchain/feat/pre-idv-device-check
Feat/pre idv device check
2 parents ccb7874 + 0be7a0e commit 70cd193

18 files changed

Lines changed: 190 additions & 139 deletions

File tree

config/mocks/wallet-options-v4.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,9 @@
329329
"apiKey": "b7a7c320c19ea3a8e276c8921bc3ff79ec064d2cd9d98ab969acc648246b4be5ab2379af704c5d3a3021c0ddf82b3e479590718847c1301e1a85331d2d2a8370",
330330
"upperLimit": 750
331331
}
332+
},
333+
"sift": {
334+
"apiKey": "0ecd212038"
332335
}
333336
},
334337
"ios": {},
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import React, { Component } from 'react'
2+
import { connect } from 'react-redux'
3+
import styled from 'styled-components'
4+
import { path, prop } from 'ramda'
5+
6+
const SiftScienceIframe = styled.iframe`
7+
opacity: 0;
8+
width: 0;
9+
height: 0;
10+
position: absolute;
11+
top: -1000px;
12+
left: -1000px;
13+
`
14+
15+
class SiftScience extends Component {
16+
componentDidMount () {
17+
let receiveMessage = e => {
18+
// const helperDomain = path(
19+
// ['domains', 'walletHelper'],
20+
// this.props.walletOptions
21+
// )
22+
if (!e.data.command) return
23+
if (e.data.from !== 'sift-science') return
24+
if (e.data.to !== 'exchange') return
25+
// if (e.origin !== helperDomain) return
26+
switch (e.data.command) {
27+
case 'done':
28+
this.props.onDone && this.props.onDone()
29+
break
30+
default:
31+
return null
32+
}
33+
}
34+
window.addEventListener('message', receiveMessage, false)
35+
}
36+
37+
render () {
38+
const { options, userId, sessionId = '', siftKey } = this.props
39+
40+
if (!userId) {
41+
return null
42+
}
43+
44+
const walletOptions = options || prop('data', this.props.walletOptions)
45+
const helperDomain = path(['domains', 'walletHelper'], walletOptions)
46+
let url = `${helperDomain}/wallet-helper/sift-science/#/key/${siftKey}/user/${userId}/sessionId/${sessionId}`
47+
return (
48+
<SiftScienceIframe src={url} scrolling='no' id='sift-science-iframe' />
49+
)
50+
}
51+
}
52+
53+
const mapStateToProps = state => ({
54+
walletOptions: path(['walletOptionsPath'], state)
55+
})
56+
57+
export default connect(mapStateToProps)(SiftScience)

packages/blockchain-wallet-v4-frontend/src/data/components/identityVerification/actionTypes.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,12 @@ export const SET_KYC_FLOW_LOADING = '@DATA.KYC.SET_KYC_FLOW_LOADING'
4646
export const SET_KYC_FLOW_SUCCESS = '@DATA.KYC.SET_KYC_FLOW_SUCCESS'
4747
export const SET_KYC_FLOW_FAILURE = '@DATA.KYC.SET_KYC_FLOW_FAILURE'
4848

49+
export const GET_PRE_IDV_DATA = '@EVENT.KYC.GET_PRE_IDV_DATA'
50+
export const SET_PRE_IDV_DATA_LOADING = '@DATA.KYC.SET_PRE_IDV_DATA_LOADING'
51+
export const SET_PRE_IDV_DATA_SUCCESS = '@DATA.KYC.SET_PRE_IDV_DATA_SUCCESS'
52+
53+
export const PRE_IDV_CHECK_FINISHED = '@EVENT.KYC.PRE_IDV_CHECK_FINISHED'
54+
4955
export const SEND_DEEP_LINK = '@EVENT.KYC.SEND_DEEP_LINK'
5056

5157
export const UPDATE_EMAIL = '@EVENT.KYC.UPDATE_EMAIL'

packages/blockchain-wallet-v4-frontend/src/data/components/identityVerification/actions.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,20 @@ export const sendDeeplink = () => ({
106106
type: AT.SEND_DEEP_LINK
107107
})
108108

109+
export const getPreIdvData = () => ({
110+
type: AT.GET_PRE_IDV_DATA
111+
})
112+
export const setPreIdvDataLoading = () => ({
113+
type: AT.SET_PRE_IDV_DATA_LOADING
114+
})
115+
export const setPreIdvDataSuccess = preIdvData => ({
116+
type: AT.SET_PRE_IDV_DATA_SUCCESS,
117+
payload: { preIdvData }
118+
})
119+
export const preIdvCheckFinished = () => ({
120+
type: AT.PRE_IDV_CHECK_FINISHED
121+
})
122+
109123
export const setStepsLoading = () => ({
110124
type: AT.SET_STEPS_LOADING
111125
})

packages/blockchain-wallet-v4-frontend/src/data/components/identityVerification/reducers.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ const INITIAL_STATE = {
1212
supportedCountries: Remote.NotAsked,
1313
supportedDocuments: Remote.NotAsked,
1414
flowConfig: Remote.NotAsked,
15+
preIdvData: Remote.NotAsked,
1516
states: Remote.NotAsked,
1617
steps: Remote.NotAsked
1718
}
@@ -73,6 +74,9 @@ export default (state = INITIAL_STATE, action) => {
7374
case AT.SET_KYC_FLOW_FAILURE: {
7475
return assoc('flowConfig', Remote.Failure(payload.e), state)
7576
}
77+
case AT.SET_PRE_IDV_DATA_SUCCESS: {
78+
return assoc('preIdvData', Remote.Success(payload.preIdvData), state)
79+
}
7680
case AT.SET_STEPS_LOADING: {
7781
return assoc('steps', Remote.Loading, state)
7882
}

packages/blockchain-wallet-v4-frontend/src/data/components/identityVerification/sagas.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import profileSagas from 'data/modules/profile/sagas'
66
import * as C from 'services/AlertService'
77

88
import * as A from './actions'
9+
import * as AT from './actionTypes'
910
import * as S from './selectors'
1011
import {
1112
EMAIL_STEPS,
@@ -379,6 +380,10 @@ export default ({ api, coreSagas }) => {
379380
const checkKycFlow = function * () {
380381
try {
381382
yield put(A.setKycFlowLoading())
383+
const preIdvData = yield call(api.fetchPreIdvData)
384+
yield put(A.setPreIdvDataSuccess(preIdvData))
385+
yield take(AT.PRE_IDV_CHECK_FINISHED)
386+
yield delay(1000)
382387
const { flowType } = yield call(api.fetchKycConfig)
383388
const type = FLOW_TYPES[toUpper(flowType)]
384389
if (!type) throw wrongFlowTypeError

packages/blockchain-wallet-v4-frontend/src/data/components/identityVerification/sagas.spec.js

Lines changed: 1 addition & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,9 @@ import { Remote } from 'blockchain-wallet-v4/src'
99
import { actions, model, selectors } from 'data'
1010
import * as A from './actions'
1111
import * as S from './selectors'
12-
import { EMAIL_STEPS, FLOW_TYPES, SUNRIVER_LINK_ERROR_MODAL } from './model'
12+
import { EMAIL_STEPS, SUNRIVER_LINK_ERROR_MODAL } from './model'
1313
import sagas, {
1414
logLocation,
15-
wrongFlowTypeError,
1615
noCampaignDataError,
1716
invalidLinkError
1817
} from './sagas'
@@ -34,7 +33,6 @@ const getCampaignData = jest.fn()
3433
profileSagas.mockReturnValue({ createUser, getCampaignData })
3534

3635
const {
37-
checkKycFlow,
3836
createRegisterUserCampaign,
3937
defineSteps,
4038
goToNextStep,
@@ -165,38 +163,6 @@ describe('goToNextStep saga', () => {
165163
.run())
166164
})
167165

168-
describe('checkKycFlow saga', () => {
169-
it('should set flow config', () => {
170-
const flowType = FLOW_TYPES.LOW
171-
api.fetchKycConfig.mockResolvedValue({ flowType })
172-
return expectSaga(checkKycFlow)
173-
.put(A.setKycFlowLoading())
174-
.call(api.fetchKycConfig)
175-
.put(A.setKycFlowSuccess({ flowType }))
176-
.run()
177-
})
178-
179-
it('should set wrong type error if type is not in FLOW_TYPES', () => {
180-
const flowType = FLOW_TYPES.LOW + '1'
181-
api.fetchKycConfig.mockResolvedValue({ flowType })
182-
return expectSaga(checkKycFlow)
183-
.put(A.setKycFlowLoading())
184-
.call(api.fetchKycConfig)
185-
.put(A.setKycFlowFailure(wrongFlowTypeError))
186-
.run()
187-
})
188-
189-
it('should set error if flow type endpoint rejects', () => {
190-
const error = {}
191-
api.fetchKycConfig.mockRejectedValue(error)
192-
return expectSaga(checkKycFlow)
193-
.put(A.setKycFlowLoading())
194-
.call(api.fetchKycConfig)
195-
.put(A.setKycFlowFailure(error))
196-
.run()
197-
})
198-
})
199-
200166
describe('createRegisterUserCampaign', () => {
201167
it('should call verify identity and register user campaign', () => {
202168
const saga = testSaga(createRegisterUserCampaign)

packages/blockchain-wallet-v4-frontend/src/data/components/identityVerification/selectors.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,10 @@ export const getKycFlowConfig = path([
3636
'flowConfig'
3737
])
3838

39+
export const getPreIdvData = path([
40+
'components',
41+
'identityVerification',
42+
'preIdvData'
43+
])
44+
3945
export const getSteps = path(['components', 'identityVerification', 'steps'])

packages/blockchain-wallet-v4-frontend/src/modals/Exchange/IdentityVerification/Verify/index.js

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,14 @@ import { bindActionCreators } from 'redux'
33
import { connect } from 'react-redux'
44

55
import { actions, model } from 'data'
6-
import { getData } from './selectors'
6+
import { getData, getPreIdvData } from './selectors'
77
import { MediaContextConsumer } from 'providers/MatchMediaProvider'
8+
import SiftScience from 'components/SiftScience'
89

910
import LowFlow from './template.lowflow'
1011
import HighFlow from './template.highflow'
1112
import Loading from './template.loading'
13+
import DataError from 'components/DataError'
1214
import { hasWebcam } from 'utils/helpers'
1315

1416
const { FLOW_TYPES, KYC_PROVIDERS } = model.components.identityVerification
@@ -45,9 +47,9 @@ class VerifyContainer extends React.PureComponent {
4547
}
4648

4749
render () {
48-
const { data, actions, modalActions, ...rest } = this.props
50+
const { data, preIdvData, actions, modalActions, ...rest } = this.props
4951

50-
return data.cata({
52+
const VerificationFlow = data.cata({
5153
Success: ({
5254
deeplink,
5355
docTypes,
@@ -82,13 +84,30 @@ class VerifyContainer extends React.PureComponent {
8284
},
8385
Loading: () => <Loading />,
8486
NotAsked: () => null,
87+
Failure: message => <DataError message={message} />
88+
})
89+
90+
const PreIdvCheck = preIdvData.cata({
91+
Success: val => (
92+
<SiftScience {...val} onDone={actions.preIdvCheckFinished} />
93+
),
94+
Loading: () => null,
95+
NotAsked: () => null,
8596
Failure: () => null
8697
})
98+
99+
return (
100+
<React.Fragment>
101+
{VerificationFlow}
102+
{PreIdvCheck}
103+
</React.Fragment>
104+
)
87105
}
88106
}
89107

90108
const mapStateToProps = state => ({
91-
data: getData(state)
109+
data: getData(state),
110+
preIdvData: getPreIdvData(state)
92111
})
93112

94113
const mapDispatchToProps = dispatch => ({

packages/blockchain-wallet-v4-frontend/src/modals/Exchange/IdentityVerification/Verify/selectors.js

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,42 @@ import { model, selectors } from 'data'
44
const { GENERAL, EXPIRED } = model.profile.DOC_RESUBMISSION_REASONS
55
const { getEmail } = selectors.core.settings
66
const {
7-
getSupportedDocuments,
8-
getKycFlowConfig
7+
getKycFlowConfig,
8+
getPreIdvData: getSiftData,
9+
getSupportedDocuments
910
} = selectors.components.identityVerification
1011

1112
export const getData = state => {
13+
const getEmailR = getEmail(state)
14+
const getSupportedDocumentsR = getSupportedDocuments(state)
15+
const getKycFlowConfigR = getKycFlowConfig(state)
16+
1217
return lift((email, docTypes, flowConfig) => {
1318
const needsDocResubmit = selectors.modules.profile
1419
.getKycDocResubmissionStatus(state)
1520
.map(anyPass([equals(GENERAL), equals(EXPIRED)]))
1621
.getOrElse(false)
1722

1823
return {
19-
email,
2024
deeplink: 'https://blockchainwallet.page.link/dashboard',
2125
docTypes,
26+
email,
2227
flowConfig,
2328
needsDocResubmit
2429
}
25-
})(getEmail(state), getSupportedDocuments(state), getKycFlowConfig(state))
30+
})(getEmailR, getSupportedDocumentsR, getKycFlowConfigR)
31+
}
32+
33+
export const getPreIdvData = state => {
34+
const getPreIdvDataR = getSiftData(state)
35+
const getSiftKeyR = selectors.core.walletOptions.getSiftKey(state)
36+
37+
const siftKey = getSiftKeyR.getOrElse('')
38+
39+
return lift(preIdvData => {
40+
return {
41+
...preIdvData,
42+
siftKey
43+
}
44+
})(getPreIdvDataR)
2645
}

0 commit comments

Comments
 (0)