@mattrglobal/verifier-sdk-web 1.1.1-unstable.16 → 1.1.1-unstable.160
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/README.md +63 -42
- package/dist/lib/verifier-js-no-deps.cjs.js +610 -198
- package/dist/lib/verifier-js-no-deps.cjs.js.map +1 -1
- package/dist/lib/verifier-js.cjs.js +736 -312
- package/dist/lib/verifier-js.cjs.js.map +1 -1
- package/dist/typings/common/safeFetch.d.ts +6 -3
- package/dist/typings/common/sleep.d.ts +1 -0
- package/dist/typings/index.d.ts +6 -6
- package/dist/typings/verifier/abortCredentialRequest.d.ts +6 -0
- package/dist/typings/verifier/handleRedirectCallback.d.ts +1 -1
- package/dist/typings/verifier/index.d.ts +3 -1
- package/dist/typings/verifier/initialize.d.ts +12 -0
- package/dist/typings/verifier/instanceContext.d.ts +7 -0
- package/dist/typings/verifier/requestCredentialsCrossDevice.d.ts +3 -47
- package/dist/typings/verifier/requestCredentialsDigitalCredentialsApi.d.ts +16 -0
- package/dist/typings/verifier/requestCredentialsSameDevice.d.ts +1 -1
- package/dist/typings/verifier/types/credential-presentation.d.ts +156 -21
- package/dist/typings/verifier/types/verifier-web-sdk.d.ts +129 -186
- package/dist/typings/verifier/utils.d.ts +25 -5
- package/dist/verifier-js.development.js +678 -294
- package/dist/verifier-js.development.js.map +1 -1
- package/dist/verifier-js.production.esm.js +2 -2
- package/dist/verifier-js.production.esm.js.map +1 -1
- package/dist/verifier-js.production.js +2 -2
- package/dist/verifier-js.production.js.map +1 -1
- package/package.json +2 -2
- package/dist/typings/verifier/initialise.d.ts +0 -12
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* Do Not Translate or Localize
|
|
8
8
|
*
|
|
9
9
|
* Bundle of @mattrglobal/verifier-sdk-web
|
|
10
|
-
* Generated: 2025-
|
|
10
|
+
* Generated: 2025-05-20
|
|
11
11
|
* Version: 1.1.0
|
|
12
12
|
* Dependencies:
|
|
13
13
|
*/
|
|
@@ -89,47 +89,21 @@ const assertType = (validator, message) => data => {
|
|
|
89
89
|
}
|
|
90
90
|
};
|
|
91
91
|
|
|
92
|
-
var SafeFetchCommonRespondErrorType;
|
|
93
|
-
|
|
94
|
-
(function(SafeFetchCommonRespondErrorType) {
|
|
95
|
-
SafeFetchCommonRespondErrorType["UnexpectedRespond"] = "UnexpectedRespond";
|
|
96
|
-
})(SafeFetchCommonRespondErrorType || (SafeFetchCommonRespondErrorType = {}));
|
|
97
|
-
|
|
98
|
-
var SafeFetchErrorType;
|
|
99
|
-
|
|
100
|
-
(function(SafeFetchErrorType) {
|
|
101
|
-
SafeFetchErrorType["HttpError"] = "HttpError";
|
|
102
|
-
SafeFetchErrorType["UnknownError"] = "UnknownError";
|
|
103
|
-
})(SafeFetchErrorType || (SafeFetchErrorType = {}));
|
|
104
|
-
|
|
105
|
-
const safeFetch = async (input, init) => {
|
|
106
|
-
try {
|
|
107
|
-
const response = await fetch(input, init);
|
|
108
|
-
if (response.status > 299 || response.status < 200) {
|
|
109
|
-
return neverthrow.err({
|
|
110
|
-
type: SafeFetchErrorType.HttpError,
|
|
111
|
-
message: `HTTP error, status = ${response.status}`,
|
|
112
|
-
status: response.status
|
|
113
|
-
});
|
|
114
|
-
}
|
|
115
|
-
return neverthrow.ok(response);
|
|
116
|
-
} catch (error) {
|
|
117
|
-
return neverthrow.err({
|
|
118
|
-
type: SafeFetchErrorType.UnknownError,
|
|
119
|
-
message: "Unknown error",
|
|
120
|
-
cause: error
|
|
121
|
-
});
|
|
122
|
-
}
|
|
123
|
-
};
|
|
124
|
-
|
|
125
92
|
exports.MobileCredentialVerificationReasonType = void 0;
|
|
126
93
|
|
|
127
94
|
(function(MobileCredentialVerificationReasonType) {
|
|
128
|
-
MobileCredentialVerificationReasonType["
|
|
129
|
-
MobileCredentialVerificationReasonType["
|
|
130
|
-
MobileCredentialVerificationReasonType["
|
|
131
|
-
MobileCredentialVerificationReasonType["
|
|
132
|
-
MobileCredentialVerificationReasonType["
|
|
95
|
+
MobileCredentialVerificationReasonType["TrustedIssuerCertificateExpired"] = "TrustedIssuerCertificateExpired";
|
|
96
|
+
MobileCredentialVerificationReasonType["TrustedIssuerCertificateNotYetValid"] = "TrustedIssuerCertificateNotYetValid";
|
|
97
|
+
MobileCredentialVerificationReasonType["IssuerNotTrusted"] = "IssuerNotTrusted";
|
|
98
|
+
MobileCredentialVerificationReasonType["MobileCredentialInvalid"] = "MobileCredentialInvalid";
|
|
99
|
+
MobileCredentialVerificationReasonType["MobileCredentialExpired"] = "MobileCredentialExpired";
|
|
100
|
+
MobileCredentialVerificationReasonType["MobileCredentialNotYetValid"] = "MobileCredentialNotYetValid";
|
|
101
|
+
MobileCredentialVerificationReasonType["InvalidSignerCertificate"] = "InvalidSignerCertificate";
|
|
102
|
+
MobileCredentialVerificationReasonType["DeviceKeyInvalid"] = "DeviceKeyInvalid";
|
|
103
|
+
MobileCredentialVerificationReasonType["UnsupportedCurve"] = "UnsupportedCurve";
|
|
104
|
+
MobileCredentialVerificationReasonType["StatusRevoked"] = "StatusRevoked";
|
|
105
|
+
MobileCredentialVerificationReasonType["StatusSuspended"] = "StatusSuspended";
|
|
106
|
+
MobileCredentialVerificationReasonType["StatusUnknown"] = "StatusUnknown";
|
|
133
107
|
})(exports.MobileCredentialVerificationReasonType || (exports.MobileCredentialVerificationReasonType = {}));
|
|
134
108
|
|
|
135
109
|
exports.ClaimType = void 0;
|
|
@@ -164,6 +138,15 @@ exports.OpenidPresentationCredentialProfileSupported = void 0;
|
|
|
164
138
|
OpenidPresentationCredentialProfileSupported["MOBILE"] = "mobile";
|
|
165
139
|
})(exports.OpenidPresentationCredentialProfileSupported || (exports.OpenidPresentationCredentialProfileSupported = {}));
|
|
166
140
|
|
|
141
|
+
var PresentationStatusCode;
|
|
142
|
+
|
|
143
|
+
(function(PresentationStatusCode) {
|
|
144
|
+
PresentationStatusCode["AwaitingRequestRetrieval"] = "AwaitingRequestRetrieval";
|
|
145
|
+
PresentationStatusCode["AwaitingResponse"] = "AwaitingResponse";
|
|
146
|
+
PresentationStatusCode["ResponseSubmitted"] = "ResponseSubmitted";
|
|
147
|
+
PresentationStatusCode["ResultReady"] = "ResultReady";
|
|
148
|
+
})(PresentationStatusCode || (PresentationStatusCode = {}));
|
|
149
|
+
|
|
167
150
|
const CredentialQueryValidator = v__namespace.object({
|
|
168
151
|
profile: v__namespace.picklist([ exports.OpenidPresentationCredentialProfileSupported.MOBILE ]),
|
|
169
152
|
docType: v__namespace.string(),
|
|
@@ -182,6 +165,14 @@ var PresentationErrorType;
|
|
|
182
165
|
PresentationErrorType["Unknown"] = "Unknown";
|
|
183
166
|
})(PresentationErrorType || (PresentationErrorType = {}));
|
|
184
167
|
|
|
168
|
+
const PresentationSuccessResultValidator = v__namespace.object({
|
|
169
|
+
sessionId: v__namespace.string(),
|
|
170
|
+
challenge: v__namespace.string(),
|
|
171
|
+
credentialQuery: v__namespace.array(CredentialQueryValidator),
|
|
172
|
+
credentials: v__namespace.optional(v__namespace.array(v__namespace.any())),
|
|
173
|
+
credentialErrors: v__namespace.optional(v__namespace.array(v__namespace.any()))
|
|
174
|
+
});
|
|
175
|
+
|
|
185
176
|
const PresentationResultRelaxValidator = v__namespace.object({
|
|
186
177
|
sessionId: v__namespace.string(),
|
|
187
178
|
challenge: v__namespace.optional(v__namespace.string()),
|
|
@@ -191,18 +182,75 @@ const PresentationResultRelaxValidator = v__namespace.object({
|
|
|
191
182
|
error: v__namespace.optional(v__namespace.unknown())
|
|
192
183
|
});
|
|
193
184
|
|
|
185
|
+
const PresentationFailureResultValidator = v__namespace.object({
|
|
186
|
+
sessionId: v__namespace.string(),
|
|
187
|
+
challenge: v__namespace.string(),
|
|
188
|
+
credentialQuery: v__namespace.array(CredentialQueryValidator),
|
|
189
|
+
error: v__namespace.object({
|
|
190
|
+
type: v__namespace.picklist(Object.values(PresentationErrorType)),
|
|
191
|
+
message: v__namespace.string()
|
|
192
|
+
})
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
const PresentationSessionResultValidator = v__namespace.union([ PresentationSuccessResultValidator, PresentationFailureResultValidator ]);
|
|
196
|
+
|
|
197
|
+
exports.Mode = void 0;
|
|
198
|
+
|
|
199
|
+
(function(Mode) {
|
|
200
|
+
Mode["SameDevice"] = "sameDevice";
|
|
201
|
+
Mode["CrossDevice"] = "crossDevice";
|
|
202
|
+
})(exports.Mode || (exports.Mode = {}));
|
|
203
|
+
|
|
204
|
+
var SessionType;
|
|
205
|
+
|
|
206
|
+
(function(SessionType) {
|
|
207
|
+
SessionType["DigitalCredentialsApi"] = "digital-credentials-api";
|
|
208
|
+
SessionType["Openid4vp"] = "openid4vp";
|
|
209
|
+
})(SessionType || (SessionType = {}));
|
|
210
|
+
|
|
194
211
|
v__namespace.object({
|
|
195
212
|
credentialQuery: v__namespace.array(CredentialQueryValidator),
|
|
196
213
|
challenge: v__namespace.string(),
|
|
197
214
|
redirectUri: v__namespace.optional(v__namespace.string()),
|
|
198
|
-
walletProviderId: v__namespace.optional(v__namespace.string())
|
|
215
|
+
walletProviderId: v__namespace.optional(v__namespace.string()),
|
|
216
|
+
dcApiSupported: v__namespace.optional(v__namespace.boolean())
|
|
199
217
|
});
|
|
200
218
|
|
|
201
|
-
const
|
|
219
|
+
const CreateSessionDigitalCredentialsValidator = v__namespace.object({
|
|
220
|
+
type: v__namespace.literal(SessionType.DigitalCredentialsApi),
|
|
202
221
|
sessionId: v__namespace.string(),
|
|
222
|
+
sessionKey: v__namespace.string(),
|
|
223
|
+
sessionTtl: v__namespace.number(),
|
|
224
|
+
request: v__namespace.record(v__namespace.string(), v__namespace.any())
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
const CreateSessionOpenId4vpResponseValidator = v__namespace.object({
|
|
228
|
+
type: v__namespace.optional(v__namespace.literal(SessionType.Openid4vp)),
|
|
229
|
+
sessionId: v__namespace.string(),
|
|
230
|
+
sessionKey: v__namespace.string(),
|
|
203
231
|
sessionUrl: v__namespace.string()
|
|
204
232
|
});
|
|
205
233
|
|
|
234
|
+
const CreateSessionResponseValidator = v__namespace.union([ CreateSessionDigitalCredentialsValidator, CreateSessionOpenId4vpResponseValidator ]);
|
|
235
|
+
|
|
236
|
+
v__namespace.object({
|
|
237
|
+
sessionId: v__namespace.string(),
|
|
238
|
+
sessionKey: v__namespace.string(),
|
|
239
|
+
apiBaseUrl: v__namespace.string()
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
v__namespace.object({
|
|
243
|
+
sessionId: v__namespace.string(),
|
|
244
|
+
sessionKey: v__namespace.string()
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
const GetSessionStatusResponseValidator = v__namespace.union([ v__namespace.object({
|
|
248
|
+
status: v__namespace.picklist([ PresentationStatusCode.ResultReady ]),
|
|
249
|
+
responseCode: v__namespace.optional(v__namespace.string())
|
|
250
|
+
}), v__namespace.object({
|
|
251
|
+
status: v__namespace.string()
|
|
252
|
+
}) ]);
|
|
253
|
+
|
|
206
254
|
var LocalStorageKey;
|
|
207
255
|
|
|
208
256
|
(function(LocalStorageKey) {
|
|
@@ -210,12 +258,9 @@ var LocalStorageKey;
|
|
|
210
258
|
LocalStorageKey["sessionId"] = "mattr_sid";
|
|
211
259
|
})(LocalStorageKey || (LocalStorageKey = {}));
|
|
212
260
|
|
|
213
|
-
|
|
261
|
+
const MATTR_SDK_VERSION_HEADER = "x-mattr-sdk-version";
|
|
214
262
|
|
|
215
|
-
|
|
216
|
-
Mode["sameDevice"] = "sameDevice";
|
|
217
|
-
Mode["crossDevice"] = "crossDevice";
|
|
218
|
-
})(exports.Mode || (exports.Mode = {}));
|
|
263
|
+
const MATTR_SDK_VERSION_VALUE = "2.0.0";
|
|
219
264
|
|
|
220
265
|
var MessageEventDataType;
|
|
221
266
|
|
|
@@ -225,69 +270,186 @@ var MessageEventDataType;
|
|
|
225
270
|
MessageEventDataType["PresentationAbort"] = "PresentationAbort";
|
|
226
271
|
})(MessageEventDataType || (MessageEventDataType = {}));
|
|
227
272
|
|
|
228
|
-
const
|
|
229
|
-
credentialQuery: v__namespace.pipe(v__namespace.array(CredentialQueryValidator), v__namespace.nonEmpty()),
|
|
230
|
-
redirectUri: v__namespace.string(),
|
|
231
|
-
challenge: v__namespace.optional(v__namespace.string()),
|
|
273
|
+
const OpenId4vpConfigSameDeviceOptionsValidator = v__namespace.object({
|
|
232
274
|
walletProviderId: v__namespace.optional(v__namespace.string()),
|
|
233
|
-
mode: v__namespace.
|
|
275
|
+
mode: v__namespace.literal(exports.Mode.SameDevice),
|
|
276
|
+
redirectUri: v__namespace.string()
|
|
234
277
|
});
|
|
235
278
|
|
|
236
|
-
const
|
|
237
|
-
credentialQuery: v__namespace.pipe(v__namespace.array(CredentialQueryValidator), v__namespace.nonEmpty()),
|
|
238
|
-
crossDeviceCallback: v__namespace.object({
|
|
239
|
-
onComplete: v__namespace.function(),
|
|
240
|
-
onFailure: v__namespace.function()
|
|
241
|
-
}),
|
|
242
|
-
challenge: v__namespace.optional(v__namespace.string()),
|
|
279
|
+
const OpenId4vpConfigCrossDeviceOptionsValidator = v__namespace.object({
|
|
243
280
|
walletProviderId: v__namespace.optional(v__namespace.string()),
|
|
244
|
-
mode: v__namespace.
|
|
281
|
+
mode: v__namespace.literal(exports.Mode.CrossDevice)
|
|
245
282
|
});
|
|
246
283
|
|
|
247
|
-
const
|
|
248
|
-
credentialQuery: v__namespace.pipe(v__namespace.array(CredentialQueryValidator), v__namespace.nonEmpty()),
|
|
249
|
-
crossDeviceCallback: v__namespace.object({
|
|
250
|
-
onComplete: v__namespace.function(),
|
|
251
|
-
onFailure: v__namespace.function()
|
|
252
|
-
}),
|
|
253
|
-
redirectUri: v__namespace.string(),
|
|
254
|
-
challenge: v__namespace.optional(v__namespace.string()),
|
|
284
|
+
const OpenId4vpConfigAutoDetectOptionsValidator = v__namespace.object({
|
|
255
285
|
walletProviderId: v__namespace.optional(v__namespace.string()),
|
|
256
|
-
|
|
286
|
+
redirectUri: v__namespace.string(),
|
|
287
|
+
mode: v__namespace.optional(v__namespace.picklist([ exports.Mode.CrossDevice, exports.Mode.SameDevice ]))
|
|
257
288
|
});
|
|
258
289
|
|
|
259
|
-
const RequestCredentialsOptionsValidator = v__namespace.
|
|
290
|
+
const RequestCredentialsOptionsValidator = v__namespace.object({
|
|
291
|
+
credentialQuery: v__namespace.pipe(v__namespace.array(CredentialQueryValidator), v__namespace.nonEmpty()),
|
|
292
|
+
challenge: v__namespace.optional(v__namespace.string()),
|
|
293
|
+
openid4vpConfiguration: v__namespace.optional(v__namespace.union([ OpenId4vpConfigSameDeviceOptionsValidator, OpenId4vpConfigCrossDeviceOptionsValidator, OpenId4vpConfigAutoDetectOptionsValidator ]))
|
|
294
|
+
});
|
|
260
295
|
|
|
261
296
|
exports.RequestCredentialsErrorType = void 0;
|
|
262
297
|
|
|
263
298
|
(function(RequestCredentialsErrorType) {
|
|
264
299
|
RequestCredentialsErrorType["RequestCredentialsFailed"] = "RequestCredentialsFailed";
|
|
300
|
+
RequestCredentialsErrorType["Timeout"] = "Timeout";
|
|
301
|
+
RequestCredentialsErrorType["Abort"] = "Abort";
|
|
265
302
|
})(exports.RequestCredentialsErrorType || (exports.RequestCredentialsErrorType = {}));
|
|
266
303
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
304
|
+
var RequestCredentialsErrorMessage;
|
|
305
|
+
|
|
306
|
+
(function(RequestCredentialsErrorMessage) {
|
|
307
|
+
RequestCredentialsErrorMessage["FailedToGetSessionResult"] = "Failed to get session result";
|
|
308
|
+
RequestCredentialsErrorMessage["FailedToGetSessionStatus"] = "Failed to get session status";
|
|
309
|
+
RequestCredentialsErrorMessage["FailedToCreateSession"] = "Failed to create session";
|
|
310
|
+
RequestCredentialsErrorMessage["FailedToVerifyCredentialResponse"] = "Failed to verify credential response";
|
|
311
|
+
RequestCredentialsErrorMessage["MissingOpenId4vpConfig"] = "Identified openid4vp session, but missing openId4vpConfiguration on `requestCredentials`";
|
|
312
|
+
RequestCredentialsErrorMessage["DcApiError"] = "Failed to request credentials with Digital Credentials API";
|
|
313
|
+
RequestCredentialsErrorMessage["DcApiResponseParseError"] = "Failed to parse response from Digital Credentials API";
|
|
314
|
+
RequestCredentialsErrorMessage["Abort"] = "User aborted the session";
|
|
315
|
+
RequestCredentialsErrorMessage["Timeout"] = "User session timeout";
|
|
316
|
+
})(RequestCredentialsErrorMessage || (RequestCredentialsErrorMessage = {}));
|
|
317
|
+
|
|
318
|
+
exports.AbortSessionErrorType = void 0;
|
|
319
|
+
|
|
320
|
+
(function(AbortSessionErrorType) {
|
|
321
|
+
AbortSessionErrorType["AbortSessionFailed"] = "AbortSessionFailed";
|
|
322
|
+
})(exports.AbortSessionErrorType || (exports.AbortSessionErrorType = {}));
|
|
323
|
+
|
|
324
|
+
var AbortSessionErrorMessage;
|
|
325
|
+
|
|
326
|
+
(function(AbortSessionErrorMessage) {
|
|
327
|
+
AbortSessionErrorMessage["FailedToAbortSession"] = "Failed to abort session";
|
|
328
|
+
})(AbortSessionErrorMessage || (AbortSessionErrorMessage = {}));
|
|
329
|
+
|
|
330
|
+
const InitializeOptionsValidator = v__namespace.object({
|
|
331
|
+
apiBaseUrl: v__namespace.pipe(v__namespace.string(), v__namespace.nonEmpty("Must not be empty")),
|
|
332
|
+
applicationId: v__namespace.pipe(v__namespace.string(), v__namespace.nonEmpty("Must not be empty"))
|
|
270
333
|
});
|
|
271
334
|
|
|
272
|
-
|
|
335
|
+
var SafeFetchCommonResponseErrorType;
|
|
336
|
+
|
|
337
|
+
(function(SafeFetchCommonResponseErrorType) {
|
|
338
|
+
SafeFetchCommonResponseErrorType["UnexpectedResponse"] = "UnexpectedResponse";
|
|
339
|
+
})(SafeFetchCommonResponseErrorType || (SafeFetchCommonResponseErrorType = {}));
|
|
340
|
+
|
|
341
|
+
var SafeFetchErrorType;
|
|
342
|
+
|
|
343
|
+
(function(SafeFetchErrorType) {
|
|
344
|
+
SafeFetchErrorType["HttpError"] = "HttpError";
|
|
345
|
+
SafeFetchErrorType["UnknownError"] = "UnknownError";
|
|
346
|
+
})(SafeFetchErrorType || (SafeFetchErrorType = {}));
|
|
347
|
+
|
|
348
|
+
const safeFetch = async (input, init) => {
|
|
349
|
+
try {
|
|
350
|
+
const headers = Object.assign(Object.assign({}, init === null || init === void 0 ? void 0 : init.headers), {
|
|
351
|
+
[MATTR_SDK_VERSION_HEADER]: `verifier-sdk-web/${MATTR_SDK_VERSION_VALUE}`
|
|
352
|
+
});
|
|
353
|
+
const response = await fetch(input, Object.assign(Object.assign({}, init), {
|
|
354
|
+
headers: headers
|
|
355
|
+
}));
|
|
356
|
+
if (response.status > 299 || response.status < 200) {
|
|
357
|
+
return neverthrow.err({
|
|
358
|
+
type: SafeFetchErrorType.HttpError,
|
|
359
|
+
message: `HTTP error, status = ${response.status}`,
|
|
360
|
+
status: response.status
|
|
361
|
+
});
|
|
362
|
+
}
|
|
363
|
+
return neverthrow.ok(response);
|
|
364
|
+
} catch (error) {
|
|
365
|
+
return neverthrow.err({
|
|
366
|
+
type: SafeFetchErrorType.UnknownError,
|
|
367
|
+
message: "Unknown error",
|
|
368
|
+
cause: error
|
|
369
|
+
});
|
|
370
|
+
}
|
|
371
|
+
};
|
|
372
|
+
|
|
373
|
+
let initializeOptions = undefined;
|
|
374
|
+
|
|
375
|
+
var InitializeErrorMessage;
|
|
273
376
|
|
|
274
|
-
|
|
377
|
+
(function(InitializeErrorMessage) {
|
|
378
|
+
InitializeErrorMessage["SdkNotInitialized"] = "SDK not initialized";
|
|
379
|
+
})(InitializeErrorMessage || (InitializeErrorMessage = {}));
|
|
275
380
|
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
381
|
+
const initialize = options => {
|
|
382
|
+
assertType(InitializeOptionsValidator, "Invalid initialize options")(options);
|
|
383
|
+
initializeOptions = options;
|
|
384
|
+
};
|
|
385
|
+
|
|
386
|
+
const getInitializeOptions = () => initializeOptions;
|
|
387
|
+
|
|
388
|
+
let sessionAbortController = undefined;
|
|
389
|
+
|
|
390
|
+
let _sessionId = undefined;
|
|
391
|
+
|
|
392
|
+
let _sessionKey = undefined;
|
|
279
393
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
394
|
+
let _sessionTimeoutId = undefined;
|
|
395
|
+
|
|
396
|
+
const getActiveSession = () => {
|
|
397
|
+
const sessionId = _sessionId;
|
|
398
|
+
const sessionKey = _sessionKey;
|
|
399
|
+
const sessionTimeoutId = _sessionTimeoutId;
|
|
400
|
+
if (sessionId) {
|
|
401
|
+
return {
|
|
402
|
+
sessionId: sessionId,
|
|
403
|
+
sessionKey: sessionKey,
|
|
404
|
+
sessionTimeoutId: sessionTimeoutId
|
|
405
|
+
};
|
|
406
|
+
}
|
|
407
|
+
return undefined;
|
|
283
408
|
};
|
|
284
409
|
|
|
285
|
-
const
|
|
410
|
+
const setActiveSession = session => {
|
|
411
|
+
const {sessionId: sessionId, sessionKey: sessionKey, sessionTimeoutId: sessionTimeoutId} = session;
|
|
412
|
+
_sessionId = sessionId;
|
|
413
|
+
_sessionKey = sessionKey;
|
|
414
|
+
_sessionTimeoutId = sessionTimeoutId;
|
|
415
|
+
const abortController = new AbortController;
|
|
416
|
+
sessionAbortController = abortController;
|
|
417
|
+
return abortController;
|
|
418
|
+
};
|
|
419
|
+
|
|
420
|
+
const removeActiveSession = () => {
|
|
421
|
+
sessionAbortController === null || sessionAbortController === void 0 ? void 0 : sessionAbortController.abort();
|
|
422
|
+
if (_sessionTimeoutId) {
|
|
423
|
+
window.clearTimeout(_sessionTimeoutId);
|
|
424
|
+
}
|
|
425
|
+
sessionAbortController = undefined;
|
|
426
|
+
_sessionKey = undefined;
|
|
427
|
+
_sessionId = undefined;
|
|
428
|
+
_sessionTimeoutId = undefined;
|
|
429
|
+
};
|
|
286
430
|
|
|
287
431
|
const defaultRetryDelay = attempt => Math.pow(2, attempt) * 1e3;
|
|
288
432
|
|
|
289
433
|
const defaultRetry = 2;
|
|
290
434
|
|
|
435
|
+
const withRetry = async (fn, options) => {
|
|
436
|
+
const {retries: retries = defaultRetry, retryDelay: retryDelay = defaultRetryDelay, attempt: attempt = 0} = options;
|
|
437
|
+
try {
|
|
438
|
+
return await fn();
|
|
439
|
+
} catch (err) {
|
|
440
|
+
if (retries > 0) {
|
|
441
|
+
const delay = typeof retryDelay === "function" ? retryDelay(attempt) : retryDelay;
|
|
442
|
+
await new Promise((resolve => setTimeout(resolve, delay)));
|
|
443
|
+
return await withRetry(fn, Object.assign(Object.assign({}, options), {
|
|
444
|
+
retries: retries - 1,
|
|
445
|
+
retryDelay: retryDelay,
|
|
446
|
+
attempt: attempt + 1
|
|
447
|
+
}));
|
|
448
|
+
}
|
|
449
|
+
throw err;
|
|
450
|
+
}
|
|
451
|
+
};
|
|
452
|
+
|
|
291
453
|
const withRetrySafeFetch = async (fn, options) => {
|
|
292
454
|
const {retries: retries = defaultRetry, retryDelay: retryDelay = defaultRetryDelay, attempt: attempt = 0, retryHttpStatus: retryHttpStatus} = options;
|
|
293
455
|
const result = await fn();
|
|
@@ -316,17 +478,15 @@ const getHashParamValue = (hash, param) => {
|
|
|
316
478
|
return urlParams.get(param);
|
|
317
479
|
};
|
|
318
480
|
|
|
319
|
-
const createSession = async ({credentialQuery: credentialQuery, challenge: challenge, redirectUri: redirectUri, apiBaseUrl: apiBaseUrl,
|
|
320
|
-
const postData =
|
|
481
|
+
const createSession = async ({credentialQuery: credentialQuery, challenge: challenge, redirectUri: redirectUri, apiBaseUrl: apiBaseUrl, walletProviderId: walletProviderId, dcApiSupported: dcApiSupported, applicationId: applicationId}) => {
|
|
482
|
+
const postData = {
|
|
321
483
|
credentialQuery: credentialQuery,
|
|
322
|
-
challenge: challenge
|
|
323
|
-
|
|
324
|
-
redirectUri: redirectUri
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
}
|
|
328
|
-
walletProviderId: walletProviderId
|
|
329
|
-
} : {});
|
|
484
|
+
challenge: challenge,
|
|
485
|
+
applicationId: applicationId,
|
|
486
|
+
redirectUri: redirectUri,
|
|
487
|
+
walletProviderId: walletProviderId,
|
|
488
|
+
dcApiSupported: dcApiSupported
|
|
489
|
+
};
|
|
330
490
|
const responseResult = await safeFetch(`${apiBaseUrl}/v2/presentations/sessions`, {
|
|
331
491
|
method: "POST",
|
|
332
492
|
headers: {
|
|
@@ -340,8 +500,42 @@ const createSession = async ({credentialQuery: credentialQuery, challenge: chall
|
|
|
340
500
|
const data = await responseResult.value.json();
|
|
341
501
|
if (!isType(CreateSessionResponseValidator)(data)) {
|
|
342
502
|
return neverthrow.err({
|
|
343
|
-
type:
|
|
344
|
-
message: "Create session
|
|
503
|
+
type: SafeFetchCommonResponseErrorType.UnexpectedResponse,
|
|
504
|
+
message: "Create session returned unsupported response"
|
|
505
|
+
});
|
|
506
|
+
}
|
|
507
|
+
return neverthrow.ok(data);
|
|
508
|
+
};
|
|
509
|
+
|
|
510
|
+
const abortSession = async ({apiBaseUrl: apiBaseUrl, sessionId: sessionId, sessionKey: sessionKey}) => {
|
|
511
|
+
const responseResult = await safeFetch(`${apiBaseUrl}/v2/presentations/sessions/${sessionId}/abort`, {
|
|
512
|
+
method: "POST",
|
|
513
|
+
headers: {
|
|
514
|
+
"Content-Type": "application/json",
|
|
515
|
+
Authorization: `Bearer ${sessionKey}`
|
|
516
|
+
}
|
|
517
|
+
});
|
|
518
|
+
if (responseResult.isErr()) {
|
|
519
|
+
return neverthrow.err(responseResult.error);
|
|
520
|
+
}
|
|
521
|
+
return neverthrow.ok(undefined);
|
|
522
|
+
};
|
|
523
|
+
|
|
524
|
+
const getSessionStatus = async ({apiBaseUrl: apiBaseUrl, sessionId: sessionId, sessionKey: sessionKey}) => {
|
|
525
|
+
const responseResult = await safeFetch(`${apiBaseUrl}/v2/presentations/sessions/${sessionId}/status`, {
|
|
526
|
+
method: "GET",
|
|
527
|
+
headers: {
|
|
528
|
+
Authorization: `Bearer ${sessionKey}`
|
|
529
|
+
}
|
|
530
|
+
});
|
|
531
|
+
if (responseResult.isErr()) {
|
|
532
|
+
return neverthrow.err(responseResult.error);
|
|
533
|
+
}
|
|
534
|
+
const data = await responseResult.value.json();
|
|
535
|
+
if (!isType(GetSessionStatusResponseValidator)(data)) {
|
|
536
|
+
return neverthrow.err({
|
|
537
|
+
type: SafeFetchCommonResponseErrorType.UnexpectedResponse,
|
|
538
|
+
message: "Get session status return unsupported response"
|
|
345
539
|
});
|
|
346
540
|
}
|
|
347
541
|
return neverthrow.ok(data);
|
|
@@ -369,7 +563,7 @@ const exchangeSessionResult = async ({challenge: challenge, responseCode: respon
|
|
|
369
563
|
const data = await responseResult.value.json();
|
|
370
564
|
if (!isType(PresentationResultRelaxValidator)(data)) {
|
|
371
565
|
return neverthrow.err({
|
|
372
|
-
type:
|
|
566
|
+
type: SafeFetchCommonResponseErrorType.UnexpectedResponse,
|
|
373
567
|
message: "Exchange session result return unsupported response",
|
|
374
568
|
details: {
|
|
375
569
|
data: data
|
|
@@ -384,22 +578,7 @@ const isMobileDetect = userAgent => isMobile.isMobile({
|
|
|
384
578
|
tablet: false
|
|
385
579
|
});
|
|
386
580
|
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
(function(CrossDeviceCallbackErrorType) {
|
|
390
|
-
CrossDeviceCallbackErrorType["Timeout"] = "Timeout";
|
|
391
|
-
CrossDeviceCallbackErrorType["Abort"] = "Abort";
|
|
392
|
-
CrossDeviceCallbackErrorType["RequestCredentialsFailed"] = "RequestCredentialsFailed";
|
|
393
|
-
})(exports.CrossDeviceCallbackErrorType || (exports.CrossDeviceCallbackErrorType = {}));
|
|
394
|
-
|
|
395
|
-
var CrossDeviceRequestCredentialsErrorMessage;
|
|
396
|
-
|
|
397
|
-
(function(CrossDeviceRequestCredentialsErrorMessage) {
|
|
398
|
-
CrossDeviceRequestCredentialsErrorMessage["FailedToGetSessionResult"] = "Failed to get session result";
|
|
399
|
-
CrossDeviceRequestCredentialsErrorMessage["FailedToCreateSession"] = "Failed to create session";
|
|
400
|
-
CrossDeviceRequestCredentialsErrorMessage["Abort"] = "User aborted the session";
|
|
401
|
-
CrossDeviceRequestCredentialsErrorMessage["Timeout"] = "User session timeout";
|
|
402
|
-
})(CrossDeviceRequestCredentialsErrorMessage || (CrossDeviceRequestCredentialsErrorMessage = {}));
|
|
581
|
+
const getVersion = () => MATTR_SDK_VERSION_VALUE;
|
|
403
582
|
|
|
404
583
|
var WindowEventListenerType;
|
|
405
584
|
|
|
@@ -407,10 +586,13 @@ var WindowEventListenerType;
|
|
|
407
586
|
WindowEventListenerType["message"] = "message";
|
|
408
587
|
})(WindowEventListenerType || (WindowEventListenerType = {}));
|
|
409
588
|
|
|
410
|
-
let listener;
|
|
589
|
+
let listener = undefined;
|
|
411
590
|
|
|
412
591
|
const removeWindowMessageEventListener = () => {
|
|
413
|
-
|
|
592
|
+
if (listener) {
|
|
593
|
+
window.removeEventListener(WindowEventListenerType.message, listener, false);
|
|
594
|
+
}
|
|
595
|
+
listener = undefined;
|
|
414
596
|
};
|
|
415
597
|
|
|
416
598
|
const closeCrossDeviceModal = options => {
|
|
@@ -422,8 +604,7 @@ const closeCrossDeviceModal = options => {
|
|
|
422
604
|
};
|
|
423
605
|
|
|
424
606
|
const receiveMessageHandler = options => async event => {
|
|
425
|
-
const {
|
|
426
|
-
const {onComplete: onComplete, onFailure: onFailure} = crossDeviceCallback;
|
|
607
|
+
const {onComplete: onComplete, onFailure: onFailure, container: container, sessionId: sessionId, apiBaseUrl: apiBaseUrl, challenge: challenge} = options;
|
|
427
608
|
if (event.origin !== apiBaseUrl) {
|
|
428
609
|
return;
|
|
429
610
|
}
|
|
@@ -437,8 +618,8 @@ const receiveMessageHandler = options => async event => {
|
|
|
437
618
|
});
|
|
438
619
|
if (result.isErr()) {
|
|
439
620
|
onFailure({
|
|
440
|
-
type: exports.
|
|
441
|
-
message:
|
|
621
|
+
type: exports.RequestCredentialsErrorType.RequestCredentialsFailed,
|
|
622
|
+
message: RequestCredentialsErrorMessage.FailedToGetSessionResult
|
|
442
623
|
});
|
|
443
624
|
closeCrossDeviceModal({
|
|
444
625
|
container: container
|
|
@@ -446,8 +627,9 @@ const receiveMessageHandler = options => async event => {
|
|
|
446
627
|
return;
|
|
447
628
|
}
|
|
448
629
|
onComplete({
|
|
449
|
-
result: result.value,
|
|
450
|
-
sessionId: result.value.sessionId
|
|
630
|
+
result: isType(PresentationSessionResultValidator)(result.value) ? result.value : undefined,
|
|
631
|
+
sessionId: result.value.sessionId,
|
|
632
|
+
sessionCompletedInRedirect: false
|
|
451
633
|
});
|
|
452
634
|
closeCrossDeviceModal({
|
|
453
635
|
container: container
|
|
@@ -456,8 +638,8 @@ const receiveMessageHandler = options => async event => {
|
|
|
456
638
|
}
|
|
457
639
|
if (event.data.type === MessageEventDataType.PresentationTimeout) {
|
|
458
640
|
onFailure({
|
|
459
|
-
type: exports.
|
|
460
|
-
message:
|
|
641
|
+
type: exports.RequestCredentialsErrorType.Timeout,
|
|
642
|
+
message: RequestCredentialsErrorMessage.Timeout
|
|
461
643
|
});
|
|
462
644
|
closeCrossDeviceModal({
|
|
463
645
|
container: container
|
|
@@ -466,8 +648,8 @@ const receiveMessageHandler = options => async event => {
|
|
|
466
648
|
}
|
|
467
649
|
if (event.data.type === MessageEventDataType.PresentationAbort) {
|
|
468
650
|
onFailure({
|
|
469
|
-
type: exports.
|
|
470
|
-
message:
|
|
651
|
+
type: exports.RequestCredentialsErrorType.Abort,
|
|
652
|
+
message: RequestCredentialsErrorMessage.Abort
|
|
471
653
|
});
|
|
472
654
|
closeCrossDeviceModal({
|
|
473
655
|
container: container
|
|
@@ -492,41 +674,202 @@ const openCrossDeviceModal = options => {
|
|
|
492
674
|
return modalContainer;
|
|
493
675
|
};
|
|
494
676
|
|
|
495
|
-
const
|
|
496
|
-
const {challenge: challenge,
|
|
497
|
-
const
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
677
|
+
const requestCredentialsWithCrossDevice = async options => {
|
|
678
|
+
const {challenge: challenge, apiBaseUrl: apiBaseUrl, sessionUrl: sessionUrl, sessionId: sessionId, sessionKey: sessionKey} = options;
|
|
679
|
+
const container = openCrossDeviceModal({
|
|
680
|
+
sessionUrl: sessionUrl
|
|
681
|
+
});
|
|
682
|
+
return await new Promise((resolve => {
|
|
683
|
+
const abortController = setActiveSession({
|
|
684
|
+
sessionId: sessionId,
|
|
685
|
+
sessionKey: sessionKey
|
|
686
|
+
});
|
|
687
|
+
abortController.signal.addEventListener("abort", (() => {
|
|
688
|
+
closeCrossDeviceModal({
|
|
689
|
+
container: container
|
|
690
|
+
});
|
|
691
|
+
resolve(neverthrow.err({
|
|
692
|
+
type: exports.RequestCredentialsErrorType.Abort,
|
|
693
|
+
message: RequestCredentialsErrorMessage.Abort
|
|
694
|
+
}));
|
|
695
|
+
}));
|
|
696
|
+
removeWindowMessageEventListener();
|
|
697
|
+
listener = receiveMessageHandler({
|
|
698
|
+
container: container,
|
|
699
|
+
sessionId: sessionId,
|
|
700
|
+
apiBaseUrl: apiBaseUrl,
|
|
701
|
+
challenge: challenge,
|
|
702
|
+
onComplete: data => resolve(neverthrow.ok(data)),
|
|
703
|
+
onFailure: error => resolve(neverthrow.err(error))
|
|
704
|
+
});
|
|
705
|
+
window.addEventListener(WindowEventListenerType.message, listener, false);
|
|
706
|
+
}));
|
|
707
|
+
};
|
|
708
|
+
|
|
709
|
+
const abortCredentialRequest = async () => {
|
|
710
|
+
const initializeOptions = getInitializeOptions();
|
|
711
|
+
if (!initializeOptions) {
|
|
712
|
+
throw new Exception(InitializeErrorMessage.SdkNotInitialized);
|
|
713
|
+
}
|
|
714
|
+
const {apiBaseUrl: apiBaseUrl} = initializeOptions;
|
|
715
|
+
const session = getActiveSession();
|
|
716
|
+
if (!session || !session.sessionKey) {
|
|
717
|
+
return neverthrow.ok(undefined);
|
|
718
|
+
}
|
|
719
|
+
const {sessionId: sessionId, sessionKey: sessionKey} = session;
|
|
720
|
+
removeActiveSession();
|
|
721
|
+
const abortSessionResult = await abortSession({
|
|
501
722
|
apiBaseUrl: apiBaseUrl,
|
|
502
|
-
|
|
503
|
-
|
|
723
|
+
sessionId: sessionId,
|
|
724
|
+
sessionKey: sessionKey
|
|
504
725
|
});
|
|
505
|
-
if (
|
|
726
|
+
if (abortSessionResult.isErr()) {
|
|
506
727
|
return neverthrow.err({
|
|
507
|
-
type: exports.
|
|
508
|
-
message:
|
|
509
|
-
cause:
|
|
728
|
+
type: exports.AbortSessionErrorType.AbortSessionFailed,
|
|
729
|
+
message: AbortSessionErrorMessage.FailedToAbortSession,
|
|
730
|
+
cause: abortSessionResult.error
|
|
510
731
|
});
|
|
511
732
|
}
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
}
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
container: container,
|
|
733
|
+
return neverthrow.ok(undefined);
|
|
734
|
+
};
|
|
735
|
+
|
|
736
|
+
const requestCredentialsWithDigitalCredentialsApi = async options => {
|
|
737
|
+
const {apiBaseUrl: apiBaseUrl, sessionId: sessionId, sessionKey: sessionKey, challenge: challenge, request: request, sessionTtl: sessionTtl} = options;
|
|
738
|
+
const sessionTimeoutId = window.setTimeout((() => removeActiveSession()), sessionTtl * 1e3);
|
|
739
|
+
const abortController = setActiveSession({
|
|
520
740
|
sessionId: sessionId,
|
|
741
|
+
sessionKey: sessionKey,
|
|
742
|
+
sessionTimeoutId: sessionTimeoutId
|
|
743
|
+
});
|
|
744
|
+
const credentialResponseResult = await getCredentials(request, abortController);
|
|
745
|
+
if (credentialResponseResult.isErr()) {
|
|
746
|
+
await abortCredentialRequest();
|
|
747
|
+
return neverthrow.err(credentialResponseResult.error);
|
|
748
|
+
}
|
|
749
|
+
const credentialResponse = credentialResponseResult.value;
|
|
750
|
+
const parsedCredentialResponseResult = parseCredentialResponse(credentialResponse);
|
|
751
|
+
if (parsedCredentialResponseResult.isErr()) {
|
|
752
|
+
await abortCredentialRequest();
|
|
753
|
+
return neverthrow.err(parsedCredentialResponseResult.error);
|
|
754
|
+
}
|
|
755
|
+
const parsedCredentialResponse = parsedCredentialResponseResult.value;
|
|
756
|
+
const credentialVerificationResult = await verifyCredentialResponse({
|
|
521
757
|
apiBaseUrl: apiBaseUrl,
|
|
522
|
-
|
|
758
|
+
sessionId: sessionId,
|
|
759
|
+
sessionKey: sessionKey,
|
|
760
|
+
challenge: challenge,
|
|
761
|
+
protocol: parsedCredentialResponse.protocol,
|
|
762
|
+
data: parsedCredentialResponse.data
|
|
523
763
|
});
|
|
524
|
-
|
|
764
|
+
if (credentialVerificationResult.isErr()) {
|
|
765
|
+
return neverthrow.err({
|
|
766
|
+
type: exports.RequestCredentialsErrorType.RequestCredentialsFailed,
|
|
767
|
+
message: RequestCredentialsErrorMessage.FailedToVerifyCredentialResponse,
|
|
768
|
+
cause: credentialVerificationResult.error
|
|
769
|
+
});
|
|
770
|
+
}
|
|
771
|
+
const verificationResult = credentialVerificationResult.value;
|
|
525
772
|
return neverthrow.ok({
|
|
773
|
+
result: isType(PresentationSessionResultValidator)(verificationResult) ? verificationResult : undefined,
|
|
526
774
|
sessionId: sessionId
|
|
527
775
|
});
|
|
528
776
|
};
|
|
529
777
|
|
|
778
|
+
const getCredentials = async (request, abortController) => {
|
|
779
|
+
try {
|
|
780
|
+
const credentialResponse = await navigator.credentials.get(Object.assign(Object.assign({}, request), {
|
|
781
|
+
signal: abortController.signal
|
|
782
|
+
}));
|
|
783
|
+
return neverthrow.ok(credentialResponse);
|
|
784
|
+
} catch (exception) {
|
|
785
|
+
return neverthrow.err({
|
|
786
|
+
type: exports.RequestCredentialsErrorType.RequestCredentialsFailed,
|
|
787
|
+
message: RequestCredentialsErrorMessage.DcApiError,
|
|
788
|
+
cause: exception
|
|
789
|
+
});
|
|
790
|
+
}
|
|
791
|
+
};
|
|
792
|
+
|
|
793
|
+
const parseCredentialResponse = credentialResponse => {
|
|
794
|
+
if (!credentialResponse) {
|
|
795
|
+
return neverthrow.err({
|
|
796
|
+
type: exports.RequestCredentialsErrorType.RequestCredentialsFailed,
|
|
797
|
+
message: RequestCredentialsErrorMessage.DcApiResponseParseError,
|
|
798
|
+
details: {
|
|
799
|
+
response: credentialResponse
|
|
800
|
+
}
|
|
801
|
+
});
|
|
802
|
+
}
|
|
803
|
+
if (typeof credentialResponse === "object") {
|
|
804
|
+
return neverthrow.ok(credentialResponse);
|
|
805
|
+
}
|
|
806
|
+
if (typeof credentialResponse === "string") {
|
|
807
|
+
try {
|
|
808
|
+
const parsed = JSON.parse(credentialResponse);
|
|
809
|
+
return neverthrow.ok(parsed);
|
|
810
|
+
} catch (_a) {
|
|
811
|
+
return neverthrow.err({
|
|
812
|
+
type: exports.RequestCredentialsErrorType.RequestCredentialsFailed,
|
|
813
|
+
message: RequestCredentialsErrorMessage.DcApiResponseParseError,
|
|
814
|
+
details: {
|
|
815
|
+
response: credentialResponse
|
|
816
|
+
}
|
|
817
|
+
});
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
return neverthrow.err({
|
|
821
|
+
type: exports.RequestCredentialsErrorType.RequestCredentialsFailed,
|
|
822
|
+
message: RequestCredentialsErrorMessage.DcApiResponseParseError,
|
|
823
|
+
details: {
|
|
824
|
+
response: credentialResponse
|
|
825
|
+
}
|
|
826
|
+
});
|
|
827
|
+
};
|
|
828
|
+
|
|
829
|
+
const verifyCredentialResponse = async options => {
|
|
830
|
+
const {apiBaseUrl: apiBaseUrl, sessionId: sessionId, sessionKey: sessionKey, challenge: challenge, protocol: protocol, data: data} = options;
|
|
831
|
+
const requestBody = {
|
|
832
|
+
protocol: protocol,
|
|
833
|
+
data: data,
|
|
834
|
+
challenge: challenge
|
|
835
|
+
};
|
|
836
|
+
const credentialVerificationResult = await safeFetch(`${apiBaseUrl}/v2/presentations/sessions/${sessionId}/dc-api/response`, {
|
|
837
|
+
method: "POST",
|
|
838
|
+
headers: {
|
|
839
|
+
"Content-Type": "application/json",
|
|
840
|
+
Authorization: `Bearer ${sessionKey}`
|
|
841
|
+
},
|
|
842
|
+
body: JSON.stringify(requestBody)
|
|
843
|
+
});
|
|
844
|
+
if (credentialVerificationResult.isErr()) {
|
|
845
|
+
return neverthrow.err(credentialVerificationResult.error);
|
|
846
|
+
}
|
|
847
|
+
const credentialVerificationResponse = await credentialVerificationResult.value.json();
|
|
848
|
+
if (!isType(PresentationResultRelaxValidator)(credentialVerificationResponse)) {
|
|
849
|
+
return neverthrow.err({
|
|
850
|
+
type: SafeFetchCommonResponseErrorType.UnexpectedResponse,
|
|
851
|
+
message: "Verify credential returned unsupported response",
|
|
852
|
+
details: {
|
|
853
|
+
response: credentialVerificationResponse
|
|
854
|
+
}
|
|
855
|
+
});
|
|
856
|
+
}
|
|
857
|
+
return neverthrow.ok(credentialVerificationResponse);
|
|
858
|
+
};
|
|
859
|
+
|
|
860
|
+
const isDigitalCredentialsApiSupported = () => {
|
|
861
|
+
var _a;
|
|
862
|
+
return "DigitalCredential" in window && typeof window.DigitalCredential === "function" && typeof ((_a = navigator === null || navigator === void 0 ? void 0 : navigator.credentials) === null || _a === void 0 ? void 0 : _a.get) === "function";
|
|
863
|
+
};
|
|
864
|
+
|
|
865
|
+
const sleep = ms => new Promise((resolve => setTimeout(resolve, ms)));
|
|
866
|
+
|
|
867
|
+
const SESSION_STATUS_POLLING_MAX_RETRY = 1e3;
|
|
868
|
+
|
|
869
|
+
const SESSION_STATUS_POLLING_INTERVAL_MS = 3e3;
|
|
870
|
+
|
|
871
|
+
const SESSION_STATUS_POLLING_INITIAL_DELAY_MS = 3e3;
|
|
872
|
+
|
|
530
873
|
var SameDeviceRequestCredentialsErrorMessage;
|
|
531
874
|
|
|
532
875
|
(function(SameDeviceRequestCredentialsErrorMessage) {
|
|
@@ -535,65 +878,135 @@ var SameDeviceRequestCredentialsErrorMessage;
|
|
|
535
878
|
})(SameDeviceRequestCredentialsErrorMessage || (SameDeviceRequestCredentialsErrorMessage = {}));
|
|
536
879
|
|
|
537
880
|
const requestCredentialsSameDevice = async options => {
|
|
538
|
-
const {challenge: challenge,
|
|
539
|
-
const
|
|
881
|
+
const {challenge: challenge, apiBaseUrl: apiBaseUrl, applicationId: applicationId, sessionUrl: sessionUrl, sessionKey: sessionKey, sessionId: sessionId} = options;
|
|
882
|
+
const abortController = setActiveSession({
|
|
883
|
+
sessionId: sessionId,
|
|
884
|
+
sessionKey: sessionKey
|
|
885
|
+
});
|
|
886
|
+
window.localStorage.setItem(LocalStorageKey.sessionId, sessionId);
|
|
540
887
|
window.localStorage.setItem(LocalStorageKey.challenge, challenge);
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
888
|
+
window.location.assign(sessionUrl);
|
|
889
|
+
await sleep(SESSION_STATUS_POLLING_INITIAL_DELAY_MS);
|
|
890
|
+
const checkResult = await withRetry((async () => {
|
|
891
|
+
const statusResult = await getSessionStatus({
|
|
892
|
+
apiBaseUrl: apiBaseUrl,
|
|
893
|
+
applicationId: applicationId,
|
|
894
|
+
sessionId: sessionId,
|
|
895
|
+
sessionKey: sessionKey
|
|
546
896
|
});
|
|
897
|
+
if (abortController.signal.aborted) {
|
|
898
|
+
return neverthrow.err({
|
|
899
|
+
type: exports.RequestCredentialsErrorType.Abort,
|
|
900
|
+
message: RequestCredentialsErrorMessage.Abort
|
|
901
|
+
});
|
|
902
|
+
}
|
|
903
|
+
if (statusResult.isErr()) {
|
|
904
|
+
if (statusResult.error.status === 404) {
|
|
905
|
+
return neverthrow.err({
|
|
906
|
+
type: exports.RequestCredentialsErrorType.Timeout,
|
|
907
|
+
message: RequestCredentialsErrorMessage.Timeout
|
|
908
|
+
});
|
|
909
|
+
}
|
|
910
|
+
throw Error("Unexpected status response. Retry");
|
|
911
|
+
}
|
|
912
|
+
if (statusResult.value.status !== PresentationStatusCode.ResultReady) {
|
|
913
|
+
throw Error("Result is not ready. Retry");
|
|
914
|
+
}
|
|
915
|
+
return neverthrow.ok(undefined);
|
|
916
|
+
}), {
|
|
917
|
+
retries: SESSION_STATUS_POLLING_MAX_RETRY,
|
|
918
|
+
retryDelay: SESSION_STATUS_POLLING_INTERVAL_MS
|
|
919
|
+
});
|
|
920
|
+
if (checkResult.isErr()) {
|
|
921
|
+
return neverthrow.err(checkResult.error);
|
|
922
|
+
}
|
|
923
|
+
window.close();
|
|
924
|
+
return neverthrow.ok({
|
|
925
|
+
sessionId: sessionId,
|
|
926
|
+
sessionCompletedInRedirect: true
|
|
927
|
+
});
|
|
928
|
+
};
|
|
929
|
+
|
|
930
|
+
const requestCredentials = async options => {
|
|
931
|
+
var _a;
|
|
932
|
+
const initializeOptions = getInitializeOptions();
|
|
933
|
+
if (!initializeOptions) {
|
|
934
|
+
throw new Exception(InitializeErrorMessage.SdkNotInitialized);
|
|
547
935
|
}
|
|
936
|
+
assertType(RequestCredentialsOptionsValidator, "Invalid request credential options")(options);
|
|
937
|
+
const {apiBaseUrl: apiBaseUrl, applicationId: applicationId} = initializeOptions;
|
|
938
|
+
const {challenge: challenge = generateChallenge(), credentialQuery: credentialQuery, openid4vpConfiguration: openid4vpConfiguration} = options;
|
|
939
|
+
const dcApiSupported = isDigitalCredentialsApiSupported();
|
|
940
|
+
const openId4VpRedirectUri = deriveOpenId4vpRedirectUri(openid4vpConfiguration);
|
|
548
941
|
const createSessionResult = await createSession({
|
|
549
942
|
credentialQuery: credentialQuery,
|
|
550
|
-
challenge:
|
|
551
|
-
redirectUri:
|
|
943
|
+
challenge: challenge,
|
|
944
|
+
redirectUri: openId4VpRedirectUri,
|
|
945
|
+
walletProviderId: (_a = openid4vpConfiguration === null || openid4vpConfiguration === void 0 ? void 0 : openid4vpConfiguration.walletProviderId) !== null && _a !== void 0 ? _a : undefined,
|
|
552
946
|
apiBaseUrl: apiBaseUrl,
|
|
553
947
|
applicationId: applicationId,
|
|
554
|
-
|
|
948
|
+
dcApiSupported: dcApiSupported
|
|
555
949
|
});
|
|
556
950
|
if (createSessionResult.isErr()) {
|
|
557
951
|
return neverthrow.err({
|
|
558
952
|
type: exports.RequestCredentialsErrorType.RequestCredentialsFailed,
|
|
559
|
-
message:
|
|
953
|
+
message: RequestCredentialsErrorMessage.FailedToCreateSession,
|
|
560
954
|
cause: createSessionResult.error
|
|
561
955
|
});
|
|
562
956
|
}
|
|
563
|
-
const
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
957
|
+
const session = createSessionResult.value;
|
|
958
|
+
const {sessionKey: sessionKey, sessionId: sessionId} = session;
|
|
959
|
+
if (session.type === SessionType.DigitalCredentialsApi) {
|
|
960
|
+
const {request: request, sessionTtl: sessionTtl} = session;
|
|
961
|
+
return await requestCredentialsWithDigitalCredentialsApi({
|
|
962
|
+
apiBaseUrl: apiBaseUrl,
|
|
963
|
+
request: request,
|
|
964
|
+
sessionId: sessionId,
|
|
965
|
+
sessionKey: sessionKey,
|
|
966
|
+
challenge: challenge,
|
|
967
|
+
sessionTtl: sessionTtl
|
|
968
|
+
});
|
|
969
|
+
}
|
|
970
|
+
if (!openid4vpConfiguration) {
|
|
971
|
+
return neverthrow.err({
|
|
972
|
+
type: exports.RequestCredentialsErrorType.RequestCredentialsFailed,
|
|
973
|
+
message: RequestCredentialsErrorMessage.MissingOpenId4vpConfig
|
|
974
|
+
});
|
|
975
|
+
}
|
|
976
|
+
const {sessionUrl: sessionUrl} = session;
|
|
977
|
+
if (openId4VpRedirectUri) {
|
|
978
|
+
return await requestCredentialsSameDevice({
|
|
979
|
+
challenge: challenge,
|
|
980
|
+
apiBaseUrl: apiBaseUrl,
|
|
981
|
+
applicationId: applicationId,
|
|
982
|
+
sessionUrl: sessionUrl,
|
|
983
|
+
sessionKey: sessionKey,
|
|
984
|
+
sessionId: sessionId
|
|
985
|
+
});
|
|
986
|
+
}
|
|
987
|
+
return await requestCredentialsWithCrossDevice({
|
|
988
|
+
challenge: challenge,
|
|
989
|
+
apiBaseUrl: apiBaseUrl,
|
|
990
|
+
sessionUrl: sessionUrl,
|
|
991
|
+
sessionKey: sessionKey,
|
|
567
992
|
sessionId: sessionId
|
|
568
993
|
});
|
|
569
994
|
};
|
|
570
995
|
|
|
571
|
-
const
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
if (!initialiseOptions) {
|
|
575
|
-
throw new Exception(InitialiseErrorMessage.SdkNotInitialised);
|
|
996
|
+
const deriveOpenId4vpRedirectUri = openid4vpConfiguration => {
|
|
997
|
+
if (!openid4vpConfiguration) {
|
|
998
|
+
return undefined;
|
|
576
999
|
}
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
initialiseOptions: initialiseOptions,
|
|
583
|
-
challenge: challenge,
|
|
584
|
-
mode: mode
|
|
585
|
-
}));
|
|
1000
|
+
let detectedMode;
|
|
1001
|
+
if (openid4vpConfiguration && openid4vpConfiguration.mode) {
|
|
1002
|
+
detectedMode = openid4vpConfiguration.mode;
|
|
1003
|
+
} else {
|
|
1004
|
+
detectedMode = isMobileDetect(navigator.userAgent) ? exports.Mode.SameDevice : exports.Mode.CrossDevice;
|
|
586
1005
|
}
|
|
587
|
-
if (
|
|
588
|
-
return
|
|
589
|
-
initialiseOptions: initialiseOptions,
|
|
590
|
-
challenge: challenge,
|
|
591
|
-
mode: mode
|
|
592
|
-
}));
|
|
1006
|
+
if (detectedMode === exports.Mode.SameDevice && !isType(OpenId4vpConfigCrossDeviceOptionsValidator)(openid4vpConfiguration) && openid4vpConfiguration.redirectUri) {
|
|
1007
|
+
return openid4vpConfiguration.redirectUri;
|
|
593
1008
|
}
|
|
594
|
-
|
|
595
|
-
data: options
|
|
596
|
-
});
|
|
1009
|
+
return undefined;
|
|
597
1010
|
};
|
|
598
1011
|
|
|
599
1012
|
exports.HandleRedirectCallbackErrorType = void 0;
|
|
@@ -607,16 +1020,16 @@ var HandleRedirectCallbackErrorMessage;
|
|
|
607
1020
|
(function(HandleRedirectCallbackErrorMessage) {
|
|
608
1021
|
HandleRedirectCallbackErrorMessage["FailedToFindResponseCode"] = "Failed to find response code";
|
|
609
1022
|
HandleRedirectCallbackErrorMessage["FailedToFindChallenge"] = "Failed to find challenge";
|
|
610
|
-
HandleRedirectCallbackErrorMessage["
|
|
1023
|
+
HandleRedirectCallbackErrorMessage["FailedToFindActiveSession"] = "Failed to find active session";
|
|
611
1024
|
HandleRedirectCallbackErrorMessage["FailedToGetSessionResult"] = "Failed to get session result";
|
|
612
1025
|
})(HandleRedirectCallbackErrorMessage || (HandleRedirectCallbackErrorMessage = {}));
|
|
613
1026
|
|
|
614
1027
|
const handleRedirectCallback = async () => {
|
|
615
|
-
const
|
|
616
|
-
if (!
|
|
617
|
-
throw new Exception(
|
|
1028
|
+
const initializeOptions = getInitializeOptions();
|
|
1029
|
+
if (!initializeOptions) {
|
|
1030
|
+
throw new Exception(InitializeErrorMessage.SdkNotInitialized);
|
|
618
1031
|
}
|
|
619
|
-
const {apiBaseUrl: apiBaseUrl} =
|
|
1032
|
+
const {apiBaseUrl: apiBaseUrl} = initializeOptions;
|
|
620
1033
|
const responseCode = getHashParamValue(window.location.hash, "response_code");
|
|
621
1034
|
if (!responseCode) {
|
|
622
1035
|
return neverthrow.err({
|
|
@@ -624,18 +1037,12 @@ const handleRedirectCallback = async () => {
|
|
|
624
1037
|
message: HandleRedirectCallbackErrorMessage.FailedToFindResponseCode
|
|
625
1038
|
});
|
|
626
1039
|
}
|
|
627
|
-
const challenge = window.localStorage.getItem(LocalStorageKey.challenge);
|
|
628
|
-
if (!challenge) {
|
|
629
|
-
return neverthrow.err({
|
|
630
|
-
type: exports.HandleRedirectCallbackErrorType.HandleRedirectCallbackFailed,
|
|
631
|
-
message: HandleRedirectCallbackErrorMessage.FailedToFindChallenge
|
|
632
|
-
});
|
|
633
|
-
}
|
|
634
1040
|
const sessionId = window.localStorage.getItem(LocalStorageKey.sessionId);
|
|
635
|
-
|
|
1041
|
+
const challenge = window.localStorage.getItem(LocalStorageKey.challenge);
|
|
1042
|
+
if (!sessionId || !challenge) {
|
|
636
1043
|
return neverthrow.err({
|
|
637
1044
|
type: exports.HandleRedirectCallbackErrorType.HandleRedirectCallbackFailed,
|
|
638
|
-
message: HandleRedirectCallbackErrorMessage.
|
|
1045
|
+
message: HandleRedirectCallbackErrorMessage.FailedToFindActiveSession
|
|
639
1046
|
});
|
|
640
1047
|
}
|
|
641
1048
|
const result = await exchangeSessionResult({
|
|
@@ -652,19 +1059,24 @@ const handleRedirectCallback = async () => {
|
|
|
652
1059
|
});
|
|
653
1060
|
}
|
|
654
1061
|
return neverthrow.ok({
|
|
655
|
-
result: result.value,
|
|
1062
|
+
result: "challenge" in result.value ? result.value : undefined,
|
|
656
1063
|
sessionId: result.value.sessionId
|
|
657
1064
|
});
|
|
658
1065
|
};
|
|
659
1066
|
|
|
660
1067
|
const utils = {
|
|
661
1068
|
generateChallenge: generateChallenge,
|
|
1069
|
+
getVersion: getVersion,
|
|
662
1070
|
unwrap: unwrap
|
|
663
1071
|
};
|
|
664
1072
|
|
|
1073
|
+
exports.abortCredentialRequest = abortCredentialRequest;
|
|
1074
|
+
|
|
665
1075
|
exports.handleRedirectCallback = handleRedirectCallback;
|
|
666
1076
|
|
|
667
|
-
exports.
|
|
1077
|
+
exports.initialize = initialize;
|
|
1078
|
+
|
|
1079
|
+
exports.isDigitalCredentialsApiSupported = isDigitalCredentialsApiSupported;
|
|
668
1080
|
|
|
669
1081
|
exports.requestCredentials = requestCredentials;
|
|
670
1082
|
|