idmission-web-sdk 1.0.59 → 1.0.61

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.
@@ -5,3 +5,8 @@ export declare class SubmissionError extends Error {
5
5
  }
6
6
  export declare class NetworkError extends Error {
7
7
  }
8
+ export declare class TokenPublicKeyError extends Error {
9
+ err: Error;
10
+ host: string;
11
+ constructor(err: Error, host: string);
12
+ }
@@ -1,5 +1,6 @@
1
1
  import { ReactElement } from 'react';
2
2
  import { CardData, LivenessCheckRequest, PersonalData, SubmissionAction, SubmissionEnvironment, SubmissionRequest, SubmissionResponse } from '../../contexts/SubmissionContext';
3
+ export type TokenState = 'NOT_PARSED' | 'PARSING' | 'GOOD' | 'EXPIRED' | 'INVALID_FORMAT' | 'INVALID_SIGNATURE' | 'MISSING' | 'PUBLIC_KEY_LOAD_FAILED';
3
4
  export type SubmissionProviderProps = {
4
5
  action: SubmissionAction;
5
6
  children: ReactElement;
@@ -0,0 +1,2 @@
1
+ import React from 'react';
2
+ export declare const TokenExpiredErrorOverlay: () => React.JSX.Element;
@@ -0,0 +1,2 @@
1
+ import React from 'react';
2
+ export declare const TokenInvalidFormatErrorOverlay: () => React.JSX.Element;
@@ -0,0 +1,2 @@
1
+ import React from 'react';
2
+ export declare const TokenInvalidSignatureErrorOverlay: () => React.JSX.Element;
@@ -0,0 +1,2 @@
1
+ import React from 'react';
2
+ export declare const TokenMissingErrorOverlay: () => React.JSX.Element;
@@ -0,0 +1,5 @@
1
+ import React from 'react';
2
+ import { TokenPublicKeyError } from './Errors';
3
+ export declare const TokenPublicKeyErrorOverlay: ({ error, }: {
4
+ error: TokenPublicKeyError | null;
5
+ }) => React.JSX.Element;
@@ -181,6 +181,7 @@ export type SubmissionState = {
181
181
  retryLocationAccess: () => void;
182
182
  };
183
183
  export declare const SubmissionContext: import("react").Context<SubmissionState>;
184
+ export declare function parseJwt(token: string): Record<string, unknown>;
184
185
  export declare function determineSubmissionHost(environment: SubmissionEnvironment, token?: string): string;
185
186
  export declare function determineSubmissionEndpoint(action: SubmissionAction, hasId: boolean, hasSelfie: boolean, hasToken: boolean): string;
186
187
  export declare function liveCheckEndpoint(hasToken: boolean): string;
@@ -7,6 +7,7 @@ var React = require('react');
7
7
  var ReactDOM = require('react-dom/client');
8
8
  var styled = require('styled-components');
9
9
  var reactI18next = require('react-i18next');
10
+ var jsrsasign = require('jsrsasign');
10
11
  var tf = require('@tensorflow/tfjs');
11
12
  var useResizeObserver = require('use-resize-observer');
12
13
  var LanguageDetector = require('i18next-browser-languagedetector');
@@ -46,7 +47,7 @@ var LanguageDetector__default = /*#__PURE__*/_interopDefaultLegacy(LanguageDetec
46
47
  var i18n__default = /*#__PURE__*/_interopDefaultLegacy(i18n);
47
48
  var SignatureCanvas__default = /*#__PURE__*/_interopDefaultLegacy(SignatureCanvas);
48
49
 
49
- var webSdkVersion = '1.0.59';
50
+ var webSdkVersion = '1.0.61';
50
51
 
51
52
  function getPlatform() {
52
53
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
@@ -418,6 +419,16 @@ var NetworkError = /** @class */function (_super) {
418
419
  }
419
420
  return NetworkError;
420
421
  }(Error);
422
+ var TokenPublicKeyError = /** @class */function (_super) {
423
+ tslib.__extends(TokenPublicKeyError, _super);
424
+ function TokenPublicKeyError(err, host) {
425
+ var _this = _super.call(this, err.message) || this;
426
+ _this.err = err;
427
+ _this.host = host;
428
+ return _this;
429
+ }
430
+ return TokenPublicKeyError;
431
+ }(Error);
421
432
 
422
433
  var SubmissionErrorOverlay = function SubmissionErrorOverlay(_a) {
423
434
  var error = _a.error,
@@ -482,6 +493,161 @@ var NetworkErrorContent = function NetworkErrorContent(_a) {
482
493
  }, retryText))));
