@prove-identity/prove-auth 2.13.1 → 2.15.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/bundle/release/prove-auth.js +1 -1
- package/build/lib/index.d.ts +3 -2
- package/build/lib/index.js +1 -2
- package/build/lib/proveauth/authenticator-builder.d.ts +5 -0
- package/build/lib/proveauth/authenticator-builder.js +25 -2
- package/build/lib/proveauth/external/@authid/web-component/authid-web-component.d.ts +3 -0
- package/build/lib/proveauth/external/@authid/web-component/authid-web-component.js +55 -0
- package/build/lib/proveauth/instantlink.d.ts +2 -6
- package/build/lib/proveauth/instantlink.js +1 -11
- package/build/lib/proveauth/internal/auth-request.d.ts +5 -3
- package/build/lib/proveauth/internal/auth-response.d.ts +24 -28
- package/build/lib/proveauth/internal/auth-session.d.ts +6 -1
- package/build/lib/proveauth/internal/auth-session.js +34 -7
- package/build/lib/proveauth/internal/auth-token-claims.d.ts +22 -3
- package/build/lib/proveauth/internal/device-passive-register-step.js +8 -9
- package/build/lib/proveauth/internal/device-passive-silent-step.js +13 -6
- package/build/lib/proveauth/internal/device-passive-step.js +10 -5
- package/build/lib/proveauth/internal/device-passive-stepup-step.js +1 -19
- package/build/lib/proveauth/internal/device-passive-verify-step.js +2 -18
- package/build/lib/proveauth/internal/main-authenticator.js +3 -0
- package/build/lib/proveauth/internal/mobile-instant-step.js +2 -2
- package/build/lib/proveauth/internal/mobile-instantlink-step.d.ts +0 -3
- package/build/lib/proveauth/internal/mobile-instantlink-step.js +22 -122
- package/build/lib/proveauth/internal/mobile-otp-step.js +3 -3
- package/build/lib/proveauth/internal/platform.d.ts +11 -0
- package/build/lib/proveauth/internal/report-error-step.js +5 -2
- package/build/lib/proveauth/internal/settings.d.ts +3 -0
- package/build/lib/proveauth/internal/settings.js +14 -0
- package/build/lib/proveauth/internal/user-mobileactive-step.js +1 -3
- package/build/lib/proveauth/internal/user-ppb-steps.d.ts +24 -0
- package/build/lib/proveauth/internal/user-ppb-steps.js +103 -0
- package/build/lib/proveauth/internal/user-present-step.js +1 -3
- package/build/lib/proveauth/internal/web-platform.d.ts +3 -1
- package/build/lib/proveauth/internal/web-platform.js +101 -0
- package/build/lib/proveauth/ppb.d.ts +9 -0
- package/build/lib/proveauth/ppb.js +2 -0
- package/build/lib/proveauth/version.d.ts +2 -2
- package/build/lib/proveauth/version.js +2 -2
- package/package.json +1 -1
|
@@ -18,25 +18,10 @@ class DevicePassiveVerifyStep {
|
|
|
18
18
|
}
|
|
19
19
|
static runFidoVerify(log, session) {
|
|
20
20
|
return new Promise((resolve, reject) => {
|
|
21
|
-
session
|
|
22
|
-
.getFingerprintData()
|
|
23
|
-
.then((signal) => {
|
|
24
|
-
const signals = { fingerprint: signal };
|
|
25
|
-
DevicePassiveVerifyStep.makeFidoVerifyFinishRequest(log, session, signals)
|
|
26
|
-
.then(resolve)
|
|
27
|
-
.catch(reject);
|
|
28
|
-
})
|
|
29
|
-
.catch((error) => {
|
|
30
|
-
const errorMsg = `Unexpected error happened during Fingerprint data collection ${error.toString}`;
|
|
31
|
-
log.warn(errorMsg);
|
|
32
|
-
const signals = { fingerprint: { error: errorMsg } };
|
|
33
|
-
DevicePassiveVerifyStep.makeFidoVerifyFinishRequest(log, session, signals)
|
|
34
|
-
.then(resolve)
|
|
35
|
-
.catch(reject);
|
|
36
|
-
});
|
|
21
|
+
DevicePassiveVerifyStep.makeFidoVerifyFinishRequest(log, session).then(resolve).catch(reject);
|
|
37
22
|
});
|
|
38
23
|
}
|
|
39
|
-
static makeFidoVerifyFinishRequest(log, session
|
|
24
|
+
static makeFidoVerifyFinishRequest(log, session) {
|
|
40
25
|
return new Promise((resolve, reject) => {
|
|
41
26
|
const credential = session.credential;
|
|
42
27
|
const assertion = credential.response;
|
|
@@ -55,7 +40,6 @@ class DevicePassiveVerifyStep {
|
|
|
55
40
|
: undefined,
|
|
56
41
|
},
|
|
57
42
|
},
|
|
58
|
-
signals: signals,
|
|
59
43
|
})
|
|
60
44
|
.then((response) => {
|
|
61
45
|
if (response.error) {
|
|
@@ -138,6 +138,9 @@ class MainAuthenticator {
|
|
|
138
138
|
session.lastStep = step;
|
|
139
139
|
return new Promise((resolve, reject) => {
|
|
140
140
|
if ([MainAuthenticator.AUTH_DONE, MainAuthenticator.AUTH_EMPTY].includes(step)) {
|
|
141
|
+
if (!session.settings.deviceId && session.settings.fingerPrintTimestamp) {
|
|
142
|
+
session.resetFptts();
|
|
143
|
+
}
|
|
141
144
|
resolve();
|
|
142
145
|
}
|
|
143
146
|
else if (attempt > MainAuthenticator.MAX_ATTEMPTS) {
|
|
@@ -56,15 +56,15 @@ class MobileInstantStep {
|
|
|
56
56
|
implementation: this.implementation,
|
|
57
57
|
})
|
|
58
58
|
.then((response) => {
|
|
59
|
-
var _a;
|
|
60
59
|
if (response.error) {
|
|
61
60
|
this.nextBak = response.next;
|
|
62
61
|
this.errorCodeBak = response.error.code;
|
|
63
62
|
reject(new auth_error_1.default(response.error.message, response.error.code, response.next, false));
|
|
64
63
|
}
|
|
65
64
|
else {
|
|
65
|
+
const data = response.data;
|
|
66
66
|
resolve({
|
|
67
|
-
authUrl:
|
|
67
|
+
authUrl: data ? data.redirectUrl : undefined,
|
|
68
68
|
});
|
|
69
69
|
}
|
|
70
70
|
})
|
|
@@ -10,10 +10,7 @@ export default class MobileInstantLinkStep extends AuthStatusActions implements
|
|
|
10
10
|
private readonly retryStep?;
|
|
11
11
|
private readonly getDeviceIp;
|
|
12
12
|
constructor(startStep?: InstantLinkStartStep, retryStep?: InstantLinkRetryStep, getDeviceIp?: () => string | null);
|
|
13
|
-
private isTestMode;
|
|
14
13
|
execute(session: AuthSession): Promise<string>;
|
|
15
|
-
private getInstantLinkError;
|
|
16
14
|
private runStartStep;
|
|
17
15
|
private runRetryStep;
|
|
18
|
-
private handleTestMode;
|
|
19
16
|
}
|
|
@@ -9,7 +9,6 @@ const phone_number_input_1 = require("./phone-number-input");
|
|
|
9
9
|
const auth_error_1 = __importDefault(require("./auth-error"));
|
|
10
10
|
const auth_status_actions_1 = require("./auth-status-actions");
|
|
11
11
|
const mobile_otp_step_1 = __importDefault(require("./mobile-otp-step"));
|
|
12
|
-
const SIMULATED_LINK_CLICK_DELAY = 100;
|
|
13
12
|
class MobileInstantLinkStep extends auth_status_actions_1.AuthStatusActions {
|
|
14
13
|
constructor(startStep, retryStep, getDeviceIp) {
|
|
15
14
|
super();
|
|
@@ -19,16 +18,8 @@ class MobileInstantLinkStep extends auth_status_actions_1.AuthStatusActions {
|
|
|
19
18
|
this.retryStep = retryStep;
|
|
20
19
|
this.getDeviceIp = getDeviceIp !== null && getDeviceIp !== void 0 ? getDeviceIp : (() => null);
|
|
21
20
|
}
|
|
22
|
-
isTestMode(session) {
|
|
23
|
-
var _a, _b, _c;
|
|
24
|
-
var testMode = false;
|
|
25
|
-
if ((_c = (_b = (_a = session.claims) === null || _a === void 0 ? void 0 : _a.auth.subs.mob) === null || _b === void 0 ? void 0 : _b.auths.inln) === null || _c === void 0 ? void 0 : _c.tme) {
|
|
26
|
-
testMode = true;
|
|
27
|
-
}
|
|
28
|
-
return testMode;
|
|
29
|
-
}
|
|
30
21
|
execute(session) {
|
|
31
|
-
this.log.
|
|
22
|
+
this.log.debug('Executing');
|
|
32
23
|
return new Promise((resolve, reject) => {
|
|
33
24
|
var _a, _b, _c;
|
|
34
25
|
var phoneNumberNeeded = true;
|
|
@@ -40,34 +31,6 @@ class MobileInstantLinkStep extends auth_status_actions_1.AuthStatusActions {
|
|
|
40
31
|
this.waitForStatus(session).then(resolve).catch(reject);
|
|
41
32
|
});
|
|
42
33
|
}
|
|
43
|
-
getInstantLinkError(responseData) {
|
|
44
|
-
const errorCode = responseData.code;
|
|
45
|
-
var errorMessage = '';
|
|
46
|
-
if (errorCode) {
|
|
47
|
-
errorMessage += `Error Code: ${responseData.code}, `;
|
|
48
|
-
}
|
|
49
|
-
let instantLinkError;
|
|
50
|
-
if (errorCode === 10005) {
|
|
51
|
-
if (responseData.message) {
|
|
52
|
-
errorMessage += `${responseData.message}`;
|
|
53
|
-
}
|
|
54
|
-
else {
|
|
55
|
-
errorMessage += `Max number of retires reached.`;
|
|
56
|
-
}
|
|
57
|
-
instantLinkError = new instantlink_1.InstantLinkMaxRetryError(errorMessage, responseData.code);
|
|
58
|
-
}
|
|
59
|
-
else {
|
|
60
|
-
if (responseData.message) {
|
|
61
|
-
errorMessage += `${responseData.message}`;
|
|
62
|
-
}
|
|
63
|
-
else {
|
|
64
|
-
errorMessage += `Error validating phone number`;
|
|
65
|
-
}
|
|
66
|
-
instantLinkError = new phone_number_input_1.PhoneValidationError(errorMessage, responseData.code);
|
|
67
|
-
}
|
|
68
|
-
this.log.error(`Server reports instant link error: ${errorMessage}`);
|
|
69
|
-
return instantLinkError;
|
|
70
|
-
}
|
|
71
34
|
runStartStep(session, phoneNumberNeeded, instantLinkError) {
|
|
72
35
|
return new Promise((resolve, reject) => {
|
|
73
36
|
if (this.startStep) {
|
|
@@ -90,50 +53,30 @@ class MobileInstantLinkStep extends auth_status_actions_1.AuthStatusActions {
|
|
|
90
53
|
reject(new auth_error_1.default(authResponse.error.message, authResponse.error.code, response.next, false));
|
|
91
54
|
}
|
|
92
55
|
else if (authResponse.data) {
|
|
93
|
-
const
|
|
56
|
+
const data = authResponse.data;
|
|
57
|
+
const errorCode = data.code;
|
|
94
58
|
var errorMessage = '';
|
|
95
59
|
if (errorCode) {
|
|
96
|
-
errorMessage += `Error Code: ${
|
|
60
|
+
errorMessage += `Error Code: ${errorCode}, `;
|
|
97
61
|
}
|
|
98
|
-
if (
|
|
99
|
-
|
|
100
|
-
errorMessage += `${authResponse.data.message}`;
|
|
101
|
-
}
|
|
102
|
-
else {
|
|
103
|
-
errorMessage += `Max number of retires reached.`;
|
|
104
|
-
}
|
|
105
|
-
let maxRetryError = new instantlink_1.InstantLinkMaxRetryError(errorMessage, authResponse.data.code);
|
|
106
|
-
if (this.retryStep) {
|
|
107
|
-
this.runRetryStep(session, maxRetryError).then(resolve).catch(reject);
|
|
108
|
-
}
|
|
109
|
-
else {
|
|
110
|
-
this.log.error('Max number of retires reached but retry step is undefined.');
|
|
111
|
-
}
|
|
62
|
+
if (data.message) {
|
|
63
|
+
errorMessage += `${data.message}`;
|
|
112
64
|
}
|
|
113
65
|
else {
|
|
114
|
-
|
|
115
|
-
errorMessage += `${authResponse.data.message}`;
|
|
116
|
-
}
|
|
117
|
-
else {
|
|
118
|
-
errorMessage += `Error validating phone number.`;
|
|
119
|
-
}
|
|
120
|
-
let invalidPhoneError = new phone_number_input_1.PhoneValidationError(errorMessage, authResponse.data.code);
|
|
121
|
-
this.runStartStep(session, phoneNumberNeeded, invalidPhoneError)
|
|
122
|
-
.then(resolve)
|
|
123
|
-
.catch(reject);
|
|
66
|
+
errorMessage += `Error validating phone number.`;
|
|
124
67
|
}
|
|
68
|
+
let invalidPhoneError = new phone_number_input_1.PhoneValidationError(errorMessage, data.code);
|
|
69
|
+
this.runStartStep(session, phoneNumberNeeded, invalidPhoneError)
|
|
70
|
+
.then(resolve)
|
|
71
|
+
.catch(reject);
|
|
125
72
|
}
|
|
126
73
|
else {
|
|
127
|
-
this.
|
|
128
|
-
.then(()
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
resolve(authResponse.next);
|
|
134
|
-
}
|
|
135
|
-
})
|
|
136
|
-
.catch(reject);
|
|
74
|
+
if (this.retryStep) {
|
|
75
|
+
this.runRetryStep(session).then(resolve).catch(reject);
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
resolve(authResponse.next);
|
|
79
|
+
}
|
|
137
80
|
}
|
|
138
81
|
})
|
|
139
82
|
.catch(reject);
|
|
@@ -146,11 +89,11 @@ class MobileInstantLinkStep extends auth_status_actions_1.AuthStatusActions {
|
|
|
146
89
|
}
|
|
147
90
|
});
|
|
148
91
|
}
|
|
149
|
-
runRetryStep(session
|
|
92
|
+
runRetryStep(session) {
|
|
150
93
|
return new Promise((resolve, reject) => {
|
|
151
94
|
if (this.retryStep) {
|
|
152
95
|
this.retryStep
|
|
153
|
-
.execute(
|
|
96
|
+
.execute()
|
|
154
97
|
.then((resultType) => {
|
|
155
98
|
if (resultType === instantlink_1.InstantLinkResultType.OnResend) {
|
|
156
99
|
session
|
|
@@ -163,26 +106,8 @@ class MobileInstantLinkStep extends auth_status_actions_1.AuthStatusActions {
|
|
|
163
106
|
if (authResponse.error) {
|
|
164
107
|
reject(new auth_error_1.default(authResponse.error.message, authResponse.error.code, response.next, false));
|
|
165
108
|
}
|
|
166
|
-
else if (authResponse.data) {
|
|
167
|
-
const errorCode = authResponse.data.code;
|
|
168
|
-
var errorMessage = '';
|
|
169
|
-
if (errorCode) {
|
|
170
|
-
errorMessage += `Error Code: ${authResponse.data.code}, `;
|
|
171
|
-
}
|
|
172
|
-
if (authResponse.data.message) {
|
|
173
|
-
errorMessage += `${authResponse.data.message}`;
|
|
174
|
-
}
|
|
175
|
-
else {
|
|
176
|
-
errorMessage += `Max number of retires reached.`;
|
|
177
|
-
}
|
|
178
|
-
let maxRetryError = new instantlink_1.InstantLinkMaxRetryError(errorMessage, authResponse.data.code);
|
|
179
|
-
this.runRetryStep(session, maxRetryError).then(resolve).catch(reject);
|
|
180
|
-
}
|
|
181
109
|
else {
|
|
182
|
-
this.
|
|
183
|
-
.then(() => this.runRetryStep(session))
|
|
184
|
-
.then(resolve)
|
|
185
|
-
.catch(reject);
|
|
110
|
+
this.runRetryStep(session);
|
|
186
111
|
}
|
|
187
112
|
})
|
|
188
113
|
.catch(reject);
|
|
@@ -191,42 +116,17 @@ class MobileInstantLinkStep extends auth_status_actions_1.AuthStatusActions {
|
|
|
191
116
|
this.runStartStep(session, true).then(resolve).catch(reject);
|
|
192
117
|
}
|
|
193
118
|
else {
|
|
194
|
-
this.log.warn('
|
|
119
|
+
this.log.warn('Unknown enum of ', resultType);
|
|
195
120
|
}
|
|
196
121
|
})
|
|
197
122
|
.catch(reject);
|
|
198
123
|
}
|
|
199
124
|
else {
|
|
200
|
-
this.log.debug("Retry step doesn't
|
|
125
|
+
this.log.debug("Retry step doesn't exist, skip.");
|
|
201
126
|
resolve('');
|
|
202
127
|
}
|
|
203
128
|
});
|
|
204
129
|
}
|
|
205
|
-
handleTestMode(session) {
|
|
206
|
-
return new Promise((resolve, reject) => {
|
|
207
|
-
if (this.isTestMode(session)) {
|
|
208
|
-
this.log.info('Simulating user clicking the instant link');
|
|
209
|
-
setTimeout(() => {
|
|
210
|
-
session.platform
|
|
211
|
-
.fetch(session.backendOrigin +
|
|
212
|
-
'/v1/client/mobile/instantlink/finish?token=' +
|
|
213
|
-
encodeURIComponent(session.authToken) +
|
|
214
|
-
'&vfp=test-vfp', {
|
|
215
|
-
mode: 'no-cors',
|
|
216
|
-
method: 'GET',
|
|
217
|
-
})
|
|
218
|
-
.then(() => resolve)
|
|
219
|
-
.catch((e) => {
|
|
220
|
-
this.log.error('Calling AuthFinish in test mode has failed: ', auth_error_1.default.extractMessage(e));
|
|
221
|
-
reject(e);
|
|
222
|
-
});
|
|
223
|
-
}, SIMULATED_LINK_CLICK_DELAY);
|
|
224
|
-
}
|
|
225
|
-
else {
|
|
226
|
-
resolve();
|
|
227
|
-
}
|
|
228
|
-
});
|
|
229
|
-
}
|
|
230
130
|
}
|
|
231
131
|
MobileInstantLinkStep.NAME = 'mobile/instantlink';
|
|
232
132
|
exports.default = MobileInstantLinkStep;
|
|
@@ -69,7 +69,7 @@ class MobileOtpStep {
|
|
|
69
69
|
reject(new auth_error_1.default(authResponse.error.message, authResponse.error.code, response.next, false));
|
|
70
70
|
}
|
|
71
71
|
else if (authResponse.data) {
|
|
72
|
-
|
|
72
|
+
const data = authResponse.data;
|
|
73
73
|
var errorMessage = '';
|
|
74
74
|
if (data === null || data === void 0 ? void 0 : data.code) {
|
|
75
75
|
errorMessage += `Error Code: ${data.code}, `;
|
|
@@ -170,7 +170,7 @@ class MobileOtpStep {
|
|
|
170
170
|
reject(new auth_error_1.default(authResponse.error.message, authResponse.error.code, response.next, false));
|
|
171
171
|
}
|
|
172
172
|
else if (authResponse.data) {
|
|
173
|
-
|
|
173
|
+
const data = authResponse.data;
|
|
174
174
|
var errorMessage = '';
|
|
175
175
|
if (data === null || data === void 0 ? void 0 : data.code) {
|
|
176
176
|
errorMessage += `Error Code: ${data.code}, `;
|
|
@@ -181,7 +181,7 @@ class MobileOtpStep {
|
|
|
181
181
|
else {
|
|
182
182
|
errorMessage += `Error validating OTP`;
|
|
183
183
|
}
|
|
184
|
-
|
|
184
|
+
const otpError = new otp_1.OtpError(errorMessage, data === null || data === void 0 ? void 0 : data.code);
|
|
185
185
|
this.log.error(`Server reports invalid OTP: ${errorMessage}`);
|
|
186
186
|
this.runOtpFinishStep(session, otpStartStep, otpFinishStep, phoneNumberNeeded, otpError)
|
|
187
187
|
.then(resolve)
|
|
@@ -4,6 +4,7 @@ import { AuthRequest } from './auth-request';
|
|
|
4
4
|
import AuthResponse from './auth-response';
|
|
5
5
|
import DeviceAuth, { DeviceRegistration } from './device-auth';
|
|
6
6
|
import { Agent } from '@fingerprintjs/fingerprintjs-pro';
|
|
7
|
+
import { PpbOperation } from '../ppb';
|
|
7
8
|
export declare const DEVICE_CAPABILITY_WEBAUTHN = "webauthn";
|
|
8
9
|
export interface MessageChannel {
|
|
9
10
|
addEventListener: (type: string, listener: (event: any) => void) => void;
|
|
@@ -27,6 +28,15 @@ export interface AuthSessionIntegration {
|
|
|
27
28
|
getDeviceRegistration: () => Promise<DeviceRegistration | null>;
|
|
28
29
|
fetchFromBackend: (query: string, body: AuthRequest) => Promise<AuthResponse>;
|
|
29
30
|
}
|
|
31
|
+
export interface PpbAuthResult {
|
|
32
|
+
authIdSuccess?: boolean;
|
|
33
|
+
}
|
|
34
|
+
export interface PpbAuthOptions {
|
|
35
|
+
authIdEndpointUrl?: string;
|
|
36
|
+
authIdOperation?: PpbOperation;
|
|
37
|
+
authIdOperationId?: string;
|
|
38
|
+
authIdOneTimeSecret?: string;
|
|
39
|
+
}
|
|
30
40
|
export default interface Platform {
|
|
31
41
|
readonly webauthn: WebAuthN;
|
|
32
42
|
readonly deviceAuth: DeviceAuth;
|
|
@@ -43,6 +53,7 @@ export default interface Platform {
|
|
|
43
53
|
getFpPromise: () => Promise<Agent> | undefined;
|
|
44
54
|
setFpPromise: (fpPromise: Promise<Agent>) => void;
|
|
45
55
|
getOrigin: () => string;
|
|
56
|
+
ppbAuthenticate: (options: PpbAuthOptions) => Promise<PpbAuthResult>;
|
|
46
57
|
}
|
|
47
58
|
export declare function stringToArrayBuffer(input: string): ArrayBuffer;
|
|
48
59
|
export declare function arrayBufferToString(input: ArrayBuffer): string;
|
|
@@ -16,6 +16,7 @@ const mobile_otp_step_1 = __importDefault(require("./mobile-otp-step"));
|
|
|
16
16
|
const user_present_step_1 = __importDefault(require("./user-present-step"));
|
|
17
17
|
const device_passive_stepup_step_1 = __importDefault(require("./device-passive-stepup-step"));
|
|
18
18
|
const device_universal_redirect_steps_1 = require("./device-universal-redirect-steps");
|
|
19
|
+
const user_ppb_steps_1 = require("./user-ppb-steps");
|
|
19
20
|
class ReportErrorStep {
|
|
20
21
|
constructor(error) {
|
|
21
22
|
this.logger = logger_1.LoggerFactory.getLogger('report-error-step');
|
|
@@ -82,11 +83,13 @@ ReportErrorStep.endpointMap = new Map([
|
|
|
82
83
|
[device_passive_register_step_1.default.NAME, 'device/fido2'],
|
|
83
84
|
[device_passive_verify_step_1.default.NAME, 'device/fido2'],
|
|
84
85
|
[device_passive_stepup_step_1.default.NAME, 'device/fido2'],
|
|
86
|
+
[device_universal_redirect_steps_1.DeviceUniversalRedirectExchangeStep.NAME, 'device/universal'],
|
|
87
|
+
[device_universal_redirect_steps_1.DeviceUniversalRedirectFinishStep.NAME, 'device/universal'],
|
|
85
88
|
[mobile_instant_step_1.default.NAME, 'mobile/instant'],
|
|
86
89
|
[mobile_instantlink_step_1.default.NAME, 'mobile/instantlink'],
|
|
87
90
|
[mobile_otp_step_1.default.NAME, 'mobile/otp'],
|
|
88
91
|
[user_present_step_1.default.NAME, 'user/mobileactive'],
|
|
89
|
-
[
|
|
90
|
-
[
|
|
92
|
+
[user_ppb_steps_1.UserPpbEnrollStep.NAME, 'user/ppb'],
|
|
93
|
+
[user_ppb_steps_1.UserPpbVerifyStep.NAME, 'user/ppb'],
|
|
91
94
|
]);
|
|
92
95
|
exports.default = ReportErrorStep;
|
|
@@ -3,6 +3,7 @@ export default class Settings {
|
|
|
3
3
|
static readonly DEVICE_ID_KEY = "DeviceId";
|
|
4
4
|
static readonly NAMESPACE_KEY = "namespace";
|
|
5
5
|
static readonly FIDO_PASSKEY_REGISTERED_KEY = "fidoPasskeyRegistered";
|
|
6
|
+
static readonly FP_TIMESTAMPT = "fingerPrintTimestamp";
|
|
6
7
|
private readonly log;
|
|
7
8
|
private storage;
|
|
8
9
|
upkEnabled: boolean;
|
|
@@ -11,6 +12,8 @@ export default class Settings {
|
|
|
11
12
|
get deviceId(): string | null;
|
|
12
13
|
set deviceId(val: string | null);
|
|
13
14
|
get fidoPasskeyRegistered(): boolean;
|
|
15
|
+
set fingerPrintTimestamp(val: number | null);
|
|
16
|
+
get fingerPrintTimestamp(): number | null;
|
|
14
17
|
set fidoPasskeyRegistered(val: boolean);
|
|
15
18
|
get namespace(): string | null;
|
|
16
19
|
set namespace(val: string | null);
|
|
@@ -12,6 +12,7 @@ class Settings {
|
|
|
12
12
|
this.deviceId = null;
|
|
13
13
|
this.namespace = null;
|
|
14
14
|
this.fidoPasskeyRegistered = false;
|
|
15
|
+
this.fingerPrintTimestamp = null;
|
|
15
16
|
}
|
|
16
17
|
get deviceId() {
|
|
17
18
|
return this.storage.getItem(this.getKey(Settings.DEVICE_ID_KEY));
|
|
@@ -22,6 +23,18 @@ class Settings {
|
|
|
22
23
|
get fidoPasskeyRegistered() {
|
|
23
24
|
return this.storage.getItem(this.getKey(Settings.FIDO_PASSKEY_REGISTERED_KEY)) === 'true';
|
|
24
25
|
}
|
|
26
|
+
set fingerPrintTimestamp(val) {
|
|
27
|
+
const assignedValue = val !== null ? val.toString() : null;
|
|
28
|
+
this.setOrRemove(Settings.FP_TIMESTAMPT, assignedValue);
|
|
29
|
+
}
|
|
30
|
+
get fingerPrintTimestamp() {
|
|
31
|
+
const storedTimestampString = this.storage.getItem(this.getKey(Settings.FP_TIMESTAMPT));
|
|
32
|
+
if (!storedTimestampString) {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
let fingerprintTimestamp = parseInt(storedTimestampString);
|
|
36
|
+
return isNaN(fingerprintTimestamp) ? null : fingerprintTimestamp;
|
|
37
|
+
}
|
|
25
38
|
set fidoPasskeyRegistered(val) {
|
|
26
39
|
this.setOrRemove(Settings.FIDO_PASSKEY_REGISTERED_KEY, val ? 'true' : null);
|
|
27
40
|
}
|
|
@@ -48,4 +61,5 @@ Settings.KEY_PREFIX = 'ProveAuth';
|
|
|
48
61
|
Settings.DEVICE_ID_KEY = 'DeviceId';
|
|
49
62
|
Settings.NAMESPACE_KEY = 'namespace';
|
|
50
63
|
Settings.FIDO_PASSKEY_REGISTERED_KEY = 'fidoPasskeyRegistered';
|
|
64
|
+
Settings.FP_TIMESTAMPT = 'fingerPrintTimestamp';
|
|
51
65
|
exports.default = Settings;
|
|
@@ -9,9 +9,7 @@ class UserMobileActiveStep {
|
|
|
9
9
|
this.name = UserMobileActiveStep.NAME;
|
|
10
10
|
}
|
|
11
11
|
execute(session) {
|
|
12
|
-
return new
|
|
13
|
-
reject(new auth_error_1.default(`Step ${this.name} is not supported yet`));
|
|
14
|
-
});
|
|
12
|
+
return Promise.reject(new auth_error_1.default(`Step ${this.name} is not supported`));
|
|
15
13
|
}
|
|
16
14
|
}
|
|
17
15
|
UserMobileActiveStep.NAME = 'user/mobileactive';
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import AuthStep from './auth-step';
|
|
2
|
+
import AuthSession from './auth-session';
|
|
3
|
+
import { PpbFinishStep, PpbOperation, PpbStartStep } from '../ppb';
|
|
4
|
+
declare abstract class UserPpbBaseStep implements AuthStep {
|
|
5
|
+
readonly name: string;
|
|
6
|
+
private readonly log;
|
|
7
|
+
private readonly enabled;
|
|
8
|
+
private readonly operation;
|
|
9
|
+
private readonly startStep;
|
|
10
|
+
private readonly finishStep;
|
|
11
|
+
constructor(enabled: boolean, operation: PpbOperation, startStep?: PpbStartStep, finishStep?: PpbFinishStep);
|
|
12
|
+
execute(session: AuthSession): Promise<string>;
|
|
13
|
+
}
|
|
14
|
+
export declare class UserPpbEnrollStep extends UserPpbBaseStep {
|
|
15
|
+
static readonly NAME = "user/ppb/register";
|
|
16
|
+
readonly name = "user/ppb/register";
|
|
17
|
+
constructor(enabled: boolean, startStep?: PpbStartStep, finishStep?: PpbFinishStep);
|
|
18
|
+
}
|
|
19
|
+
export declare class UserPpbVerifyStep extends UserPpbBaseStep {
|
|
20
|
+
static readonly NAME = "user/ppb/verify";
|
|
21
|
+
readonly name = "user/ppb/verify";
|
|
22
|
+
constructor(enabled: boolean, startStep?: PpbStartStep, finishStep?: PpbFinishStep);
|
|
23
|
+
}
|
|
24
|
+
export {};
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.UserPpbVerifyStep = exports.UserPpbEnrollStep = void 0;
|
|
7
|
+
const logger_1 = require("../common/logger");
|
|
8
|
+
const auth_error_1 = __importDefault(require("./auth-error"));
|
|
9
|
+
class UserPpbBaseStep {
|
|
10
|
+
constructor(enabled, operation, startStep, finishStep) {
|
|
11
|
+
this.log = logger_1.LoggerFactory.getLogger('user-ppb-base-step');
|
|
12
|
+
this.enabled = enabled;
|
|
13
|
+
this.operation = operation;
|
|
14
|
+
this.startStep = startStep;
|
|
15
|
+
this.finishStep = finishStep;
|
|
16
|
+
}
|
|
17
|
+
execute(session) {
|
|
18
|
+
if (!this.enabled) {
|
|
19
|
+
return Promise.reject(new auth_error_1.default('PPB is not enabled'));
|
|
20
|
+
}
|
|
21
|
+
const data = session.lastData;
|
|
22
|
+
if (!data || !data.ppb) {
|
|
23
|
+
return Promise.reject(new auth_error_1.default('PPB session is not initialized'));
|
|
24
|
+
}
|
|
25
|
+
return new Promise((resolve, reject) => {
|
|
26
|
+
const callStart = () => {
|
|
27
|
+
try {
|
|
28
|
+
if (this.startStep) {
|
|
29
|
+
return this.startStep.execute(this.operation);
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
return Promise.resolve();
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
catch (e) {
|
|
36
|
+
this.log.warn('PPB start step has failed:', e);
|
|
37
|
+
return Promise.reject(e);
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
const callFinish = (error) => {
|
|
41
|
+
try {
|
|
42
|
+
if (this.finishStep) {
|
|
43
|
+
return this.finishStep.execute(this.operation, error);
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
return Promise.resolve();
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
catch (e) {
|
|
50
|
+
this.log.warn('PPB finish step has failed:', e);
|
|
51
|
+
return Promise.reject(e);
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
callStart()
|
|
55
|
+
.then(() => {
|
|
56
|
+
var _a, _b, _c, _d, _e;
|
|
57
|
+
return session.platform.ppbAuthenticate({
|
|
58
|
+
authIdOperation: this.operation,
|
|
59
|
+
authIdEndpointUrl: (_c = (_b = (_a = session.claims) === null || _a === void 0 ? void 0 : _a.auth.subs.usr) === null || _b === void 0 ? void 0 : _b.auths.ppb) === null || _c === void 0 ? void 0 : _c.endp,
|
|
60
|
+
authIdOperationId: (_d = data.ppb) === null || _d === void 0 ? void 0 : _d.operationId,
|
|
61
|
+
authIdOneTimeSecret: (_e = data.ppb) === null || _e === void 0 ? void 0 : _e.oneTimeSecret,
|
|
62
|
+
});
|
|
63
|
+
})
|
|
64
|
+
.catch(reject)
|
|
65
|
+
.then((result) => {
|
|
66
|
+
var _a;
|
|
67
|
+
this.log.info('PPB authentication result', result);
|
|
68
|
+
return session.fetchFromBackend('/v1/client/user/ppb/finish', {
|
|
69
|
+
requestId: crypto.randomUUID(),
|
|
70
|
+
operationId: (_a = data.ppb) === null || _a === void 0 ? void 0 : _a.operationId,
|
|
71
|
+
});
|
|
72
|
+
})
|
|
73
|
+
.then((response) => {
|
|
74
|
+
var _a, _b;
|
|
75
|
+
const ppbResponse = response;
|
|
76
|
+
if (ppbResponse.error) {
|
|
77
|
+
const message = (_b = (_a = response.error) === null || _a === void 0 ? void 0 : _a.message) !== null && _b !== void 0 ? _b : 'PPB authentication failed';
|
|
78
|
+
callFinish(new Error(message)).then(() => reject(new auth_error_1.default(response.error.message, response.error.code, response.next, false)));
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
callFinish().then(() => resolve(ppbResponse.next));
|
|
82
|
+
}
|
|
83
|
+
})
|
|
84
|
+
.catch(reject);
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
class UserPpbEnrollStep extends UserPpbBaseStep {
|
|
89
|
+
constructor(enabled, startStep, finishStep) {
|
|
90
|
+
super(enabled, 'enroll', startStep, finishStep);
|
|
91
|
+
this.name = UserPpbEnrollStep.NAME;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
UserPpbEnrollStep.NAME = 'user/ppb/register';
|
|
95
|
+
exports.UserPpbEnrollStep = UserPpbEnrollStep;
|
|
96
|
+
class UserPpbVerifyStep extends UserPpbBaseStep {
|
|
97
|
+
constructor(enabled, startStep, finishStep) {
|
|
98
|
+
super(enabled, 'verify', startStep, finishStep);
|
|
99
|
+
this.name = UserPpbVerifyStep.NAME;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
UserPpbVerifyStep.NAME = 'user/ppb/verify';
|
|
103
|
+
exports.UserPpbVerifyStep = UserPpbVerifyStep;
|
|
@@ -9,9 +9,7 @@ class UserPresentStep {
|
|
|
9
9
|
this.name = UserPresentStep.NAME;
|
|
10
10
|
}
|
|
11
11
|
execute(session) {
|
|
12
|
-
return new
|
|
13
|
-
reject(new auth_error_1.default(`Step ${this.name} is not supported yet`));
|
|
14
|
-
});
|
|
12
|
+
return Promise.reject(new auth_error_1.default(`Step ${this.name} is not supported`));
|
|
15
13
|
}
|
|
16
14
|
}
|
|
17
15
|
UserPresentStep.NAME = 'user/present';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AuthenticatorBuilder } from '@prove-identity/mobile-auth';
|
|
2
|
-
import Platform, { AuthSessionIntegration, MessageChannel, RequestSigner } from './platform';
|
|
2
|
+
import Platform, { AuthSessionIntegration, MessageChannel, PpbAuthOptions, PpbAuthResult, RequestSigner } from './platform';
|
|
3
3
|
import WebDeviceAuth from './web-device-auth';
|
|
4
4
|
import { Agent } from '@fingerprintjs/fingerprintjs-pro';
|
|
5
5
|
export declare class WebSocketMessageChannel implements MessageChannel {
|
|
@@ -10,6 +10,7 @@ export declare class WebSocketMessageChannel implements MessageChannel {
|
|
|
10
10
|
close(): void;
|
|
11
11
|
}
|
|
12
12
|
export declare class WebPlatform implements Platform {
|
|
13
|
+
private readonly log;
|
|
13
14
|
private fpPromise;
|
|
14
15
|
readonly webauthn: {
|
|
15
16
|
getCredentials: (options?: CredentialRequestOptions) => Promise<CredentialType | null>;
|
|
@@ -22,6 +23,7 @@ export declare class WebPlatform implements Platform {
|
|
|
22
23
|
fetch(input: string, init?: RequestInit): Promise<Response>;
|
|
23
24
|
createMessageChannel(input: string): MessageChannel;
|
|
24
25
|
createRequestSigner(session: AuthSessionIntegration): RequestSigner;
|
|
26
|
+
ppbAuthenticate(options: PpbAuthOptions): Promise<PpbAuthResult>;
|
|
25
27
|
private getBrowserName;
|
|
26
28
|
private getBrowserVersion;
|
|
27
29
|
getOSName(): string;
|