@versini/auth-provider 2.0.2 → 2.1.1

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/dist/index.d.ts CHANGED
@@ -8,17 +8,21 @@ type AuthProviderProps = {
8
8
  accessType?: string;
9
9
  };
10
10
 
11
- type AuthContextProps = {
12
- login: (username: string, password: string) => Promise<boolean>;
13
- logout: () => void;
11
+ type AuthState = {
14
12
  isAuthenticated: boolean;
13
+ idToken?: string;
15
14
  accessToken?: string;
16
15
  refreshToken?: string;
17
- idToken?: string;
18
16
  logoutReason?: string;
17
+ userId?: string;
19
18
  };
20
19
 
21
- declare const AuthProvider: ({ children, sessionExpiration, clientId, accessType, }: AuthProviderProps) => react_jsx_runtime.JSX.Element;
20
+ type AuthContextProps = {
21
+ login: (username: string, password: string) => Promise<boolean>;
22
+ logout: () => void;
23
+ } & AuthState;
24
+
25
+ declare const AuthProvider: ({ children, sessionExpiration, clientId, }: AuthProviderProps) => react_jsx_runtime.JSX.Element;
22
26
 
23
27
  declare const useAuth: (context?: react.Context<AuthContextProps>) => AuthContextProps;
24
28
 
package/dist/index.js CHANGED
@@ -1,148 +1,165 @@
1
- import { jsx as z } from "react/jsx-runtime";
2
- import { useCallback as w, useState as x, useEffect as f, useRef as R, useLayoutEffect as F, createContext as M, useContext as H } from "react";
1
+ import { jsx as ne } from "react/jsx-runtime";
2
+ import * as A from "react";
3
+ import { useRef as oe, useEffect as G, createContext as ae, useState as se, useContext as ie } from "react";
3
4
  /*!
4
- @versini/auth-provider v2.0.2
5
+ @versini/auth-provider v2.1.1
5
6
  © 2024 gizmette.com
6
7
  */
7
8
  try {
8
9
  window.__VERSINI_AUTH_CLIENT__ || (window.__VERSINI_AUTH_CLIENT__ = {
9
- version: "2.0.2",
10
- buildTime: "06/20/2024 03:39 AM EDT",
10
+ version: "2.1.1",
11
+ buildTime: "06/24/2024 03:44 PM EDT",
11
12
  homepage: "https://github.com/aversini/auth-client",
12
13
  license: "MIT"
13
14
  });
14
15
  } catch {
15
16
  }
16
17
  /*!
17
- @versini/auth-common v2.0.0
18
+ @versini/auth-common v2.1.0
18
19
  © 2024 gizmette.com
19
20
  */
20
21
  try {
21
22
  window.__VERSINI_AUTH_COMMON__ || (window.__VERSINI_AUTH_COMMON__ = {
22
- version: "2.0.0",
23
- buildTime: "06/20/2024 03:38 AM EDT",
23
+ version: "2.1.0",
24
+ buildTime: "06/24/2024 03:43 PM EDT",
24
25
  homepage: "https://github.com/aversini/auth-client",
25
26
  license: "MIT"
26
27
  });
27
28
  } catch {
28
29
  }
29
- const X = {
30
+ const ce = {
30
31
  ID_TOKEN: "id_token"
31
- }, G = {
32
+ }, ue = {
32
33
  CLIENT_ID: "X-Auth-ClientId"
34
+ }, b = {
35
+ ALG: "RS256",
36
+ USER_ID_KEY: "_id",
37
+ ISSUER: "gizmette.com"
33
38
  };
34
- var j = typeof window < "u" ? F : f;
35
- function b(t, e, o, n) {
36
- const c = R(e);
37
- j(() => {
38
- c.current = e;
39
- }, [e]), f(() => {
40
- const d = window;
41
- if (!(d && d.addEventListener))
42
- return;
43
- const u = (h) => {
44
- c.current(h);
45
- };
46
- return d.addEventListener(t, u, n), () => {
47
- d.removeEventListener(t, u, n);
48
- };
49
- }, [t, o, n]);
39
+ function Y(e, t) {
40
+ window.dispatchEvent(new StorageEvent("storage", { key: e, newValue: t }));
50
41
  }
51
- function A(t) {
52
- const e = R(() => {
53
- throw new Error("Cannot call an event handler while rendering.");
54
- });
55
- return j(() => {
56
- e.current = t;
57
- }, [t]), w((...o) => {
58
- var n;
59
- return (n = e.current) == null ? void 0 : n.call(e, ...o);
60
- }, [e]);
61
- }
62
- var k = typeof window > "u";
63
- function S(t, e, o = {}) {
64
- const { initializeWithValue: n = !0 } = o, c = w(
65
- (r) => o.serializer ? o.serializer(r) : JSON.stringify(r),
66
- [o]
67
- ), d = w(
68
- (r) => {
69
- if (o.deserializer)
70
- return o.deserializer(r);
71
- if (r === "undefined")
72
- return;
73
- const a = e instanceof Function ? e() : e;
74
- let g;
42
+ const D = (e, t) => {
43
+ const n = JSON.stringify(
44
+ typeof t == "function" ? t() : t
45
+ );
46
+ window.localStorage.setItem(e, n), Y(e, n);
47
+ }, de = (e) => {
48
+ window.localStorage.removeItem(e), Y(e, null);
49
+ }, K = (e) => window.localStorage.getItem(e), le = (e) => (window.addEventListener("storage", e), () => window.removeEventListener("storage", e));
50
+ function fe({
51
+ key: e,
52
+ initialValue: t
53
+ }) {
54
+ const n = () => K(e), r = A.useSyncExternalStore(
55
+ le,
56
+ n
57
+ ), o = A.useCallback(
58
+ (i) => {
75
59
  try {
76
- g = JSON.parse(r);
77
- } catch (y) {
78
- return console.error("Error parsing JSON:", y), a;
60
+ const c = typeof i == "function" ? i(JSON.parse(r)) : i;
61
+ c == null ? de(e) : D(e, c);
62
+ } catch (c) {
63
+ console.warn(c);
79
64
  }
80
- return g;
81
65
  },
82
- [o, e]
83
- ), u = w(() => {
84
- const r = e instanceof Function ? e() : e;
85
- if (k)
86
- return r;
87
- try {
88
- const a = window.localStorage.getItem(t);
89
- return a ? d(a) : r;
90
- } catch (a) {
91
- return console.warn(`Error reading localStorage key “${t}”:`, a), r;
92
- }
93
- }, [e, t, d]), [h, p] = x(() => n ? u() : e instanceof Function ? e() : e), _ = A((r) => {
94
- k && console.warn(
95
- `Tried setting localStorage key “${t}” even though environment is not a client`
96
- );
66
+ [e, r]
67
+ ), s = A.useCallback(() => {
68
+ o(t);
69
+ }, [t, o]), a = A.useCallback(() => {
70
+ o(null);
71
+ }, [o]);
72
+ return A.useEffect(() => {
97
73
  try {
98
- const a = r instanceof Function ? r(u()) : r;
99
- window.localStorage.setItem(t, c(a)), p(a), window.dispatchEvent(new StorageEvent("local-storage", { key: t }));
100
- } catch (a) {
101
- console.warn(`Error setting localStorage key “${t}”:`, a);
74
+ K(e) === null && typeof t < "u" && D(e, t);
75
+ } catch (i) {
76
+ console.warn(i);
102
77
  }
103
- }), i = A(() => {
104
- k && console.warn(
105
- `Tried removing localStorage key “${t}” even though environment is not a client`
106
- );
107
- const r = e instanceof Function ? e() : e;
108
- window.localStorage.removeItem(t), p(r), window.dispatchEvent(new StorageEvent("local-storage", { key: t }));
109
- });
110
- f(() => {
111
- p(u());
112
- }, [t]);
113
- const v = w(
114
- (r) => {
115
- r.key && r.key !== t || p(u());
116
- },
117
- [t, u]
118
- );
119
- return b("storage", v), b("local-storage", v), [h, _, i];
120
- }
121
- new TextEncoder();
122
- const L = new TextDecoder(), K = (t) => {
123
- const e = atob(t), o = new Uint8Array(e.length);
124
- for (let n = 0; n < e.length; n++)
125
- o[n] = e.charCodeAt(n);
126
- return o;
127
- }, B = (t) => {
128
- let e = t;
129
- e instanceof Uint8Array && (e = L.decode(e)), e = e.replace(/-/g, "+").replace(/_/g, "/").replace(/\s/g, "");
78
+ }, [e, t]), [r ? JSON.parse(r) : null, o, s, a];
79
+ }
80
+ const he = "Oops! It looks like your session has expired. For your security, please log in again to continue.", pe = "Your session has been successfully terminated.", me = "You forgot to wrap your component in <AuthProvider>.", L = {
81
+ dev: "https://auth.gizmette.local.com:3003",
82
+ prod: "https://mylogin.gizmette.com"
83
+ }, ye = "@@auth@@", Se = `-----BEGIN PUBLIC KEY-----
84
+ MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsF6i3Jd9fY/3COqCw/m7
85
+ w5PKyTYLGAI2I6SIIdpe6i6DOCbEkmDz7LdVsBqwNtVi8gvWYIj+8ol6rU3qu1v5
86
+ i1Jd45GSK4kzkVdgCmQZbM5ak0KI99q5wsrAIzUd+LRJ2HRvWtr5IYdsIiXaQjle
87
+ aMwPFOIcJH+rKfFgNcHLcaS5syp7zU1ANwZ+trgR+DifBr8TLVkBynmNeTyhDm2+
88
+ l0haqjMk0UoNPPE8iYBWUHQJJE1Dqstj65d6Eh5g64Pao25y4cmYJbKjiblIGEkE
89
+ sjqybA9mARAqh9k/eiIopecWSiffNQTwVQVd2I9ZH3BalhEXHlqFgrjz51kFqg81
90
+ awIDAQAB
91
+ -----END PUBLIC KEY-----`, J = crypto, q = (e) => e instanceof CryptoKey, _ = new TextEncoder(), R = new TextDecoder();
92
+ function we(...e) {
93
+ const t = e.reduce((o, { length: s }) => o + s, 0), n = new Uint8Array(t);
94
+ let r = 0;
95
+ for (const o of e)
96
+ n.set(o, r), r += o.length;
97
+ return n;
98
+ }
99
+ const Ee = (e) => {
100
+ const t = atob(e), n = new Uint8Array(t.length);
101
+ for (let r = 0; r < t.length; r++)
102
+ n[r] = t.charCodeAt(r);
103
+ return n;
104
+ }, x = (e) => {
105
+ let t = e;
106
+ t instanceof Uint8Array && (t = R.decode(t)), t = t.replace(/-/g, "+").replace(/_/g, "/").replace(/\s/g, "");
130
107
  try {
131
- return K(e);
108
+ return Ee(t);
132
109
  } catch {
133
110
  throw new TypeError("The input to be decoded is not correctly encoded.");
134
111
  }
135
112
  };
136
- class Y extends Error {
113
+ class g extends Error {
137
114
  static get code() {
138
115
  return "ERR_JOSE_GENERIC";
139
116
  }
140
- constructor(e) {
141
- var o;
142
- super(e), this.code = "ERR_JOSE_GENERIC", this.name = this.constructor.name, (o = Error.captureStackTrace) == null || o.call(Error, this, this.constructor);
117
+ constructor(t) {
118
+ var n;
119
+ super(t), this.code = "ERR_JOSE_GENERIC", this.name = this.constructor.name, (n = Error.captureStackTrace) == null || n.call(Error, this, this.constructor);
120
+ }
121
+ }
122
+ class m extends g {
123
+ static get code() {
124
+ return "ERR_JWT_CLAIM_VALIDATION_FAILED";
125
+ }
126
+ constructor(t, n, r = "unspecified", o = "unspecified") {
127
+ super(t), this.code = "ERR_JWT_CLAIM_VALIDATION_FAILED", this.claim = r, this.reason = o, this.payload = n;
128
+ }
129
+ }
130
+ class W extends g {
131
+ static get code() {
132
+ return "ERR_JWT_EXPIRED";
133
+ }
134
+ constructor(t, n, r = "unspecified", o = "unspecified") {
135
+ super(t), this.code = "ERR_JWT_EXPIRED", this.claim = r, this.reason = o, this.payload = n;
136
+ }
137
+ }
138
+ class ge extends g {
139
+ constructor() {
140
+ super(...arguments), this.code = "ERR_JOSE_ALG_NOT_ALLOWED";
141
+ }
142
+ static get code() {
143
+ return "ERR_JOSE_ALG_NOT_ALLOWED";
144
+ }
145
+ }
146
+ class C extends g {
147
+ constructor() {
148
+ super(...arguments), this.code = "ERR_JOSE_NOT_SUPPORTED";
149
+ }
150
+ static get code() {
151
+ return "ERR_JOSE_NOT_SUPPORTED";
152
+ }
153
+ }
154
+ class l extends g {
155
+ constructor() {
156
+ super(...arguments), this.code = "ERR_JWS_INVALID";
157
+ }
158
+ static get code() {
159
+ return "ERR_JWS_INVALID";
143
160
  }
144
161
  }
145
- class T extends Y {
162
+ class z extends g {
146
163
  constructor() {
147
164
  super(...arguments), this.code = "ERR_JWT_INVALID";
148
165
  }
@@ -150,199 +167,655 @@ class T extends Y {
150
167
  return "ERR_JWT_INVALID";
151
168
  }
152
169
  }
153
- function q(t) {
154
- return typeof t == "object" && t !== null;
170
+ class be extends g {
171
+ constructor() {
172
+ super(...arguments), this.code = "ERR_JWS_SIGNATURE_VERIFICATION_FAILED", this.message = "signature verification failed";
173
+ }
174
+ static get code() {
175
+ return "ERR_JWS_SIGNATURE_VERIFICATION_FAILED";
176
+ }
177
+ }
178
+ function S(e, t = "algorithm.name") {
179
+ return new TypeError(`CryptoKey does not support this operation, its ${t} must be ${e}`);
155
180
  }
156
- function Q(t) {
157
- if (!q(t) || Object.prototype.toString.call(t) !== "[object Object]")
158
- return !1;
159
- if (Object.getPrototypeOf(t) === null)
181
+ function T(e, t) {
182
+ return e.name === t;
183
+ }
184
+ function O(e) {
185
+ return parseInt(e.name.slice(4), 10);
186
+ }
187
+ function Ae(e) {
188
+ switch (e) {
189
+ case "ES256":
190
+ return "P-256";
191
+ case "ES384":
192
+ return "P-384";
193
+ case "ES512":
194
+ return "P-521";
195
+ default:
196
+ throw new Error("unreachable");
197
+ }
198
+ }
199
+ function Ie(e, t) {
200
+ if (t.length && !t.some((n) => e.usages.includes(n))) {
201
+ let n = "CryptoKey does not support this operation, its usages must include ";
202
+ if (t.length > 2) {
203
+ const r = t.pop();
204
+ n += `one of ${t.join(", ")}, or ${r}.`;
205
+ } else
206
+ t.length === 2 ? n += `one of ${t[0]} or ${t[1]}.` : n += `${t[0]}.`;
207
+ throw new TypeError(n);
208
+ }
209
+ }
210
+ function _e(e, t, ...n) {
211
+ switch (t) {
212
+ case "HS256":
213
+ case "HS384":
214
+ case "HS512": {
215
+ if (!T(e.algorithm, "HMAC"))
216
+ throw S("HMAC");
217
+ const r = parseInt(t.slice(2), 10);
218
+ if (O(e.algorithm.hash) !== r)
219
+ throw S(`SHA-${r}`, "algorithm.hash");
220
+ break;
221
+ }
222
+ case "RS256":
223
+ case "RS384":
224
+ case "RS512": {
225
+ if (!T(e.algorithm, "RSASSA-PKCS1-v1_5"))
226
+ throw S("RSASSA-PKCS1-v1_5");
227
+ const r = parseInt(t.slice(2), 10);
228
+ if (O(e.algorithm.hash) !== r)
229
+ throw S(`SHA-${r}`, "algorithm.hash");
230
+ break;
231
+ }
232
+ case "PS256":
233
+ case "PS384":
234
+ case "PS512": {
235
+ if (!T(e.algorithm, "RSA-PSS"))
236
+ throw S("RSA-PSS");
237
+ const r = parseInt(t.slice(2), 10);
238
+ if (O(e.algorithm.hash) !== r)
239
+ throw S(`SHA-${r}`, "algorithm.hash");
240
+ break;
241
+ }
242
+ case "EdDSA": {
243
+ if (e.algorithm.name !== "Ed25519" && e.algorithm.name !== "Ed448")
244
+ throw S("Ed25519 or Ed448");
245
+ break;
246
+ }
247
+ case "ES256":
248
+ case "ES384":
249
+ case "ES512": {
250
+ if (!T(e.algorithm, "ECDSA"))
251
+ throw S("ECDSA");
252
+ const r = Ae(t);
253
+ if (e.algorithm.namedCurve !== r)
254
+ throw S(r, "algorithm.namedCurve");
255
+ break;
256
+ }
257
+ default:
258
+ throw new TypeError("CryptoKey does not support this operation");
259
+ }
260
+ Ie(e, n);
261
+ }
262
+ function X(e, t, ...n) {
263
+ var r;
264
+ if (n.length > 2) {
265
+ const o = n.pop();
266
+ e += `one of type ${n.join(", ")}, or ${o}.`;
267
+ } else
268
+ n.length === 2 ? e += `one of type ${n[0]} or ${n[1]}.` : e += `of type ${n[0]}.`;
269
+ return t == null ? e += ` Received ${t}` : typeof t == "function" && t.name ? e += ` Received function ${t.name}` : typeof t == "object" && t != null && (r = t.constructor) != null && r.name && (e += ` Received an instance of ${t.constructor.name}`), e;
270
+ }
271
+ const H = (e, ...t) => X("Key must be ", e, ...t);
272
+ function j(e, t, ...n) {
273
+ return X(`Key for the ${e} algorithm must be `, t, ...n);
274
+ }
275
+ const Q = (e) => q(e), E = ["CryptoKey"], Te = (...e) => {
276
+ const t = e.filter(Boolean);
277
+ if (t.length === 0 || t.length === 1)
160
278
  return !0;
161
- let e = t;
162
- for (; Object.getPrototypeOf(e) !== null; )
163
- e = Object.getPrototypeOf(e);
164
- return Object.getPrototypeOf(t) === e;
165
- }
166
- const Z = B;
167
- function N(t) {
168
- if (typeof t != "string")
169
- throw new T("JWTs must use Compact JWS serialization, JWT must be a string");
170
- const { 1: e, length: o } = t.split(".");
171
- if (o === 5)
172
- throw new T("Only JWTs using Compact JWS serialization can be decoded");
173
- if (o !== 3)
174
- throw new T("Invalid JWT");
175
- if (!e)
176
- throw new T("JWTs must contain a payload");
177
279
  let n;
280
+ for (const r of t) {
281
+ const o = Object.keys(r);
282
+ if (!n || n.size === 0) {
283
+ n = new Set(o);
284
+ continue;
285
+ }
286
+ for (const s of o) {
287
+ if (n.has(s))
288
+ return !1;
289
+ n.add(s);
290
+ }
291
+ }
292
+ return !0;
293
+ };
294
+ function ve(e) {
295
+ return typeof e == "object" && e !== null;
296
+ }
297
+ function U(e) {
298
+ if (!ve(e) || Object.prototype.toString.call(e) !== "[object Object]")
299
+ return !1;
300
+ if (Object.getPrototypeOf(e) === null)
301
+ return !0;
302
+ let t = e;
303
+ for (; Object.getPrototypeOf(t) !== null; )
304
+ t = Object.getPrototypeOf(t);
305
+ return Object.getPrototypeOf(e) === t;
306
+ }
307
+ const Re = (e, t) => {
308
+ if (e.startsWith("RS") || e.startsWith("PS")) {
309
+ const { modulusLength: n } = t.algorithm;
310
+ if (typeof n != "number" || n < 2048)
311
+ throw new TypeError(`${e} requires key modulusLength to be 2048 bits or larger`);
312
+ }
313
+ }, w = (e, t, n = 0) => {
314
+ n === 0 && (t.unshift(t.length), t.unshift(6));
315
+ const r = e.indexOf(t[0], n);
316
+ if (r === -1)
317
+ return !1;
318
+ const o = e.subarray(r, r + t.length);
319
+ return o.length !== t.length ? !1 : o.every((s, a) => s === t[a]) || w(e, t, r + 1);
320
+ }, $ = (e) => {
321
+ switch (!0) {
322
+ case w(e, [42, 134, 72, 206, 61, 3, 1, 7]):
323
+ return "P-256";
324
+ case w(e, [43, 129, 4, 0, 34]):
325
+ return "P-384";
326
+ case w(e, [43, 129, 4, 0, 35]):
327
+ return "P-521";
328
+ case w(e, [43, 101, 110]):
329
+ return "X25519";
330
+ case w(e, [43, 101, 111]):
331
+ return "X448";
332
+ case w(e, [43, 101, 112]):
333
+ return "Ed25519";
334
+ case w(e, [43, 101, 113]):
335
+ return "Ed448";
336
+ default:
337
+ throw new C("Invalid or unsupported EC Key Curve or OKP Key Sub Type");
338
+ }
339
+ }, Ce = async (e, t, n, r, o) => {
340
+ let s, a;
341
+ const i = new Uint8Array(atob(n.replace(e, "")).split("").map((c) => c.charCodeAt(0)));
342
+ switch (r) {
343
+ case "PS256":
344
+ case "PS384":
345
+ case "PS512":
346
+ s = { name: "RSA-PSS", hash: `SHA-${r.slice(-3)}` }, a = ["verify"];
347
+ break;
348
+ case "RS256":
349
+ case "RS384":
350
+ case "RS512":
351
+ s = { name: "RSASSA-PKCS1-v1_5", hash: `SHA-${r.slice(-3)}` }, a = ["verify"];
352
+ break;
353
+ case "RSA-OAEP":
354
+ case "RSA-OAEP-256":
355
+ case "RSA-OAEP-384":
356
+ case "RSA-OAEP-512":
357
+ s = {
358
+ name: "RSA-OAEP",
359
+ hash: `SHA-${parseInt(r.slice(-3), 10) || 1}`
360
+ }, a = ["encrypt", "wrapKey"];
361
+ break;
362
+ case "ES256":
363
+ s = { name: "ECDSA", namedCurve: "P-256" }, a = ["verify"];
364
+ break;
365
+ case "ES384":
366
+ s = { name: "ECDSA", namedCurve: "P-384" }, a = ["verify"];
367
+ break;
368
+ case "ES512":
369
+ s = { name: "ECDSA", namedCurve: "P-521" }, a = ["verify"];
370
+ break;
371
+ case "ECDH-ES":
372
+ case "ECDH-ES+A128KW":
373
+ case "ECDH-ES+A192KW":
374
+ case "ECDH-ES+A256KW": {
375
+ const c = $(i);
376
+ s = c.startsWith("P-") ? { name: "ECDH", namedCurve: c } : { name: c }, a = [];
377
+ break;
378
+ }
379
+ case "EdDSA":
380
+ s = { name: $(i) }, a = ["verify"];
381
+ break;
382
+ default:
383
+ throw new C('Invalid or unsupported "alg" (Algorithm) value');
384
+ }
385
+ return J.subtle.importKey(t, i, s, !1, a);
386
+ }, Pe = (e, t, n) => Ce(/(?:-----(?:BEGIN|END) PUBLIC KEY-----|\s)/g, "spki", e, t);
387
+ async function xe(e, t, n) {
388
+ if (e.indexOf("-----BEGIN PUBLIC KEY-----") !== 0)
389
+ throw new TypeError('"spki" must be SPKI formatted string');
390
+ return Pe(e, t);
391
+ }
392
+ const Oe = (e, t) => {
393
+ if (!(t instanceof Uint8Array)) {
394
+ if (!Q(t))
395
+ throw new TypeError(j(e, t, ...E, "Uint8Array"));
396
+ if (t.type !== "secret")
397
+ throw new TypeError(`${E.join(" or ")} instances for symmetric algorithms must be of type "secret"`);
398
+ }
399
+ }, Ne = (e, t, n) => {
400
+ if (!Q(t))
401
+ throw new TypeError(j(e, t, ...E));
402
+ if (t.type === "secret")
403
+ throw new TypeError(`${E.join(" or ")} instances for asymmetric algorithms must not be of type "secret"`);
404
+ if (t.algorithm && n === "verify" && t.type === "private")
405
+ throw new TypeError(`${E.join(" or ")} instances for asymmetric algorithm verifying must be of type "public"`);
406
+ if (t.algorithm && n === "encrypt" && t.type === "private")
407
+ throw new TypeError(`${E.join(" or ")} instances for asymmetric algorithm encryption must be of type "public"`);
408
+ }, Ue = (e, t, n) => {
409
+ e.startsWith("HS") || e === "dir" || e.startsWith("PBES2") || /^A\d{3}(?:GCM)?KW$/.test(e) ? Oe(e, t) : Ne(e, t, n);
410
+ };
411
+ function Je(e, t, n, r, o) {
412
+ if (o.crit !== void 0 && (r == null ? void 0 : r.crit) === void 0)
413
+ throw new e('"crit" (Critical) Header Parameter MUST be integrity protected');
414
+ if (!r || r.crit === void 0)
415
+ return /* @__PURE__ */ new Set();
416
+ if (!Array.isArray(r.crit) || r.crit.length === 0 || r.crit.some((a) => typeof a != "string" || a.length === 0))
417
+ throw new e('"crit" (Critical) Header Parameter MUST be an array of non-empty strings when present');
418
+ let s;
419
+ n !== void 0 ? s = new Map([...Object.entries(n), ...t.entries()]) : s = t;
420
+ for (const a of r.crit) {
421
+ if (!s.has(a))
422
+ throw new C(`Extension Header Parameter "${a}" is not recognized`);
423
+ if (o[a] === void 0)
424
+ throw new e(`Extension Header Parameter "${a}" is missing`);
425
+ if (s.get(a) && r[a] === void 0)
426
+ throw new e(`Extension Header Parameter "${a}" MUST be integrity protected`);
427
+ }
428
+ return new Set(r.crit);
429
+ }
430
+ const ke = (e, t) => {
431
+ if (t !== void 0 && (!Array.isArray(t) || t.some((n) => typeof n != "string")))
432
+ throw new TypeError(`"${e}" option must be an array of strings`);
433
+ if (t)
434
+ return new Set(t);
435
+ };
436
+ function De(e, t) {
437
+ const n = `SHA-${e.slice(-3)}`;
438
+ switch (e) {
439
+ case "HS256":
440
+ case "HS384":
441
+ case "HS512":
442
+ return { hash: n, name: "HMAC" };
443
+ case "PS256":
444
+ case "PS384":
445
+ case "PS512":
446
+ return { hash: n, name: "RSA-PSS", saltLength: e.slice(-3) >> 3 };
447
+ case "RS256":
448
+ case "RS384":
449
+ case "RS512":
450
+ return { hash: n, name: "RSASSA-PKCS1-v1_5" };
451
+ case "ES256":
452
+ case "ES384":
453
+ case "ES512":
454
+ return { hash: n, name: "ECDSA", namedCurve: t.namedCurve };
455
+ case "EdDSA":
456
+ return { name: t.name };
457
+ default:
458
+ throw new C(`alg ${e} is not supported either by JOSE or your javascript runtime`);
459
+ }
460
+ }
461
+ function Ke(e, t, n) {
462
+ if (q(t))
463
+ return _e(t, e, n), t;
464
+ if (t instanceof Uint8Array) {
465
+ if (!e.startsWith("HS"))
466
+ throw new TypeError(H(t, ...E));
467
+ return J.subtle.importKey("raw", t, { hash: `SHA-${e.slice(-3)}`, name: "HMAC" }, !1, [n]);
468
+ }
469
+ throw new TypeError(H(t, ...E, "Uint8Array"));
470
+ }
471
+ const Le = async (e, t, n, r) => {
472
+ const o = await Ke(e, t, "verify");
473
+ Re(e, o);
474
+ const s = De(e, o.algorithm);
178
475
  try {
179
- n = Z(e);
476
+ return await J.subtle.verify(s, o, n, r);
180
477
  } catch {
181
- throw new T("Failed to base64url decode the payload");
478
+ return !1;
182
479
  }
183
- let c;
480
+ };
481
+ async function We(e, t, n) {
482
+ if (!U(e))
483
+ throw new l("Flattened JWS must be an object");
484
+ if (e.protected === void 0 && e.header === void 0)
485
+ throw new l('Flattened JWS must have either of the "protected" or "header" members');
486
+ if (e.protected !== void 0 && typeof e.protected != "string")
487
+ throw new l("JWS Protected Header incorrect type");
488
+ if (e.payload === void 0)
489
+ throw new l("JWS Payload missing");
490
+ if (typeof e.signature != "string")
491
+ throw new l("JWS Signature missing or incorrect type");
492
+ if (e.header !== void 0 && !U(e.header))
493
+ throw new l("JWS Unprotected Header incorrect type");
494
+ let r = {};
495
+ if (e.protected)
496
+ try {
497
+ const P = x(e.protected);
498
+ r = JSON.parse(R.decode(P));
499
+ } catch {
500
+ throw new l("JWS Protected Header is invalid");
501
+ }
502
+ if (!Te(r, e.header))
503
+ throw new l("JWS Protected and JWS Unprotected Header Parameter names must be disjoint");
504
+ const o = {
505
+ ...r,
506
+ ...e.header
507
+ }, s = Je(l, /* @__PURE__ */ new Map([["b64", !0]]), n == null ? void 0 : n.crit, r, o);
508
+ let a = !0;
509
+ if (s.has("b64") && (a = r.b64, typeof a != "boolean"))
510
+ throw new l('The "b64" (base64url-encode payload) Header Parameter must be a boolean');
511
+ const { alg: i } = o;
512
+ if (typeof i != "string" || !i)
513
+ throw new l('JWS "alg" (Algorithm) Header Parameter missing or invalid');
514
+ const c = n && ke("algorithms", n.algorithms);
515
+ if (c && !c.has(i))
516
+ throw new ge('"alg" (Algorithm) Header Parameter value not allowed');
517
+ if (a) {
518
+ if (typeof e.payload != "string")
519
+ throw new l("JWS Payload must be a string");
520
+ } else if (typeof e.payload != "string" && !(e.payload instanceof Uint8Array))
521
+ throw new l("JWS Payload must be a string or an Uint8Array instance");
522
+ let h = !1;
523
+ typeof t == "function" && (t = await t(r, e), h = !0), Ue(i, t, "verify");
524
+ const y = we(_.encode(e.protected ?? ""), _.encode("."), typeof e.payload == "string" ? _.encode(e.payload) : e.payload);
525
+ let u;
184
526
  try {
185
- c = JSON.parse(L.decode(n));
527
+ u = x(e.signature);
186
528
  } catch {
187
- throw new T("Failed to parse the decoded payload as JSON");
529
+ throw new l("Failed to base64url decode the signature");
188
530
  }
189
- if (!Q(c))
190
- throw new T("Invalid JWT Claims Set");
191
- return c;
531
+ if (!await Le(i, t, u, y))
532
+ throw new be();
533
+ let f;
534
+ if (a)
535
+ try {
536
+ f = x(e.payload);
537
+ } catch {
538
+ throw new l("Failed to base64url decode the payload");
539
+ }
540
+ else
541
+ typeof e.payload == "string" ? f = _.encode(e.payload) : f = e.payload;
542
+ const p = { payload: f };
543
+ return e.protected !== void 0 && (p.protectedHeader = r), e.header !== void 0 && (p.unprotectedHeader = e.header), h ? { ...p, key: t } : p;
192
544
  }
193
- const C = "Oops! It looks like your session has expired. For your security, please log in again to continue.", ee = "You forgot to wrap your component in <AuthProvider>.", J = {
194
- dev: "https://auth.gizmette.local.com:3003",
195
- prod: "https://mylogin.gizmette.com"
545
+ async function He(e, t, n) {
546
+ if (e instanceof Uint8Array && (e = R.decode(e)), typeof e != "string")
547
+ throw new l("Compact JWS must be a string or Uint8Array");
548
+ const { 0: r, 1: o, 2: s, length: a } = e.split(".");
549
+ if (a !== 3)
550
+ throw new l("Invalid Compact JWS");
551
+ const i = await We({ payload: o, protected: r, signature: s }, t, n), c = { payload: i.payload, protectedHeader: i.protectedHeader };
552
+ return typeof t == "function" ? { ...c, key: i.key } : c;
553
+ }
554
+ const $e = (e) => Math.floor(e.getTime() / 1e3), Z = 60, ee = Z * 60, k = ee * 24, Me = k * 7, Ve = k * 365.25, Be = /^(\+|\-)? ?(\d+|\d+\.\d+) ?(seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)(?: (ago|from now))?$/i, M = (e) => {
555
+ const t = Be.exec(e);
556
+ if (!t || t[4] && t[1])
557
+ throw new TypeError("Invalid time period format");
558
+ const n = parseFloat(t[2]), r = t[3].toLowerCase();
559
+ let o;
560
+ switch (r) {
561
+ case "sec":
562
+ case "secs":
563
+ case "second":
564
+ case "seconds":
565
+ case "s":
566
+ o = Math.round(n);
567
+ break;
568
+ case "minute":
569
+ case "minutes":
570
+ case "min":
571
+ case "mins":
572
+ case "m":
573
+ o = Math.round(n * Z);
574
+ break;
575
+ case "hour":
576
+ case "hours":
577
+ case "hr":
578
+ case "hrs":
579
+ case "h":
580
+ o = Math.round(n * ee);
581
+ break;
582
+ case "day":
583
+ case "days":
584
+ case "d":
585
+ o = Math.round(n * k);
586
+ break;
587
+ case "week":
588
+ case "weeks":
589
+ case "w":
590
+ o = Math.round(n * Me);
591
+ break;
592
+ default:
593
+ o = Math.round(n * Ve);
594
+ break;
595
+ }
596
+ return t[1] === "-" || t[4] === "ago" ? -o : o;
597
+ }, V = (e) => e.toLowerCase().replace(/^application\//, ""), Fe = (e, t) => typeof e == "string" ? t.includes(e) : Array.isArray(e) ? t.some(Set.prototype.has.bind(new Set(e))) : !1, Ge = (e, t, n = {}) => {
598
+ let r;
599
+ try {
600
+ r = JSON.parse(R.decode(t));
601
+ } catch {
602
+ }
603
+ if (!U(r))
604
+ throw new z("JWT Claims Set must be a top-level JSON object");
605
+ const { typ: o } = n;
606
+ if (o && (typeof e.typ != "string" || V(e.typ) !== V(o)))
607
+ throw new m('unexpected "typ" JWT header value', r, "typ", "check_failed");
608
+ const { requiredClaims: s = [], issuer: a, subject: i, audience: c, maxTokenAge: h } = n, y = [...s];
609
+ h !== void 0 && y.push("iat"), c !== void 0 && y.push("aud"), i !== void 0 && y.push("sub"), a !== void 0 && y.push("iss");
610
+ for (const p of new Set(y.reverse()))
611
+ if (!(p in r))
612
+ throw new m(`missing required "${p}" claim`, r, p, "missing");
613
+ if (a && !(Array.isArray(a) ? a : [a]).includes(r.iss))
614
+ throw new m('unexpected "iss" claim value', r, "iss", "check_failed");
615
+ if (i && r.sub !== i)
616
+ throw new m('unexpected "sub" claim value', r, "sub", "check_failed");
617
+ if (c && !Fe(r.aud, typeof c == "string" ? [c] : c))
618
+ throw new m('unexpected "aud" claim value', r, "aud", "check_failed");
619
+ let u;
620
+ switch (typeof n.clockTolerance) {
621
+ case "string":
622
+ u = M(n.clockTolerance);
623
+ break;
624
+ case "number":
625
+ u = n.clockTolerance;
626
+ break;
627
+ case "undefined":
628
+ u = 0;
629
+ break;
630
+ default:
631
+ throw new TypeError("Invalid clockTolerance option type");
632
+ }
633
+ const { currentDate: I } = n, f = $e(I || /* @__PURE__ */ new Date());
634
+ if ((r.iat !== void 0 || h) && typeof r.iat != "number")
635
+ throw new m('"iat" claim must be a number', r, "iat", "invalid");
636
+ if (r.nbf !== void 0) {
637
+ if (typeof r.nbf != "number")
638
+ throw new m('"nbf" claim must be a number', r, "nbf", "invalid");
639
+ if (r.nbf > f + u)
640
+ throw new m('"nbf" claim timestamp check failed', r, "nbf", "check_failed");
641
+ }
642
+ if (r.exp !== void 0) {
643
+ if (typeof r.exp != "number")
644
+ throw new m('"exp" claim must be a number', r, "exp", "invalid");
645
+ if (r.exp <= f - u)
646
+ throw new W('"exp" claim timestamp check failed', r, "exp", "check_failed");
647
+ }
648
+ if (h) {
649
+ const p = f - r.iat, P = typeof h == "number" ? h : M(h);
650
+ if (p - u > P)
651
+ throw new W('"iat" claim timestamp check failed (too far in the past)', r, "iat", "check_failed");
652
+ if (p < 0 - u)
653
+ throw new m('"iat" claim timestamp check failed (it should be in the past)', r, "iat", "check_failed");
654
+ }
655
+ return r;
196
656
  };
197
- var s = [];
198
- for (var O = 0; O < 256; ++O)
199
- s.push((O + 256).toString(16).slice(1));
200
- function te(t, e = 0) {
201
- return (s[t[e + 0]] + s[t[e + 1]] + s[t[e + 2]] + s[t[e + 3]] + "-" + s[t[e + 4]] + s[t[e + 5]] + "-" + s[t[e + 6]] + s[t[e + 7]] + "-" + s[t[e + 8]] + s[t[e + 9]] + "-" + s[t[e + 10]] + s[t[e + 11]] + s[t[e + 12]] + s[t[e + 13]] + s[t[e + 14]] + s[t[e + 15]]).toLowerCase();
202
- }
203
- var m, oe = new Uint8Array(16);
204
- function ne() {
205
- if (!m && (m = typeof crypto < "u" && crypto.getRandomValues && crypto.getRandomValues.bind(crypto), !m))
657
+ async function Ye(e, t, n) {
658
+ var a;
659
+ const r = await He(e, t, n);
660
+ if ((a = r.protectedHeader.crit) != null && a.includes("b64") && r.protectedHeader.b64 === !1)
661
+ throw new z("JWTs MUST NOT use unencoded payload");
662
+ const s = { payload: Ge(r.protectedHeader, r.payload, n), protectedHeader: r.protectedHeader };
663
+ return typeof t == "function" ? { ...s, key: r.key } : s;
664
+ }
665
+ var d = [];
666
+ for (var N = 0; N < 256; ++N)
667
+ d.push((N + 256).toString(16).slice(1));
668
+ function qe(e, t = 0) {
669
+ return (d[e[t + 0]] + d[e[t + 1]] + d[e[t + 2]] + d[e[t + 3]] + "-" + d[e[t + 4]] + d[e[t + 5]] + "-" + d[e[t + 6]] + d[e[t + 7]] + "-" + d[e[t + 8]] + d[e[t + 9]] + "-" + d[e[t + 10]] + d[e[t + 11]] + d[e[t + 12]] + d[e[t + 13]] + d[e[t + 14]] + d[e[t + 15]]).toLowerCase();
670
+ }
671
+ var v, ze = new Uint8Array(16);
672
+ function Xe() {
673
+ if (!v && (v = typeof crypto < "u" && crypto.getRandomValues && crypto.getRandomValues.bind(crypto), !v))
206
674
  throw new Error("crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported");
207
- return m(oe);
675
+ return v(ze);
208
676
  }
209
- var re = typeof crypto < "u" && crypto.randomUUID && crypto.randomUUID.bind(crypto);
210
- const D = {
211
- randomUUID: re
677
+ var je = typeof crypto < "u" && crypto.randomUUID && crypto.randomUUID.bind(crypto);
678
+ const B = {
679
+ randomUUID: je
212
680
  };
213
- function se(t, e, o) {
214
- if (D.randomUUID && !e && !t)
215
- return D.randomUUID();
216
- t = t || {};
217
- var n = t.random || (t.rng || ne)();
218
- return n[6] = n[6] & 15 | 64, n[8] = n[8] & 63 | 128, te(n);
219
- }
220
- const ce = process.env.NODE_ENV === "production", ae = !ce, ie = async ({ params: t = {} }) => {
681
+ function Qe(e, t, n) {
682
+ if (B.randomUUID && !t && !e)
683
+ return B.randomUUID();
684
+ e = e || {};
685
+ var r = e.random || (e.rng || Xe)();
686
+ return r[6] = r[6] & 15 | 64, r[8] = r[8] & 63 | 128, qe(r);
687
+ }
688
+ const Ze = process.env.NODE_ENV === "production", et = !Ze, tt = async ({ params: e = {} }) => {
221
689
  try {
222
- const e = se(), o = await fetch(
223
- ae ? `${J.dev}/authenticate` : `${J.prod}/authenticate`,
690
+ const t = Qe(), n = await fetch(
691
+ et ? `${L.dev}/authenticate` : `${L.prod}/authenticate`,
224
692
  {
225
693
  credentials: "include",
226
694
  method: "POST",
227
695
  headers: {
228
696
  "Content-Type": "application/json",
229
- [G.CLIENT_ID]: `${t.clientId}`
697
+ [ue.CLIENT_ID]: `${e.clientId}`
230
698
  },
231
- body: JSON.stringify({ ...t, nonce: e })
699
+ body: JSON.stringify({ ...e, nonce: t })
232
700
  }
233
701
  );
234
- if (o.status !== 200)
235
- return { status: o.status, data: [] };
236
- const { data: n, errors: c } = await o.json();
237
- return n.nonce !== e ? { status: 500, data: [] } : {
238
- status: o.status,
239
- data: n,
240
- errors: c
702
+ if (n.status !== 200)
703
+ return { status: n.status, data: [] };
704
+ const { data: r, errors: o } = await n.json();
705
+ return r.nonce !== t ? { status: 500, data: [] } : {
706
+ status: n.status,
707
+ data: r,
708
+ errors: o
709
+ };
710
+ } catch (t) {
711
+ return console.error(t), { status: 500, data: [] };
712
+ }
713
+ }, te = async (e, t) => {
714
+ try {
715
+ const n = b.ALG, o = await xe(Se, n);
716
+ return await Ye(e, o, {
717
+ issuer: b.ISSUER,
718
+ audience: t
719
+ });
720
+ } catch {
721
+ return;
722
+ }
723
+ }, rt = async ({
724
+ username: e,
725
+ password: t,
726
+ clientId: n,
727
+ sessionExpiration: r
728
+ }) => {
729
+ try {
730
+ const o = await tt({
731
+ params: {
732
+ type: ce.ID_TOKEN,
733
+ username: e,
734
+ password: t,
735
+ sessionExpiration: r,
736
+ clientId: n
737
+ }
738
+ }), s = await te(o.data.idToken, n);
739
+ return s && s.payload[b.USER_ID_KEY] !== "" ? {
740
+ idToken: o.data.idToken,
741
+ userId: s.payload[b.USER_ID_KEY],
742
+ status: !0
743
+ } : {
744
+ status: !1
745
+ };
746
+ } catch {
747
+ return {
748
+ status: !1
241
749
  };
242
- } catch (e) {
243
- return console.error(e), { status: 500, data: [] };
244
750
  }
245
751
  };
246
- function ue(t) {
247
- const e = R();
248
- return f(() => {
249
- e.current = t;
250
- }), e.current;
251
- }
252
- const U = () => {
253
- throw new Error(ee);
254
- }, P = M({
752
+ function nt(e) {
753
+ const t = oe();
754
+ return G(() => {
755
+ t.current = e;
756
+ }), t.current;
757
+ }
758
+ const F = () => {
759
+ throw new Error(me);
760
+ }, re = ae({
255
761
  isAuthenticated: !1,
256
- login: U,
257
- logout: U,
762
+ login: F,
763
+ logout: F,
258
764
  accessToken: void 0,
259
765
  refreshToken: void 0,
260
766
  idToken: void 0,
261
767
  logoutReason: ""
262
- }), he = ({
263
- children: t,
264
- sessionExpiration: e,
265
- clientId: o,
266
- accessType: n
768
+ }), st = ({
769
+ children: e,
770
+ sessionExpiration: t,
771
+ clientId: n
267
772
  }) => {
268
- const [c, d, u] = S(
269
- `@@auth@@::${o}::@@access@@`,
270
- ""
271
- ), [h, p, _] = S(
272
- `@@auth@@::${o}::@@refresh@@`,
273
- ""
274
- ), [i, v, r] = S(
275
- `@@auth@@::${o}::@@user@@`,
276
- ""
277
- ), [a, g] = x({
278
- isAuthenticated: !!i,
279
- accessToken: c,
280
- refreshToken: h,
281
- idToken: i,
773
+ const [r, o, , s] = fe({
774
+ key: `${ye}::${n}::@@user@@`
775
+ }), [a, i] = se({
776
+ isAuthenticated: !!r,
282
777
  logoutReason: "",
283
778
  userId: ""
284
- }), y = ue(i) || "";
285
- f(() => {
286
- if (y !== i && i !== "")
779
+ }), c = nt(r) || "";
780
+ G(() => {
781
+ c !== r && r !== null && (async () => {
287
782
  try {
288
- const { _id: E } = N(i);
289
- g({
783
+ const u = await te(r, n);
784
+ u && u.payload[b.USER_ID_KEY] !== "" && i({
290
785
  isAuthenticated: !0,
291
- accessToken: c,
292
- refreshToken: h,
293
- idToken: i,
294
786
  logoutReason: "",
295
- userId: E || ""
787
+ userId: u.payload[b.USER_ID_KEY]
296
788
  });
297
789
  } catch {
298
- g({
790
+ i({
299
791
  isAuthenticated: !1,
300
- accessToken: "",
301
- refreshToken: "",
302
- idToken: "",
303
- logoutReason: C,
792
+ logoutReason: he,
304
793
  userId: ""
305
794
  });
306
795
  }
307
- else
308
- y !== i && i === "" && g({
309
- isAuthenticated: !1,
310
- accessToken: "",
311
- refreshToken: "",
312
- idToken: "",
313
- logoutReason: C,
314
- userId: ""
315
- });
316
- }, [c, h, i, y]);
317
- const $ = async (E, W) => {
318
- const l = await ie({
319
- params: {
320
- type: n || X.ID_TOKEN,
321
- username: E,
322
- password: W,
323
- sessionExpiration: e,
324
- clientId: o
325
- }
796
+ })();
797
+ }, [r, c, n]);
798
+ const h = async (u, I) => {
799
+ const f = await rt({
800
+ username: u,
801
+ password: I,
802
+ clientId: n,
803
+ sessionExpiration: t
326
804
  });
327
- try {
328
- const { _id: I } = N(l.data.idToken);
329
- return I ? (v(l.data.idToken), l.data.accessToken && d(l.data.accessToken), l.data.refreshToken && p(l.data.refreshToken), g({
330
- isAuthenticated: !0,
331
- idToken: l.data.idToken,
332
- accessToken: l.data.accessToken,
333
- refreshToken: l.data.refreshToken,
334
- userId: I,
335
- logoutReason: ""
336
- }), !0) : !1;
337
- } catch {
338
- return !1;
339
- }
340
- }, V = () => {
341
- u(), _(), r();
805
+ return f.status ? (o(f.idToken), i({
806
+ isAuthenticated: !0,
807
+ userId: f.userId
808
+ }), !0) : !1;
809
+ }, y = () => {
810
+ i({
811
+ isAuthenticated: !1,
812
+ logoutReason: pe,
813
+ userId: ""
814
+ }), s();
342
815
  };
343
- return /* @__PURE__ */ z(P.Provider, { value: { ...a, login: $, logout: V }, children: t });
344
- }, ge = (t = P) => H(t);
816
+ return /* @__PURE__ */ ne(re.Provider, { value: { ...a, login: h, logout: y }, children: e });
817
+ }, it = (e = re) => ie(e);
345
818
  export {
346
- he as AuthProvider,
347
- ge as useAuth
819
+ st as AuthProvider,
820
+ it as useAuth
348
821
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@versini/auth-provider",
3
- "version": "2.0.2",
3
+ "version": "2.1.1",
4
4
  "license": "MIT",
5
5
  "author": "Arno Versini",
6
6
  "publishConfig": {
@@ -44,10 +44,10 @@
44
44
  "react-dom": "18.3.1"
45
45
  },
46
46
  "dependencies": {
47
- "@versini/auth-common": "2.0.0",
48
- "@versini/ui-hooks": "3.0.0",
47
+ "@versini/auth-common": "2.1.0",
48
+ "@versini/ui-hooks": "4.0.0",
49
49
  "jose": "5.4.1",
50
50
  "uuid": "10.0.0"
51
51
  },
52
- "gitHead": "e60af859117bfbd5af8dd27504cd1ca214c28194"
52
+ "gitHead": "1b07ca8f692468b40f3c579a94cb3b933cc3a88f"
53
53
  }