oidc-spa 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/oidc.ts ADDED
@@ -0,0 +1,398 @@
1
+ import { UserManager, type User } from "oidc-client-ts";
2
+ import { id } from "tsafe/id";
3
+ import { readExpirationTimeInJwt } from "./tools/readExpirationTimeInJwt";
4
+ import { assert } from "tsafe/assert";
5
+ import { addParamToUrl, retrieveParamFromUrl } from "./tools/urlSearchParams";
6
+ import { fnv1aHashToHex } from "./tools/fnv1aHashToHex";
7
+ import { Deferred } from "./tools/Deferred";
8
+
9
+ export declare type Oidc = Oidc.LoggedIn | Oidc.NotLoggedIn;
10
+
11
+ export declare namespace Oidc {
12
+ export type Common = {
13
+ params: {
14
+ issuerUri: string;
15
+ clientId: string;
16
+ };
17
+ };
18
+
19
+ export type NotLoggedIn = Common & {
20
+ isUserLoggedIn: false;
21
+ login: (params: { doesCurrentHrefRequiresAuth: boolean }) => Promise<never>;
22
+ };
23
+
24
+ export type LoggedIn = Common & {
25
+ isUserLoggedIn: true;
26
+ renewTokens(): Promise<void>;
27
+ getTokens: () => Tokens;
28
+ logout: (params: { redirectTo: "home" | "current page" }) => Promise<never>;
29
+ };
30
+
31
+ export type Tokens = {
32
+ accessToken: string;
33
+ accessTokenExpirationTime: number;
34
+ idToken: string;
35
+ refreshToken: string;
36
+ refreshTokenExpirationTime: number;
37
+ };
38
+ }
39
+
40
+ const paramsToRetrieveFromSuccessfulLogin = ["code", "state", "session_state"] as const;
41
+
42
+ export async function createOidc(params: {
43
+ issuerUri: string;
44
+ clientId: string;
45
+ transformUrlBeforeRedirect?: (url: string) => string;
46
+ /** Default `${window.location.origin}/silent-sso.html` */
47
+ silentSsoUrl?: string;
48
+ }): Promise<Oidc> {
49
+ const {
50
+ issuerUri,
51
+ clientId,
52
+ silentSsoUrl = `${window.location.origin}/silent-sso.html`,
53
+ transformUrlBeforeRedirect = url => url
54
+ } = params;
55
+
56
+ const configHash = fnv1aHashToHex(`${issuerUri} ${clientId}`);
57
+ const configHashKey = "configHash";
58
+
59
+ const userManager = new UserManager({
60
+ "authority": issuerUri,
61
+ "client_id": clientId,
62
+ "redirect_uri": "" /* provided when calling login */,
63
+ "response_type": "code",
64
+ "scope": "openid profile",
65
+ "automaticSilentRenew": false,
66
+ "silent_redirect_uri": `${silentSsoUrl}?${configHashKey}=${configHash}`
67
+ });
68
+
69
+ const login: Oidc.NotLoggedIn["login"] = async ({ doesCurrentHrefRequiresAuth }) => {
70
+ //NOTE: We know there is a extraQueryParameter option but it doesn't allow
71
+ // to control the encoding so we have to hack the global URL Class that is
72
+ // used internally by oidc-client-ts
73
+
74
+ const URL_real = window.URL;
75
+
76
+ function URL(...args: ConstructorParameters<typeof URL_real>) {
77
+ const urlInstance = new URL_real(...args);
78
+
79
+ return new Proxy(urlInstance, {
80
+ "get": (target, prop) => {
81
+ if (prop === "href") {
82
+ return transformUrlBeforeRedirect(urlInstance.href);
83
+ }
84
+
85
+ //@ts-expect-error
86
+ return target[prop];
87
+ }
88
+ });
89
+ }
90
+
91
+ Object.defineProperty(window, "URL", { "value": URL });
92
+
93
+ const { newUrl: redirect_uri } = addParamToUrl({
94
+ "url": window.location.href,
95
+ "name": configHashKey,
96
+ "value": configHash
97
+ });
98
+
99
+ await userManager.signinRedirect({
100
+ redirect_uri,
101
+ "redirectMethod": doesCurrentHrefRequiresAuth ? "replace" : "assign"
102
+ });
103
+ return new Promise<never>(() => {});
104
+ };
105
+
106
+ const currentTokens = await (async function getUser() {
107
+ read_successful_login_query_params: {
108
+ let url = window.location.href;
109
+
110
+ {
111
+ const result = retrieveParamFromUrl({ "name": configHashKey, url });
112
+
113
+ if (!result.wasPresent || result.value !== configHash) {
114
+ break read_successful_login_query_params;
115
+ }
116
+
117
+ url = result.newUrl;
118
+ }
119
+
120
+ {
121
+ const result = retrieveParamFromUrl({ "name": "error", url });
122
+
123
+ if (result.wasPresent) {
124
+ throw new Error(`OIDC error: ${result.value}`);
125
+ }
126
+ }
127
+
128
+ let loginSuccessUrl = "https://dummy.com";
129
+
130
+ for (const name of paramsToRetrieveFromSuccessfulLogin) {
131
+ const result = retrieveParamFromUrl({ name, url });
132
+
133
+ assert(result.wasPresent);
134
+
135
+ loginSuccessUrl = addParamToUrl({
136
+ "url": loginSuccessUrl,
137
+ "name": name,
138
+ "value": result.value
139
+ }).newUrl;
140
+
141
+ url = result.newUrl;
142
+ }
143
+
144
+ window.history.pushState(null, "", url);
145
+
146
+ let user: User | undefined = undefined;
147
+
148
+ try {
149
+ user = await userManager.signinRedirectCallback(loginSuccessUrl);
150
+ } catch {
151
+ //NOTE: The user has likely pressed the back button just after logging in.
152
+ return undefined;
153
+ }
154
+
155
+ return user;
156
+ }
157
+
158
+ restore_from_session: {
159
+ const user = await userManager.getUser();
160
+
161
+ if (user === null) {
162
+ break restore_from_session;
163
+ }
164
+
165
+ // The server might have restarted and the session might have been lost.
166
+ try {
167
+ await userManager.signinSilent();
168
+ } catch {
169
+ return undefined;
170
+ }
171
+
172
+ return user;
173
+ }
174
+
175
+ restore_from_http_only_cookie: {
176
+ const dLoginSuccessUrl = new Deferred<string | undefined>();
177
+
178
+ const timeout = setTimeout(
179
+ () =>
180
+ dLoginSuccessUrl.reject(
181
+ new Error(`SSO silent login timeout with clientId: ${clientId}`)
182
+ ),
183
+ 5000
184
+ );
185
+
186
+ const listener = (event: MessageEvent) => {
187
+ if (event.origin !== window.location.origin || typeof event.data !== "string") {
188
+ return;
189
+ }
190
+
191
+ const url = event.data;
192
+
193
+ {
194
+ let result: ReturnType<typeof retrieveParamFromUrl>;
195
+
196
+ try {
197
+ result = retrieveParamFromUrl({ "name": configHashKey, url });
198
+ } catch {
199
+ // This could possibly happen if url is not a valid url.
200
+ return;
201
+ }
202
+
203
+ if (!result.wasPresent || result.value !== configHash) {
204
+ return;
205
+ }
206
+ }
207
+
208
+ clearTimeout(timeout);
209
+
210
+ window.removeEventListener("message", listener);
211
+
212
+ {
213
+ const result = retrieveParamFromUrl({ "name": "error", url });
214
+
215
+ if (result.wasPresent) {
216
+ dLoginSuccessUrl.resolve(undefined);
217
+ return;
218
+ }
219
+ }
220
+
221
+ let loginSuccessUrl = "https://dummy.com";
222
+
223
+ for (const name of paramsToRetrieveFromSuccessfulLogin) {
224
+ const result = retrieveParamFromUrl({ name, url });
225
+
226
+ assert(result.wasPresent);
227
+
228
+ loginSuccessUrl = addParamToUrl({
229
+ "url": loginSuccessUrl,
230
+ "name": name,
231
+ "value": result.value
232
+ }).newUrl;
233
+ }
234
+
235
+ dLoginSuccessUrl.resolve(loginSuccessUrl);
236
+ };
237
+
238
+ window.addEventListener("message", listener, false);
239
+
240
+ userManager.signinSilent({ "silentRequestTimeoutInSeconds": 1 }).catch(() => {
241
+ /* error expected */
242
+ });
243
+
244
+ const loginSuccessUrl = await dLoginSuccessUrl.pr;
245
+
246
+ if (loginSuccessUrl === undefined) {
247
+ break restore_from_http_only_cookie;
248
+ }
249
+
250
+ const user = await userManager.signinRedirectCallback(loginSuccessUrl);
251
+
252
+ return user;
253
+ }
254
+
255
+ return undefined;
256
+ })().then(user => {
257
+ if (user === undefined) {
258
+ return undefined;
259
+ }
260
+
261
+ const tokens = userToTokens(user);
262
+
263
+ if (tokens.refreshTokenExpirationTime < tokens.accessTokenExpirationTime) {
264
+ console.warn(
265
+ [
266
+ "The OIDC refresh token shorter than the one of the access token.",
267
+ "This is very unusual and probably a misconfiguration.",
268
+ `Check your oidc server configuration for ${clientId} ${issuerUri}`
269
+ ].join(" ")
270
+ );
271
+ }
272
+
273
+ return tokens;
274
+ });
275
+
276
+ const common: Oidc.Common = {
277
+ "params": {
278
+ issuerUri,
279
+ clientId
280
+ }
281
+ };
282
+
283
+ if (currentTokens === undefined) {
284
+ return id<Oidc.NotLoggedIn>({
285
+ ...common,
286
+ "isUserLoggedIn": false,
287
+ login
288
+ });
289
+ }
290
+
291
+ const oidc = id<Oidc.LoggedIn>({
292
+ ...common,
293
+ "isUserLoggedIn": true,
294
+ "getTokens": () => ({
295
+ "accessToken": currentTokens.accessToken,
296
+ "idToken": currentTokens.idToken,
297
+ "refreshToken": currentTokens.refreshToken,
298
+ "refreshTokenExpirationTime": currentTokens.refreshTokenExpirationTime,
299
+ "accessTokenExpirationTime": currentTokens.accessTokenExpirationTime
300
+ }),
301
+ "logout": async ({ redirectTo }) => {
302
+ await userManager.signoutRedirect({
303
+ "post_logout_redirect_uri": (() => {
304
+ switch (redirectTo) {
305
+ case "current page":
306
+ return window.location.href;
307
+ case "home":
308
+ return window.location.origin;
309
+ }
310
+ })()
311
+ });
312
+ return new Promise<never>(() => {});
313
+ },
314
+ "renewTokens": async () => {
315
+ const user = await userManager.signinSilent();
316
+
317
+ assert(user !== null);
318
+
319
+ Object.assign(currentTokens, userToTokens(user));
320
+ }
321
+ });
322
+
323
+ (function scheduleAutomaticRenew() {
324
+ const msBeforeExpiration =
325
+ Math.min(currentTokens.accessTokenExpirationTime, currentTokens.refreshTokenExpirationTime) -
326
+ Date.now();
327
+
328
+ setTimeout(async () => {
329
+ try {
330
+ await oidc.renewTokens();
331
+ } catch {
332
+ await login({ "doesCurrentHrefRequiresAuth": true });
333
+ }
334
+
335
+ scheduleAutomaticRenew();
336
+ }, msBeforeExpiration - /* min validity in seconds */ 25 * 1000);
337
+ })();
338
+
339
+ return oidc;
340
+ }
341
+
342
+ function userToTokens(user: User): Oidc.Tokens {
343
+ const accessToken = user.access_token;
344
+
345
+ const accessTokenExpirationTime = (() => {
346
+ read_from_metadata: {
347
+ const { expires_at } = user;
348
+
349
+ if (expires_at === undefined) {
350
+ break read_from_metadata;
351
+ }
352
+
353
+ return expires_at * 1000;
354
+ }
355
+
356
+ read_from_jwt: {
357
+ const expirationTime = readExpirationTimeInJwt(accessToken);
358
+
359
+ if (expirationTime === undefined) {
360
+ break read_from_jwt;
361
+ }
362
+
363
+ return expirationTime;
364
+ }
365
+
366
+ assert(false, "Failed to get access token expiration time");
367
+ })();
368
+
369
+ const refreshToken = user.refresh_token;
370
+
371
+ assert(refreshToken !== undefined, "No refresh token provided by the oidc server");
372
+
373
+ const refreshTokenExpirationTime = (() => {
374
+ read_from_jwt: {
375
+ const expirationTime = readExpirationTimeInJwt(refreshToken);
376
+
377
+ if (expirationTime === undefined) {
378
+ break read_from_jwt;
379
+ }
380
+
381
+ return expirationTime;
382
+ }
383
+
384
+ assert(false, "Failed to get refresh token expiration time");
385
+ })();
386
+
387
+ const idToken = user.id_token;
388
+
389
+ assert(idToken !== undefined, "No id token provided by the oidc server");
390
+
391
+ return {
392
+ accessToken,
393
+ accessTokenExpirationTime,
394
+ refreshToken,
395
+ refreshTokenExpirationTime,
396
+ idToken
397
+ };
398
+ }
package/src/react.tsx ADDED
@@ -0,0 +1,33 @@
1
+ import { useEffect, useState, createContext, useContext, type ReactNode } from "react";
2
+ import { createOidc, type Oidc } from "./oidc";
3
+ import { assert } from "tsafe/assert";
4
+
5
+ const oidcClientContext = createContext<Oidc | undefined>(undefined);
6
+
7
+ export function createOidcClientProvider(params: Parameters<typeof createOidc>[0]) {
8
+ const prOidc = createOidc(params);
9
+
10
+ function OidcClientProvider(props: { fallback?: ReactNode; children: ReactNode }) {
11
+ const { children, fallback } = props;
12
+
13
+ const [oidcClient, setOidcClient] = useState<Oidc | undefined>(undefined);
14
+
15
+ useEffect(() => {
16
+ prOidc.then(setOidcClient);
17
+ }, []);
18
+
19
+ if (oidcClient === undefined) {
20
+ return <>{fallback === undefined ? null : fallback}</>;
21
+ }
22
+
23
+ return <oidcClientContext.Provider value={oidcClient}>{children}</oidcClientContext.Provider>;
24
+ }
25
+
26
+ return { OidcClientProvider };
27
+ }
28
+
29
+ export function useOidc() {
30
+ const oidc = useContext(oidcClientContext);
31
+ assert(oidc !== undefined, "You must use useOidc inside a OidcClientProvider");
32
+ return { oidc };
33
+ }
@@ -0,0 +1,39 @@
1
+ import { overwriteReadonlyProp } from "tsafe/lab/overwriteReadonlyProp";
2
+
3
+ export class Deferred<T> {
4
+ public readonly pr: Promise<T>;
5
+
6
+ /** NOTE: Does not need to be called bound to instance*/
7
+ public readonly resolve: (value: T) => void;
8
+ public readonly reject: (error: any) => void;
9
+
10
+ constructor() {
11
+ let resolve!: (value: T) => void;
12
+ let reject!: (error: any) => void;
13
+
14
+ this.pr = new Promise<T>((resolve_, reject_) => {
15
+ resolve = value => {
16
+ overwriteReadonlyProp(this, "isPending", false);
17
+ resolve_(value);
18
+ };
19
+
20
+ reject = error => {
21
+ overwriteReadonlyProp(this, "isPending", false);
22
+ reject_(error);
23
+ };
24
+ });
25
+
26
+ this.resolve = resolve;
27
+ this.reject = reject;
28
+ }
29
+
30
+ public readonly isPending: boolean = true;
31
+ }
32
+
33
+ export namespace Deferred {
34
+ export type Unpack<T extends Deferred<any>> = T extends Deferred<infer U> ? U : never;
35
+ }
36
+
37
+ export class VoidDeferred extends Deferred<undefined> {
38
+ public declare readonly resolve: () => void;
39
+ }
@@ -0,0 +1,8 @@
1
+ export function fnv1aHashToHex(str: string) {
2
+ let hash = 2166136261;
3
+ for (let i = 0; i < str.length; i++) {
4
+ hash ^= str.charCodeAt(i);
5
+ hash += (hash << 1) + (hash << 4) + (hash << 7) + (hash << 8) + (hash << 24);
6
+ }
7
+ return (hash >>> 0).toString(16); // Convert to unsigned 32-bit integer and then to hexadecimal
8
+ }
@@ -0,0 +1,17 @@
1
+ import decodeJwt from "jwt-decode";
2
+ import { assert } from "tsafe/assert";
3
+
4
+ // Return undefined if token provided wasn't a JWT or if it hasn't an exp claim number
5
+ export function readExpirationTimeInJwt(token: string): number | undefined {
6
+ let expirationTime: number;
7
+
8
+ try {
9
+ expirationTime = decodeJwt<{ exp: number }>(token).exp * 1000;
10
+
11
+ assert(typeof expirationTime === "number" && !isNaN(expirationTime));
12
+ } catch {
13
+ return undefined;
14
+ }
15
+
16
+ return expirationTime;
17
+ }
@@ -0,0 +1,86 @@
1
+ export function addParamToUrl(params: { url: string; name: string; value: string }): { newUrl: string } {
2
+ const { url, name, value } = params;
3
+
4
+ let newUrl = url;
5
+
6
+ const result = retrieveParamFromUrl({
7
+ url,
8
+ name
9
+ });
10
+
11
+ if (result.wasPresent) {
12
+ newUrl = result.newUrl;
13
+ }
14
+
15
+ newUrl += `${
16
+ newUrl.includes("?") ? "&" : newUrl.endsWith("?") ? "" : "?"
17
+ }${name}=${encodeURIComponent(value)}`;
18
+
19
+ return { newUrl };
20
+ }
21
+
22
+ export function retrieveAllParamStartingWithPrefixFromUrl<
23
+ Prefix extends string,
24
+ DoLeave extends boolean
25
+ >(params: {
26
+ url: string;
27
+ prefix: Prefix;
28
+ doLeavePrefixInResults: DoLeave;
29
+ }): { newUrl: string; values: Record<DoLeave extends true ? `${Prefix}${string}` : string, string> } {
30
+ const { url, prefix, doLeavePrefixInResults } = params;
31
+
32
+ const [baseUrl, locationSearch = ""] = url.split("?");
33
+
34
+ const values: Record<string, string> = {};
35
+
36
+ const { newLocationSearch } = (() => {
37
+ let newLocationSearch = locationSearch
38
+ .replace(/^\?/, "")
39
+ .split("&")
40
+ .map(part => part.split("=") as [string, string])
41
+ .filter(([key, value_i]) =>
42
+ !key.startsWith(prefix)
43
+ ? true
44
+ : ((values[doLeavePrefixInResults ? key : key.substring(prefix.length)] =
45
+ decodeURIComponent(value_i)),
46
+ false)
47
+ )
48
+ .map(entry => entry.join("="))
49
+ .join("&");
50
+ newLocationSearch = newLocationSearch === "" ? "" : `?${newLocationSearch}`;
51
+
52
+ return { newLocationSearch };
53
+ })();
54
+
55
+ return {
56
+ "newUrl": `${baseUrl}${newLocationSearch}`,
57
+ values
58
+ };
59
+ }
60
+
61
+ export function retrieveParamFromUrl(params: {
62
+ url: string;
63
+ name: string;
64
+ }): { wasPresent: false } | { wasPresent: true; newUrl: string; value: string } {
65
+ const { url, name } = params;
66
+
67
+ const { newUrl, values } = retrieveAllParamStartingWithPrefixFromUrl({
68
+ url,
69
+ "prefix": name,
70
+ "doLeavePrefixInResults": true
71
+ });
72
+
73
+ return name in values
74
+ ? {
75
+ "wasPresent": true,
76
+ newUrl,
77
+ "value": values[name]
78
+ }
79
+ : {
80
+ "wasPresent": false
81
+ };
82
+ }
83
+
84
+ export function updateSearchBarUrl(url: string) {
85
+ window.history.replaceState("", "", url);
86
+ }
@@ -0,0 +1,14 @@
1
+ export declare class Deferred<T> {
2
+ readonly pr: Promise<T>;
3
+ /** NOTE: Does not need to be called bound to instance*/
4
+ readonly resolve: (value: T) => void;
5
+ readonly reject: (error: any) => void;
6
+ constructor();
7
+ readonly isPending: boolean;
8
+ }
9
+ export declare namespace Deferred {
10
+ type Unpack<T extends Deferred<any>> = T extends Deferred<infer U> ? U : never;
11
+ }
12
+ export declare class VoidDeferred extends Deferred<undefined> {
13
+ readonly resolve: () => void;
14
+ }
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+ var __extends = (this && this.__extends) || (function () {
3
+ var extendStatics = function (d, b) {
4
+ extendStatics = Object.setPrototypeOf ||
5
+ ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
6
+ function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
7
+ return extendStatics(d, b);
8
+ };
9
+ return function (d, b) {
10
+ if (typeof b !== "function" && b !== null)
11
+ throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
12
+ extendStatics(d, b);
13
+ function __() { this.constructor = d; }
14
+ d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
15
+ };
16
+ })();
17
+ Object.defineProperty(exports, "__esModule", { value: true });
18
+ exports.VoidDeferred = exports.Deferred = void 0;
19
+ var overwriteReadonlyProp_1 = require("tsafe/lab/overwriteReadonlyProp");
20
+ var Deferred = /** @class */ (function () {
21
+ function Deferred() {
22
+ var _this = this;
23
+ this.isPending = true;
24
+ var resolve;
25
+ var reject;
26
+ this.pr = new Promise(function (resolve_, reject_) {
27
+ resolve = function (value) {
28
+ (0, overwriteReadonlyProp_1.overwriteReadonlyProp)(_this, "isPending", false);
29
+ resolve_(value);
30
+ };
31
+ reject = function (error) {
32
+ (0, overwriteReadonlyProp_1.overwriteReadonlyProp)(_this, "isPending", false);
33
+ reject_(error);
34
+ };
35
+ });
36
+ this.resolve = resolve;
37
+ this.reject = reject;
38
+ }
39
+ return Deferred;
40
+ }());
41
+ exports.Deferred = Deferred;
42
+ var VoidDeferred = /** @class */ (function (_super) {
43
+ __extends(VoidDeferred, _super);
44
+ function VoidDeferred() {
45
+ return _super !== null && _super.apply(this, arguments) || this;
46
+ }
47
+ return VoidDeferred;
48
+ }(Deferred));
49
+ exports.VoidDeferred = VoidDeferred;
50
+ //# sourceMappingURL=Deferred.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Deferred.js","sourceRoot":"","sources":["../src/tools/Deferred.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;AAAA,yEAAwE;AAExE;IAOI;QAAA,iBAkBC;QAEe,cAAS,GAAY,IAAI,CAAC;QAnBtC,IAAI,OAA4B,CAAC;QACjC,IAAI,MAA6B,CAAC;QAElC,IAAI,CAAC,EAAE,GAAG,IAAI,OAAO,CAAI,UAAC,QAAQ,EAAE,OAAO;YACvC,OAAO,GAAG,UAAA,KAAK;gBACX,IAAA,6CAAqB,EAAC,KAAI,EAAE,WAAW,EAAE,KAAK,CAAC,CAAC;gBAChD,QAAQ,CAAC,KAAK,CAAC,CAAC;YACpB,CAAC,CAAC;YAEF,MAAM,GAAG,UAAA,KAAK;gBACV,IAAA,6CAAqB,EAAC,KAAI,EAAE,WAAW,EAAE,KAAK,CAAC,CAAC;gBAChD,OAAO,CAAC,KAAK,CAAC,CAAC;YACnB,CAAC,CAAC;QACN,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACzB,CAAC;IAGL,eAAC;AAAD,CAAC,AA5BD,IA4BC;AA5BY,4BAAQ;AAkCrB;IAAkC,gCAAmB;IAArD;;IAEA,CAAC;IAAD,mBAAC;AAAD,CAAC,AAFD,CAAkC,QAAQ,GAEzC;AAFY,oCAAY"}
@@ -0,0 +1 @@
1
+ export declare function fnv1aHashToHex(str: string): string;
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.fnv1aHashToHex = void 0;
4
+ function fnv1aHashToHex(str) {
5
+ var hash = 2166136261;
6
+ for (var i = 0; i < str.length; i++) {
7
+ hash ^= str.charCodeAt(i);
8
+ hash += (hash << 1) + (hash << 4) + (hash << 7) + (hash << 8) + (hash << 24);
9
+ }
10
+ return (hash >>> 0).toString(16); // Convert to unsigned 32-bit integer and then to hexadecimal
11
+ }
12
+ exports.fnv1aHashToHex = fnv1aHashToHex;
13
+ //# sourceMappingURL=fnv1aHashToHex.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fnv1aHashToHex.js","sourceRoot":"","sources":["../src/tools/fnv1aHashToHex.ts"],"names":[],"mappings":";;;AAAA,SAAgB,cAAc,CAAC,GAAW;IACtC,IAAI,IAAI,GAAG,UAAU,CAAC;IACtB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;QACjC,IAAI,IAAI,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;QAC1B,IAAI,IAAI,CAAC,IAAI,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;KAChF;IACD,OAAO,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,6DAA6D;AACnG,CAAC;AAPD,wCAOC"}
@@ -0,0 +1 @@
1
+ export declare function readExpirationTimeInJwt(token: string): number | undefined;