483
494
  };
484
495
 
496
+ var TokenMissingErrorOverlay = function TokenMissingErrorOverlay() {
497
+ return /*#__PURE__*/React__default['default'].createElement(OverlayContainer, null, /*#__PURE__*/React__default['default'].createElement(OverlayInner, {
498
+ style: {
499
+ justifyContent: 'center'
500
+ }
501
+ }, /*#__PURE__*/React__default['default'].createElement("h3", {
502
+ style: {
503
+ marginBottom: 8
504
+ }
505
+ }, "IDmission WebSDK failed to load"), /*#__PURE__*/React__default['default'].createElement("p", {
506
+ style: {
507
+ marginBottom: 0
508
+ }
509
+ }, "Required property ", /*#__PURE__*/React__default['default'].createElement("code", null, "submissionToken"), " is missing."), /*#__PURE__*/React__default['default'].createElement("p", {
510
+ style: {
511
+ lineHeight: '1.5rem'
512
+ }
513
+ }, "Please refer to the", ' ', /*#__PURE__*/React__default['default'].createElement("a", {
514
+ href: "https://www.npmjs.com/package/idmission-web-sdk#getting-started",
515
+ target: "_blank",
516
+ rel: "noreferrer"
517
+ }, "Getting Started"), ' ', "section of the documentation for information on how to use your credentials to generate a valid", ' ', /*#__PURE__*/React__default['default'].createElement("a", {
518
+ href: "https://jwt.io",
519
+ target: "_blank",
520
+ rel: "noreferrer"
521
+ }, "JSON Web Token"), ' ', "for your IDmission account. Every usage of the IDmission WebSDK must be authorized with a valid JWT from IDmission's servers.")));
522
+ };
523
+
524
+ var TokenInvalidFormatErrorOverlay = function TokenInvalidFormatErrorOverlay() {
525
+ return /*#__PURE__*/React__default['default'].createElement(OverlayContainer, null, /*#__PURE__*/React__default['default'].createElement(OverlayInner, {
526
+ style: {
527
+ justifyContent: 'center'
528
+ }
529
+ }, /*#__PURE__*/React__default['default'].createElement("h3", {
530
+ style: {
531
+ marginBottom: 8
532
+ }
533
+ }, "IDmission WebSDK failed to load"), /*#__PURE__*/React__default['default'].createElement("p", {
534
+ style: {
535
+ marginBottom: 0
536
+ }
537
+ }, "Required property ", /*#__PURE__*/React__default['default'].createElement("code", null, "submissionToken"), " is invalid."), /*#__PURE__*/React__default['default'].createElement("p", null, "JSON Web Tokens consist of three parts separated by dots (", /*#__PURE__*/React__default['default'].createElement("code", null, "."), "), which are:"), /*#__PURE__*/React__default['default'].createElement("div", {
538
+ style: {
539
+ display: 'flex'
540
+ }
541
+ }, /*#__PURE__*/React__default['default'].createElement("ul", {
542
+ style: {
543
+ display: 'inline',
544
+ margin: '0 auto'
545
+ }
546
+ }, /*#__PURE__*/React__default['default'].createElement("li", null, "Header"), /*#__PURE__*/React__default['default'].createElement("li", null, "Payload"), /*#__PURE__*/React__default['default'].createElement("li", null, "Signature"))), /*#__PURE__*/React__default['default'].createElement("p", null, "Therefore, a JWT typically looks like the following:", ' ', /*#__PURE__*/React__default['default'].createElement("code", null, "xxxxx.yyyyy.zzzzz")), /*#__PURE__*/React__default['default'].createElement("p", {
547
+ style: {
548
+ lineHeight: '1.5rem'
549
+ }
550
+ }, "Please refer to the", ' ', /*#__PURE__*/React__default['default'].createElement("a", {
551
+ href: "https://www.npmjs.com/package/idmission-web-sdk#getting-started",
552
+ target: "_blank",
553
+ rel: "noreferrer"
554
+ }, "Getting Started"), ' ', "section of the documentation for information on how to use your credentials to generate a valid", ' ', /*#__PURE__*/React__default['default'].createElement("a", {
555
+ href: "https://jwt.io",
556
+ target: "_blank",
557
+ rel: "noreferrer"
558
+ }, "JSON Web Token"), ' ', "for your IDmission account. Every usage of the IDmission WebSDK must be authorized with a valid JWT from IDmission's servers.")));
559
+ };
560
+
561
+ var TokenInvalidSignatureErrorOverlay = function TokenInvalidSignatureErrorOverlay() {
562
+ return /*#__PURE__*/React__default['default'].createElement(OverlayContainer, null, /*#__PURE__*/React__default['default'].createElement(OverlayInner, {
563
+ style: {
564
+ justifyContent: 'center'
565
+ }
566
+ }, /*#__PURE__*/React__default['default'].createElement("h3", {
567
+ style: {
568
+ marginBottom: 8
569
+ }
570
+ }, "IDmission WebSDK failed to load"), /*#__PURE__*/React__default['default'].createElement("p", {
571
+ style: {
572
+ marginBottom: 0
573
+ }
574
+ }, "Required property ", /*#__PURE__*/React__default['default'].createElement("code", null, "submissionToken"), " could not be validated."), /*#__PURE__*/React__default['default'].createElement("p", {
575
+ style: {
576
+ marginBottom: 0,
577
+ lineHeight: '1.5rem'
578
+ }
579
+ }, "The signature of your token could not be validated. Check your token generation routine, it's possible that some malicious behavior is at play. This can also happen if you attempt to manually modify your token before passing it to the IDmission WebSDK."), /*#__PURE__*/React__default['default'].createElement("p", {
580
+ style: {
581
+ marginBottom: 0,
582
+ lineHeight: '1.5rem'
583
+ }
584
+ }, "If you believe you have reached this page in error, please contact us at ", /*#__PURE__*/React__default['default'].createElement("a", {
585
+ href: "mailto:support@idmission.com"
586
+ }, "support@idmission.com"), ".")));
587
+ };
588
+
589
+ var TokenExpiredErrorOverlay = function TokenExpiredErrorOverlay() {
590
+ return /*#__PURE__*/React__default['default'].createElement(OverlayContainer, null, /*#__PURE__*/React__default['default'].createElement(OverlayInner, {
591
+ style: {
592
+ justifyContent: 'center'
593
+ }
594
+ }, /*#__PURE__*/React__default['default'].createElement("h3", {
595
+ style: {
596
+ marginBottom: 8
597
+ }
598
+ }, "IDmission WebSDK failed to load"), /*#__PURE__*/React__default['default'].createElement("p", {
599
+ style: {
600
+ marginBottom: 0
601
+ }
602
+ }, "Required property ", /*#__PURE__*/React__default['default'].createElement("code", null, "submissionToken"), " is expired."), /*#__PURE__*/React__default['default'].createElement("p", {
603
+ style: {
604
+ marginBottom: 0,
605
+ lineHeight: '1.5rem'
606
+ }
607
+ }, "Ensure you are generating a fresh token for each request to the IDmission WebSDK."), /*#__PURE__*/React__default['default'].createElement("p", {
608
+ style: {
609
+ lineHeight: '1.5rem'
610
+ }
611
+ }, "Please refer to the", ' ', /*#__PURE__*/React__default['default'].createElement("a", {
612
+ href: "https://www.npmjs.com/package/idmission-web-sdk#getting-started",
613
+ target: "_blank",
614
+ rel: "noreferrer"
615
+ }, "Getting Started"), ' ', "section of the documentation for information on how to use your credentials to generate a valid", ' ', /*#__PURE__*/React__default['default'].createElement("a", {
616
+ href: "https://jwt.io",
617
+ target: "_blank",
618
+ rel: "noreferrer"
619
+ }, "JSON Web Token"), ' ', "for your IDmission account. Every usage of the IDmission WebSDK must be authorized with a valid JWT from IDmission's servers.")));
620
+ };
621
+
622
+ var TokenPublicKeyErrorOverlay = function TokenPublicKeyErrorOverlay(_a) {
623
+ var error = _a.error;
624
+ return /*#__PURE__*/React__default['default'].createElement(OverlayContainer, null, /*#__PURE__*/React__default['default'].createElement(OverlayInner, {
625
+ style: {
626
+ justifyContent: 'center'
627
+ }
628
+ }, /*#__PURE__*/React__default['default'].createElement("h3", {
629
+ style: {
630
+ marginBottom: 8
631
+ }
632
+ }, "IDmission WebSDK failed to load"), /*#__PURE__*/React__default['default'].createElement("p", {
633
+ style: {
634
+ marginBottom: 0
635
+ }
636
+ }, (error === null || error === void 0 ? void 0 : error.host) ? ( /*#__PURE__*/React__default['default'].createElement(React__default['default'].Fragment, null, "Failed to reach ", /*#__PURE__*/React__default['default'].createElement("code", null, error.host), ".")) : ( /*#__PURE__*/React__default['default'].createElement(React__default['default'].Fragment, null, "Failed to obtain public key for ", /*#__PURE__*/React__default['default'].createElement("code", null, "submissionToken"), "."))), (error === null || error === void 0 ? void 0 : error.message) && ( /*#__PURE__*/React__default['default'].createElement("p", {
637
+ style: {
638
+ marginBottom: 0,
639
+ lineHeight: '1.5rem'
640
+ }
641
+ }, /*#__PURE__*/React__default['default'].createElement("code", null, error.message))), /*#__PURE__*/React__default['default'].createElement("p", {
642
+ style: {
643
+ marginBottom: 0,
644
+ lineHeight: '1.5rem'
645
+ }
646
+ }, "Please ensure that IDmission's servers can be reached. If you believe you have reached this page in error, please contact us at", ' ', /*#__PURE__*/React__default['default'].createElement("a", {
647
+ href: "mailto:support@idmission.com"
648
+ }, "support@idmission.com"), ".")));
649
+ };
650
+
485
651
  var SubmissionProvider = function SubmissionProvider(_a) {
486
652
  var action = _a.action,
487
653
  children = _a.children,
@@ -933,6 +1099,64 @@ var SubmissionProvider = function SubmissionProvider(_a) {
933
1099
  setSubmissionStatus(SubmissionStatus.READY);
934
1100
  retrySubmission();
935
1101
  }, [retrySubmission]);
