@prove-identity/prove-auth 2.4.5 → 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 +12 -2
- package/build/lib/proveauth/authenticator-builder.js +114 -7
- 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 +13 -8
- package/build/lib/proveauth/internal/auth-session.js +97 -20
- package/build/lib/proveauth/internal/auth-token-claims.d.ts +4 -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 +5 -3
- package/build/lib/proveauth/internal/device-passive-silent-step.js +30 -11
- 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/main-authenticator.d.ts +2 -3
- package/build/lib/proveauth/internal/main-authenticator.js +6 -10
- package/build/lib/proveauth/internal/mobile-instantlink-step.js +1 -1
- package/build/lib/proveauth/internal/platform.d.ts +5 -1
- package/build/lib/proveauth/internal/report-error-step.d.ts +2 -2
- package/build/lib/proveauth/internal/report-error-step.js +5 -5
- 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 +7 -1
- package/build/lib/proveauth/internal/web-platform.js +11 -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 +9 -1
- package/build/bundle/release/prove-auth.js +0 -1
package/build/lib/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { VERSION } from './proveauth/version';
|
|
2
2
|
import AuthenticatorBuilder, { AuthMessageHandler, DeviceRole, MobileAuthImplementation } from './proveauth/authenticator-builder';
|
|
3
|
+
import DeviceContextOptions, { BuildConfig } from './proveauth/device-context-options';
|
|
3
4
|
import AuthMessage from './proveauth/internal/auth-message';
|
|
4
5
|
import { AuthResponseStatus } from './proveauth/internal/auth-response-status';
|
|
5
6
|
import { LoggerFactory, LogWriter, LogLevel, Logger } from './proveauth/common/logger';
|
|
@@ -9,4 +10,5 @@ import Authenticator from './proveauth/authenticator';
|
|
|
9
10
|
import { PhoneValidationError } from './proveauth/internal/phone-number-input';
|
|
10
11
|
import { OtpError, OtpStartStep, OtpStartInput, OtpStartStepFn, OtpFinishStep, OtpFinishInput, OtpFinishStepFn, OtpFinishResult, OtpFinishResultType } from './proveauth/otp';
|
|
11
12
|
import { InstantLinkStartInput, InstantLinkStartStep, InstantLinkStartStepFn } from './proveauth/instantlink';
|
|
12
|
-
|
|
13
|
+
import UserConsentStep, { UserConsentOutput, UserConsentStepFn } from './proveauth/user-consent-step';
|
|
14
|
+
export { VERSION, AuthFinishStep, AuthFinishStepFn, AuthFinishStepInput, Authenticator, AuthenticatorBuilder, AuthMessage, AuthMessageHandler, AuthResponseStatus, CancelablePromise, DeviceRole, InstantLinkStartStep, InstantLinkStartInput, InstantLinkStartStepFn, Logger, LoggerFactory, LogLevel, LogWriter, MobileAuthImplementation, OtpFinishStep, OtpFinishInput, OtpFinishResult, OtpFinishStepFn, OtpFinishResultType, OtpStartStep, OtpStartInput, OtpStartStepFn, OtpError, PhoneValidationError, BuildConfig, DeviceContextOptions, UserConsentStep, UserConsentStepFn, UserConsentOutput, };
|
package/build/lib/index.js
CHANGED
|
@@ -26,13 +26,15 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
26
26
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
27
|
};
|
|
28
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
-
exports.PhoneValidationError = exports.OtpError = exports.OtpFinishResultType = exports.MobileAuthImplementation = exports.LogLevel = exports.LoggerFactory = exports.DeviceRole = exports.CancelablePromise = exports.AuthResponseStatus = exports.AuthenticatorBuilder = exports.VERSION = void 0;
|
|
29
|
+
exports.BuildConfig = exports.PhoneValidationError = exports.OtpError = exports.OtpFinishResultType = exports.MobileAuthImplementation = exports.LogLevel = exports.LoggerFactory = exports.DeviceRole = exports.CancelablePromise = exports.AuthResponseStatus = exports.AuthenticatorBuilder = exports.VERSION = void 0;
|
|
30
30
|
const version_1 = require("./proveauth/version");
|
|
31
31
|
Object.defineProperty(exports, "VERSION", { enumerable: true, get: function () { return version_1.VERSION; } });
|
|
32
32
|
const authenticator_builder_1 = __importStar(require("./proveauth/authenticator-builder"));
|
|
33
33
|
exports.AuthenticatorBuilder = authenticator_builder_1.default;
|
|
34
34
|
Object.defineProperty(exports, "DeviceRole", { enumerable: true, get: function () { return authenticator_builder_1.DeviceRole; } });
|
|
35
35
|
Object.defineProperty(exports, "MobileAuthImplementation", { enumerable: true, get: function () { return authenticator_builder_1.MobileAuthImplementation; } });
|
|
36
|
+
const device_context_options_1 = require("./proveauth/device-context-options");
|
|
37
|
+
Object.defineProperty(exports, "BuildConfig", { enumerable: true, get: function () { return device_context_options_1.BuildConfig; } });
|
|
36
38
|
const auth_response_status_1 = require("./proveauth/internal/auth-response-status");
|
|
37
39
|
Object.defineProperty(exports, "AuthResponseStatus", { enumerable: true, get: function () { return auth_response_status_1.AuthResponseStatus; } });
|
|
38
40
|
const logger_1 = require("./proveauth/common/logger");
|
|
@@ -5,6 +5,9 @@ import { AuthResponseStatus } from './internal/auth-response-status';
|
|
|
5
5
|
import Platform from './internal/platform';
|
|
6
6
|
import { OtpFinishStep, OtpFinishStepFn, OtpStartStep, OtpStartStepFn } from './otp';
|
|
7
7
|
import { InstantLinkStartStep, InstantLinkStartStepFn } from './instantlink';
|
|
8
|
+
import type { Region } from '@fingerprintjs/fingerprintjs-pro';
|
|
9
|
+
import DeviceContextOptions, { BuildConfig } from './device-context-options';
|
|
10
|
+
import UserConsentStep, { UserConsentStepFn } from './user-consent-step';
|
|
8
11
|
export type AuthMessageHandler = (message: AuthMessage) => Promise<AuthResponseStatus>;
|
|
9
12
|
export declare enum DeviceRole {
|
|
10
13
|
Primary = 0,
|
|
@@ -26,9 +29,12 @@ export default class AuthenticatorBuilder {
|
|
|
26
29
|
private otpStartStep?;
|
|
27
30
|
private otpFinishStep?;
|
|
28
31
|
private instantLinkStartStep?;
|
|
29
|
-
private
|
|
30
|
-
private
|
|
32
|
+
private upkEnabled;
|
|
33
|
+
private userConsentStep?;
|
|
34
|
+
private readonly log;
|
|
35
|
+
private deviceContextOptions?;
|
|
31
36
|
constructor();
|
|
37
|
+
withDeviceContext(options: DeviceContextOptions): AuthenticatorBuilder;
|
|
32
38
|
withAuthFinishStep(step: AuthFinishStep | AuthFinishStepFn): AuthenticatorBuilder;
|
|
33
39
|
withDisplayName(displayName: string | (() => string | null) | null): AuthenticatorBuilder;
|
|
34
40
|
withAuthMessageHandler(handler: AuthMessageHandler): AuthenticatorBuilder;
|
|
@@ -40,5 +46,9 @@ export default class AuthenticatorBuilder {
|
|
|
40
46
|
withOtpFallback(startStep: OtpStartStep | OtpStartStepFn, finishStep: OtpFinishStep | OtpFinishStepFn): AuthenticatorBuilder;
|
|
41
47
|
withInstantLinkFallback(startStep: InstantLinkStartStep | InstantLinkStartStepFn): AuthenticatorBuilder;
|
|
42
48
|
withUPKEnabled(): this;
|
|
49
|
+
withUniversalProveKey(step?: UserConsentStep | UserConsentStepFn): this;
|
|
50
|
+
getUrlsByBuildConfig(buildConfig?: BuildConfig): [string | undefined, string | undefined];
|
|
51
|
+
getRegionByBuildConfig(buildConfig?: BuildConfig): Region;
|
|
52
|
+
private getFpPromiseInstanceFromOptions;
|
|
43
53
|
build(): Authenticator;
|
|
44
54
|
}
|
|
@@ -18,6 +18,9 @@ const device_passive_stepup_step_1 = __importDefault(require("./internal/device-
|
|
|
18
18
|
const device_universal_step_1 = __importDefault(require("./internal/device-universal-step"));
|
|
19
19
|
const device_universal_redirect_steps_1 = require("./internal/device-universal-redirect-steps");
|
|
20
20
|
const main_authenticator_1 = __importDefault(require("./internal/main-authenticator"));
|
|
21
|
+
const logger_1 = require("./common/logger");
|
|
22
|
+
const settings_1 = __importDefault(require("./internal/settings"));
|
|
23
|
+
const device_context_options_1 = require("./device-context-options");
|
|
21
24
|
var DeviceRole;
|
|
22
25
|
(function (DeviceRole) {
|
|
23
26
|
DeviceRole[DeviceRole["Primary"] = 0] = "Primary";
|
|
@@ -32,13 +35,17 @@ class AuthenticatorBuilder {
|
|
|
32
35
|
constructor() {
|
|
33
36
|
this.role = DeviceRole.Primary;
|
|
34
37
|
this.mobileAuthImplementation = MobileAuthImplementation.Fetch;
|
|
35
|
-
this.
|
|
36
|
-
this.
|
|
38
|
+
this.upkEnabled = false;
|
|
39
|
+
this.log = logger_1.LoggerFactory.getLogger('authenticator-builder');
|
|
37
40
|
if (typeof window !== 'undefined') {
|
|
38
41
|
this.storage = window.localStorage;
|
|
39
42
|
this.platform = new web_platform_1.WebPlatform();
|
|
40
43
|
}
|
|
41
44
|
}
|
|
45
|
+
withDeviceContext(options) {
|
|
46
|
+
this.deviceContextOptions = options;
|
|
47
|
+
return this;
|
|
48
|
+
}
|
|
42
49
|
withAuthFinishStep(step) {
|
|
43
50
|
if (typeof step === 'function') {
|
|
44
51
|
this.authFinishStep = {
|
|
@@ -103,18 +110,118 @@ class AuthenticatorBuilder {
|
|
|
103
110
|
return this;
|
|
104
111
|
}
|
|
105
112
|
withUPKEnabled() {
|
|
106
|
-
this.
|
|
113
|
+
return this.withUniversalProveKey();
|
|
114
|
+
}
|
|
115
|
+
withUniversalProveKey(step) {
|
|
116
|
+
if (!step) {
|
|
117
|
+
this.userConsentStep = { execute: () => Promise.resolve({ consentGranted: true }) };
|
|
118
|
+
}
|
|
119
|
+
else if (typeof step === 'function') {
|
|
120
|
+
this.userConsentStep = { execute: step };
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
this.userConsentStep = step;
|
|
124
|
+
}
|
|
125
|
+
this.upkEnabled = this.userConsentStep != null;
|
|
107
126
|
return this;
|
|
108
127
|
}
|
|
128
|
+
getUrlsByBuildConfig(buildConfig) {
|
|
129
|
+
switch (buildConfig) {
|
|
130
|
+
case device_context_options_1.BuildConfig.US_PROD:
|
|
131
|
+
return [
|
|
132
|
+
device_context_options_1.ProveAuthProxyScriptUrl.DEFAULT_US_PROD_SCRIPT_URL.toString(),
|
|
133
|
+
device_context_options_1.ProveAuthProxyEndpoint.DEFAULT_US_PROD_ENDPOINT.toString(),
|
|
134
|
+
];
|
|
135
|
+
case device_context_options_1.BuildConfig.US_UAT:
|
|
136
|
+
return [
|
|
137
|
+
device_context_options_1.ProveAuthProxyScriptUrl.DEFAULT_US_UAT_SCRIPT_URL.toString(),
|
|
138
|
+
device_context_options_1.ProveAuthProxyEndpoint.DEFAULT_US_UAT_ENDPOINT.toString(),
|
|
139
|
+
];
|
|
140
|
+
case device_context_options_1.BuildConfig.DEV:
|
|
141
|
+
this.log.debug("Recommended for Prove's internal testing only, BuildConfig.DEV might need custom endpoint URL and custom script URL values to bypass ad blockers");
|
|
142
|
+
return [undefined, undefined];
|
|
143
|
+
default:
|
|
144
|
+
this.log.warn('Unknown BuildConfig value: ' + buildConfig);
|
|
145
|
+
return [undefined, undefined];
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
getRegionByBuildConfig(buildConfig) {
|
|
149
|
+
var region;
|
|
150
|
+
switch (buildConfig) {
|
|
151
|
+
case device_context_options_1.BuildConfig.DEV:
|
|
152
|
+
case device_context_options_1.BuildConfig.US_PROD:
|
|
153
|
+
case device_context_options_1.BuildConfig.US_UAT:
|
|
154
|
+
region = 'us';
|
|
155
|
+
break;
|
|
156
|
+
default:
|
|
157
|
+
this.log.warn('Unknown BuildConfig value, set Region to default value: us');
|
|
158
|
+
region = 'us';
|
|
159
|
+
break;
|
|
160
|
+
}
|
|
161
|
+
return region;
|
|
162
|
+
}
|
|
163
|
+
getFpPromiseInstanceFromOptions(options) {
|
|
164
|
+
try {
|
|
165
|
+
const FingerprintJS = require('@fingerprintjs/fingerprintjs-pro');
|
|
166
|
+
if (!FingerprintJS) {
|
|
167
|
+
this.log.debug('fingerprintjs package is not installed or failed to load');
|
|
168
|
+
}
|
|
169
|
+
else if (!options) {
|
|
170
|
+
this.log.warn('Prove Key Persistence feature is not enabled');
|
|
171
|
+
}
|
|
172
|
+
else {
|
|
173
|
+
let region = this.getRegionByBuildConfig(options.buildConfig);
|
|
174
|
+
let [scriptUrl, endpointUrl] = this.getUrlsByBuildConfig(options.buildConfig);
|
|
175
|
+
if (options.customScriptUrl && options.customEndpointUrl) {
|
|
176
|
+
scriptUrl = options.customScriptUrl;
|
|
177
|
+
endpointUrl = options.customEndpointUrl;
|
|
178
|
+
}
|
|
179
|
+
const scriptUrlPattern = scriptUrl
|
|
180
|
+
? [
|
|
181
|
+
`${scriptUrl}?apiKey=<apiKey>&version=<version>&loaderVersion=<loaderVersion>`,
|
|
182
|
+
FingerprintJS.defaultScriptUrlPattern,
|
|
183
|
+
]
|
|
184
|
+
: [FingerprintJS.defaultScriptUrlPattern];
|
|
185
|
+
const endpoint = endpointUrl
|
|
186
|
+
? [`${endpointUrl}?region=${region}`, FingerprintJS.defaultEndpoint]
|
|
187
|
+
: [FingerprintJS.defaultEndpoint];
|
|
188
|
+
const fpPromise = FingerprintJS.load({
|
|
189
|
+
apiKey: options.publicApiKey,
|
|
190
|
+
endpoint: endpoint,
|
|
191
|
+
scriptUrlPattern: scriptUrlPattern,
|
|
192
|
+
region: region,
|
|
193
|
+
});
|
|
194
|
+
const status = fpPromise ? 'successfully' : 'unsuccessfully with null instance';
|
|
195
|
+
this.log.trace(`Instantiating FingerprintJS ${status}`);
|
|
196
|
+
return fpPromise;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
catch (error) {
|
|
200
|
+
this.log.trace('FingerprintJS is not installed or failed to load', error);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
109
203
|
build() {
|
|
204
|
+
var _a;
|
|
205
|
+
if (!this.platform) {
|
|
206
|
+
throw new Error('Implementation of Platform is required');
|
|
207
|
+
}
|
|
208
|
+
if (!this.storage) {
|
|
209
|
+
throw new Error('Implementation of Storage is required');
|
|
210
|
+
}
|
|
211
|
+
const fpPromise = this.getFpPromiseInstanceFromOptions(this.deviceContextOptions);
|
|
212
|
+
if (fpPromise) {
|
|
213
|
+
(_a = this.platform) === null || _a === void 0 ? void 0 : _a.setFpPromise(fpPromise);
|
|
214
|
+
}
|
|
215
|
+
const settings = new settings_1.default(this.storage);
|
|
216
|
+
settings.upkEnabled = this.upkEnabled;
|
|
110
217
|
if (this.role === DeviceRole.Primary) {
|
|
111
|
-
return new main_authenticator_1.default(this.platform,
|
|
112
|
-
new device_universal_step_1.default(this.
|
|
218
|
+
return new main_authenticator_1.default(this.platform, settings, this.authFinishStep, [
|
|
219
|
+
new device_universal_step_1.default(this.upkEnabled),
|
|
113
220
|
new device_universal_redirect_steps_1.DeviceUniversalRedirectExchangeStep(),
|
|
114
221
|
new device_universal_redirect_steps_1.DeviceUniversalRedirectFinishStep(),
|
|
115
222
|
new device_passive_step_1.default(this.getDisplayName, this.role),
|
|
116
223
|
new device_passive_stepup_step_1.default(this.getDisplayName),
|
|
117
|
-
new device_passive_silent_step_1.default(this.
|
|
224
|
+
new device_passive_silent_step_1.default(this.upkEnabled, this.userConsentStep),
|
|
118
225
|
new device_passive_register_step_1.default(),
|
|
119
226
|
new device_passive_verify_step_1.default(),
|
|
120
227
|
new mobile_instant_step_1.default(this.mobileAuthImplementation, this.getDeviceIp),
|
|
@@ -125,7 +232,7 @@ class AuthenticatorBuilder {
|
|
|
125
232
|
]);
|
|
126
233
|
}
|
|
127
234
|
else {
|
|
128
|
-
return new main_authenticator_1.default(this.platform,
|
|
235
|
+
return new main_authenticator_1.default(this.platform, settings, this.authFinishStep, [
|
|
129
236
|
new device_passive_step_1.default(this.getDisplayName, this.role),
|
|
130
237
|
new mobile_instant_step_1.default(this.mobileAuthImplementation, this.getDeviceIp),
|
|
131
238
|
new mobile_instantlink_step_1.default(this.instantLinkStartStep, this.getDeviceIp),
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export declare enum ProveAuthProxyScriptUrl {
|
|
2
|
+
DEFAULT_US_UAT_SCRIPT_URL = "https://upk.uat.prove-auth.proveapis.com/vFqZceQyx8/uqLttozA7q",
|
|
3
|
+
DEFAULT_US_PROD_SCRIPT_URL = "https://upk.prove-auth.proveapis.com/vf82rhgDRK/r4VnwuwPUd"
|
|
4
|
+
}
|
|
5
|
+
export declare enum ProveAuthProxyEndpoint {
|
|
6
|
+
DEFAULT_US_UAT_ENDPOINT = "https://upk.uat.prove-auth.proveapis.com/vFqZceQyx8/bt9xhGAgQw",
|
|
7
|
+
DEFAULT_US_PROD_ENDPOINT = "https://upk.prove-auth.proveapis.com/vf82rhgDRK/ePaZsNne4X"
|
|
8
|
+
}
|
|
9
|
+
export declare enum BuildConfig {
|
|
10
|
+
DEV = "DEV",
|
|
11
|
+
US_UAT = "US_UAT",
|
|
12
|
+
US_PROD = "US_PROD"
|
|
13
|
+
}
|
|
14
|
+
export default interface DeviceContextOptions {
|
|
15
|
+
readonly buildConfig: BuildConfig;
|
|
16
|
+
readonly publicApiKey: string;
|
|
17
|
+
readonly customScriptUrl?: string;
|
|
18
|
+
readonly customEndpointUrl?: string;
|
|
19
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BuildConfig = exports.ProveAuthProxyEndpoint = exports.ProveAuthProxyScriptUrl = void 0;
|
|
4
|
+
var ProveAuthProxyScriptUrl;
|
|
5
|
+
(function (ProveAuthProxyScriptUrl) {
|
|
6
|
+
ProveAuthProxyScriptUrl["DEFAULT_US_UAT_SCRIPT_URL"] = "https://upk.uat.prove-auth.proveapis.com/vFqZceQyx8/uqLttozA7q";
|
|
7
|
+
ProveAuthProxyScriptUrl["DEFAULT_US_PROD_SCRIPT_URL"] = "https://upk.prove-auth.proveapis.com/vf82rhgDRK/r4VnwuwPUd";
|
|
8
|
+
})(ProveAuthProxyScriptUrl = exports.ProveAuthProxyScriptUrl || (exports.ProveAuthProxyScriptUrl = {}));
|
|
9
|
+
var ProveAuthProxyEndpoint;
|
|
10
|
+
(function (ProveAuthProxyEndpoint) {
|
|
11
|
+
ProveAuthProxyEndpoint["DEFAULT_US_UAT_ENDPOINT"] = "https://upk.uat.prove-auth.proveapis.com/vFqZceQyx8/bt9xhGAgQw";
|
|
12
|
+
ProveAuthProxyEndpoint["DEFAULT_US_PROD_ENDPOINT"] = "https://upk.prove-auth.proveapis.com/vf82rhgDRK/ePaZsNne4X";
|
|
13
|
+
})(ProveAuthProxyEndpoint = exports.ProveAuthProxyEndpoint || (exports.ProveAuthProxyEndpoint = {}));
|
|
14
|
+
var BuildConfig;
|
|
15
|
+
(function (BuildConfig) {
|
|
16
|
+
BuildConfig["DEV"] = "DEV";
|
|
17
|
+
BuildConfig["US_UAT"] = "US_UAT";
|
|
18
|
+
BuildConfig["US_PROD"] = "US_PROD";
|
|
19
|
+
})(BuildConfig = exports.BuildConfig || (exports.BuildConfig = {}));
|
|
@@ -32,6 +32,7 @@ export interface V1ClientDeviceFido2RegisterFinish {
|
|
|
32
32
|
deviceName: string;
|
|
33
33
|
deviceCapabilities: string[];
|
|
34
34
|
registrations: AuthRegistration[];
|
|
35
|
+
signals?: Signals;
|
|
35
36
|
}
|
|
36
37
|
export interface V1ClientDeviceFido2VerifyStart {
|
|
37
38
|
deviceId: string;
|
|
@@ -50,16 +51,19 @@ export interface WebAuthnAssertion {
|
|
|
50
51
|
}
|
|
51
52
|
export interface V1ClientDeviceFido2VerifyFinish {
|
|
52
53
|
webAuthnAssertion: WebAuthnAssertion;
|
|
54
|
+
signals?: Signals;
|
|
53
55
|
}
|
|
54
56
|
export interface V1ClientDevicePassiveRegister {
|
|
55
57
|
deviceName: string;
|
|
56
58
|
deviceCapabilities: string[];
|
|
57
59
|
registrations: PassiveRegistration[];
|
|
60
|
+
signals?: Signals;
|
|
58
61
|
}
|
|
59
62
|
export interface V1ClientDevicePassiveVerify {
|
|
60
63
|
deviceId: string;
|
|
61
64
|
keyId: string;
|
|
62
65
|
signature: string;
|
|
66
|
+
signals?: Signals;
|
|
63
67
|
}
|
|
64
68
|
export interface V1ClientUserResponse {
|
|
65
69
|
response: AuthResponseStatus;
|
|
@@ -88,3 +92,11 @@ export interface V1ClientOtpStart {
|
|
|
88
92
|
export interface V1ClientOtpFinish {
|
|
89
93
|
otp: string;
|
|
90
94
|
}
|
|
95
|
+
export interface Signals {
|
|
96
|
+
fingerprint?: Signal;
|
|
97
|
+
darwinium?: Signal;
|
|
98
|
+
}
|
|
99
|
+
export interface Signal {
|
|
100
|
+
results?: string;
|
|
101
|
+
error?: string;
|
|
102
|
+
}
|
|
@@ -16,6 +16,7 @@ export interface RegisterStartAuthResponse extends AuthResponse {
|
|
|
16
16
|
}
|
|
17
17
|
export interface RegisterFinishAuthResponseData {
|
|
18
18
|
deviceId: string;
|
|
19
|
+
passkey: boolean;
|
|
19
20
|
}
|
|
20
21
|
export interface RegisterFinishAuthResponse extends AuthResponse {
|
|
21
22
|
data: RegisterFinishAuthResponseData;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/// <reference types="webappsec-credential-management" />
|
|
2
2
|
import AuthMessage from './auth-message';
|
|
3
|
-
import { AuthRequest } from './auth-request';
|
|
3
|
+
import { AuthRequest, Signal } from './auth-request';
|
|
4
4
|
import AuthResponse from './auth-response';
|
|
5
5
|
import AuthTokenClaims, { UserVerificationLevel } from './auth-token-claims';
|
|
6
6
|
import { DeviceRegistration } from './device-auth';
|
|
@@ -13,20 +13,25 @@ export default class AuthSession implements AuthSessionIntegration {
|
|
|
13
13
|
readonly settings: Settings;
|
|
14
14
|
readonly requestSigner: RequestSigner;
|
|
15
15
|
readonly channels: Set<MessageChannel>;
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
16
|
+
private readonly log;
|
|
17
|
+
lastStep?: string;
|
|
18
|
+
credential?: CredentialType;
|
|
19
|
+
authMessage?: AuthMessage;
|
|
20
|
+
uvLevel?: UserVerificationLevel;
|
|
21
|
+
backendOriginOverride?: string;
|
|
21
22
|
get namespace(): string;
|
|
22
|
-
get
|
|
23
|
+
get backendOrigin(): string;
|
|
24
|
+
set backendOrigin(backendOrigin: string);
|
|
23
25
|
get authId(): string;
|
|
24
26
|
get challenge(): string;
|
|
25
27
|
get next(): string;
|
|
26
28
|
constructor(settings: Settings, platform: Platform, authToken?: string);
|
|
27
29
|
fetchFromBackend(query: string, body: AuthRequest): Promise<AuthResponse>;
|
|
28
|
-
createMessageChannel(
|
|
30
|
+
createMessageChannel(query: string, onClose: () => void, onError: (message: string) => void, onMessage: (data: string) => void): MessageChannel;
|
|
29
31
|
closeAllMessageChannels(): void;
|
|
30
32
|
getDeviceRegistration(): Promise<DeviceRegistration | null>;
|
|
33
|
+
embedFpResultToDeviceRegistration(registration: DeviceRegistration): Promise<DeviceRegistration>;
|
|
34
|
+
getFingerprintData(): Promise<Signal | undefined>;
|
|
35
|
+
shouldCollectFP(): boolean;
|
|
31
36
|
private parseJwt;
|
|
32
37
|
}
|
|
@@ -12,9 +12,12 @@ class AuthSession {
|
|
|
12
12
|
var _a;
|
|
13
13
|
return ((_a = this.claims) === null || _a === void 0 ? void 0 : _a.auth.ans) || this.settings.namespace;
|
|
14
14
|
}
|
|
15
|
-
get
|
|
15
|
+
get backendOrigin() {
|
|
16
16
|
var _a;
|
|
17
|
-
return ((_a = this.claims) === null || _a === void 0 ? void 0 : _a.auth.endp)
|
|
17
|
+
return this.backendOriginOverride || ((_a = this.claims) === null || _a === void 0 ? void 0 : _a.auth.endp);
|
|
18
|
+
}
|
|
19
|
+
set backendOrigin(backendOrigin) {
|
|
20
|
+
this.backendOriginOverride = backendOrigin;
|
|
18
21
|
}
|
|
19
22
|
get authId() {
|
|
20
23
|
var _a;
|
|
@@ -31,11 +34,7 @@ class AuthSession {
|
|
|
31
34
|
constructor(settings, platform, authToken) {
|
|
32
35
|
var _a, _b;
|
|
33
36
|
this.channels = new Set();
|
|
34
|
-
this.
|
|
35
|
-
this.credential = null;
|
|
36
|
-
this.authMessage = null;
|
|
37
|
-
this.uvLevel = null;
|
|
38
|
-
this.backendUrlOverride = null;
|
|
37
|
+
this.log = logger_1.LoggerFactory.getLogger('auth-session');
|
|
39
38
|
this.platform = platform;
|
|
40
39
|
this.authToken = authToken;
|
|
41
40
|
this.settings = settings;
|
|
@@ -73,7 +72,7 @@ class AuthSession {
|
|
|
73
72
|
headers.set('PA-Signature', signature.signature);
|
|
74
73
|
}
|
|
75
74
|
this.platform
|
|
76
|
-
.fetch(this.
|
|
75
|
+
.fetch(this.backendOrigin + query, {
|
|
77
76
|
mode: 'cors',
|
|
78
77
|
method: method,
|
|
79
78
|
headers: headers,
|
|
@@ -94,41 +93,56 @@ class AuthSession {
|
|
|
94
93
|
.catch(reject);
|
|
95
94
|
});
|
|
96
95
|
}
|
|
97
|
-
createMessageChannel(
|
|
96
|
+
createMessageChannel(query, onClose, onError, onMessage) {
|
|
98
97
|
if (!this.authToken) {
|
|
99
98
|
throw new Error('Authentication token is not initialized, cannot create MessageChannel');
|
|
100
99
|
}
|
|
101
100
|
const KEEP_ALIVE_INTERVAL = 30000;
|
|
102
|
-
const endpoint = this.
|
|
103
|
-
const channel = this.platform.createMessageChannel(endpoint +
|
|
104
|
-
|
|
101
|
+
const endpoint = this.backendOrigin.replace(/^http/, 'ws');
|
|
102
|
+
const channel = this.platform.createMessageChannel(endpoint + query);
|
|
103
|
+
var pongReceived = true;
|
|
105
104
|
const keepAlive = setInterval(() => {
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
105
|
+
if (pongReceived) {
|
|
106
|
+
this.log.trace('Sending ping message');
|
|
107
|
+
pongReceived = false;
|
|
108
|
+
channel.send('ping');
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
this.log.error('Failed to receive ping response in time, closing the channel');
|
|
111
112
|
clearInterval(keepAlive);
|
|
113
|
+
channel.close();
|
|
114
|
+
onError('Channel communication stalled');
|
|
115
|
+
this.channels.delete(channel);
|
|
112
116
|
}
|
|
117
|
+
}, KEEP_ALIVE_INTERVAL);
|
|
118
|
+
channel.addEventListener('close', (_) => {
|
|
119
|
+
clearInterval(keepAlive);
|
|
113
120
|
onClose();
|
|
114
121
|
this.channels.delete(channel);
|
|
115
122
|
});
|
|
116
123
|
channel.addEventListener('error', (event) => {
|
|
124
|
+
clearInterval(keepAlive);
|
|
117
125
|
if ('message' in event) {
|
|
118
126
|
onError(event['message']);
|
|
119
127
|
}
|
|
120
128
|
else {
|
|
121
129
|
onError(event.toString());
|
|
122
130
|
}
|
|
131
|
+
this.channels.delete(channel);
|
|
123
132
|
});
|
|
124
133
|
channel.addEventListener('message', (event) => {
|
|
125
134
|
if ('origin' in event && event['origin'] !== endpoint) {
|
|
126
135
|
onError('Unexpected origin');
|
|
127
136
|
}
|
|
128
137
|
else {
|
|
129
|
-
|
|
138
|
+
const data = event.data;
|
|
130
139
|
if (data && typeof data === 'string') {
|
|
131
|
-
|
|
140
|
+
if (data === 'pong') {
|
|
141
|
+
pongReceived = true;
|
|
142
|
+
}
|
|
143
|
+
else {
|
|
144
|
+
onMessage(data);
|
|
145
|
+
}
|
|
132
146
|
}
|
|
133
147
|
else {
|
|
134
148
|
onMessage(event.toString());
|
|
@@ -150,13 +164,76 @@ class AuthSession {
|
|
|
150
164
|
.getRegistration(this.namespace)
|
|
151
165
|
.then((registration) => {
|
|
152
166
|
if (registration) {
|
|
153
|
-
this.
|
|
167
|
+
if (!this.backendOriginOverride) {
|
|
168
|
+
this.backendOriginOverride = registration.endpoint;
|
|
169
|
+
this.log.debug('backend URL overridden with ' + this.backendOriginOverride);
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
this.log.debug('Not overriding backend URL since it has been already set');
|
|
173
|
+
}
|
|
154
174
|
}
|
|
155
175
|
resolve(registration);
|
|
156
176
|
})
|
|
157
177
|
.catch(reject);
|
|
158
178
|
});
|
|
159
179
|
}
|
|
180
|
+
embedFpResultToDeviceRegistration(registration) {
|
|
181
|
+
return new Promise((resolve) => {
|
|
182
|
+
this.getFingerprintData()
|
|
183
|
+
.then((result) => {
|
|
184
|
+
if (result) {
|
|
185
|
+
registration.setFpSignal(result);
|
|
186
|
+
}
|
|
187
|
+
resolve(registration);
|
|
188
|
+
})
|
|
189
|
+
.catch((error) => {
|
|
190
|
+
const errorMsg = `Unexpected error happened during Fingerprint data collection: ${error.toString}`;
|
|
191
|
+
this.log.warn(errorMsg);
|
|
192
|
+
registration.setFpSignal({ error: errorMsg });
|
|
193
|
+
});
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
getFingerprintData() {
|
|
197
|
+
return new Promise((resolve) => {
|
|
198
|
+
var fpPromise = this.platform.getFpPromise();
|
|
199
|
+
if (!this.shouldCollectFP()) {
|
|
200
|
+
this.log.debug('Fingerprint is not enabled from AuthToken');
|
|
201
|
+
resolve(undefined);
|
|
202
|
+
}
|
|
203
|
+
else if (!fpPromise) {
|
|
204
|
+
const msg = 'Found null instance of Fingerprint, check if your input API key is valid';
|
|
205
|
+
this.log.warn(msg);
|
|
206
|
+
resolve({ error: msg });
|
|
207
|
+
}
|
|
208
|
+
else {
|
|
209
|
+
fpPromise
|
|
210
|
+
.then((fp) => fp.get())
|
|
211
|
+
.then((result) => {
|
|
212
|
+
if (result.sealedResult) {
|
|
213
|
+
this.log.debug(`FP result: ${result.sealedResult}`);
|
|
214
|
+
resolve({ results: result.sealedResult });
|
|
215
|
+
}
|
|
216
|
+
else {
|
|
217
|
+
const msg = 'Cannot found sealed result in Fingerprint returned payload';
|
|
218
|
+
this.log.warn(msg);
|
|
219
|
+
resolve({ error: msg });
|
|
220
|
+
}
|
|
221
|
+
})
|
|
222
|
+
.catch((error) => {
|
|
223
|
+
const msg = `Error in collecting Fingerprint data: ${error.toString}`;
|
|
224
|
+
this.log.warn(msg);
|
|
225
|
+
resolve({ error: msg });
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
shouldCollectFP() {
|
|
231
|
+
var _a, _b, _c;
|
|
232
|
+
if ((_c = (_b = (_a = this.claims) === null || _a === void 0 ? void 0 : _a.auth.subs.dev) === null || _b === void 0 ? void 0 : _b.sgnls) === null || _c === void 0 ? void 0 : _c.fpt) {
|
|
233
|
+
return true;
|
|
234
|
+
}
|
|
235
|
+
return false;
|
|
236
|
+
}
|
|
160
237
|
parseJwt(token) {
|
|
161
238
|
return JSON.parse(atob(token.split('.')[1]));
|
|
162
239
|
}
|
|
@@ -27,8 +27,12 @@ export interface Authenticators {
|
|
|
27
27
|
otp?: OtpAuthenticator;
|
|
28
28
|
unvsl?: UniversalAuthenticator;
|
|
29
29
|
}
|
|
30
|
+
export interface Signals {
|
|
31
|
+
fpt?: boolean;
|
|
32
|
+
}
|
|
30
33
|
export interface DeviceAuthSubjectClaim {
|
|
31
34
|
auths: Authenticators;
|
|
35
|
+
sgnls?: Signals;
|
|
32
36
|
}
|
|
33
37
|
export interface MobileAuthSubjectClaim {
|
|
34
38
|
auths: Authenticators;
|
|
@@ -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,11 +1,13 @@
|
|
|
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
|
|
8
|
-
|
|
7
|
+
private readonly log;
|
|
8
|
+
private readonly forUPK;
|
|
9
|
+
private readonly userConsentStep;
|
|
10
|
+
constructor(forUPK: boolean, userConsentStep?: UserConsentStep);
|
|
9
11
|
execute(session: AuthSession): Promise<string>;
|
|
10
12
|
private getBackendRegisterEndpoint;
|
|
11
13
|
private getBackendVerifyEndpoint;
|