@auth0/auth0-spa-js 2.3.0 → 2.4.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.
Files changed (43) hide show
  1. package/README.md +1 -1
  2. package/dist/auth0-spa-js.development.js +600 -14
  3. package/dist/auth0-spa-js.development.js.map +1 -1
  4. package/dist/auth0-spa-js.production.esm.js +1 -1
  5. package/dist/auth0-spa-js.production.esm.js.map +1 -1
  6. package/dist/auth0-spa-js.production.js +1 -1
  7. package/dist/auth0-spa-js.production.js.map +1 -1
  8. package/dist/auth0-spa-js.worker.development.js +10 -2
  9. package/dist/auth0-spa-js.worker.development.js.map +1 -1
  10. package/dist/auth0-spa-js.worker.production.js +1 -1
  11. package/dist/auth0-spa-js.worker.production.js.map +1 -1
  12. package/dist/lib/auth0-spa-js.cjs.js +641 -14
  13. package/dist/lib/auth0-spa-js.cjs.js.map +1 -1
  14. package/dist/typings/Auth0Client.d.ts +50 -0
  15. package/dist/typings/Auth0Client.utils.d.ts +1 -1
  16. package/dist/typings/api.d.ts +1 -1
  17. package/dist/typings/cache/shared.d.ts +1 -0
  18. package/dist/typings/dpop/dpop.d.ts +17 -0
  19. package/dist/typings/dpop/storage.d.ts +27 -0
  20. package/dist/typings/dpop/utils.d.ts +15 -0
  21. package/dist/typings/errors.d.ts +7 -0
  22. package/dist/typings/fetcher.d.ts +48 -0
  23. package/dist/typings/global.d.ts +19 -0
  24. package/dist/typings/http.d.ts +2 -1
  25. package/dist/typings/index.d.ts +2 -1
  26. package/dist/typings/utils.d.ts +6 -0
  27. package/dist/typings/version.d.ts +1 -1
  28. package/package.json +22 -19
  29. package/src/Auth0Client.ts +112 -5
  30. package/src/Auth0Client.utils.ts +4 -2
  31. package/src/api.ts +6 -1
  32. package/src/cache/shared.ts +1 -0
  33. package/src/dpop/dpop.ts +56 -0
  34. package/src/dpop/storage.ts +134 -0
  35. package/src/dpop/utils.ts +66 -0
  36. package/src/errors.ts +11 -0
  37. package/src/fetcher.ts +224 -0
  38. package/src/global.ts +21 -0
  39. package/src/http.ts +70 -5
  40. package/src/index.ts +4 -1
  41. package/src/utils.ts +15 -0
  42. package/src/version.ts +1 -1
  43. package/src/worker/token.worker.ts +11 -5