1102
+ var _13 = React.useState('NOT_PARSED'),
1103
+ tokenState = _13[0],
1104
+ setTokenState = _13[1];
1105
+ var _14 = React.useState(null),
1106
+ tokenError = _14[0],
1107
+ setTokenError = _14[1];
1108
+ React.useEffect(function () {
1109
+ (function () {
1110
+ return tslib.__awaiter(void 0, void 0, void 0, function () {
1111
+ var parsed, iss, publicKey, resp, e_3, valid, exp;
1112
+ return tslib.__generator(this, function (_a) {
1113
+ switch (_a.label) {
1114
+ case 0:
1115
+ setTokenState('PARSING');
1116
+ if (!token) return [2 /*return*/, setTokenState('MISSING')];
1117
+ try {
1118
+ parsed = parseJwt(token);
1119
+ } catch (e) {
1120
+ console.error('error parsing token', e);
1121
+ return [2 /*return*/, setTokenState('INVALID_FORMAT')];
1122
+ }
1123
+ iss = parsed.iss;
1124
+ _a.label = 1;
1125
+ case 1:
1126
+ _a.trys.push([1, 3,, 4]);
1127
+ return [4 /*yield*/, fetch(iss).then(function (r) {
1128
+ return r.json();
1129
+ })];
1130
+ case 2:
1131
+ resp = _a.sent();
1132
+ publicKey = jsrsasign.KEYUTIL.getKey("-----BEGIN PUBLIC KEY-----\n".concat(resp.public_key, "\n-----END PUBLIC KEY-----"));
1133
+ return [3 /*break*/, 4];
1134
+ case 3:
1135
+ e_3 = _a.sent();
1136
+ console.error('error fetching public key', e_3);
1137
+ setTokenError(new TokenPublicKeyError(e_3, iss));
1138
+ return [2 /*return*/, setTokenState('PUBLIC_KEY_LOAD_FAILED')];
1139
+ case 4:
1140
+ valid = false;
1141
+ try {
1142
+ valid = jsrsasign.KJUR.jws.JWS.verifyJWT(token, publicKey, {
1143
+ alg: ['RS256']
1144
+ });
1145
+ } catch (e) {
1146
+ console.error('error validating token', e);
1147
+ }
1148
+ if (!valid) return [2 /*return*/, setTokenState('INVALID_SIGNATURE')];
1149
+ exp = parsed.exp;
1150
+ if (Date.now() >= exp * 1000) {
1151
+ return [2 /*return*/, setTokenState('EXPIRED')];
1152
+ }
1153
+ setTokenState('GOOD');
1154
+ return [2 /*return*/];
1155
+ }
1156
+ });
1157
+ });
1158
+ })();
1159
+ }, [token]);
936
1160
  var value = {
937
1161
  submit: submit,
938
1162
  submissionStatus: submissionStatus,
@@ -963,6 +1187,23 @@ var SubmissionProvider = function SubmissionProvider(_a) {
963
1187
  checkLiveness: checkLiveness,
964
1188
  retryLocationAccess: retryLocationAccess
965
1189
  };
1190
+ if (tokenState === 'MISSING') {
1191
+ return /*#__PURE__*/React__default['default'].createElement(TokenMissingErrorOverlay, null);
1192
+ }
1193
+ if (tokenState === 'INVALID_FORMAT') {
1194
+ return /*#__PURE__*/React__default['default'].createElement(TokenInvalidFormatErrorOverlay, null);
1195
+ }
1196
+ if (tokenState === 'INVALID_SIGNATURE') {
1197
+ return /*#__PURE__*/React__default['default'].createElement(TokenInvalidSignatureErrorOverlay, null);
1198
+ }
1199
+ if (tokenState === 'EXPIRED') {
1200
+ return /*#__PURE__*/React__default['default'].createElement(TokenExpiredErrorOverlay, null);
1201
+ }
1202
+ if (tokenState === 'PUBLIC_KEY_LOAD_FAILED') {
1203
+ return /*#__PURE__*/React__default['default'].createElement(TokenPublicKeyErrorOverlay, {
1204
+ error: tokenError
1205
+ });
1206
+ }
966
1207
  return /*#__PURE__*/React__default['default'].createElement(SubmissionContext.Provider, {
967
1208
  value: value
968
1209
  }, geolocationRequired && geolocationBlocked ? ( /*#__PURE__*/React__default['default'].createElement(GeolocationAccessDeniedOverlay, null)) : children, submissionError && ( /*#__PURE__*/React__default['default'].createElement(SubmissionErrorOverlay, {