@prove-identity/prove-auth 2.4.4 → 2.7.0
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/lib/index.d.ts +3 -1
- package/build/lib/index.js +3 -1
- package/build/lib/proveauth/authenticator-builder.d.ts +13 -1
- package/build/lib/proveauth/authenticator-builder.js +123 -6
- package/build/lib/proveauth/device-context-options.d.ts +19 -0
- package/build/lib/proveauth/device-context-options.js +19 -0
- package/build/lib/proveauth/internal/auth-request.d.ts +12 -0
- package/build/lib/proveauth/internal/auth-response.d.ts +1 -0
- package/build/lib/proveauth/internal/auth-session.d.ts +15 -8
- package/build/lib/proveauth/internal/auth-session.js +106 -21
- package/build/lib/proveauth/internal/auth-status-actions.d.ts +5 -0
- package/build/lib/proveauth/internal/auth-status-actions.js +48 -0
- package/build/lib/proveauth/internal/auth-token-claims.d.ts +9 -0
- package/build/lib/proveauth/internal/device-auth.d.ts +4 -1
- package/build/lib/proveauth/internal/device-passive-register-step.js +10 -9
- package/build/lib/proveauth/internal/device-passive-silent-step.d.ts +7 -1
- package/build/lib/proveauth/internal/device-passive-silent-step.js +43 -14
- package/build/lib/proveauth/internal/device-passive-step.d.ts +2 -1
- package/build/lib/proveauth/internal/device-passive-step.js +4 -3
- package/build/lib/proveauth/internal/device-passive-verify-step.d.ts +2 -0
- package/build/lib/proveauth/internal/device-passive-verify-step.js +18 -0
- package/build/lib/proveauth/internal/device-universal-redirect-steps.d.ts +14 -0
- package/build/lib/proveauth/internal/device-universal-redirect-steps.js +55 -0
- package/build/lib/proveauth/internal/device-universal-step.d.ts +10 -0
- package/build/lib/proveauth/internal/device-universal-step.js +38 -0
- package/build/lib/proveauth/internal/{base-authenticator.d.ts → main-authenticator.d.ts} +8 -5
- package/build/lib/proveauth/internal/{base-authenticator.js → main-authenticator.js} +61 -17
- package/build/lib/proveauth/internal/mobile-instantlink-step.d.ts +2 -1
- package/build/lib/proveauth/internal/mobile-instantlink-step.js +9 -5
- package/build/lib/proveauth/internal/platform.d.ts +6 -1
- package/build/lib/proveauth/internal/report-error-step.d.ts +2 -2
- package/build/lib/proveauth/internal/report-error-step.js +11 -8
- package/build/lib/proveauth/internal/settings.d.ts +1 -0
- package/build/lib/proveauth/internal/settings.js +1 -0
- package/build/lib/proveauth/internal/web-device-auth.d.ts +4 -1
- package/build/lib/proveauth/internal/web-device-auth.js +6 -0
- package/build/lib/proveauth/internal/web-platform.d.ts +8 -1
- package/build/lib/proveauth/internal/web-platform.js +14 -2
- package/build/lib/proveauth/user-consent-step.d.ts +7 -0
- package/build/lib/proveauth/user-consent-step.js +2 -0
- package/build/lib/proveauth/version.d.ts +2 -2
- package/build/lib/proveauth/version.js +2 -2
- package/package.json +12 -3
- package/build/lib/proveauth/internal/primary-authenticator.d.ts +0 -14
- package/build/lib/proveauth/internal/primary-authenticator.js +0 -64
- package/build/lib/proveauth/internal/secondary-authenticator.d.ts +0 -10
- package/build/lib/proveauth/internal/secondary-authenticator.js +0 -65
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AuthRegistration } from './auth-request';
|
|
1
|
+
import { AuthRegistration, Signal, Signals } from './auth-request';
|
|
2
2
|
export interface DeviceRegistrationOptions {
|
|
3
3
|
namespace: string;
|
|
4
4
|
endpoint: string;
|
|
@@ -9,9 +9,12 @@ export interface DeviceRegistration {
|
|
|
9
9
|
readonly algorithm: string;
|
|
10
10
|
readonly endpoint: string;
|
|
11
11
|
deviceId: string | null;
|
|
12
|
+
fingerprint?: Signal;
|
|
12
13
|
sign: (data: string) => Promise<string>;
|
|
13
14
|
getPublicKey: () => Promise<string>;
|
|
14
15
|
getAuthRegistration: (challenge: string) => Promise<AuthRegistration>;
|
|
16
|
+
setFpSignal: (fpSignal: Signal) => void;
|
|
17
|
+
getSignals: () => Signals | undefined;
|
|
15
18
|
}
|
|
16
19
|
export default interface DeviceAuth {
|
|
17
20
|
createRegistration: (options: DeviceRegistrationOptions) => Promise<DeviceRegistration>;
|
|
@@ -18,23 +18,23 @@ class DevicePassiveRegisterStep {
|
|
|
18
18
|
.getDeviceRegistration()
|
|
19
19
|
.then((devRegistration) => {
|
|
20
20
|
if (devRegistration) {
|
|
21
|
-
|
|
22
|
-
.
|
|
23
|
-
|
|
21
|
+
session.embedFpResultToDeviceRegistration(devRegistration).then((devRegistration) => {
|
|
22
|
+
this.finishRegistration(session, [this.getFido2Registration(session)], devRegistration.getSignals())
|
|
23
|
+
.then(resolve)
|
|
24
|
+
.catch(reject);
|
|
25
|
+
});
|
|
24
26
|
}
|
|
25
27
|
else {
|
|
26
28
|
session.platform.deviceAuth
|
|
27
29
|
.createRegistration({
|
|
28
30
|
namespace: session.namespace,
|
|
29
|
-
endpoint: session.
|
|
31
|
+
endpoint: session.backendOrigin,
|
|
30
32
|
})
|
|
33
|
+
.then((devRegistration) => session.embedFpResultToDeviceRegistration(devRegistration))
|
|
31
34
|
.then((devRegistration) => {
|
|
32
35
|
devRegistration
|
|
33
36
|
.getAuthRegistration(session.challenge)
|
|
34
|
-
.then((authRegistration) => this.finishRegistration(session, [
|
|
35
|
-
this.getFido2Registration(session),
|
|
36
|
-
authRegistration,
|
|
37
|
-
]))
|
|
37
|
+
.then((authRegistration) => this.finishRegistration(session, [this.getFido2Registration(session), authRegistration], devRegistration.getSignals()))
|
|
38
38
|
.then((next) => {
|
|
39
39
|
devRegistration.deviceId = session.settings.deviceId;
|
|
40
40
|
session.platform.deviceAuth
|
|
@@ -50,13 +50,14 @@ class DevicePassiveRegisterStep {
|
|
|
50
50
|
.catch(reject);
|
|
51
51
|
});
|
|
52
52
|
}
|
|
53
|
-
finishRegistration(session, registrations) {
|
|
53
|
+
finishRegistration(session, registrations, signals) {
|
|
54
54
|
return new Promise((resolve, reject) => {
|
|
55
55
|
session
|
|
56
56
|
.fetchFromBackend('/v1/client/device/fido2/register/finish', {
|
|
57
57
|
deviceName: session.platform.getPlatformName(),
|
|
58
58
|
deviceCapabilities: session.platform.getDeviceCapabilities(),
|
|
59
59
|
registrations: registrations,
|
|
60
|
+
signals: signals,
|
|
60
61
|
})
|
|
61
62
|
.then((response) => {
|
|
62
63
|
if (response.error) {
|
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
import AuthSession from './auth-session';
|
|
2
2
|
import AuthStep from './auth-step';
|
|
3
|
+
import UserConsentStep from '../user-consent-step';
|
|
3
4
|
export default class DevicePassiveSilentStep implements AuthStep {
|
|
4
5
|
static readonly NAME = "device/passive/silent";
|
|
5
|
-
private readonly log;
|
|
6
6
|
readonly name = "device/passive/silent";
|
|
7
|
+
private readonly log;
|
|
8
|
+
private readonly forUPK;
|
|
9
|
+
private readonly userConsentStep;
|
|
10
|
+
constructor(forUPK: boolean, userConsentStep?: UserConsentStep);
|
|
7
11
|
execute(session: AuthSession): Promise<string>;
|
|
12
|
+
private getBackendRegisterEndpoint;
|
|
13
|
+
private getBackendVerifyEndpoint;
|
|
8
14
|
private register;
|
|
9
15
|
private verify;
|
|
10
16
|
}
|
|
@@ -6,9 +6,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
const logger_1 = require("../common/logger");
|
|
7
7
|
const auth_error_1 = __importDefault(require("./auth-error"));
|
|
8
8
|
class DevicePassiveSilentStep {
|
|
9
|
-
constructor() {
|
|
10
|
-
this.log = logger_1.LoggerFactory.getLogger('device-passive-silent-step');
|
|
9
|
+
constructor(forUPK, userConsentStep) {
|
|
11
10
|
this.name = DevicePassiveSilentStep.NAME;
|
|
11
|
+
this.log = logger_1.LoggerFactory.getLogger('device-passive-silent-step');
|
|
12
|
+
this.forUPK = forUPK;
|
|
13
|
+
this.userConsentStep = userConsentStep !== null && userConsentStep !== void 0 ? userConsentStep : {
|
|
14
|
+
execute: () => Promise.resolve({ consentGranted: true }),
|
|
15
|
+
};
|
|
12
16
|
}
|
|
13
17
|
execute(session) {
|
|
14
18
|
this.log.trace('Executing');
|
|
@@ -17,42 +21,66 @@ class DevicePassiveSilentStep {
|
|
|
17
21
|
.getDeviceRegistration()
|
|
18
22
|
.then((registration) => {
|
|
19
23
|
if (registration) {
|
|
20
|
-
|
|
24
|
+
session.embedFpResultToDeviceRegistration(registration).then((registration) => {
|
|
25
|
+
this.verify(session, registration).then(resolve).catch(reject);
|
|
26
|
+
});
|
|
21
27
|
}
|
|
22
28
|
else {
|
|
23
|
-
|
|
24
|
-
.
|
|
25
|
-
|
|
26
|
-
|
|
29
|
+
this.userConsentStep
|
|
30
|
+
.execute()
|
|
31
|
+
.then((output) => {
|
|
32
|
+
if (output.consentGranted) {
|
|
33
|
+
session.platform.deviceAuth
|
|
34
|
+
.createRegistration({
|
|
35
|
+
namespace: session.namespace,
|
|
36
|
+
endpoint: session.backendOrigin,
|
|
37
|
+
})
|
|
38
|
+
.then((registration) => session.embedFpResultToDeviceRegistration(registration))
|
|
39
|
+
.then((registration) => this.register(session, registration))
|
|
40
|
+
.then(resolve)
|
|
41
|
+
.catch(reject);
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
reject(new Error('User denied the consent to register the device'));
|
|
45
|
+
}
|
|
27
46
|
})
|
|
28
|
-
.then((registration) => this.register(session, registration))
|
|
29
|
-
.then(resolve)
|
|
30
47
|
.catch(reject);
|
|
31
48
|
}
|
|
32
49
|
})
|
|
33
50
|
.catch(reject);
|
|
34
51
|
});
|
|
35
52
|
}
|
|
53
|
+
getBackendRegisterEndpoint() {
|
|
54
|
+
return this.forUPK
|
|
55
|
+
? '/v1/client/device/universal/register'
|
|
56
|
+
: '/v1/client/device/passive/register';
|
|
57
|
+
}
|
|
58
|
+
getBackendVerifyEndpoint() {
|
|
59
|
+
return this.forUPK ? '/v1/client/device/universal/verify' : '/v1/client/device/passive/verify';
|
|
60
|
+
}
|
|
36
61
|
register(session, registration) {
|
|
37
62
|
this.log.trace('Registering');
|
|
38
63
|
return new Promise((resolve, reject) => {
|
|
39
64
|
registration.getAuthRegistration(session.challenge).then((authRegistration) => {
|
|
40
65
|
session
|
|
41
|
-
.fetchFromBackend(
|
|
66
|
+
.fetchFromBackend(this.getBackendRegisterEndpoint(), {
|
|
42
67
|
deviceName: session.platform.getPlatformName(),
|
|
43
68
|
deviceCapabilities: session.platform.getDeviceCapabilities(),
|
|
44
69
|
registrations: [authRegistration],
|
|
70
|
+
signals: registration.getSignals(),
|
|
45
71
|
})
|
|
46
72
|
.then((response) => {
|
|
47
73
|
if (response.error) {
|
|
48
|
-
reject(new auth_error_1.default(response.error.message, response.error.code, response.next));
|
|
74
|
+
reject(new auth_error_1.default(response.error.message, response.error.code, response.next, false));
|
|
49
75
|
}
|
|
50
76
|
else {
|
|
51
|
-
const
|
|
77
|
+
const deviceRegisterAuthResp = response;
|
|
78
|
+
const deviceId = deviceRegisterAuthResp.data.deviceId;
|
|
52
79
|
if (!deviceId) {
|
|
53
80
|
reject(new auth_error_1.default('Failed to register device, returned deviceId is null or empty', 0, response.next));
|
|
54
81
|
}
|
|
55
82
|
session.settings.deviceId = deviceId;
|
|
83
|
+
session.settings.fidoPasskeyRegistered = deviceRegisterAuthResp.data.passkey;
|
|
56
84
|
registration.deviceId = deviceId;
|
|
57
85
|
this.log.debug('Device ID: ' + deviceId);
|
|
58
86
|
session.platform.deviceAuth
|
|
@@ -72,14 +100,15 @@ class DevicePassiveSilentStep {
|
|
|
72
100
|
const challenge = registration.deviceId + ':' + session.challenge;
|
|
73
101
|
registration.sign(challenge).then((signature) => {
|
|
74
102
|
session
|
|
75
|
-
.fetchFromBackend(
|
|
103
|
+
.fetchFromBackend(this.getBackendVerifyEndpoint(), {
|
|
76
104
|
deviceId: registration.deviceId,
|
|
77
105
|
keyId: registration.keyId,
|
|
78
106
|
signature: signature,
|
|
107
|
+
signals: registration.getSignals(),
|
|
79
108
|
})
|
|
80
109
|
.then((response) => {
|
|
81
110
|
if (response.error) {
|
|
82
|
-
reject(new auth_error_1.default(response.error.message, response.error.code, response.next));
|
|
111
|
+
reject(new auth_error_1.default(response.error.message, response.error.code, response.next, false));
|
|
83
112
|
}
|
|
84
113
|
else {
|
|
85
114
|
resolve(response.next);
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import AuthSession from './auth-session';
|
|
2
2
|
import AuthStep from './auth-step';
|
|
3
3
|
import { DeviceRole } from '../authenticator-builder';
|
|
4
|
-
|
|
4
|
+
import { AuthStatusActions } from './auth-status-actions';
|
|
5
|
+
export declare class DevicePassiveActions extends AuthStatusActions {
|
|
5
6
|
protected log: import("../common/logger").Logger;
|
|
6
7
|
private readonly getDisplayName;
|
|
7
8
|
protected constructor(getDisplayName?: () => string | null);
|
|
@@ -10,9 +10,10 @@ const device_passive_silent_step_1 = __importDefault(require("./device-passive-s
|
|
|
10
10
|
const auth_token_claims_1 = require("./auth-token-claims");
|
|
11
11
|
const auth_error_1 = __importDefault(require("./auth-error"));
|
|
12
12
|
const authenticator_builder_1 = require("../authenticator-builder");
|
|
13
|
-
const
|
|
14
|
-
class DevicePassiveActions {
|
|
13
|
+
const auth_status_actions_1 = require("./auth-status-actions");
|
|
14
|
+
class DevicePassiveActions extends auth_status_actions_1.AuthStatusActions {
|
|
15
15
|
constructor(getDisplayName) {
|
|
16
|
+
super();
|
|
16
17
|
this.log = logger_1.LoggerFactory.getLogger('device-passive-actions');
|
|
17
18
|
this.getDisplayName = getDisplayName ? getDisplayName : () => null;
|
|
18
19
|
}
|
|
@@ -114,7 +115,7 @@ class DevicePassiveStep extends DevicePassiveActions {
|
|
|
114
115
|
}
|
|
115
116
|
execute(session) {
|
|
116
117
|
if (this.role == authenticator_builder_1.DeviceRole.Secondary) {
|
|
117
|
-
return
|
|
118
|
+
return this.waitForStatus(session);
|
|
118
119
|
}
|
|
119
120
|
if (!session.platform.isFidoSupported() ||
|
|
120
121
|
session.uvLevel === auth_token_claims_1.UserVerificationLevel.Discouraged) {
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import AuthSession from './auth-session';
|
|
2
2
|
import AuthStep from './auth-step';
|
|
3
|
+
import { Signals } from './auth-request';
|
|
3
4
|
export default class DevicePassiveVerifyStep implements AuthStep {
|
|
4
5
|
static readonly NAME = "device/passive/verify";
|
|
5
6
|
private readonly log;
|
|
6
7
|
readonly name = "device/passive/verify";
|
|
7
8
|
execute(session: AuthSession): Promise<string>;
|
|
9
|
+
runFidoVerifyFinish(session: AuthSession, signals?: Signals): Promise<string>;
|
|
8
10
|
}
|
|
@@ -12,6 +12,23 @@ class DevicePassiveVerifyStep {
|
|
|
12
12
|
this.name = DevicePassiveVerifyStep.NAME;
|
|
13
13
|
}
|
|
14
14
|
execute(session) {
|
|
15
|
+
return new Promise((resolve, reject) => {
|
|
16
|
+
session
|
|
17
|
+
.getFingerprintData()
|
|
18
|
+
.then((signal) => {
|
|
19
|
+
const signals = signal ? { fingerprint: signal } : undefined;
|
|
20
|
+
this.runFidoVerifyFinish(session, signals).then(resolve).catch(reject);
|
|
21
|
+
})
|
|
22
|
+
.catch((error) => {
|
|
23
|
+
var errorMsg = `Unexpected error happened during Fingerprint data collection ${error.toString}`;
|
|
24
|
+
this.log.warn(errorMsg);
|
|
25
|
+
this.runFidoVerifyFinish(session, { fingerprint: { error: errorMsg } })
|
|
26
|
+
.then(resolve)
|
|
27
|
+
.catch(reject);
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
runFidoVerifyFinish(session, signals) {
|
|
15
32
|
return new Promise((resolve, reject) => {
|
|
16
33
|
const credential = session.credential;
|
|
17
34
|
const assertion = credential.response;
|
|
@@ -30,6 +47,7 @@ class DevicePassiveVerifyStep {
|
|
|
30
47
|
: undefined,
|
|
31
48
|
},
|
|
32
49
|
},
|
|
50
|
+
signals: signals,
|
|
33
51
|
})
|
|
34
52
|
.then((response) => {
|
|
35
53
|
if (response.error) {
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import AuthStep from './auth-step';
|
|
2
|
+
import AuthSession from './auth-session';
|
|
3
|
+
export declare class DeviceUniversalRedirectBaseStep implements AuthStep {
|
|
4
|
+
name: string;
|
|
5
|
+
execute(session: AuthSession): Promise<string>;
|
|
6
|
+
}
|
|
7
|
+
export declare class DeviceUniversalRedirectFinishStep extends DeviceUniversalRedirectBaseStep {
|
|
8
|
+
static readonly NAME = "redirect/finish";
|
|
9
|
+
readonly name = "redirect/finish";
|
|
10
|
+
}
|
|
11
|
+
export declare class DeviceUniversalRedirectExchangeStep extends DeviceUniversalRedirectBaseStep {
|
|
12
|
+
static readonly NAME = "redirect/exchange";
|
|
13
|
+
readonly name = "redirect/exchange";
|
|
14
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
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.DeviceUniversalRedirectExchangeStep = exports.DeviceUniversalRedirectFinishStep = exports.DeviceUniversalRedirectBaseStep = void 0;
|
|
7
|
+
const auth_error_1 = __importDefault(require("./auth-error"));
|
|
8
|
+
class DeviceUniversalRedirectBaseStep {
|
|
9
|
+
constructor() {
|
|
10
|
+
this.name = '';
|
|
11
|
+
}
|
|
12
|
+
execute(session) {
|
|
13
|
+
return new Promise((resolve, reject) => {
|
|
14
|
+
var _a, _b, _c;
|
|
15
|
+
let redirectUrl = (_c = (_b = (_a = session.claims) === null || _a === void 0 ? void 0 : _a.auth.subs.dev) === null || _b === void 0 ? void 0 : _b.auths.unvsl) === null || _c === void 0 ? void 0 : _c.ftu;
|
|
16
|
+
if (typeof redirectUrl != 'undefined' && redirectUrl) {
|
|
17
|
+
redirectUrl += `?authId=${session.authId}`;
|
|
18
|
+
let upkNext = '';
|
|
19
|
+
if (this.name === 'redirect/exchange') {
|
|
20
|
+
upkNext = 'authexchange';
|
|
21
|
+
}
|
|
22
|
+
else if (this.name === 'redirect/finish') {
|
|
23
|
+
upkNext = 'authfinish';
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
reject(new auth_error_1.default(`Unknown UPK Step: ${this.name}`, 0, session.next, true));
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
redirectUrl += `&next=${upkNext}`;
|
|
30
|
+
session.platform.urlRedirect(redirectUrl);
|
|
31
|
+
resolve('');
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
reject(new auth_error_1.default('AuthToken claims do not contain final target URL', 0, session.next, true));
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
exports.DeviceUniversalRedirectBaseStep = DeviceUniversalRedirectBaseStep;
|
|
40
|
+
class DeviceUniversalRedirectFinishStep extends DeviceUniversalRedirectBaseStep {
|
|
41
|
+
constructor() {
|
|
42
|
+
super(...arguments);
|
|
43
|
+
this.name = DeviceUniversalRedirectFinishStep.NAME;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
DeviceUniversalRedirectFinishStep.NAME = 'redirect/finish';
|
|
47
|
+
exports.DeviceUniversalRedirectFinishStep = DeviceUniversalRedirectFinishStep;
|
|
48
|
+
class DeviceUniversalRedirectExchangeStep extends DeviceUniversalRedirectBaseStep {
|
|
49
|
+
constructor() {
|
|
50
|
+
super(...arguments);
|
|
51
|
+
this.name = DeviceUniversalRedirectExchangeStep.NAME;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
DeviceUniversalRedirectExchangeStep.NAME = 'redirect/exchange';
|
|
55
|
+
exports.DeviceUniversalRedirectExchangeStep = DeviceUniversalRedirectExchangeStep;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import AuthStep from './auth-step';
|
|
2
|
+
import AuthSession from './auth-session';
|
|
3
|
+
export default class DeviceUniversalStep implements AuthStep {
|
|
4
|
+
static readonly NAME = "device/universal";
|
|
5
|
+
private readonly log;
|
|
6
|
+
readonly name = "device/universal";
|
|
7
|
+
private forUPK;
|
|
8
|
+
constructor(forUPK: boolean);
|
|
9
|
+
execute(session: AuthSession): Promise<string>;
|
|
10
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
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
|
+
const logger_1 = require("../common/logger");
|
|
7
|
+
const auth_error_1 = __importDefault(require("./auth-error"));
|
|
8
|
+
const device_passive_silent_step_1 = __importDefault(require("./device-passive-silent-step"));
|
|
9
|
+
class DeviceUniversalStep {
|
|
10
|
+
constructor(forUPK) {
|
|
11
|
+
this.log = logger_1.LoggerFactory.getLogger('device-universal-step');
|
|
12
|
+
this.name = DeviceUniversalStep.NAME;
|
|
13
|
+
this.forUPK = false;
|
|
14
|
+
this.forUPK = forUPK;
|
|
15
|
+
}
|
|
16
|
+
execute(session) {
|
|
17
|
+
this.log.trace('Executing');
|
|
18
|
+
return new Promise((resolve, reject) => {
|
|
19
|
+
var _a, _b, _c;
|
|
20
|
+
if (this.forUPK) {
|
|
21
|
+
resolve(device_passive_silent_step_1.default.NAME);
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
let redirectUrl = (_c = (_b = (_a = session.claims) === null || _a === void 0 ? void 0 : _a.auth.subs.dev) === null || _b === void 0 ? void 0 : _b.auths.unvsl) === null || _c === void 0 ? void 0 : _c.endp;
|
|
25
|
+
if (typeof redirectUrl != 'undefined' && redirectUrl) {
|
|
26
|
+
redirectUrl += `?authId=${session.authId}&authtoken=${session.authToken}`;
|
|
27
|
+
session.platform.urlRedirect(redirectUrl);
|
|
28
|
+
resolve('');
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
reject(new auth_error_1.default('AuthToken claims do not contain universal redirect URL', 0, session.next, true));
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
DeviceUniversalStep.NAME = 'device/universal';
|
|
38
|
+
exports.default = DeviceUniversalStep;
|
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
import AuthFinishStep from '../auth-finish-step';
|
|
2
2
|
import Authenticator from '../authenticator';
|
|
3
3
|
import Settings from './settings';
|
|
4
|
-
import { Logger } from '../common/logger';
|
|
5
4
|
import Platform from './platform';
|
|
6
5
|
import CancelablePromise from '../common/cancelable-promise';
|
|
7
6
|
import AuthSession from './auth-session';
|
|
8
|
-
|
|
7
|
+
import AuthStep from './auth-step';
|
|
8
|
+
export default class MainAuthenticator implements Authenticator {
|
|
9
9
|
static readonly AUTH_DONE = "done";
|
|
10
10
|
static readonly AUTH_EMPTY = "";
|
|
11
11
|
static readonly MAX_ATTEMPTS = 50;
|
|
12
|
-
|
|
12
|
+
private readonly steps;
|
|
13
|
+
protected log: import("../common/logger").Logger;
|
|
13
14
|
protected readonly platform: Platform;
|
|
14
15
|
protected readonly settings: Settings;
|
|
15
16
|
protected readonly authFinishStep?: AuthFinishStep;
|
|
16
|
-
constructor(platform
|
|
17
|
+
constructor(platform: Platform, settings: Settings, finishStep?: AuthFinishStep, steps?: Array<AuthStep>);
|
|
17
18
|
isPasskeyRegistered(): boolean;
|
|
18
19
|
isFidoSupported(): boolean;
|
|
19
20
|
isDeviceRegistered(): boolean;
|
|
@@ -24,5 +25,7 @@ export default abstract class BaseAuthenticator implements Authenticator {
|
|
|
24
25
|
unregisterDevice(): Promise<void>;
|
|
25
26
|
unregisterPasskey(): Promise<void>;
|
|
26
27
|
private unregister;
|
|
27
|
-
|
|
28
|
+
process(session: AuthSession): CancelablePromise<void>;
|
|
29
|
+
private nextStep;
|
|
30
|
+
private getNextStep;
|
|
28
31
|
}
|
|
@@ -3,23 +3,24 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
const settings_1 = __importDefault(require("./settings"));
|
|
7
6
|
const logger_1 = require("../common/logger");
|
|
8
7
|
const cancelable_promise_1 = __importDefault(require("../common/cancelable-promise"));
|
|
9
8
|
const auth_session_1 = __importDefault(require("./auth-session"));
|
|
10
9
|
const auth_error_1 = __importDefault(require("./auth-error"));
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
throw new Error('Implementation of Storage is required');
|
|
18
|
-
}
|
|
19
|
-
this.log = logger_1.LoggerFactory.getLogger('base-authenticator');
|
|
10
|
+
const report_error_step_1 = __importDefault(require("./report-error-step"));
|
|
11
|
+
const error_code_1 = __importDefault(require("./error-code"));
|
|
12
|
+
class MainAuthenticator {
|
|
13
|
+
constructor(platform, settings, finishStep, steps) {
|
|
14
|
+
this.steps = new Map();
|
|
15
|
+
this.log = logger_1.LoggerFactory.getLogger('main-authenticator');
|
|
20
16
|
this.platform = platform;
|
|
21
17
|
this.authFinishStep = finishStep;
|
|
22
|
-
this.settings =
|
|
18
|
+
this.settings = settings;
|
|
19
|
+
if (steps) {
|
|
20
|
+
for (let step of steps) {
|
|
21
|
+
this.steps.set(step.name, step);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
23
24
|
}
|
|
24
25
|
isPasskeyRegistered() {
|
|
25
26
|
return this.settings.fidoPasskeyRegistered;
|
|
@@ -51,12 +52,15 @@ class BaseAuthenticator {
|
|
|
51
52
|
}
|
|
52
53
|
try {
|
|
53
54
|
const session = new auth_session_1.default(this.settings, this.platform, authToken);
|
|
54
|
-
|
|
55
|
+
if (this.settings.upkEnabled) {
|
|
56
|
+
session.backendOriginOverride = this.platform.getOrigin();
|
|
57
|
+
}
|
|
58
|
+
const processing = this.process(session);
|
|
55
59
|
onCancel(() => processing.cancel());
|
|
56
60
|
processing
|
|
57
61
|
.then(() => {
|
|
58
62
|
var _a;
|
|
59
|
-
if (session.lastStep !==
|
|
63
|
+
if (session.lastStep !== MainAuthenticator.AUTH_EMPTY) {
|
|
60
64
|
this.log.info('Authentication flow has been completed.');
|
|
61
65
|
return (_a = this.authFinishStep) === null || _a === void 0 ? void 0 : _a.execute({ authId: session.authId });
|
|
62
66
|
}
|
|
@@ -122,8 +126,48 @@ class BaseAuthenticator {
|
|
|
122
126
|
}
|
|
123
127
|
});
|
|
124
128
|
}
|
|
129
|
+
process(session) {
|
|
130
|
+
return new cancelable_promise_1.default((resolve, reject, onCancel) => {
|
|
131
|
+
onCancel(() => {
|
|
132
|
+
this.log.info('Canceled');
|
|
133
|
+
session.closeAllMessageChannels();
|
|
134
|
+
resolve();
|
|
135
|
+
});
|
|
136
|
+
this.nextStep(session, session.next, 1).then(resolve).catch(reject);
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
nextStep(session, step, attempt) {
|
|
140
|
+
this.log.debug(`Authentication attempt ${attempt}, next step: ${step}`);
|
|
141
|
+
session.lastStep = step;
|
|
142
|
+
return new Promise((resolve, reject) => {
|
|
143
|
+
if ([MainAuthenticator.AUTH_DONE, MainAuthenticator.AUTH_EMPTY].includes(step)) {
|
|
144
|
+
resolve();
|
|
145
|
+
}
|
|
146
|
+
else if (attempt > MainAuthenticator.MAX_ATTEMPTS) {
|
|
147
|
+
reject(new auth_error_1.default('Too many authentication steps', error_code_1.default.ERROR_MAX_ATTEMPTS));
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
this.getNextStep(step)
|
|
151
|
+
.execute(session)
|
|
152
|
+
.then((next) => this.nextStep(session, next, attempt + 1))
|
|
153
|
+
.then(resolve)
|
|
154
|
+
.catch((e) => new report_error_step_1.default(e)
|
|
155
|
+
.execute(session)
|
|
156
|
+
.then((next) => this.nextStep(session, next, attempt + 1))
|
|
157
|
+
.then(resolve)
|
|
158
|
+
.catch(reject));
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
getNextStep(step) {
|
|
163
|
+
var nextStep = this.steps.get(step);
|
|
164
|
+
if (nextStep) {
|
|
165
|
+
return nextStep;
|
|
166
|
+
}
|
|
167
|
+
return new report_error_step_1.default('Unknown authentication step: ' + step);
|
|
168
|
+
}
|
|
125
169
|
}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
exports.default =
|
|
170
|
+
MainAuthenticator.AUTH_DONE = 'done';
|
|
171
|
+
MainAuthenticator.AUTH_EMPTY = '';
|
|
172
|
+
MainAuthenticator.MAX_ATTEMPTS = 50;
|
|
173
|
+
exports.default = MainAuthenticator;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import AuthSession from './auth-session';
|
|
2
2
|
import AuthStep from './auth-step';
|
|
3
3
|
import { InstantLinkStartStep } from '../instantlink';
|
|
4
|
-
|
|
4
|
+
import { AuthStatusActions } from './auth-status-actions';
|
|
5
|
+
export default class MobileInstantLinkStep extends AuthStatusActions implements AuthStep {
|
|
5
6
|
static readonly NAME = "mobile/instantlink";
|
|
6
7
|
readonly name = "mobile/instantlink";
|
|
7
8
|
protected log: import("../common/logger").Logger;
|
|
@@ -6,15 +6,18 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
const logger_1 = require("../common/logger");
|
|
7
7
|
const phone_number_input_1 = require("./phone-number-input");
|
|
8
8
|
const auth_error_1 = __importDefault(require("./auth-error"));
|
|
9
|
+
const auth_status_actions_1 = require("./auth-status-actions");
|
|
9
10
|
const SIMULATED_LINK_CLICK_DELAY = 100;
|
|
10
|
-
class MobileInstantLinkStep {
|
|
11
|
+
class MobileInstantLinkStep extends auth_status_actions_1.AuthStatusActions {
|
|
11
12
|
constructor(startStep, getDeviceIp) {
|
|
13
|
+
super();
|
|
12
14
|
this.name = MobileInstantLinkStep.NAME;
|
|
13
15
|
this.log = logger_1.LoggerFactory.getLogger('mobile-instantlink-step');
|
|
14
16
|
this.startStep = startStep;
|
|
15
17
|
this.getDeviceIp = getDeviceIp !== null && getDeviceIp !== void 0 ? getDeviceIp : (() => null);
|
|
16
18
|
}
|
|
17
19
|
execute(session) {
|
|
20
|
+
this.log.trace('Executing');
|
|
18
21
|
return new Promise((resolve, reject) => {
|
|
19
22
|
var _a, _b, _c, _d, _e, _f;
|
|
20
23
|
var phoneNumberNeeded = true;
|
|
@@ -26,9 +29,10 @@ class MobileInstantLinkStep {
|
|
|
26
29
|
testMode = true;
|
|
27
30
|
}
|
|
28
31
|
this.runStartStep(session, phoneNumberNeeded)
|
|
29
|
-
.then((
|
|
32
|
+
.then((_) => {
|
|
30
33
|
this.runFinishStep(session, testMode)
|
|
31
|
-
.then(() =>
|
|
34
|
+
.then(() => this.waitForStatus(session))
|
|
35
|
+
.then((next) => resolve(next))
|
|
32
36
|
.catch(reject);
|
|
33
37
|
})
|
|
34
38
|
.catch(reject);
|
|
@@ -87,9 +91,9 @@ class MobileInstantLinkStep {
|
|
|
87
91
|
this.log.info('Simulating user clicking the instant link');
|
|
88
92
|
setTimeout(() => {
|
|
89
93
|
session.platform
|
|
90
|
-
.fetch(session.
|
|
94
|
+
.fetch(session.backendOrigin +
|
|
91
95
|
'/v1/client/mobile/instantlink/finish?token=' +
|
|
92
|
-
session.authToken +
|
|
96
|
+
encodeURIComponent(session.authToken) +
|
|
93
97
|
'&vfp=test-vfp', {
|
|
94
98
|
mode: 'cors',
|
|
95
99
|
method: 'GET',
|
|
@@ -3,6 +3,7 @@ import { AuthenticatorBuilder } from '@prove-identity/mobile-auth';
|
|
|
3
3
|
import { AuthRequest } from './auth-request';
|
|
4
4
|
import AuthResponse from './auth-response';
|
|
5
5
|
import DeviceAuth, { DeviceRegistration } from './device-auth';
|
|
6
|
+
import { Agent } from '@fingerprintjs/fingerprintjs-pro';
|
|
6
7
|
export declare const DEVICE_CAPABILITY_WEBAUTHN = "webauthn";
|
|
7
8
|
export interface MessageChannel {
|
|
8
9
|
addEventListener: (type: string, listener: (event: any) => void) => void;
|
|
@@ -33,11 +34,15 @@ export default interface Platform {
|
|
|
33
34
|
getUserAgent: () => string | null;
|
|
34
35
|
isFidoSupported: () => boolean;
|
|
35
36
|
fetch: (input: string, init?: RequestInit) => Promise<Response>;
|
|
36
|
-
createMessageChannel: (
|
|
37
|
+
createMessageChannel: (input: string) => MessageChannel;
|
|
37
38
|
createRequestSigner: (session: AuthSessionIntegration) => RequestSigner;
|
|
38
39
|
getDeviceCapabilities: () => string[];
|
|
39
40
|
getMobileAuthBuilder: () => AuthenticatorBuilder<any>;
|
|
40
41
|
exit: (code?: number) => void;
|
|
42
|
+
urlRedirect: (url: string) => void;
|
|
43
|
+
getFpPromise: () => Promise<Agent> | undefined;
|
|
44
|
+
setFpPromise: (fpPromise: Promise<Agent>) => void;
|
|
45
|
+
getOrigin: () => string;
|
|
41
46
|
}
|
|
42
47
|
export declare function stringToArrayBuffer(input: string): ArrayBuffer;
|
|
43
48
|
export declare function arrayBufferToString(input: ArrayBuffer): string;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import AuthSession from './auth-session';
|
|
2
2
|
import AuthStep from './auth-step';
|
|
3
3
|
export default class ReportErrorStep implements AuthStep {
|
|
4
|
-
private static readonly
|
|
4
|
+
private static readonly errorMap;
|
|
5
5
|
private readonly logger;
|
|
6
6
|
private _message;
|
|
7
7
|
private _code?;
|
|
@@ -12,5 +12,5 @@ export default class ReportErrorStep implements AuthStep {
|
|
|
12
12
|
get code(): number | undefined;
|
|
13
13
|
get message(): string;
|
|
14
14
|
execute(session: AuthSession): Promise<string>;
|
|
15
|
-
private
|
|
15
|
+
private lookupError;
|
|
16
16
|
}
|