@icp-sdk/auth 4.0.0-beta.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.
@@ -0,0 +1,144 @@
1
+ type IdleCB = () => unknown;
2
+
3
+ export type IdleManagerOptions = {
4
+ /**
5
+ * Callback after the user has gone idle
6
+ */
7
+ onIdle?: IdleCB;
8
+ /**
9
+ * timeout in ms
10
+ * @default 30 minutes [600_000]
11
+ */
12
+ idleTimeout?: number;
13
+ /**
14
+ * capture scroll events
15
+ * @default false
16
+ */
17
+ captureScroll?: boolean;
18
+ /**
19
+ * scroll debounce time in ms
20
+ * @default 100
21
+ */
22
+ scrollDebounce?: number;
23
+ };
24
+
25
+ const events = ['mousedown', 'mousemove', 'keydown', 'touchstart', 'wheel'];
26
+
27
+ /**
28
+ * Detects if the user has been idle for a duration of `idleTimeout` ms, and calls `onIdle` and registered callbacks.
29
+ * By default, the IdleManager will log a user out after 10 minutes of inactivity.
30
+ * To override these defaults, you can pass an `onIdle` callback, or configure a custom `idleTimeout` in milliseconds
31
+ */
32
+ export class IdleManager {
33
+ callbacks: IdleCB[] = [];
34
+ idleTimeout: IdleManagerOptions['idleTimeout'] = 10 * 60 * 1000;
35
+ timeoutID?: number = undefined;
36
+
37
+ /**
38
+ * Creates an {@link IdleManager}
39
+ * @param {IdleManagerOptions} options Optional configuration
40
+ * @see {@link IdleManagerOptions}
41
+ * @param options.onIdle Callback once user has been idle. Use to prompt for fresh login, and use `Actor.agentOf(your_actor).invalidateIdentity()` to protect the user
42
+ * @param options.idleTimeout timeout in ms
43
+ * @param options.captureScroll capture scroll events
44
+ * @param options.scrollDebounce scroll debounce time in ms
45
+ */
46
+ public static create(
47
+ options: {
48
+ /**
49
+ * Callback after the user has gone idle
50
+ * @see {@link IdleCB}
51
+ */
52
+ onIdle?: () => unknown;
53
+ /**
54
+ * timeout in ms
55
+ * @default 10 minutes [600_000]
56
+ */
57
+ idleTimeout?: number;
58
+ /**
59
+ * capture scroll events
60
+ * @default false
61
+ */
62
+ captureScroll?: boolean;
63
+ /**
64
+ * scroll debounce time in ms
65
+ * @default 100
66
+ */
67
+ scrollDebounce?: number;
68
+ } = {},
69
+ ): IdleManager {
70
+ return new IdleManager(options);
71
+ }
72
+
73
+ /**
74
+ * @protected
75
+ * @param options {@link IdleManagerOptions}
76
+ */
77
+ protected constructor(options: IdleManagerOptions = {}) {
78
+ const { onIdle, idleTimeout = 10 * 60 * 1000 } = options || {};
79
+
80
+ this.callbacks = onIdle ? [onIdle] : [];
81
+ this.idleTimeout = idleTimeout;
82
+
83
+ const _resetTimer = this._resetTimer.bind(this);
84
+
85
+ window.addEventListener('load', _resetTimer, true);
86
+
87
+ events.forEach((name) => {
88
+ document.addEventListener(name, _resetTimer, true);
89
+ });
90
+
91
+ const debounce = (func: (...args: unknown[]) => void, wait: number) => {
92
+ let timeout: number | undefined;
93
+ return (...args: unknown[]) => {
94
+ const context = this;
95
+ const later = () => {
96
+ timeout = undefined;
97
+ func.apply(context, args);
98
+ };
99
+ clearTimeout(timeout);
100
+ timeout = window.setTimeout(later, wait);
101
+ };
102
+ };
103
+
104
+ if (options?.captureScroll) {
105
+ // debounce scroll events
106
+ const scroll = debounce(_resetTimer, options?.scrollDebounce ?? 100);
107
+ window.addEventListener('scroll', scroll, true);
108
+ }
109
+
110
+ _resetTimer();
111
+ }
112
+
113
+ /**
114
+ * @param {IdleCB} callback function to be called when user goes idle
115
+ */
116
+ public registerCallback(callback: IdleCB): void {
117
+ this.callbacks.push(callback);
118
+ }
119
+
120
+ /**
121
+ * Cleans up the idle manager and its listeners
122
+ */
123
+ public exit(): void {
124
+ clearTimeout(this.timeoutID);
125
+ window.removeEventListener('load', this._resetTimer, true);
126
+
127
+ const _resetTimer = this._resetTimer.bind(this);
128
+ events.forEach((name) => {
129
+ document.removeEventListener(name, _resetTimer, true);
130
+ });
131
+ this.callbacks.forEach((cb) => {
132
+ cb();
133
+ });
134
+ }
135
+
136
+ /**
137
+ * Resets the timeouts during cleanup
138
+ */
139
+ _resetTimer(): void {
140
+ const exit = this.exit.bind(this);
141
+ window.clearTimeout(this.timeoutID);
142
+ this.timeoutID = window.setTimeout(exit, this.idleTimeout);
143
+ }
144
+ }
@@ -0,0 +1,10 @@
1
+ export * from './auth-client.ts';
2
+ export { type DBCreateOptions, IdbKeyVal } from './db.ts';
3
+ export * from './idle-manager.ts';
4
+ export {
5
+ type AuthClientStorage,
6
+ IdbStorage,
7
+ KEY_STORAGE_DELEGATION,
8
+ KEY_STORAGE_KEY,
9
+ LocalStorage,
10
+ } from './storage.ts';
@@ -0,0 +1,112 @@
1
+ import { type DBCreateOptions, IdbKeyVal } from './db.ts';
2
+
3
+ export const KEY_STORAGE_KEY = 'identity';
4
+ export const KEY_STORAGE_DELEGATION = 'delegation';
5
+ export const KEY_VECTOR = 'iv';
6
+ // Increment if any fields are modified
7
+ export const DB_VERSION = 1;
8
+
9
+ export type StoredKey = string | CryptoKeyPair;
10
+
11
+ /**
12
+ * Interface for persisting user authentication data
13
+ */
14
+ export interface AuthClientStorage {
15
+ get(key: string): Promise<StoredKey | null>;
16
+
17
+ set(key: string, value: StoredKey): Promise<void>;
18
+
19
+ remove(key: string): Promise<void>;
20
+ }
21
+
22
+ /**
23
+ * Legacy implementation of AuthClientStorage, for use where IndexedDb is not available
24
+ */
25
+ export class LocalStorage implements AuthClientStorage {
26
+ constructor(
27
+ public readonly prefix = 'ic-',
28
+ private readonly _localStorage?: Storage,
29
+ ) {}
30
+
31
+ public get(key: string): Promise<string | null> {
32
+ return Promise.resolve(this._getLocalStorage().getItem(this.prefix + key));
33
+ }
34
+
35
+ public set(key: string, value: string): Promise<void> {
36
+ this._getLocalStorage().setItem(this.prefix + key, value);
37
+ return Promise.resolve();
38
+ }
39
+
40
+ public remove(key: string): Promise<void> {
41
+ this._getLocalStorage().removeItem(this.prefix + key);
42
+ return Promise.resolve();
43
+ }
44
+
45
+ private _getLocalStorage() {
46
+ if (this._localStorage) {
47
+ return this._localStorage;
48
+ }
49
+
50
+ const ls = globalThis.localStorage;
51
+ if (!ls) {
52
+ throw new Error('Could not find local storage.');
53
+ }
54
+
55
+ return ls;
56
+ }
57
+ }
58
+
59
+ /**
60
+ * IdbStorage is an interface for simple storage of string key-value pairs built on {@link IdbKeyVal}
61
+ *
62
+ * It replaces {@link LocalStorage}
63
+ * @see implements {@link AuthClientStorage}
64
+ */
65
+ export class IdbStorage implements AuthClientStorage {
66
+ #options: DBCreateOptions;
67
+
68
+ /**
69
+ * @param options - DBCreateOptions
70
+ * @param options.dbName - name for the indexeddb database
71
+ * @param options.storeName - name for the indexeddb Data Store
72
+ * @param options.version - version of the database. Increment to safely upgrade
73
+ * @example
74
+ * ```ts
75
+ * const storage = new IdbStorage({ dbName: 'my-db', storeName: 'my-store', version: 2 });
76
+ * ```
77
+ */
78
+ constructor(options?: DBCreateOptions) {
79
+ this.#options = options ?? {};
80
+ }
81
+
82
+ // Initializes a KeyVal on first request
83
+ private initializedDb: IdbKeyVal | undefined;
84
+ get _db(): Promise<IdbKeyVal> {
85
+ return new Promise((resolve) => {
86
+ if (this.initializedDb) {
87
+ resolve(this.initializedDb);
88
+ return;
89
+ }
90
+ IdbKeyVal.create(this.#options).then((db) => {
91
+ this.initializedDb = db;
92
+ resolve(db);
93
+ });
94
+ });
95
+ }
96
+
97
+ public async get<T = string>(key: string): Promise<T | null> {
98
+ const db = await this._db;
99
+ return await db.get<T>(key);
100
+ // return (await db.get<string>(key)) ?? null;
101
+ }
102
+
103
+ public async set<T = string>(key: string, value: T): Promise<void> {
104
+ const db = await this._db;
105
+ await db.set(key, value);
106
+ }
107
+
108
+ public async remove(key: string): Promise<void> {
109
+ const db = await this._db;
110
+ await db.remove(key);
111
+ }
112
+ }
package/src/index.ts ADDED
@@ -0,0 +1,3 @@
1
+ throw new Error(
2
+ 'There are no exports in the root module of this package. Import from submodules instead. Use intellisense or the docs to find the available submodules.',
3
+ );