@prove-identity/prove-auth 2.3.2
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/LICENSE +404 -0
- package/README.md +17 -0
- package/build/lib/index.d.ts +12 -0
- package/build/lib/index.js +47 -0
- package/build/lib/proveauth/auth-finish-step.d.ts +7 -0
- package/build/lib/proveauth/auth-finish-step.js +2 -0
- package/build/lib/proveauth/authenticator-builder.d.ts +42 -0
- package/build/lib/proveauth/authenticator-builder.js +126 -0
- package/build/lib/proveauth/authenticator.d.ts +12 -0
- package/build/lib/proveauth/authenticator.js +2 -0
- package/build/lib/proveauth/common/base64.d.ts +5 -0
- package/build/lib/proveauth/common/base64.js +19 -0
- package/build/lib/proveauth/common/cancelable-promise.d.ts +5 -0
- package/build/lib/proveauth/common/cancelable-promise.js +15 -0
- package/build/lib/proveauth/common/logger.d.ts +25 -0
- package/build/lib/proveauth/common/logger.js +85 -0
- package/build/lib/proveauth/instantlink.d.ts +4 -0
- package/build/lib/proveauth/instantlink.js +2 -0
- package/build/lib/proveauth/internal/auth-error.d.ts +7 -0
- package/build/lib/proveauth/internal/auth-error.js +27 -0
- package/build/lib/proveauth/internal/auth-message.d.ts +12 -0
- package/build/lib/proveauth/internal/auth-message.js +2 -0
- package/build/lib/proveauth/internal/auth-request.d.ts +90 -0
- package/build/lib/proveauth/internal/auth-request.js +2 -0
- package/build/lib/proveauth/internal/auth-response-status.d.ts +8 -0
- package/build/lib/proveauth/internal/auth-response-status.js +12 -0
- package/build/lib/proveauth/internal/auth-response.d.ts +61 -0
- package/build/lib/proveauth/internal/auth-response.js +2 -0
- package/build/lib/proveauth/internal/auth-session.d.ts +30 -0
- package/build/lib/proveauth/internal/auth-session.js +156 -0
- package/build/lib/proveauth/internal/auth-step.d.ts +5 -0
- package/build/lib/proveauth/internal/auth-step.js +2 -0
- package/build/lib/proveauth/internal/auth-token-claims.d.ts +46 -0
- package/build/lib/proveauth/internal/auth-token-claims.js +9 -0
- package/build/lib/proveauth/internal/base-authenticator.d.ts +28 -0
- package/build/lib/proveauth/internal/base-authenticator.js +129 -0
- package/build/lib/proveauth/internal/device-auth.d.ts +22 -0
- package/build/lib/proveauth/internal/device-auth.js +2 -0
- package/build/lib/proveauth/internal/device-passive-register-step.d.ts +10 -0
- package/build/lib/proveauth/internal/device-passive-register-step.js +97 -0
- package/build/lib/proveauth/internal/device-passive-silent-step.d.ts +10 -0
- package/build/lib/proveauth/internal/device-passive-silent-step.js +98 -0
- package/build/lib/proveauth/internal/device-passive-step.d.ts +17 -0
- package/build/lib/proveauth/internal/device-passive-step.js +133 -0
- package/build/lib/proveauth/internal/device-passive-stepup-step.d.ts +9 -0
- package/build/lib/proveauth/internal/device-passive-stepup-step.js +25 -0
- package/build/lib/proveauth/internal/device-passive-verify-step.d.ts +8 -0
- package/build/lib/proveauth/internal/device-passive-verify-step.js +54 -0
- package/build/lib/proveauth/internal/error-code.d.ts +9 -0
- package/build/lib/proveauth/internal/error-code.js +12 -0
- package/build/lib/proveauth/internal/mobile-instant-step.d.ts +15 -0
- package/build/lib/proveauth/internal/mobile-instant-step.js +100 -0
- package/build/lib/proveauth/internal/mobile-instantlink-step.d.ts +14 -0
- package/build/lib/proveauth/internal/mobile-instantlink-step.js +108 -0
- package/build/lib/proveauth/internal/mobile-otp-step.d.ts +14 -0
- package/build/lib/proveauth/internal/mobile-otp-step.js +141 -0
- package/build/lib/proveauth/internal/phone-number-input.d.ts +11 -0
- package/build/lib/proveauth/internal/phone-number-input.js +13 -0
- package/build/lib/proveauth/internal/platform.d.ts +45 -0
- package/build/lib/proveauth/internal/platform.js +20 -0
- package/build/lib/proveauth/internal/primary-authenticator.d.ts +14 -0
- package/build/lib/proveauth/internal/primary-authenticator.js +64 -0
- package/build/lib/proveauth/internal/report-error-step.d.ts +16 -0
- package/build/lib/proveauth/internal/report-error-step.js +88 -0
- package/build/lib/proveauth/internal/request-signer-v3.d.ts +10 -0
- package/build/lib/proveauth/internal/request-signer-v3.js +104 -0
- package/build/lib/proveauth/internal/scan-message-step.d.ts +11 -0
- package/build/lib/proveauth/internal/scan-message-step.js +45 -0
- package/build/lib/proveauth/internal/secondary-authenticator.d.ts +10 -0
- package/build/lib/proveauth/internal/secondary-authenticator.js +65 -0
- package/build/lib/proveauth/internal/settings.d.ts +18 -0
- package/build/lib/proveauth/internal/settings.js +50 -0
- package/build/lib/proveauth/internal/user-mobileactive-step.d.ts +7 -0
- package/build/lib/proveauth/internal/user-mobileactive-step.js +18 -0
- package/build/lib/proveauth/internal/user-present-step.d.ts +7 -0
- package/build/lib/proveauth/internal/user-present-step.js +18 -0
- package/build/lib/proveauth/internal/web-device-auth.d.ts +32 -0
- package/build/lib/proveauth/internal/web-device-auth.js +242 -0
- package/build/lib/proveauth/internal/web-platform.d.ts +30 -0
- package/build/lib/proveauth/internal/web-platform.js +160 -0
- package/build/lib/proveauth/otp.d.ts +23 -0
- package/build/lib/proveauth/otp.js +18 -0
- package/build/lib/proveauth/version.d.ts +3 -0
- package/build/lib/proveauth/version.js +6 -0
- package/package.json +75 -0
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.UserVerificationLevel = void 0;
|
|
4
|
+
var UserVerificationLevel;
|
|
5
|
+
(function (UserVerificationLevel) {
|
|
6
|
+
UserVerificationLevel["Discouraged"] = "none";
|
|
7
|
+
UserVerificationLevel["Preferred"] = "pref";
|
|
8
|
+
UserVerificationLevel["Required"] = "req";
|
|
9
|
+
})(UserVerificationLevel = exports.UserVerificationLevel || (exports.UserVerificationLevel = {}));
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import AuthFinishStep from '../auth-finish-step';
|
|
2
|
+
import Authenticator from '../authenticator';
|
|
3
|
+
import Settings from './settings';
|
|
4
|
+
import { Logger } from '../common/logger';
|
|
5
|
+
import Platform from './platform';
|
|
6
|
+
import CancelablePromise from '../common/cancelable-promise';
|
|
7
|
+
import AuthSession from './auth-session';
|
|
8
|
+
export default abstract class BaseAuthenticator implements Authenticator {
|
|
9
|
+
static readonly AUTH_DONE = "done";
|
|
10
|
+
static readonly AUTH_EMPTY = "";
|
|
11
|
+
static readonly MAX_ATTEMPTS = 50;
|
|
12
|
+
protected log: Logger;
|
|
13
|
+
protected readonly platform: Platform;
|
|
14
|
+
protected readonly settings: Settings;
|
|
15
|
+
protected readonly authFinishStep?: AuthFinishStep;
|
|
16
|
+
constructor(platform?: Platform, storage?: Storage, finishStep?: AuthFinishStep);
|
|
17
|
+
isPasskeyRegistered(): boolean;
|
|
18
|
+
isFidoSupported(): boolean;
|
|
19
|
+
isDeviceRegistered(): boolean;
|
|
20
|
+
isMobileWeb(): boolean;
|
|
21
|
+
getDeviceId(): string | null;
|
|
22
|
+
resetDeviceSettings(): void;
|
|
23
|
+
authenticate(authToken: string): CancelablePromise<void>;
|
|
24
|
+
unregisterDevice(): Promise<void>;
|
|
25
|
+
unregisterPasskey(): Promise<void>;
|
|
26
|
+
private unregister;
|
|
27
|
+
abstract process(session: AuthSession): CancelablePromise<void>;
|
|
28
|
+
}
|
|
@@ -0,0 +1,129 @@
|
|
|
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 settings_1 = __importDefault(require("./settings"));
|
|
7
|
+
const logger_1 = require("../common/logger");
|
|
8
|
+
const cancelable_promise_1 = __importDefault(require("../common/cancelable-promise"));
|
|
9
|
+
const auth_session_1 = __importDefault(require("./auth-session"));
|
|
10
|
+
const auth_error_1 = __importDefault(require("./auth-error"));
|
|
11
|
+
class BaseAuthenticator {
|
|
12
|
+
constructor(platform, storage, finishStep) {
|
|
13
|
+
if (!platform) {
|
|
14
|
+
throw new Error('Implementation of Platform is required');
|
|
15
|
+
}
|
|
16
|
+
if (!storage) {
|
|
17
|
+
throw new Error('Implementation of Storage is required');
|
|
18
|
+
}
|
|
19
|
+
this.log = logger_1.LoggerFactory.getLogger('base-authenticator');
|
|
20
|
+
this.platform = platform;
|
|
21
|
+
this.authFinishStep = finishStep;
|
|
22
|
+
this.settings = new settings_1.default(storage);
|
|
23
|
+
}
|
|
24
|
+
isPasskeyRegistered() {
|
|
25
|
+
return this.settings.fidoPasskeyRegistered;
|
|
26
|
+
}
|
|
27
|
+
isFidoSupported() {
|
|
28
|
+
return this.platform.isFidoSupported();
|
|
29
|
+
}
|
|
30
|
+
isDeviceRegistered() {
|
|
31
|
+
return this.settings.deviceId !== null;
|
|
32
|
+
}
|
|
33
|
+
isMobileWeb() {
|
|
34
|
+
const userAgent = this.platform.getUserAgent();
|
|
35
|
+
return (userAgent !== null && /Mobi|Android|webOS|iPhone|iPad|BlackBerry|Opera Mini/i.test(userAgent));
|
|
36
|
+
}
|
|
37
|
+
getDeviceId() {
|
|
38
|
+
return this.settings.deviceId;
|
|
39
|
+
}
|
|
40
|
+
resetDeviceSettings() {
|
|
41
|
+
this.settings.reset();
|
|
42
|
+
this.platform.deviceAuth.reset();
|
|
43
|
+
}
|
|
44
|
+
authenticate(authToken) {
|
|
45
|
+
return new cancelable_promise_1.default((resolve, reject, onCancel) => {
|
|
46
|
+
if (!authToken) {
|
|
47
|
+
reject(new Error('No authentication token provided'));
|
|
48
|
+
}
|
|
49
|
+
if (!this.authFinishStep) {
|
|
50
|
+
reject(new Error('AuthFinish step must be specified'));
|
|
51
|
+
}
|
|
52
|
+
try {
|
|
53
|
+
const session = new auth_session_1.default(this.settings, this.platform, authToken);
|
|
54
|
+
var processing = this.process(session);
|
|
55
|
+
onCancel(() => processing.cancel());
|
|
56
|
+
processing
|
|
57
|
+
.then(() => {
|
|
58
|
+
var _a;
|
|
59
|
+
if (session.lastStep !== BaseAuthenticator.AUTH_EMPTY) {
|
|
60
|
+
this.log.info('Authentication flow has been completed.');
|
|
61
|
+
return (_a = this.authFinishStep) === null || _a === void 0 ? void 0 : _a.execute({ authId: session.authId });
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
this.log.info('Next step is not provided, authentication flow is terminated without completion.');
|
|
65
|
+
resolve();
|
|
66
|
+
}
|
|
67
|
+
})
|
|
68
|
+
.then(resolve)
|
|
69
|
+
.catch(reject);
|
|
70
|
+
}
|
|
71
|
+
catch (e) {
|
|
72
|
+
reject(e);
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
unregisterDevice() {
|
|
77
|
+
if (!this.isDeviceRegistered()) {
|
|
78
|
+
return Promise.resolve();
|
|
79
|
+
}
|
|
80
|
+
return new Promise((resolve, reject) => {
|
|
81
|
+
this.unregister('/v1/client/device/unregister')
|
|
82
|
+
.then(() => {
|
|
83
|
+
this.resetDeviceSettings();
|
|
84
|
+
resolve();
|
|
85
|
+
})
|
|
86
|
+
.catch(reject);
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
unregisterPasskey() {
|
|
90
|
+
if (!this.settings.fidoPasskeyRegistered) {
|
|
91
|
+
return Promise.resolve();
|
|
92
|
+
}
|
|
93
|
+
return new Promise((resolve, reject) => {
|
|
94
|
+
this.unregister('/v1/client/stepup/unregister')
|
|
95
|
+
.then(() => {
|
|
96
|
+
this.settings.fidoPasskeyRegistered = false;
|
|
97
|
+
resolve();
|
|
98
|
+
})
|
|
99
|
+
.catch(reject);
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
unregister(endpointPath) {
|
|
103
|
+
return new Promise((resolve, reject) => {
|
|
104
|
+
try {
|
|
105
|
+
let session = new auth_session_1.default(this.settings, this.platform);
|
|
106
|
+
session
|
|
107
|
+
.fetchFromBackend(endpointPath, {
|
|
108
|
+
deviceId: this.getDeviceId(),
|
|
109
|
+
})
|
|
110
|
+
.then((response) => {
|
|
111
|
+
if (response.error) {
|
|
112
|
+
reject(new auth_error_1.default(response.error.message, response.error.code, response.next));
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
resolve();
|
|
116
|
+
}
|
|
117
|
+
})
|
|
118
|
+
.catch(reject);
|
|
119
|
+
}
|
|
120
|
+
catch (e) {
|
|
121
|
+
reject(e);
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
BaseAuthenticator.AUTH_DONE = 'done';
|
|
127
|
+
BaseAuthenticator.AUTH_EMPTY = '';
|
|
128
|
+
BaseAuthenticator.MAX_ATTEMPTS = 50;
|
|
129
|
+
exports.default = BaseAuthenticator;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { AuthRegistration } from './auth-request';
|
|
2
|
+
export interface DeviceRegistrationOptions {
|
|
3
|
+
namespace: string;
|
|
4
|
+
endpoint: string;
|
|
5
|
+
}
|
|
6
|
+
export interface DeviceRegistration {
|
|
7
|
+
readonly namespace: string;
|
|
8
|
+
readonly keyId: string;
|
|
9
|
+
readonly algorithm: string;
|
|
10
|
+
readonly endpoint: string;
|
|
11
|
+
deviceId: string | null;
|
|
12
|
+
sign: (data: string) => Promise<string>;
|
|
13
|
+
getPublicKey: () => Promise<string>;
|
|
14
|
+
getAuthRegistration: (challenge: string) => Promise<AuthRegistration>;
|
|
15
|
+
}
|
|
16
|
+
export default interface DeviceAuth {
|
|
17
|
+
createRegistration: (options: DeviceRegistrationOptions) => Promise<DeviceRegistration>;
|
|
18
|
+
getRegistration: (namespace: string) => Promise<DeviceRegistration | null>;
|
|
19
|
+
storeRegistration: (registration: DeviceRegistration) => Promise<void>;
|
|
20
|
+
deleteRegistration: (namespace: string) => Promise<void>;
|
|
21
|
+
reset: () => Promise<void>;
|
|
22
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import AuthSession from './auth-session';
|
|
2
|
+
import AuthStep from './auth-step';
|
|
3
|
+
export default class DevicePassiveRegisterStep implements AuthStep {
|
|
4
|
+
static readonly NAME = "device/passive/register";
|
|
5
|
+
private readonly log;
|
|
6
|
+
readonly name = "device/passive/register";
|
|
7
|
+
execute(session: AuthSession): Promise<string>;
|
|
8
|
+
private finishRegistration;
|
|
9
|
+
private getFido2Registration;
|
|
10
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
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 base64_1 = __importDefault(require("../common/base64"));
|
|
7
|
+
const logger_1 = require("../common/logger");
|
|
8
|
+
const auth_error_1 = __importDefault(require("./auth-error"));
|
|
9
|
+
const error_code_1 = __importDefault(require("./error-code"));
|
|
10
|
+
class DevicePassiveRegisterStep {
|
|
11
|
+
constructor() {
|
|
12
|
+
this.log = logger_1.LoggerFactory.getLogger('device-passive-register-step');
|
|
13
|
+
this.name = DevicePassiveRegisterStep.NAME;
|
|
14
|
+
}
|
|
15
|
+
execute(session) {
|
|
16
|
+
return new Promise((resolve, reject) => {
|
|
17
|
+
session
|
|
18
|
+
.getDeviceRegistration()
|
|
19
|
+
.then((devRegistration) => {
|
|
20
|
+
if (devRegistration) {
|
|
21
|
+
this.finishRegistration(session, [this.getFido2Registration(session)])
|
|
22
|
+
.then(resolve)
|
|
23
|
+
.catch(reject);
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
session.platform.deviceAuth
|
|
27
|
+
.createRegistration({
|
|
28
|
+
namespace: session.namespace,
|
|
29
|
+
endpoint: session.backendUrl,
|
|
30
|
+
})
|
|
31
|
+
.then((devRegistration) => {
|
|
32
|
+
devRegistration
|
|
33
|
+
.getAuthRegistration(session.challenge)
|
|
34
|
+
.then((authRegistration) => this.finishRegistration(session, [
|
|
35
|
+
this.getFido2Registration(session),
|
|
36
|
+
authRegistration,
|
|
37
|
+
]))
|
|
38
|
+
.then((next) => {
|
|
39
|
+
devRegistration.deviceId = session.settings.deviceId;
|
|
40
|
+
session.platform.deviceAuth
|
|
41
|
+
.storeRegistration(devRegistration)
|
|
42
|
+
.then(() => resolve(next))
|
|
43
|
+
.catch(reject);
|
|
44
|
+
})
|
|
45
|
+
.catch(reject);
|
|
46
|
+
})
|
|
47
|
+
.catch(reject);
|
|
48
|
+
}
|
|
49
|
+
})
|
|
50
|
+
.catch(reject);
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
finishRegistration(session, registrations) {
|
|
54
|
+
return new Promise((resolve, reject) => {
|
|
55
|
+
session
|
|
56
|
+
.fetchFromBackend('/v1/client/device/fido2/register/finish', {
|
|
57
|
+
deviceName: session.platform.getPlatformName(),
|
|
58
|
+
deviceCapabilities: session.platform.getDeviceCapabilities(),
|
|
59
|
+
registrations: registrations,
|
|
60
|
+
})
|
|
61
|
+
.then((response) => {
|
|
62
|
+
if (response.error) {
|
|
63
|
+
reject(new auth_error_1.default(response.error.message, response.error.code, response.next));
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
const data = response.data;
|
|
67
|
+
if (data && data.deviceId) {
|
|
68
|
+
session.settings.deviceId = data.deviceId;
|
|
69
|
+
session.settings.fidoPasskeyRegistered = true;
|
|
70
|
+
resolve(response.next);
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
reject(new auth_error_1.default('Failed to register device, returned deviceId is null or empty', error_code_1.default.ERROR_AUTHENTICATION_FAILURE, response.next, false));
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
})
|
|
77
|
+
.catch(reject);
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
getFido2Registration(session) {
|
|
81
|
+
const credential = session.credential;
|
|
82
|
+
const attestation = credential.response;
|
|
83
|
+
return {
|
|
84
|
+
webAuthnCredential: {
|
|
85
|
+
type: credential === null || credential === void 0 ? void 0 : credential.type,
|
|
86
|
+
id: credential === null || credential === void 0 ? void 0 : credential.id,
|
|
87
|
+
rawId: base64_1.default.bufferEncode(credential === null || credential === void 0 ? void 0 : credential.rawId),
|
|
88
|
+
response: {
|
|
89
|
+
attestationObject: base64_1.default.bufferEncode(attestation.attestationObject),
|
|
90
|
+
clientDataJSON: base64_1.default.bufferEncode(attestation.clientDataJSON),
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
DevicePassiveRegisterStep.NAME = 'device/passive/register';
|
|
97
|
+
exports.default = DevicePassiveRegisterStep;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import AuthSession from './auth-session';
|
|
2
|
+
import AuthStep from './auth-step';
|
|
3
|
+
export default class DevicePassiveSilentStep implements AuthStep {
|
|
4
|
+
static readonly NAME = "device/passive/silent";
|
|
5
|
+
private readonly log;
|
|
6
|
+
readonly name = "device/passive/silent";
|
|
7
|
+
execute(session: AuthSession): Promise<string>;
|
|
8
|
+
private register;
|
|
9
|
+
private verify;
|
|
10
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
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
|
+
class DevicePassiveSilentStep {
|
|
9
|
+
constructor() {
|
|
10
|
+
this.log = logger_1.LoggerFactory.getLogger('device-passive-silent-step');
|
|
11
|
+
this.name = DevicePassiveSilentStep.NAME;
|
|
12
|
+
}
|
|
13
|
+
execute(session) {
|
|
14
|
+
this.log.trace('Executing');
|
|
15
|
+
return new Promise((resolve, reject) => {
|
|
16
|
+
session
|
|
17
|
+
.getDeviceRegistration()
|
|
18
|
+
.then((registration) => {
|
|
19
|
+
if (registration) {
|
|
20
|
+
this.verify(session, registration).then(resolve).catch(reject);
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
session.platform.deviceAuth
|
|
24
|
+
.createRegistration({
|
|
25
|
+
namespace: session.namespace,
|
|
26
|
+
endpoint: session.backendUrl,
|
|
27
|
+
})
|
|
28
|
+
.then((registration) => this.register(session, registration))
|
|
29
|
+
.then(resolve)
|
|
30
|
+
.catch(reject);
|
|
31
|
+
}
|
|
32
|
+
})
|
|
33
|
+
.catch(reject);
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
register(session, registration) {
|
|
37
|
+
this.log.trace('Registering');
|
|
38
|
+
return new Promise((resolve, reject) => {
|
|
39
|
+
registration.getAuthRegistration(session.challenge).then((authRegistration) => {
|
|
40
|
+
session
|
|
41
|
+
.fetchFromBackend('/v1/client/device/passive/register', {
|
|
42
|
+
deviceName: session.platform.getPlatformName(),
|
|
43
|
+
deviceCapabilities: session.platform.getDeviceCapabilities(),
|
|
44
|
+
registrations: [authRegistration],
|
|
45
|
+
})
|
|
46
|
+
.then((response) => {
|
|
47
|
+
if (response.error) {
|
|
48
|
+
reject(new auth_error_1.default(response.error.message, response.error.code, response.next));
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
const deviceId = response.data.deviceId;
|
|
52
|
+
if (!deviceId) {
|
|
53
|
+
reject(new auth_error_1.default('Failed to register device, returned deviceId is null or empty', 0, response.next));
|
|
54
|
+
}
|
|
55
|
+
session.settings.deviceId = deviceId;
|
|
56
|
+
registration.deviceId = deviceId;
|
|
57
|
+
this.log.debug('Device ID: ' + deviceId);
|
|
58
|
+
session.platform.deviceAuth
|
|
59
|
+
.storeRegistration(registration)
|
|
60
|
+
.then(() => resolve(response.next))
|
|
61
|
+
.catch(reject);
|
|
62
|
+
}
|
|
63
|
+
})
|
|
64
|
+
.catch(reject);
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
verify(session, registration) {
|
|
69
|
+
this.log.trace('Verifying');
|
|
70
|
+
return new Promise((resolve, reject) => {
|
|
71
|
+
if (registration.deviceId) {
|
|
72
|
+
const challenge = registration.deviceId + ':' + session.challenge;
|
|
73
|
+
registration.sign(challenge).then((signature) => {
|
|
74
|
+
session
|
|
75
|
+
.fetchFromBackend('/v1/client/device/passive/verify', {
|
|
76
|
+
deviceId: registration.deviceId,
|
|
77
|
+
keyId: registration.keyId,
|
|
78
|
+
signature: signature,
|
|
79
|
+
})
|
|
80
|
+
.then((response) => {
|
|
81
|
+
if (response.error) {
|
|
82
|
+
reject(new auth_error_1.default(response.error.message, response.error.code, response.next));
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
resolve(response.next);
|
|
86
|
+
}
|
|
87
|
+
})
|
|
88
|
+
.catch(reject);
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
reject(new auth_error_1.default('Failed to initiate verification, DeviceId is missing'));
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
DevicePassiveSilentStep.NAME = 'device/passive/silent';
|
|
98
|
+
exports.default = DevicePassiveSilentStep;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import AuthSession from './auth-session';
|
|
2
|
+
import AuthStep from './auth-step';
|
|
3
|
+
import { DeviceRole } from '../authenticator-builder';
|
|
4
|
+
export declare class DevicePassiveActions {
|
|
5
|
+
protected log: import("../common/logger").Logger;
|
|
6
|
+
private readonly getDisplayName;
|
|
7
|
+
protected constructor(getDisplayName?: () => string | null);
|
|
8
|
+
protected register(session: AuthSession): Promise<string>;
|
|
9
|
+
protected verify(session: AuthSession): Promise<string>;
|
|
10
|
+
}
|
|
11
|
+
export default class DevicePassiveStep extends DevicePassiveActions implements AuthStep {
|
|
12
|
+
static readonly NAME = "device/passive";
|
|
13
|
+
readonly name = "device/passive";
|
|
14
|
+
private readonly role;
|
|
15
|
+
constructor(getDisplayName?: () => string | null, role?: DeviceRole);
|
|
16
|
+
execute(session: AuthSession): Promise<string>;
|
|
17
|
+
}
|
|
@@ -0,0 +1,133 @@
|
|
|
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.DevicePassiveActions = void 0;
|
|
7
|
+
const logger_1 = require("../common/logger");
|
|
8
|
+
const base64_1 = __importDefault(require("../common/base64"));
|
|
9
|
+
const device_passive_silent_step_1 = __importDefault(require("./device-passive-silent-step"));
|
|
10
|
+
const auth_token_claims_1 = require("./auth-token-claims");
|
|
11
|
+
const auth_error_1 = __importDefault(require("./auth-error"));
|
|
12
|
+
const authenticator_builder_1 = require("../authenticator-builder");
|
|
13
|
+
const base_authenticator_1 = __importDefault(require("./base-authenticator"));
|
|
14
|
+
class DevicePassiveActions {
|
|
15
|
+
constructor(getDisplayName) {
|
|
16
|
+
this.log = logger_1.LoggerFactory.getLogger('device-passive-actions');
|
|
17
|
+
this.getDisplayName = getDisplayName ? getDisplayName : () => null;
|
|
18
|
+
}
|
|
19
|
+
register(session) {
|
|
20
|
+
this.log.trace('Registering');
|
|
21
|
+
return new Promise((resolve, reject) => {
|
|
22
|
+
const displayName = this.getDisplayName();
|
|
23
|
+
session
|
|
24
|
+
.fetchFromBackend('/v1/client/device/fido2/register/start', {
|
|
25
|
+
displayName: displayName ? displayName : undefined,
|
|
26
|
+
})
|
|
27
|
+
.then((response) => {
|
|
28
|
+
if (response.error) {
|
|
29
|
+
reject(new auth_error_1.default(response.error.message, response.error.code, response.next));
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
let options = response.data.credCreateOptions;
|
|
33
|
+
options.challenge = base64_1.default.bufferDecode(options.challenge);
|
|
34
|
+
options.user.id = base64_1.default.bufferDecode(options.user.id);
|
|
35
|
+
if (displayName) {
|
|
36
|
+
options.user.displayName = displayName;
|
|
37
|
+
}
|
|
38
|
+
if (options.excludeCredentials) {
|
|
39
|
+
options.excludeCredentials.forEach((i) => {
|
|
40
|
+
i.id = base64_1.default.bufferDecode(i.id);
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
session.platform.webauthn
|
|
44
|
+
.createCredentials({
|
|
45
|
+
publicKey: options,
|
|
46
|
+
})
|
|
47
|
+
.then((credential) => {
|
|
48
|
+
if (!credential) {
|
|
49
|
+
reject(new auth_error_1.default('Failed to create FIDO2 credentials'));
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
session.credential = credential;
|
|
53
|
+
resolve(response.next);
|
|
54
|
+
}
|
|
55
|
+
})
|
|
56
|
+
.catch(reject);
|
|
57
|
+
}
|
|
58
|
+
})
|
|
59
|
+
.catch(reject);
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
verify(session) {
|
|
63
|
+
this.log.trace('Verifying');
|
|
64
|
+
return new Promise((resolve, reject) => {
|
|
65
|
+
if (session.settings.deviceId) {
|
|
66
|
+
session
|
|
67
|
+
.fetchFromBackend('/v1/client/device/fido2/verify/start', {
|
|
68
|
+
deviceId: session.settings.deviceId,
|
|
69
|
+
})
|
|
70
|
+
.then((response) => {
|
|
71
|
+
var _a;
|
|
72
|
+
if (response.error) {
|
|
73
|
+
reject(new auth_error_1.default(response.error.message, response.error.code, response.next));
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
let options = response.data.credRequestOptions;
|
|
77
|
+
options.challenge = base64_1.default.bufferDecode(options.challenge);
|
|
78
|
+
if (options.allowCredentials) {
|
|
79
|
+
(_a = options.allowCredentials) === null || _a === void 0 ? void 0 : _a.forEach((i) => {
|
|
80
|
+
i.id = base64_1.default.bufferDecode(i.id);
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
session.platform.webauthn
|
|
84
|
+
.getCredentials({
|
|
85
|
+
publicKey: options,
|
|
86
|
+
})
|
|
87
|
+
.then((credential) => {
|
|
88
|
+
if (!credential) {
|
|
89
|
+
reject(new Error('Failed to load FIDO2 credentials'));
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
session.credential = credential;
|
|
93
|
+
resolve(response.next);
|
|
94
|
+
}
|
|
95
|
+
})
|
|
96
|
+
.catch(reject);
|
|
97
|
+
}
|
|
98
|
+
})
|
|
99
|
+
.catch(reject);
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
reject(new auth_error_1.default('Failed to start verification, DeviceId is missing'));
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
exports.DevicePassiveActions = DevicePassiveActions;
|
|
108
|
+
class DevicePassiveStep extends DevicePassiveActions {
|
|
109
|
+
constructor(getDisplayName, role) {
|
|
110
|
+
super(getDisplayName);
|
|
111
|
+
this.name = DevicePassiveStep.NAME;
|
|
112
|
+
this.role = role !== null && role !== void 0 ? role : authenticator_builder_1.DeviceRole.Primary;
|
|
113
|
+
this.log = logger_1.LoggerFactory.getLogger('device-passive-step');
|
|
114
|
+
}
|
|
115
|
+
execute(session) {
|
|
116
|
+
if (this.role == authenticator_builder_1.DeviceRole.Secondary) {
|
|
117
|
+
return Promise.resolve(base_authenticator_1.default.AUTH_DONE);
|
|
118
|
+
}
|
|
119
|
+
if (!session.platform.isFidoSupported() ||
|
|
120
|
+
session.uvLevel === auth_token_claims_1.UserVerificationLevel.Discouraged) {
|
|
121
|
+
return Promise.resolve(device_passive_silent_step_1.default.NAME);
|
|
122
|
+
}
|
|
123
|
+
if (session.settings.deviceId) {
|
|
124
|
+
if (session.settings.fidoPasskeyRegistered) {
|
|
125
|
+
return this.verify(session);
|
|
126
|
+
}
|
|
127
|
+
return Promise.resolve(device_passive_silent_step_1.default.NAME);
|
|
128
|
+
}
|
|
129
|
+
return this.register(session);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
DevicePassiveStep.NAME = 'device/passive';
|
|
133
|
+
exports.default = DevicePassiveStep;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import AuthSession from './auth-session';
|
|
2
|
+
import AuthStep from './auth-step';
|
|
3
|
+
import { DevicePassiveActions } from './device-passive-step';
|
|
4
|
+
export default class DevicePassiveStepupStep extends DevicePassiveActions implements AuthStep {
|
|
5
|
+
static readonly NAME = "device/passive/stepup";
|
|
6
|
+
readonly name = "device/passive/stepup";
|
|
7
|
+
constructor(getDisplayName?: () => string | null);
|
|
8
|
+
execute(session: AuthSession): Promise<string>;
|
|
9
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const logger_1 = require("../common/logger");
|
|
4
|
+
const device_passive_step_1 = require("./device-passive-step");
|
|
5
|
+
class DevicePassiveStepupStep extends device_passive_step_1.DevicePassiveActions {
|
|
6
|
+
constructor(getDisplayName) {
|
|
7
|
+
super(getDisplayName);
|
|
8
|
+
this.name = DevicePassiveStepupStep.NAME;
|
|
9
|
+
this.log = logger_1.LoggerFactory.getLogger('device-passive-stepup-step');
|
|
10
|
+
}
|
|
11
|
+
execute(session) {
|
|
12
|
+
if (!session.platform.isFidoSupported()) {
|
|
13
|
+
return Promise.reject(new Error('FIDO2 is not supported'));
|
|
14
|
+
}
|
|
15
|
+
if (!session.settings.deviceId) {
|
|
16
|
+
return Promise.reject(new Error('Device is not registered'));
|
|
17
|
+
}
|
|
18
|
+
if (session.settings.fidoPasskeyRegistered) {
|
|
19
|
+
return Promise.reject(new Error('FIDO2 Passkey is already registered'));
|
|
20
|
+
}
|
|
21
|
+
return this.register(session);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
DevicePassiveStepupStep.NAME = 'device/passive/stepup';
|
|
25
|
+
exports.default = DevicePassiveStepupStep;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import AuthSession from './auth-session';
|
|
2
|
+
import AuthStep from './auth-step';
|
|
3
|
+
export default class DevicePassiveVerifyStep implements AuthStep {
|
|
4
|
+
static readonly NAME = "device/passive/verify";
|
|
5
|
+
private readonly log;
|
|
6
|
+
readonly name = "device/passive/verify";
|
|
7
|
+
execute(session: AuthSession): Promise<string>;
|
|
8
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
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 base64_1 = __importDefault(require("../common/base64"));
|
|
7
|
+
const logger_1 = require("../common/logger");
|
|
8
|
+
const auth_error_1 = __importDefault(require("./auth-error"));
|
|
9
|
+
class DevicePassiveVerifyStep {
|
|
10
|
+
constructor() {
|
|
11
|
+
this.log = logger_1.LoggerFactory.getLogger('device-passive-verify-step');
|
|
12
|
+
this.name = DevicePassiveVerifyStep.NAME;
|
|
13
|
+
}
|
|
14
|
+
execute(session) {
|
|
15
|
+
return new Promise((resolve, reject) => {
|
|
16
|
+
const credential = session.credential;
|
|
17
|
+
const assertion = credential.response;
|
|
18
|
+
session
|
|
19
|
+
.fetchFromBackend('/v1/client/device/fido2/verify/finish', {
|
|
20
|
+
webAuthnAssertion: {
|
|
21
|
+
type: credential === null || credential === void 0 ? void 0 : credential.type,
|
|
22
|
+
id: credential === null || credential === void 0 ? void 0 : credential.id,
|
|
23
|
+
rawId: base64_1.default.bufferEncode(credential === null || credential === void 0 ? void 0 : credential.rawId),
|
|
24
|
+
response: {
|
|
25
|
+
authenticatorData: base64_1.default.bufferEncode(assertion.authenticatorData),
|
|
26
|
+
clientDataJSON: base64_1.default.bufferEncode(assertion.clientDataJSON),
|
|
27
|
+
signature: base64_1.default.bufferEncode(assertion.signature),
|
|
28
|
+
userHandle: assertion.userHandle
|
|
29
|
+
? base64_1.default.bufferEncode(assertion.userHandle)
|
|
30
|
+
: undefined,
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
})
|
|
34
|
+
.then((response) => {
|
|
35
|
+
if (response.error) {
|
|
36
|
+
reject(new auth_error_1.default(response.error.message, response.error.code, response.next));
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
const data = response.data;
|
|
40
|
+
if (data && data.scanMessage) {
|
|
41
|
+
session.authMessage = data.scanMessage;
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
this.log.warn('No data was received in the response');
|
|
45
|
+
}
|
|
46
|
+
resolve(response.next);
|
|
47
|
+
}
|
|
48
|
+
})
|
|
49
|
+
.catch(reject);
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
DevicePassiveVerifyStep.NAME = 'device/passive/verify';
|
|
54
|
+
exports.default = DevicePassiveVerifyStep;
|