@@ -550,7 +550,7 @@ var browserTabsLock = createCommonjsModule((function(module, exports) {
550
550
 
551
551
  var Lock = unwrapExports(browserTabsLock);
552
552
 
553
- var version = "2.3.0";
553
+ var version = "2.4.0";
554
554
 
555
555
  const DEFAULT_AUTHORIZE_TIMEOUT_IN_SECONDS = 60;
556
556
 
@@ -642,6 +642,14 @@ class MissingRefreshTokenError extends GenericError {
642
642
  }
643
643
  }
644
644
 
645
+ class UseDpopNonceError extends GenericError {
646
+ constructor(newDpopNonce) {
647
+ super("use_dpop_nonce", "Server rejected DPoP proof: wrong nonce");
648
+ this.newDpopNonce = newDpopNonce;
649
+ Object.setPrototypeOf(this, UseDpopNonceError.prototype);
650
+ }
651
+ }
652
+
645
653
  function valueOrEmptyString(value, exclude = []) {
646
654
  return value && !exclude.includes(value) ? value : "";
647
655
  }
@@ -809,6 +817,351 @@ const parseNumber = value => {
809
817
  return parseInt(value, 10) || undefined;
810
818
  };
811
819
 
820
+ const fromEntries = iterable => [ ...iterable ].reduce(((obj, [key, val]) => {
821
+ obj[key] = val;
822
+ return obj;
823
+ }), {});
824
+
825
+ const encoder = new TextEncoder;
826
+
827
+ const decoder = new TextDecoder;
828
+
829
+ function buf(input) {
830
+ if (typeof input === "string") {
831
+ return encoder.encode(input);
832
+ }
833
+ return decoder.decode(input);
834
+ }
835
+
836
+ function checkRsaKeyAlgorithm(algorithm) {
837
+ if (typeof algorithm.modulusLength !== "number" || algorithm.modulusLength < 2048) {
838
+ throw new OperationProcessingError(`${algorithm.name} modulusLength must be at least 2048 bits`);
839
+ }
840
+ }
841
+
842
+ function subtleAlgorithm(key) {
843
+ switch (key.algorithm.name) {
844
+ case "ECDSA":
845
+ return {
846
+ name: key.algorithm.name,
847
+ hash: "SHA-256"
848
+ };
849
+
850
+ case "RSA-PSS":
851
+ checkRsaKeyAlgorithm(key.algorithm);
852
+ return {
853
+ name: key.algorithm.name,
854
+ saltLength: 256 >> 3
855
+ };
856
+
857
+ case "RSASSA-PKCS1-v1_5":
858
+ checkRsaKeyAlgorithm(key.algorithm);
859
+ return {
860
+ name: key.algorithm.name
861
+ };
862
+
863
+ case "Ed25519":
864
+ return {
865
+ name: key.algorithm.name
866
+ };
867
+ }
868
+ throw new UnsupportedOperationError;
869
+ }
870
+
871
+ async function jwt(header, claimsSet, key) {
872
+ if (key.usages.includes("sign") === false) {
873
+ throw new TypeError('private CryptoKey instances used for signing assertions must include "sign" in their "usages"');
874
+ }
875
+ const input = `${b64u(buf(JSON.stringify(header)))}.${b64u(buf(JSON.stringify(claimsSet)))}`;
876
+ const signature = b64u(await crypto.subtle.sign(subtleAlgorithm(key), key, buf(input)));
877
+ return `${input}.${signature}`;
878
+ }
879
+
880
+ let encodeBase64Url;
881
+
882
+ if (Uint8Array.prototype.toBase64) {
883
+ encodeBase64Url = input => {
884
+ if (input instanceof ArrayBuffer) {
885
+ input = new Uint8Array(input);
886
+ }
887
+ return input.toBase64({
888
+ alphabet: "base64url",
889
+ omitPadding: true
890
+ });
891
+ };
892
+ } else {
893
+ const CHUNK_SIZE = 32768;
894
+ encodeBase64Url = input => {
895
+ if (input instanceof ArrayBuffer) {
896
+ input = new Uint8Array(input);
897
+ }
898
+ const arr = [];
899
+ for (let i = 0; i < input.byteLength; i += CHUNK_SIZE) {
900
+ arr.push(String.fromCharCode.apply(null, input.subarray(i, i + CHUNK_SIZE)));
901
+ }
902
+ return btoa(arr.join("")).replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_");
903
+ };
904
+ }
905
+
906
+ function b64u(input) {
907
+ return encodeBase64Url(input);
908
+ }
909
+
910
+ class UnsupportedOperationError extends Error {
911
+ constructor(message) {
912
+ var _a;
913
+ super(message !== null && message !== void 0 ? message : "operation not supported");
914
+ this.name = this.constructor.name;
915
+ (_a = Error.captureStackTrace) === null || _a === void 0 ? void 0 : _a.call(Error, this, this.constructor);
916
+ }
917
+ }
918
+
919
+ class OperationProcessingError extends Error {
920
+ constructor(message) {
921
+ var _a;
922
+ super(message);
923
+ this.name = this.constructor.name;
924
+ (_a = Error.captureStackTrace) === null || _a === void 0 ? void 0 : _a.call(Error, this, this.constructor);
925
+ }
926
+ }
927
+
928
+ function psAlg(key) {
929
+ switch (key.algorithm.hash.name) {
930
+ case "SHA-256":
931
+ return "PS256";
932
+
933
+ default:
934
+ throw new UnsupportedOperationError("unsupported RsaHashedKeyAlgorithm hash name");
935
+ }
936
+ }
937
+
938
+ function rsAlg(key) {
939
+ switch (key.algorithm.hash.name) {
940
+ case "SHA-256":
941
+ return "RS256";
942
+
943
+ default:
944
+ throw new UnsupportedOperationError("unsupported RsaHashedKeyAlgorithm hash name");
945
+ }
946
+ }
947
+
948
+ function esAlg(key) {
949
+ switch (key.algorithm.namedCurve) {
950
+ case "P-256":
951
+ return "ES256";
952
+
953
+ default:
954
+ throw new UnsupportedOperationError("unsupported EcKeyAlgorithm namedCurve");
955
+ }
956
+ }
957
+
958
+ function determineJWSAlgorithm(key) {
959
+ switch (key.algorithm.name) {
960
+ case "RSA-PSS":
961
+ return psAlg(key);
962
+
963
+ case "RSASSA-PKCS1-v1_5":
964
+ return rsAlg(key);
965
+
966
+ case "ECDSA":
967
+ return esAlg(key);
968
+
969
+ case "Ed25519":
970
+ return "Ed25519";
971
+
972
+ default:
973
+ throw new UnsupportedOperationError("unsupported CryptoKey algorithm name");
974
+ }
975
+ }
976
+
977
+ function isCryptoKey(key) {
978
+ return key instanceof CryptoKey;
979
+ }
980
+
981
+ function isPrivateKey(key) {
982
+ return isCryptoKey(key) && key.type === "private";
983
+ }
984
+
985
+ function isPublicKey(key) {
986
+ return isCryptoKey(key) && key.type === "public";
987
+ }
988
+
989
+ function epochTime() {
990
+ return Math.floor(Date.now() / 1e3);
991
+ }
992
+
993
+ async function generateProof$1(keypair, htu, htm, nonce, accessToken, additional) {
994
+ const privateKey = keypair === null || keypair === void 0 ? void 0 : keypair.privateKey;
995
+ const publicKey = keypair === null || keypair === void 0 ? void 0 : keypair.publicKey;
996
+ if (!isPrivateKey(privateKey)) {
997
+ throw new TypeError('"keypair.privateKey" must be a private CryptoKey');
998
+ }
999
+ if (!isPublicKey(publicKey)) {
1000
+ throw new TypeError('"keypair.publicKey" must be a public CryptoKey');
1001
+ }
1002
+ if (publicKey.extractable !== true) {
1003
+ throw new TypeError('"keypair.publicKey.extractable" must be true');
1004
+ }
1005
+ if (typeof htu !== "string") {
1006
+ throw new TypeError('"htu" must be a string');
1007
+ }
1008
+ if (typeof htm !== "string") {
1009
+ throw new TypeError('"htm" must be a string');
1010
+ }
1011
+ if (nonce !== undefined && typeof nonce !== "string") {
1012
+ throw new TypeError('"nonce" must be a string or undefined');
1013
+ }
1014
+ if (accessToken !== undefined && typeof accessToken !== "string") {
1015
+ throw new TypeError('"accessToken" must be a string or undefined');
1016
+ }
1017
+ if (additional !== undefined && (typeof additional !== "object" || additional === null || Array.isArray(additional))) {
1018
+ throw new TypeError('"additional" must be an object');
1019
+ }
1020
+ return jwt({
1021
+ alg: determineJWSAlgorithm(privateKey),
1022
+ typ: "dpop+jwt",
1023
+ jwk: await publicJwk(publicKey)
1024
+ }, Object.assign(Object.assign({}, additional), {
1025
+ iat: epochTime(),
1026
+ jti: crypto.randomUUID(),
1027
+ htm: htm,
1028
+ nonce: nonce,
1029
+ htu: htu,
1030
+ ath: accessToken ? b64u(await crypto.subtle.digest("SHA-256", buf(accessToken))) : undefined
1031
+ }), privateKey);
1032
+ }
1033
+
1034
+ async function publicJwk(key) {
1035
+ const {kty: kty, e: e, n: n, x: x, y: y, crv: crv} = await crypto.subtle.exportKey("jwk", key);
1036
+ return {
1037
+ kty: kty,
1038
+ crv: crv,
1039
+ e: e,
1040
+ n: n,
1041
+ x: x,
1042
+ y: y
1043
+ };
1044
+ }
1045
+
1046
+ async function generateKeyPair$1(alg, options) {
1047
+ var _a;
1048
+ let algorithm;
1049
+ if (typeof alg !== "string" || alg.length === 0) {
1050
+ throw new TypeError('"alg" must be a non-empty string');
1051
+ }
1052
+ switch (alg) {
1053
+ case "PS256":
1054
+ algorithm = {
1055
+ name: "RSA-PSS",
1056
+ hash: "SHA-256",
1057
+ modulusLength: 2048,
1058
+ publicExponent: new Uint8Array([ 1, 0, 1 ])
1059
+ };
1060
+ break;
1061
+
1062
+ case "RS256":
1063
+ algorithm = {
1064
+ name: "RSASSA-PKCS1-v1_5",
1065
+ hash: "SHA-256",
1066
+ modulusLength: 2048,
1067
+ publicExponent: new Uint8Array([ 1, 0, 1 ])
1068
+ };
1069
+ break;
1070
+
1071
+ case "ES256":
1072
+ algorithm = {
1073
+ name: "ECDSA",
1074
+ namedCurve: "P-256"
1075
+ };
1076
+ break;
1077
+
1078
+ case "Ed25519":
1079
+ algorithm = {
1080
+ name: "Ed25519"
1081
+ };
1082
+ break;
1083
+
1084
+ default:
1085
+ throw new UnsupportedOperationError;
1086
+ }
1087
+ return crypto.subtle.generateKey(algorithm, (_a = options === null || options === void 0 ? void 0 : options.extractable) !== null && _a !== void 0 ? _a : false, [ "sign", "verify" ]);
1088
+ }
1089
+
1090
+ async function calculateThumbprint$1(publicKey) {
1091
+ if (!isPublicKey(publicKey)) {
1092
+ throw new TypeError('"publicKey" must be a public CryptoKey');
1093
+ }
1094
+ if (publicKey.extractable !== true) {
1095
+ throw new TypeError('"publicKey.extractable" must be true');
1096
+ }
1097
+ const jwk = await publicJwk(publicKey);
1098
+ let components;
1099
+ switch (jwk.kty) {
1100
+ case "EC":
1101
+ components = {
1102
+ crv: jwk.crv,
1103
+ kty: jwk.kty,
1104
+ x: jwk.x,
1105
+ y: jwk.y
1106
+ };
1107
+ break;
1108
+
1109
+ case "OKP":
1110
+ components = {
1111
+ crv: jwk.crv,
1112
+ kty: jwk.kty,
1113
+ x: jwk.x
1114
+ };
1115
+ break;
1116
+
1117
+ case "RSA":
1118
+ components = {
1119
+ e: jwk.e,
1120
+ kty: jwk.kty,
1121
+ n: jwk.n
1122
+ };
1123
+ break;
1124
+
1125
+ default:
1126
+ throw new UnsupportedOperationError("unsupported JWK kty");
1127
+ }
1128
+ return b64u(await crypto.subtle.digest({
1129
+ name: "SHA-256"
1130
+ }, buf(JSON.stringify(components))));
1131
+ }
1132
+
1133
+ const DPOP_NONCE_HEADER = "dpop-nonce";
1134
+
1135
+ const KEY_PAIR_ALGORITHM = "ES256";
1136
+
1137
+ const SUPPORTED_GRANT_TYPES = [ "authorization_code", "refresh_token", "urn:ietf:params:oauth:grant-type:token-exchange" ];
1138
+
1139
+ function generateKeyPair() {
1140
+ return generateKeyPair$1(KEY_PAIR_ALGORITHM, {
1141
+ extractable: false
1142
+ });
1143
+ }
1144
+
1145
+ function calculateThumbprint(keyPair) {
1146
+ return calculateThumbprint$1(keyPair.publicKey);
1147
+ }
1148
+
1149
+ function normalizeUrl(url) {
1150
+ const parsedUrl = new URL(url);
1151
+ parsedUrl.search = "";
1152
+ parsedUrl.hash = "";
1153
+ return parsedUrl.href;
1154
+ }
1155
+
1156
+ function generateProof({keyPair: keyPair, url: url, method: method, nonce: nonce, accessToken: accessToken}) {
1157
+ const normalizedUrl = normalizeUrl(url);
1158
+ return generateProof$1(keyPair, normalizedUrl, method, nonce, accessToken);
1159
+ }
1160
+
1161
+ function isGrantTypeSupported(grantType) {
1162
+ return SUPPORTED_GRANT_TYPES.includes(grantType);
1163
+ }
1164
+
812
1165
  const sendMessage = (message, to) => new Promise((function(resolve, reject) {
813
1166
  const messageChannel = new MessageChannel;
814
1167
  messageChannel.port1.onmessage = function(event) {
@@ -828,7 +1181,8 @@ const dofetch = async (fetchUrl, fetchOptions) => {
828
1181
  const response = await fetch(fetchUrl, fetchOptions);
829
1182
  return {
830
1183
  ok: response.ok,
831
- json: await response.json()
1184
+ json: await response.json(),
1185
+ headers: fromEntries(response.headers)
832
1186
  };
833
1187
  };
834
1188
 
@@ -865,7 +1219,17 @@ const switchFetch = async (fetchUrl, audience, scope, fetchOptions, worker, useF
865
1219
  }
866
1220
  };
867
1221
 
868
- async function getJSON(url, timeout, audience, scope, options, worker, useFormData) {
1222
+ async function getJSON(url, timeout, audience, scope, options, worker, useFormData, dpop, isDpopRetry) {
1223
+ if (dpop) {
1224
+ const dpopProof = await dpop.generateProof({
1225
+ url: url,
1226
+ method: options.method || "GET",
1227
+ nonce: await dpop.getNonce()
1228
+ });
1229
+ options.headers = Object.assign(Object.assign({}, options.headers), {
1230
+ dpop: dpopProof
1231
+ });
1232
+ }
869
1233
  let fetchError = null;
870
1234
  let response;
871
1235
  for (let i = 0; i < DEFAULT_SILENT_TOKEN_RETRY_COUNT; i++) {
@@ -880,7 +1244,14 @@ async function getJSON(url, timeout, audience, scope, options, worker, useFormDa
880
1244
  if (fetchError) {
881
1245
  throw fetchError;
882
1246
  }
883
- const _a = response.json, {error: error, error_description: error_description} = _a, data = __rest(_a, [ "error", "error_description" ]), {ok: ok} = response;
1247
+ const _a = response.json, {error: error, error_description: error_description} = _a, data = __rest(_a, [ "error", "error_description" ]), {headers: headers, ok: ok} = response;
1248
+ let newDpopNonce;
1249
+ if (dpop) {
1250
+ newDpopNonce = headers[DPOP_NONCE_HEADER];
1251
+ if (newDpopNonce) {
1252
+ await dpop.setNonce(newDpopNonce);
1253
+ }
1254
+ }
884
1255
  if (!ok) {
885
1256
  const errorMessage = error_description || `HTTP error. Unable to fetch ${url}`;
886
1257
  if (error === "mfa_required") {
@@ -889,13 +1260,19 @@ async function getJSON(url, timeout, audience, scope, options, worker, useFormDa
889
1260
  if (error === "missing_refresh_token") {
890
1261
  throw new MissingRefreshTokenError(audience, scope);
891
1262
  }
1263
+ if (error === "use_dpop_nonce") {
1264
+ if (!dpop || !newDpopNonce || isDpopRetry) {
1265
+ throw new UseDpopNonceError(newDpopNonce);
1266
+ }
1267
+ return getJSON(url, timeout, audience, scope, options, worker, useFormData, dpop, true);
1268
+ }
892
1269
  throw new GenericError(error || "request_error", errorMessage);
893
1270
  }
894
1271
  return data;
895
1272
  }
896
1273
 
897
1274
  async function oauthToken(_a, worker) {
898
- var {baseUrl: baseUrl, timeout: timeout, audience: audience, scope: scope, auth0Client: auth0Client, useFormData: useFormData} = _a, options = __rest(_a, [ "baseUrl", "timeout", "audience", "scope", "auth0Client", "useFormData" ]);
1275
+ var {baseUrl: baseUrl, timeout: timeout, audience: audience, scope: scope, auth0Client: auth0Client, useFormData: useFormData, dpop: dpop} = _a, options = __rest(_a, [ "baseUrl", "timeout", "audience", "scope", "auth0Client", "useFormData", "dpop" ]);
899
1276
  const isTokenExchange = options.grant_type === "urn:ietf:params:oauth:grant-type:token-exchange";
900
1277
  const allParams = Object.assign(Object.assign(Object.assign({}, options), isTokenExchange && audience && {
901
1278
  audience: audience
@@ -903,6 +1280,7 @@ async function oauthToken(_a, worker) {
903
1280
  scope: scope
904
1281
  });
905
1282
  const body = useFormData ? createQueryParams(allParams) : JSON.stringify(allParams);
1283
+ const isDpopSupported = isGrantTypeSupported(options.grant_type);
906
1284
  return await getJSON(`${baseUrl}/oauth/token`, timeout, audience || "default", scope, {
907
1285
  method: "POST",
908
1286
  body: body,
@@ -910,7 +1288,7 @@ async function oauthToken(_a, worker) {
910
1288
  "Content-Type": useFormData ? "application/x-www-form-urlencoded" : "application/json",
911
1289
  "Auth0-Client": btoa(JSON.stringify(auth0Client || DEFAULT_AUTH0_CLIENT))
912
1290
  }
913
- }, worker, useFormData);
1291
+ }, worker, useFormData, isDpopSupported ? dpop : undefined);
914
1292
  }
915
1293
 
916
1294
  const dedupe = arr => Array.from(new Set(arr));
@@ -1483,7 +1861,7 @@ function createBase64WorkerFactory(base64, sourcemapArg, enableUnicodeArg) {
1483
1861
  };
1484
1862
  }
1485
1863
 
1486
- var WorkerFactory = createBase64WorkerFactory("Lyogcm9sbHVwLXBsdWdpbi13ZWItd29ya2VyLWxvYWRlciAqLwooZnVuY3Rpb24oKSB7CiAgICAidXNlIHN0cmljdCI7CiAgICBjbGFzcyBHZW5lcmljRXJyb3IgZXh0ZW5kcyBFcnJvciB7CiAgICAgICAgY29uc3RydWN0b3IoZXJyb3IsIGVycm9yX2Rlc2NyaXB0aW9uKSB7CiAgICAgICAgICAgIHN1cGVyKGVycm9yX2Rlc2NyaXB0aW9uKTsKICAgICAgICAgICAgdGhpcy5lcnJvciA9IGVycm9yOwogICAgICAgICAgICB0aGlzLmVycm9yX2Rlc2NyaXB0aW9uID0gZXJyb3JfZGVzY3JpcHRpb247CiAgICAgICAgICAgIE9iamVjdC5zZXRQcm90b3R5cGVPZih0aGlzLCBHZW5lcmljRXJyb3IucHJvdG90eXBlKTsKICAgICAgICB9CiAgICAgICAgc3RhdGljIGZyb21QYXlsb2FkKHtlcnJvcjogZXJyb3IsIGVycm9yX2Rlc2NyaXB0aW9uOiBlcnJvcl9kZXNjcmlwdGlvbn0pIHsKICAgICAgICAgICAgcmV0dXJuIG5ldyBHZW5lcmljRXJyb3IoZXJyb3IsIGVycm9yX2Rlc2NyaXB0aW9uKTsKICAgICAgICB9CiAgICB9CiAgICBjbGFzcyBNaXNzaW5nUmVmcmVzaFRva2VuRXJyb3IgZXh0ZW5kcyBHZW5lcmljRXJyb3IgewogICAgICAgIGNvbnN0cnVjdG9yKGF1ZGllbmNlLCBzY29wZSkgewogICAgICAgICAgICBzdXBlcigibWlzc2luZ19yZWZyZXNoX3Rva2VuIiwgYE1pc3NpbmcgUmVmcmVzaCBUb2tlbiAoYXVkaWVuY2U6ICcke3ZhbHVlT3JFbXB0eVN0cmluZyhhdWRpZW5jZSwgWyAiZGVmYXVsdCIgXSl9Jywgc2NvcGU6ICcke3ZhbHVlT3JFbXB0eVN0cmluZyhzY29wZSl9JylgKTsKICAgICAgICAgICAgdGhpcy5hdWRpZW5jZSA9IGF1ZGllbmNlOwogICAgICAgICAgICB0aGlzLnNjb3BlID0gc2NvcGU7CiAgICAgICAgICAgIE9iamVjdC5zZXRQcm90b3R5cGVPZih0aGlzLCBNaXNzaW5nUmVmcmVzaFRva2VuRXJyb3IucHJvdG90eXBlKTsKICAgICAgICB9CiAgICB9CiAgICBmdW5jdGlvbiB2YWx1ZU9yRW1wdHlTdHJpbmcodmFsdWUsIGV4Y2x1ZGUgPSBbXSkgewogICAgICAgIHJldHVybiB2YWx1ZSAmJiAhZXhjbHVkZS5pbmNsdWRlcyh2YWx1ZSkgPyB2YWx1ZSA6ICIiOwogICAgfQogICAgZnVuY3Rpb24gX19yZXN0KHMsIGUpIHsKICAgICAgICB2YXIgdCA9IHt9OwogICAgICAgIGZvciAodmFyIHAgaW4gcykgaWYgKE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChzLCBwKSAmJiBlLmluZGV4T2YocCkgPCAwKSB0W3BdID0gc1twXTsKICAgICAgICBpZiAocyAhPSBudWxsICYmIHR5cGVvZiBPYmplY3QuZ2V0T3duUHJvcGVydHlTeW1ib2xzID09PSAiZnVuY3Rpb24iKSBmb3IgKHZhciBpID0gMCwgcCA9IE9iamVjdC5nZXRPd25Qcm9wZXJ0eVN5bWJvbHMocyk7IGkgPCBwLmxlbmd0aDsgaSsrKSB7CiAgICAgICAgICAgIGlmIChlLmluZGV4T2YocFtpXSkgPCAwICYmIE9iamVjdC5wcm90b3R5cGUucHJvcGVydHlJc0VudW1lcmFibGUuY2FsbChzLCBwW2ldKSkgdFtwW2ldXSA9IHNbcFtpXV07CiAgICAgICAgfQogICAgICAgIHJldHVybiB0OwogICAgfQogICAgdHlwZW9mIFN1cHByZXNzZWRFcnJvciA9PT0gImZ1bmN0aW9uIiA/IFN1cHByZXNzZWRFcnJvciA6IGZ1bmN0aW9uKGVycm9yLCBzdXBwcmVzc2VkLCBtZXNzYWdlKSB7CiAgICAgICAgdmFyIGUgPSBuZXcgRXJyb3IobWVzc2FnZSk7CiAgICAgICAgcmV0dXJuIGUubmFtZSA9ICJTdXBwcmVzc2VkRXJyb3IiLCBlLmVycm9yID0gZXJyb3IsIGUuc3VwcHJlc3NlZCA9IHN1cHByZXNzZWQsIGU7CiAgICB9OwogICAgY29uc3Qgc3RyaXBVbmRlZmluZWQgPSBwYXJhbXMgPT4gT2JqZWN0LmtleXMocGFyYW1zKS5maWx0ZXIoKGsgPT4gdHlwZW9mIHBhcmFtc1trXSAhPT0gInVuZGVmaW5lZCIpKS5yZWR1Y2UoKChhY2MsIGtleSkgPT4gT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBhY2MpLCB7CiAgICAgICAgW2tleV06IHBhcmFtc1trZXldCiAgICB9KSksIHt9KTsKICAgIGNvbnN0IGNyZWF0ZVF1ZXJ5UGFyYW1zID0gX2EgPT4gewogICAgICAgIHZhciB7Y2xpZW50SWQ6IGNsaWVudF9pZH0gPSBfYSwgcGFyYW1zID0gX19yZXN0KF9hLCBbICJjbGllbnRJZCIgXSk7CiAgICAgICAgcmV0dXJuIG5ldyBVUkxTZWFyY2hQYXJhbXMoc3RyaXBVbmRlZmluZWQoT2JqZWN0LmFzc2lnbih7CiAgICAgICAgICAgIGNsaWVudF9pZDogY2xpZW50X2lkCiAgICAgICAgfSwgcGFyYW1zKSkpLnRvU3RyaW5nKCk7CiAgICB9OwogICAgbGV0IHJlZnJlc2hUb2tlbnMgPSB7fTsKICAgIGNvbnN0IGNhY2hlS2V5ID0gKGF1ZGllbmNlLCBzY29wZSkgPT4gYCR7YXVkaWVuY2V9fCR7c2NvcGV9YDsKICAgIGNvbnN0IGdldFJlZnJlc2hUb2tlbiA9IChhdWRpZW5jZSwgc2NvcGUpID0+IHJlZnJlc2hUb2tlbnNbY2FjaGVLZXkoYXVkaWVuY2UsIHNjb3BlKV07CiAgICBjb25zdCBzZXRSZWZyZXNoVG9rZW4gPSAocmVmcmVzaFRva2VuLCBhdWRpZW5jZSwgc2NvcGUpID0+IHJlZnJlc2hUb2tlbnNbY2FjaGVLZXkoYXVkaWVuY2UsIHNjb3BlKV0gPSByZWZyZXNoVG9rZW47CiAgICBjb25zdCBkZWxldGVSZWZyZXNoVG9rZW4gPSAoYXVkaWVuY2UsIHNjb3BlKSA9PiBkZWxldGUgcmVmcmVzaFRva2Vuc1tjYWNoZUtleShhdWRpZW5jZSwgc2NvcGUpXTsKICAgIGNvbnN0IHdhaXQgPSB0aW1lID0+IG5ldyBQcm9taXNlKChyZXNvbHZlID0+IHNldFRpbWVvdXQocmVzb2x2ZSwgdGltZSkpKTsKICAgIGNvbnN0IGZvcm1EYXRhVG9PYmplY3QgPSBmb3JtRGF0YSA9PiB7CiAgICAgICAgY29uc3QgcXVlcnlQYXJhbXMgPSBuZXcgVVJMU2VhcmNoUGFyYW1zKGZvcm1EYXRhKTsKICAgICAgICBjb25zdCBwYXJzZWRRdWVyeSA9IHt9OwogICAgICAgIHF1ZXJ5UGFyYW1zLmZvckVhY2goKCh2YWwsIGtleSkgPT4gewogICAgICAgICAgICBwYXJzZWRRdWVyeVtrZXldID0gdmFsOwogICAgICAgIH0pKTsKICAgICAgICByZXR1cm4gcGFyc2VkUXVlcnk7CiAgICB9OwogICAgY29uc3QgbWVzc2FnZUhhbmRsZXIgPSBhc3luYyAoe2RhdGE6IHt0aW1lb3V0OiB0aW1lb3V0LCBhdXRoOiBhdXRoLCBmZXRjaFVybDogZmV0Y2hVcmwsIGZldGNoT3B0aW9uczogZmV0Y2hPcHRpb25zLCB1c2VGb3JtRGF0YTogdXNlRm9ybURhdGF9LCBwb3J0czogW3BvcnRdfSkgPT4gewogICAgICAgIGxldCBqc29uOwogICAgICAgIGNvbnN0IHthdWRpZW5jZTogYXVkaWVuY2UsIHNjb3BlOiBzY29wZX0gPSBhdXRoIHx8IHt9OwogICAgICAgIHRyeSB7CiAgICAgICAgICAgIGNvbnN0IGJvZHkgPSB1c2VGb3JtRGF0YSA/IGZvcm1EYXRhVG9PYmplY3QoZmV0Y2hPcHRpb25zLmJvZHkpIDogSlNPTi5wYXJzZShmZXRjaE9wdGlvbnMuYm9keSk7CiAgICAgICAgICAgIGlmICghYm9keS5yZWZyZXNoX3Rva2VuICYmIGJvZHkuZ3JhbnRfdHlwZSA9PT0gInJlZnJlc2hfdG9rZW4iKSB7CiAgICAgICAgICAgICAgICBjb25zdCByZWZyZXNoVG9rZW4gPSBnZXRSZWZyZXNoVG9rZW4oYXVkaWVuY2UsIHNjb3BlKTsKICAgICAgICAgICAgICAgIGlmICghcmVmcmVzaFRva2VuKSB7CiAgICAgICAgICAgICAgICAgICAgdGhyb3cgbmV3IE1pc3NpbmdSZWZyZXNoVG9rZW5FcnJvcihhdWRpZW5jZSwgc2NvcGUpOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgZmV0Y2hPcHRpb25zLmJvZHkgPSB1c2VGb3JtRGF0YSA/IGNyZWF0ZVF1ZXJ5UGFyYW1zKE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgYm9keSksIHsKICAgICAgICAgICAgICAgICAgICByZWZyZXNoX3Rva2VuOiByZWZyZXNoVG9rZW4KICAgICAgICAgICAgICAgIH0pKSA6IEpTT04uc3RyaW5naWZ5KE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgYm9keSksIHsKICAgICAgICAgICAgICAgICAgICByZWZyZXNoX3Rva2VuOiByZWZyZXNoVG9rZW4KICAgICAgICAgICAgICAgIH0pKTsKICAgICAgICAgICAgfQogICAgICAgICAgICBsZXQgYWJvcnRDb250cm9sbGVyOwogICAgICAgICAgICBpZiAodHlwZW9mIEFib3J0Q29udHJvbGxlciA9PT0gImZ1bmN0aW9uIikgewogICAgICAgICAgICAgICAgYWJvcnRDb250cm9sbGVyID0gbmV3IEFib3J0Q29udHJvbGxlcjsKICAgICAgICAgICAgICAgIGZldGNoT3B0aW9ucy5zaWduYWwgPSBhYm9ydENvbnRyb2xsZXIuc2lnbmFsOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGxldCByZXNwb25zZTsKICAgICAgICAgICAgdHJ5IHsKICAgICAgICAgICAgICAgIHJlc3BvbnNlID0gYXdhaXQgUHJvbWlzZS5yYWNlKFsgd2FpdCh0aW1lb3V0KSwgZmV0Y2goZmV0Y2hVcmwsIE9iamVjdC5hc3NpZ24oe30sIGZldGNoT3B0aW9ucykpIF0pOwogICAgICAgICAgICB9IGNhdGNoIChlcnJvcikgewogICAgICAgICAgICAgICAgcG9ydC5wb3N0TWVzc2FnZSh7CiAgICAgICAgICAgICAgICAgICAgZXJyb3I6IGVycm9yLm1lc3NhZ2UKICAgICAgICAgICAgICAgIH0pOwogICAgICAgICAgICAgICAgcmV0dXJuOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGlmICghcmVzcG9uc2UpIHsKICAgICAgICAgICAgICAgIGlmIChhYm9ydENvbnRyb2xsZXIpIGFib3J0Q29udHJvbGxlci5hYm9ydCgpOwogICAgICAgICAgICAgICAgcG9ydC5wb3N0TWVzc2FnZSh7CiAgICAgICAgICAgICAgICAgICAgZXJyb3I6ICJUaW1lb3V0IHdoZW4gZXhlY3V0aW5nICdmZXRjaCciCiAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgICAgIHJldHVybjsKICAgICAgICAgICAgfQogICAgICAgICAgICBqc29uID0gYXdhaXQgcmVzcG9uc2UuanNvbigpOwogICAgICAgICAgICBpZiAoanNvbi5yZWZyZXNoX3Rva2VuKSB7CiAgICAgICAgICAgICAgICBzZXRSZWZyZXNoVG9rZW4oanNvbi5yZWZyZXNoX3Rva2VuLCBhdWRpZW5jZSwgc2NvcGUpOwogICAgICAgICAgICAgICAgZGVsZXRlIGpzb24ucmVmcmVzaF90b2tlbjsKICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgIGRlbGV0ZVJlZnJlc2hUb2tlbihhdWRpZW5jZSwgc2NvcGUpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHBvcnQucG9zdE1lc3NhZ2UoewogICAgICAgICAgICAgICAgb2s6IHJlc3BvbnNlLm9rLAogICAgICAgICAgICAgICAganNvbjoganNvbgogICAgICAgICAgICB9KTsKICAgICAgICB9IGNhdGNoIChlcnJvcikgewogICAgICAgICAgICBwb3J0LnBvc3RNZXNzYWdlKHsKICAgICAgICAgICAgICAgIG9rOiBmYWxzZSwKICAgICAgICAgICAgICAgIGpzb246IHsKICAgICAgICAgICAgICAgICAgICBlcnJvcjogZXJyb3IuZXJyb3IsCiAgICAgICAgICAgICAgICAgICAgZXJyb3JfZGVzY3JpcHRpb246IGVycm9yLm1lc3NhZ2UKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfSk7CiAgICAgICAgfQogICAgfTsKICAgIHsKICAgICAgICBhZGRFdmVudExpc3RlbmVyKCJtZXNzYWdlIiwgbWVzc2FnZUhhbmRsZXIpOwogICAgfQp9KSgpOwoK", null, false);
1864
+ var WorkerFactory = createBase64WorkerFactory("Lyogcm9sbHVwLXBsdWdpbi13ZWItd29ya2VyLWxvYWRlciAqLwooZnVuY3Rpb24oKSB7CiAgICAidXNlIHN0cmljdCI7CiAgICBjbGFzcyBHZW5lcmljRXJyb3IgZXh0ZW5kcyBFcnJvciB7CiAgICAgICAgY29uc3RydWN0b3IoZXJyb3IsIGVycm9yX2Rlc2NyaXB0aW9uKSB7CiAgICAgICAgICAgIHN1cGVyKGVycm9yX2Rlc2NyaXB0aW9uKTsKICAgICAgICAgICAgdGhpcy5lcnJvciA9IGVycm9yOwogICAgICAgICAgICB0aGlzLmVycm9yX2Rlc2NyaXB0aW9uID0gZXJyb3JfZGVzY3JpcHRpb247CiAgICAgICAgICAgIE9iamVjdC5zZXRQcm90b3R5cGVPZih0aGlzLCBHZW5lcmljRXJyb3IucHJvdG90eXBlKTsKICAgICAgICB9CiAgICAgICAgc3RhdGljIGZyb21QYXlsb2FkKHtlcnJvcjogZXJyb3IsIGVycm9yX2Rlc2NyaXB0aW9uOiBlcnJvcl9kZXNjcmlwdGlvbn0pIHsKICAgICAgICAgICAgcmV0dXJuIG5ldyBHZW5lcmljRXJyb3IoZXJyb3IsIGVycm9yX2Rlc2NyaXB0aW9uKTsKICAgICAgICB9CiAgICB9CiAgICBjbGFzcyBNaXNzaW5nUmVmcmVzaFRva2VuRXJyb3IgZXh0ZW5kcyBHZW5lcmljRXJyb3IgewogICAgICAgIGNvbnN0cnVjdG9yKGF1ZGllbmNlLCBzY29wZSkgewogICAgICAgICAgICBzdXBlcigibWlzc2luZ19yZWZyZXNoX3Rva2VuIiwgYE1pc3NpbmcgUmVmcmVzaCBUb2tlbiAoYXVkaWVuY2U6ICcke3ZhbHVlT3JFbXB0eVN0cmluZyhhdWRpZW5jZSwgWyAiZGVmYXVsdCIgXSl9Jywgc2NvcGU6ICcke3ZhbHVlT3JFbXB0eVN0cmluZyhzY29wZSl9JylgKTsKICAgICAgICAgICAgdGhpcy5hdWRpZW5jZSA9IGF1ZGllbmNlOwogICAgICAgICAgICB0aGlzLnNjb3BlID0gc2NvcGU7CiAgICAgICAgICAgIE9iamVjdC5zZXRQcm90b3R5cGVPZih0aGlzLCBNaXNzaW5nUmVmcmVzaFRva2VuRXJyb3IucHJvdG90eXBlKTsKICAgICAgICB9CiAgICB9CiAgICBmdW5jdGlvbiB2YWx1ZU9yRW1wdHlTdHJpbmcodmFsdWUsIGV4Y2x1ZGUgPSBbXSkgewogICAgICAgIHJldHVybiB2YWx1ZSAmJiAhZXhjbHVkZS5pbmNsdWRlcyh2YWx1ZSkgPyB2YWx1ZSA6ICIiOwogICAgfQogICAgZnVuY3Rpb24gX19yZXN0KHMsIGUpIHsKICAgICAgICB2YXIgdCA9IHt9OwogICAgICAgIGZvciAodmFyIHAgaW4gcykgaWYgKE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChzLCBwKSAmJiBlLmluZGV4T2YocCkgPCAwKSB0W3BdID0gc1twXTsKICAgICAgICBpZiAocyAhPSBudWxsICYmIHR5cGVvZiBPYmplY3QuZ2V0T3duUHJvcGVydHlTeW1ib2xzID09PSAiZnVuY3Rpb24iKSBmb3IgKHZhciBpID0gMCwgcCA9IE9iamVjdC5nZXRPd25Qcm9wZXJ0eVN5bWJvbHMocyk7IGkgPCBwLmxlbmd0aDsgaSsrKSB7CiAgICAgICAgICAgIGlmIChlLmluZGV4T2YocFtpXSkgPCAwICYmIE9iamVjdC5wcm90b3R5cGUucHJvcGVydHlJc0VudW1lcmFibGUuY2FsbChzLCBwW2ldKSkgdFtwW2ldXSA9IHNbcFtpXV07CiAgICAgICAgfQogICAgICAgIHJldHVybiB0OwogICAgfQogICAgdHlwZW9mIFN1cHByZXNzZWRFcnJvciA9PT0gImZ1bmN0aW9uIiA/IFN1cHByZXNzZWRFcnJvciA6IGZ1bmN0aW9uKGVycm9yLCBzdXBwcmVzc2VkLCBtZXNzYWdlKSB7CiAgICAgICAgdmFyIGUgPSBuZXcgRXJyb3IobWVzc2FnZSk7CiAgICAgICAgcmV0dXJuIGUubmFtZSA9ICJTdXBwcmVzc2VkRXJyb3IiLCBlLmVycm9yID0gZXJyb3IsIGUuc3VwcHJlc3NlZCA9IHN1cHByZXNzZWQsIGU7CiAgICB9OwogICAgY29uc3Qgc3RyaXBVbmRlZmluZWQgPSBwYXJhbXMgPT4gT2JqZWN0LmtleXMocGFyYW1zKS5maWx0ZXIoKGsgPT4gdHlwZW9mIHBhcmFtc1trXSAhPT0gInVuZGVmaW5lZCIpKS5yZWR1Y2UoKChhY2MsIGtleSkgPT4gT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBhY2MpLCB7CiAgICAgICAgW2tleV06IHBhcmFtc1trZXldCiAgICB9KSksIHt9KTsKICAgIGNvbnN0IGNyZWF0ZVF1ZXJ5UGFyYW1zID0gX2EgPT4gewogICAgICAgIHZhciB7Y2xpZW50SWQ6IGNsaWVudF9pZH0gPSBfYSwgcGFyYW1zID0gX19yZXN0KF9hLCBbICJjbGllbnRJZCIgXSk7CiAgICAgICAgcmV0dXJuIG5ldyBVUkxTZWFyY2hQYXJhbXMoc3RyaXBVbmRlZmluZWQoT2JqZWN0LmFzc2lnbih7CiAgICAgICAgICAgIGNsaWVudF9pZDogY2xpZW50X2lkCiAgICAgICAgfSwgcGFyYW1zKSkpLnRvU3RyaW5nKCk7CiAgICB9OwogICAgY29uc3QgZnJvbUVudHJpZXMgPSBpdGVyYWJsZSA9PiBbIC4uLml0ZXJhYmxlIF0ucmVkdWNlKCgob2JqLCBba2V5LCB2YWxdKSA9PiB7CiAgICAgICAgb2JqW2tleV0gPSB2YWw7CiAgICAgICAgcmV0dXJuIG9iajsKICAgIH0pLCB7fSk7CiAgICBsZXQgcmVmcmVzaFRva2VucyA9IHt9OwogICAgY29uc3QgY2FjaGVLZXkgPSAoYXVkaWVuY2UsIHNjb3BlKSA9PiBgJHthdWRpZW5jZX18JHtzY29wZX1gOwogICAgY29uc3QgZ2V0UmVmcmVzaFRva2VuID0gKGF1ZGllbmNlLCBzY29wZSkgPT4gcmVmcmVzaFRva2Vuc1tjYWNoZUtleShhdWRpZW5jZSwgc2NvcGUpXTsKICAgIGNvbnN0IHNldFJlZnJlc2hUb2tlbiA9IChyZWZyZXNoVG9rZW4sIGF1ZGllbmNlLCBzY29wZSkgPT4gcmVmcmVzaFRva2Vuc1tjYWNoZUtleShhdWRpZW5jZSwgc2NvcGUpXSA9IHJlZnJlc2hUb2tlbjsKICAgIGNvbnN0IGRlbGV0ZVJlZnJlc2hUb2tlbiA9IChhdWRpZW5jZSwgc2NvcGUpID0+IGRlbGV0ZSByZWZyZXNoVG9rZW5zW2NhY2hlS2V5KGF1ZGllbmNlLCBzY29wZSldOwogICAgY29uc3Qgd2FpdCA9IHRpbWUgPT4gbmV3IFByb21pc2UoKHJlc29sdmUgPT4gc2V0VGltZW91dChyZXNvbHZlLCB0aW1lKSkpOwogICAgY29uc3QgZm9ybURhdGFUb09iamVjdCA9IGZvcm1EYXRhID0+IHsKICAgICAgICBjb25zdCBxdWVyeVBhcmFtcyA9IG5ldyBVUkxTZWFyY2hQYXJhbXMoZm9ybURhdGEpOwogICAgICAgIGNvbnN0IHBhcnNlZFF1ZXJ5ID0ge307CiAgICAgICAgcXVlcnlQYXJhbXMuZm9yRWFjaCgoKHZhbCwga2V5KSA9PiB7CiAgICAgICAgICAgIHBhcnNlZFF1ZXJ5W2tleV0gPSB2YWw7CiAgICAgICAgfSkpOwogICAgICAgIHJldHVybiBwYXJzZWRRdWVyeTsKICAgIH07CiAgICBjb25zdCBtZXNzYWdlSGFuZGxlciA9IGFzeW5jICh7ZGF0YToge3RpbWVvdXQ6IHRpbWVvdXQsIGF1dGg6IGF1dGgsIGZldGNoVXJsOiBmZXRjaFVybCwgZmV0Y2hPcHRpb25zOiBmZXRjaE9wdGlvbnMsIHVzZUZvcm1EYXRhOiB1c2VGb3JtRGF0YX0sIHBvcnRzOiBbcG9ydF19KSA9PiB7CiAgICAgICAgbGV0IGhlYWRlcnMgPSB7fTsKICAgICAgICBsZXQganNvbjsKICAgICAgICBjb25zdCB7YXVkaWVuY2U6IGF1ZGllbmNlLCBzY29wZTogc2NvcGV9ID0gYXV0aCB8fCB7fTsKICAgICAgICB0cnkgewogICAgICAgICAgICBjb25zdCBib2R5ID0gdXNlRm9ybURhdGEgPyBmb3JtRGF0YVRvT2JqZWN0KGZldGNoT3B0aW9ucy5ib2R5KSA6IEpTT04ucGFyc2UoZmV0Y2hPcHRpb25zLmJvZHkpOwogICAgICAgICAgICBpZiAoIWJvZHkucmVmcmVzaF90b2tlbiAmJiBib2R5LmdyYW50X3R5cGUgPT09ICJyZWZyZXNoX3Rva2VuIikgewogICAgICAgICAgICAgICAgY29uc3QgcmVmcmVzaFRva2VuID0gZ2V0UmVmcmVzaFRva2VuKGF1ZGllbmNlLCBzY29wZSk7CiAgICAgICAgICAgICAgICBpZiAoIXJlZnJlc2hUb2tlbikgewogICAgICAgICAgICAgICAgICAgIHRocm93IG5ldyBNaXNzaW5nUmVmcmVzaFRva2VuRXJyb3IoYXVkaWVuY2UsIHNjb3BlKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIGZldGNoT3B0aW9ucy5ib2R5ID0gdXNlRm9ybURhdGEgPyBjcmVhdGVRdWVyeVBhcmFtcyhPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIGJvZHkpLCB7CiAgICAgICAgICAgICAgICAgICAgcmVmcmVzaF90b2tlbjogcmVmcmVzaFRva2VuCiAgICAgICAgICAgICAgICB9KSkgOiBKU09OLnN0cmluZ2lmeShPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIGJvZHkpLCB7CiAgICAgICAgICAgICAgICAgICAgcmVmcmVzaF90b2tlbjogcmVmcmVzaFRva2VuCiAgICAgICAgICAgICAgICB9KSk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgbGV0IGFib3J0Q29udHJvbGxlcjsKICAgICAgICAgICAgaWYgKHR5cGVvZiBBYm9ydENvbnRyb2xsZXIgPT09ICJmdW5jdGlvbiIpIHsKICAgICAgICAgICAgICAgIGFib3J0Q29udHJvbGxlciA9IG5ldyBBYm9ydENvbnRyb2xsZXI7CiAgICAgICAgICAgICAgICBmZXRjaE9wdGlvbnMuc2lnbmFsID0gYWJvcnRDb250cm9sbGVyLnNpZ25hbDsKICAgICAgICAgICAgfQogICAgICAgICAgICBsZXQgcmVzcG9uc2U7CiAgICAgICAgICAgIHRyeSB7CiAgICAgICAgICAgICAgICByZXNwb25zZSA9IGF3YWl0IFByb21pc2UucmFjZShbIHdhaXQodGltZW91dCksIGZldGNoKGZldGNoVXJsLCBPYmplY3QuYXNzaWduKHt9LCBmZXRjaE9wdGlvbnMpKSBdKTsKICAgICAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHsKICAgICAgICAgICAgICAgIHBvcnQucG9zdE1lc3NhZ2UoewogICAgICAgICAgICAgICAgICAgIGVycm9yOiBlcnJvci5tZXNzYWdlCiAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgICAgIHJldHVybjsKICAgICAgICAgICAgfQogICAgICAgICAgICBpZiAoIXJlc3BvbnNlKSB7CiAgICAgICAgICAgICAgICBpZiAoYWJvcnRDb250cm9sbGVyKSBhYm9ydENvbnRyb2xsZXIuYWJvcnQoKTsKICAgICAgICAgICAgICAgIHBvcnQucG9zdE1lc3NhZ2UoewogICAgICAgICAgICAgICAgICAgIGVycm9yOiAiVGltZW91dCB3aGVuIGV4ZWN1dGluZyAnZmV0Y2gnIgogICAgICAgICAgICAgICAgfSk7CiAgICAgICAgICAgICAgICByZXR1cm47CiAgICAgICAgICAgIH0KICAgICAgICAgICAgaGVhZGVycyA9IGZyb21FbnRyaWVzKHJlc3BvbnNlLmhlYWRlcnMpOwogICAgICAgICAgICBqc29uID0gYXdhaXQgcmVzcG9uc2UuanNvbigpOwogICAgICAgICAgICBpZiAoanNvbi5yZWZyZXNoX3Rva2VuKSB7CiAgICAgICAgICAgICAgICBzZXRSZWZyZXNoVG9rZW4oanNvbi5yZWZyZXNoX3Rva2VuLCBhdWRpZW5jZSwgc2NvcGUpOwogICAgICAgICAgICAgICAgZGVsZXRlIGpzb24ucmVmcmVzaF90b2tlbjsKICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgIGRlbGV0ZVJlZnJlc2hUb2tlbihhdWRpZW5jZSwgc2NvcGUpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHBvcnQucG9zdE1lc3NhZ2UoewogICAgICAgICAgICAgICAgb2s6IHJlc3BvbnNlLm9rLAogICAgICAgICAgICAgICAganNvbjoganNvbiwKICAgICAgICAgICAgICAgIGhlYWRlcnM6IGhlYWRlcnMKICAgICAgICAgICAgfSk7CiAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHsKICAgICAgICAgICAgcG9ydC5wb3N0TWVzc2FnZSh7CiAgICAgICAgICAgICAgICBvazogZmFsc2UsCiAgICAgICAgICAgICAgICBqc29uOiB7CiAgICAgICAgICAgICAgICAgICAgZXJyb3I6IGVycm9yLmVycm9yLAogICAgICAgICAgICAgICAgICAgIGVycm9yX2Rlc2NyaXB0aW9uOiBlcnJvci5tZXNzYWdlCiAgICAgICAgICAgICAgICB9LAogICAgICAgICAgICAgICAgaGVhZGVyczogaGVhZGVycwogICAgICAgICAgICB9KTsKICAgICAgICB9CiAgICB9OwogICAgewogICAgICAgIGFkZEV2ZW50TGlzdGVuZXIoIm1lc3NhZ2UiLCBtZXNzYWdlSGFuZGxlcik7CiAgICB9Cn0pKCk7Cgo=", null, false);
1487
1865
 
1488
1866
  const singlePromiseMap = {};
1489
1867
 
@@ -1561,7 +1939,7 @@ const cacheLocationBuilders = {
1561
1939
 
1562
1940
  const cacheFactory = location => cacheLocationBuilders[location];
1563
1941
 
1564
- const getAuthorizeParams = (clientOptions, scope, authorizationParams, state, nonce, code_challenge, redirect_uri, response_mode) => Object.assign(Object.assign(Object.assign({
1942
+ const getAuthorizeParams = (clientOptions, scope, authorizationParams, state, nonce, code_challenge, redirect_uri, response_mode, thumbprint) => Object.assign(Object.assign(Object.assign({
1565
1943
  client_id: clientOptions.clientId
1566
1944
  }, clientOptions.authorizationParams), authorizationParams), {
1567
1945
  scope: getUniqueScopes(scope, authorizationParams.scope),
@@ -1571,7 +1949,8 @@ const getAuthorizeParams = (clientOptions, scope, authorizationParams, state, no
1571
1949
  nonce: nonce,
1572
1950
  redirect_uri: redirect_uri || clientOptions.authorizationParams.redirect_uri,
1573
1951
  code_challenge: code_challenge,
1574
- code_challenge_method: "S256"
1952
+ code_challenge_method: "S256",
1953
+ dpop_jkt: thumbprint
1575
1954
  });
1576
1955
 
1577
1956
  const patchOpenUrlWithOnRedirect = options => {
@@ -1582,6 +1961,215 @@ const patchOpenUrlWithOnRedirect = options => {
1582
1961
  return result;
1583
1962
  };
1584
1963
 
1964
+ const VERSION = 1;
1965
+
1966
+ const NAME = "auth0-spa-js";
1967
+
1968
+ const TABLES = {
1969
+ NONCE: "nonce",
1970
+ KEYPAIR: "keypair"
1971
+ };
1972
+
1973
+ const AUTH0_NONCE_ID = "auth0";
1974
+
1975
+ class DpopStorage {
1976
+ constructor(clientId) {
1977
+ this.clientId = clientId;
1978
+ }
1979
+ getVersion() {
1980
+ return VERSION;
1981
+ }
1982
+ createDbHandle() {
1983
+ const req = window.indexedDB.open(NAME, this.getVersion());
1984
+ return new Promise(((resolve, reject) => {
1985
+ req.onupgradeneeded = () => Object.values(TABLES).forEach((t => req.result.createObjectStore(t)));
1986
+ req.onerror = () => reject(req.error);
1987
+ req.onsuccess = () => resolve(req.result);
1988
+ }));
1989
+ }
1990
+ async getDbHandle() {
1991
+ if (!this.dbHandle) {
1992
+ this.dbHandle = await this.createDbHandle();
1993
+ }
1994
+ return this.dbHandle;
1995
+ }
1996
+ async executeDbRequest(table, mode, requestFactory) {
1997
+ const db = await this.getDbHandle();
1998
+ const txn = db.transaction(table, mode);
1999
+ const store = txn.objectStore(table);
2000
+ const request = requestFactory(store);
2001
+ return new Promise(((resolve, reject) => {
2002
+ request.onsuccess = () => resolve(request.result);
2003
+ request.onerror = () => reject(request.error);
2004
+ }));
2005
+ }
2006
+ buildKey(id) {
2007
+ const finalId = id ? `_${id}` : AUTH0_NONCE_ID;
2008
+ return `${this.clientId}::${finalId}`;
2009
+ }
2010
+ setNonce(nonce, id) {
2011
+ return this.save(TABLES.NONCE, this.buildKey(id), nonce);
2012
+ }
2013
+ setKeyPair(keyPair) {
2014
+ return this.save(TABLES.KEYPAIR, this.buildKey(), keyPair);
2015
+ }
2016
+ async save(table, key, obj) {
2017
+ return void await this.executeDbRequest(table, "readwrite", (table => table.put(obj, key)));
2018
+ }
2019
+ findNonce(id) {
2020
+ return this.find(TABLES.NONCE, this.buildKey(id));
2021
+ }
2022
+ findKeyPair() {
2023
+ return this.find(TABLES.KEYPAIR, this.buildKey());
2024
+ }
2025
+ find(table, key) {
2026
+ return this.executeDbRequest(table, "readonly", (table => table.get(key)));
2027
+ }
2028
+ async deleteBy(table, predicate) {
2029
+ const allKeys = await this.executeDbRequest(table, "readonly", (table => table.getAllKeys()));
2030
+ allKeys === null || allKeys === void 0 ? void 0 : allKeys.filter(predicate).map((k => this.executeDbRequest(table, "readwrite", (table => table.delete(k)))));
2031
+ }
2032
+ deleteByClientId(table, clientId) {
2033
+ return this.deleteBy(table, (k => typeof k === "string" && k.startsWith(`${clientId}::`)));
2034
+ }
2035
+ clearNonces() {
2036
+ return this.deleteByClientId(TABLES.NONCE, this.clientId);
2037
+ }
2038
+ clearKeyPairs() {
2039
+ return this.deleteByClientId(TABLES.KEYPAIR, this.clientId);
2040
+ }
2041
+ }
2042
+
2043
+ class Dpop {
2044
+ constructor(clientId) {
2045
+ this.storage = new DpopStorage(clientId);
2046
+ }
2047
+ getNonce(id) {
2048
+ return this.storage.findNonce(id);
2049
+ }
2050
+ setNonce(nonce, id) {
2051
+ return this.storage.setNonce(nonce, id);
2052
+ }
2053
+ async getOrGenerateKeyPair() {
2054
+ let keyPair = await this.storage.findKeyPair();
2055
+ if (!keyPair) {
2056
+ keyPair = await generateKeyPair();
2057
+ await this.storage.setKeyPair(keyPair);
2058
+ }
2059
+ return keyPair;
2060
+ }
2061
+ async generateProof(params) {
2062
+ const keyPair = await this.getOrGenerateKeyPair();
2063
+ return generateProof(Object.assign({
2064
+ keyPair: keyPair
2065
+ }, params));
2066
+ }
2067
+ async calculateThumbprint() {
2068
+ const keyPair = await this.getOrGenerateKeyPair();
2069
+ return calculateThumbprint(keyPair);
2070
+ }
2071
+ async clear() {
2072
+ await Promise.all([ this.storage.clearNonces(), this.storage.clearKeyPairs() ]);
2073
+ }
2074
+ }
2075
+
2076
+ class Fetcher {
2077
+ constructor(config, hooks) {
2078
+ this.hooks = hooks;
2079
+ this.config = Object.assign(Object.assign({}, config), {
2080
+ fetch: config.fetch || (typeof window === "undefined" ? fetch : window.fetch.bind(window))
2081
+ });
2082
+ }
2083
+ isAbsoluteUrl(url) {
2084
+ return /^(https?:)?\/\//i.test(url);
2085
+ }
2086
+ buildUrl(baseUrl, url) {
2087
+ if (url) {
2088
+ if (this.isAbsoluteUrl(url)) {
2089
+ return url;
2090
+ }
2091
+ if (baseUrl) {
2092
+ return `${baseUrl.replace(/\/?\/$/, "")}/${url.replace(/^\/+/, "")}`;
2093
+ }
2094
+ }
2095
+ throw new TypeError("`url` must be absolute or `baseUrl` non-empty.");
2096
+ }
2097
+ getAccessToken() {
2098
+ return this.config.getAccessToken ? this.config.getAccessToken() : this.hooks.getAccessToken();
2099
+ }
2100
+ buildBaseRequest(info, init) {
2101
+ const request = new Request(info, init);
2102
+ if (!this.config.baseUrl) {
2103
+ return request;
2104
+ }
2105
+ return new Request(this.buildUrl(this.config.baseUrl, request.url), request);
2106
+ }
2107
+ async setAuthorizationHeader(request, accessToken) {
2108
+ request.headers.set("authorization", `${this.config.dpopNonceId ? "DPoP" : "Bearer"} ${accessToken}`);
2109
+ }
2110
+ async setDpopProofHeader(request, accessToken) {
2111
+ if (!this.config.dpopNonceId) {
2112
+ return;
2113
+ }
2114
+ const dpopNonce = await this.hooks.getDpopNonce();
2115
+ const dpopProof = await this.hooks.generateDpopProof({
2116
+ accessToken: accessToken,
2117
+ method: request.method,
2118
+ nonce: dpopNonce,
2119
+ url: request.url
2120
+ });
2121
+ request.headers.set("dpop", dpopProof);
2122
+ }
2123
+ async prepareRequest(request) {
2124
+ const accessToken = await this.getAccessToken();
2125
+ this.setAuthorizationHeader(request, accessToken);
2126
+ await this.setDpopProofHeader(request, accessToken);
2127
+ }
2128
+ getHeader(headers, name) {
2129
+ if (Array.isArray(headers)) {
2130
+ return new Headers(headers).get(name) || "";
2131
+ }
2132
+ if (typeof headers.get === "function") {
2133
+ return headers.get(name) || "";
2134
+ }
2135
+ return headers[name] || "";
2136
+ }
2137
+ hasUseDpopNonceError(response) {
2138
+ if (response.status !== 401) {
2139
+ return false;
2140
+ }
2141
+ const wwwAuthHeader = this.getHeader(response.headers, "www-authenticate");
2142
+ return wwwAuthHeader.includes("use_dpop_nonce");
2143
+ }
2144
+ async handleResponse(response, callbacks) {
2145
+ const newDpopNonce = this.getHeader(response.headers, DPOP_NONCE_HEADER);
2146
+ if (newDpopNonce) {
2147
+ await this.hooks.setDpopNonce(newDpopNonce);
2148
+ }
2149
+ if (!this.hasUseDpopNonceError(response)) {
2150
+ return response;
2151
+ }
2152
+ if (!newDpopNonce || !callbacks.onUseDpopNonceError) {
2153
+ throw new UseDpopNonceError(newDpopNonce);
2154
+ }
2155
+ return callbacks.onUseDpopNonceError();
2156
+ }
2157
+ async internalFetchWithAuth(info, init, callbacks) {
2158
+ const request = this.buildBaseRequest(info, init);
2159
+ await this.prepareRequest(request);
2160
+ const response = await this.config.fetch(request);
2161
+ return this.handleResponse(response, callbacks);
2162
+ }
2163
+ fetchWithAuth(info, init) {
2164
+ const callbacks = {
2165
+ onUseDpopNonceError: () => this.internalFetchWithAuth(info, init, Object.assign(Object.assign({}, callbacks), {
2166
+ onUseDpopNonceError: undefined
2167
+ }))
2168
+ };
2169
+ return this.internalFetchWithAuth(info, init, callbacks);
2170
+ }
2171
+ }
2172
+
1585
2173
  const lock = new Lock;
1586
2174
 
1587
2175
  class Auth0Client {
@@ -1626,6 +2214,7 @@ class Auth0Client {
1626
2214
  this.transactionManager = new TransactionManager(transactionStorage, this.options.clientId, this.options.cookieDomain);
1627
2215
  this.nowProvider = this.options.nowProvider || DEFAULT_NOW_PROVIDER;
1628
2216
  this.cacheManager = new CacheManager(cache, !cache.allKeys ? new CacheKeyManifest(cache, this.options.clientId) : undefined, this.nowProvider);
2217
+ this.dpop = this.options.useDpop ? new Dpop(this.options.clientId) : undefined;
1629
2218
  this.domainUrl = getDomain(this.options.domain);
1630
2219
  this.tokenIssuer = getTokenIssuer(this.options.issuer, this.domainUrl);
1631
2220
  if (typeof window !== "undefined" && window.Worker && this.options.useRefreshTokens && cacheLocation === CACHE_LOCATION_MEMORY) {
@@ -1669,12 +2258,14 @@ class Auth0Client {
1669
2258
  }
1670
2259
  }
1671
2260
  async _prepareAuthorizeUrl(authorizationParams, authorizeOptions, fallbackRedirectUri) {
2261
+ var _a;
1672
2262
  const state = encode(createRandomString());
1673
2263
  const nonce = encode(createRandomString());
1674
2264
  const code_verifier = createRandomString();
1675
2265
  const code_challengeBuffer = await sha256(code_verifier);
1676
2266
  const code_challenge = bufferToBase64UrlEncoded(code_challengeBuffer);
1677
- const params = getAuthorizeParams(this.options, this.scope, authorizationParams, state, nonce, code_challenge, authorizationParams.redirect_uri || this.options.authorizationParams.redirect_uri || fallbackRedirectUri, authorizeOptions === null || authorizeOptions === void 0 ? void 0 : authorizeOptions.response_mode);
2267
+ const thumbprint = await ((_a = this.dpop) === null || _a === void 0 ? void 0 : _a.calculateThumbprint());
2268
+ const params = getAuthorizeParams(this.options, this.scope, authorizationParams, state, nonce, code_challenge, authorizationParams.redirect_uri || this.options.authorizationParams.redirect_uri || fallbackRedirectUri, authorizeOptions === null || authorizeOptions === void 0 ? void 0 : authorizeOptions.response_mode, thumbprint);
1678
2269
  const url = this._authorizeUrl(params);
1679
2270
  return {
1680
2271
  nonce: nonce,
@@ -1839,9 +2430,10 @@ class Auth0Client {
1839
2430
  }
1840
2431
  }
1841
2432
  const authResult = this.options.useRefreshTokens ? await this._getTokenUsingRefreshToken(getTokenOptions) : await this._getTokenFromIFrame(getTokenOptions);
1842
- const {id_token: id_token, access_token: access_token, oauthTokenScope: oauthTokenScope, expires_in: expires_in} = authResult;
2433
+ const {id_token: id_token, token_type: token_type, access_token: access_token, oauthTokenScope: oauthTokenScope, expires_in: expires_in} = authResult;
1843
2434
  return Object.assign(Object.assign({
1844
2435
  id_token: id_token,
2436
+ token_type: token_type,
1845
2437
  access_token: access_token
1846
2438
  }, oauthTokenScope ? {
1847
2439
  scope: oauthTokenScope
@@ -1890,7 +2482,8 @@ class Auth0Client {
1890
2482
  return url + federatedQuery;
1891
2483
  }
1892
2484
  async logout(options = {}) {
1893
- const _a = patchOpenUrlWithOnRedirect(options), {openUrl: openUrl} = _a, logoutOptions = __rest(_a, [ "openUrl" ]);
2485
+ var _a;
2486
+ const _b = patchOpenUrlWithOnRedirect(options), {openUrl: openUrl} = _b, logoutOptions = __rest(_b, [ "openUrl" ]);
1894
2487
  if (options.clientId === null) {
1895
2488
  await this.cacheManager.clear();
1896
2489
  } else {
@@ -1903,6 +2496,7 @@ class Auth0Client {
1903
2496
  cookieDomain: this.options.cookieDomain
1904
2497
  });
1905
2498
  this.userCache.remove(CACHE_KEY_ID_TOKEN_SUFFIX);
2499
+ await ((_a = this.dpop) === null || _a === void 0 ? void 0 : _a.clear());
1906
2500
  const url = this._buildLogoutUrl(logoutOptions);
1907
2501
  if (openUrl) {
1908
2502
  await openUrl(url);
@@ -2024,10 +2618,11 @@ class Auth0Client {
2024
2618
  clientId: clientId
2025
2619
  }), 60);
2026
2620
  if (entry && entry.access_token) {
2027
- const {access_token: access_token, oauthTokenScope: oauthTokenScope, expires_in: expires_in} = entry;
2621
+ const {token_type: token_type, access_token: access_token, oauthTokenScope: oauthTokenScope, expires_in: expires_in} = entry;
2028
2622
  const cache = await this._getIdTokenFromCache();
2029
2623
  return cache && Object.assign(Object.assign({
2030
2624
  id_token: cache.id_token,
2625
+ token_type: token_type ? token_type : "Bearer",
2031
2626
  access_token: access_token
2032
2627
  }, oauthTokenScope ? {
2033
2628
  scope: oauthTokenScope
@@ -2043,7 +2638,8 @@ class Auth0Client {
2043
2638
  client_id: this.options.clientId,
2044
2639
  auth0Client: this.options.auth0Client,
2045
2640
  useFormData: this.options.useFormData,
2046
- timeout: this.httpTimeoutMs
2641
+ timeout: this.httpTimeoutMs,
2642
+ dpop: this.dpop
2047
2643
  }, options), this.worker);
2048
2644
  const decodedToken = await this._verifyIdToken(authResult.id_token, nonceIn, organization);
2049
2645
  await this._saveEntryInCache(Object.assign(Object.assign(Object.assign(Object.assign({}, authResult), {
@@ -2073,6 +2669,35 @@ class Auth0Client {
2073
2669
  audience: options.audience || this.options.authorizationParams.audience
2074
2670
  });
2075
2671
  }
2672
+ _assertDpop(dpop) {
2673
+ if (!dpop) {
2674
+ throw new Error("`useDpop` option must be enabled before using DPoP.");
2675
+ }
2676
+ }
2677
+ getDpopNonce(id) {
2678
+ this._assertDpop(this.dpop);
2679
+ return this.dpop.getNonce(id);
2680
+ }
2681
+ setDpopNonce(nonce, id) {
2682
+ this._assertDpop(this.dpop);
2683
+ return this.dpop.setNonce(nonce, id);
2684
+ }
2685
+ generateDpopProof(params) {
2686
+ this._assertDpop(this.dpop);
2687
+ return this.dpop.generateProof(params);
2688
+ }
2689
+ createFetcher(config = {}) {
2690
+ if (this.options.useDpop && !config.dpopNonceId) {
2691
+ throw new TypeError("When `useDpop` is enabled, `dpopNonceId` must be set when calling `createFetcher()`.");
2692
+ }
2693
+ return new Fetcher(config, {
2694
+ isDpopEnabled: () => !!this.options.useDpop,
2695
+ getAccessToken: () => this.getTokenSilently(),
2696
+ getDpopNonce: () => this.getDpopNonce(config.dpopNonceId),
2697
+ setDpopNonce: nonce => this.setDpopNonce(nonce),
2698
+ generateDpopProof: params => this.generateDpopProof(params)
2699
+ });
2700
+ }
2076
2701
  }
2077
2702
 
2078
2703
  class User {}
@@ -2105,6 +2730,8 @@ exports.PopupTimeoutError = PopupTimeoutError;
2105
2730
 
2106
2731
  exports.TimeoutError = TimeoutError;
2107
2732
 
2733
+ exports.UseDpopNonceError = UseDpopNonceError;
2734
+
2108
2735
  exports.User = User;
2109
2736
 
2110
2737
  exports.createAuth0Client = createAuth0Client;