diff --git a/docs/generated/changelog.html b/docs/generated/changelog.html
index dd5d0a447..fb773acc3 100644
--- a/docs/generated/changelog.html
+++ b/docs/generated/changelog.html
@@ -13,6 +13,10 @@
Agent-JS Changelog
Version x.x.x
- chore: adds js-sha256 dependency to principal
+ -
+ bug: fixes idlemanager initializing - now either requires createOptions.identity or
+ authClient.login to be called before starting idle timeout
+
Version 0.14.0
diff --git a/package-lock.json b/package-lock.json
index b5577d1c1..697b65236 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -22100,7 +22100,7 @@
"eslint": "^8.19.0",
"eslint-plugin-jsdoc": "^39.3.3",
"jest": "^28.1.2",
- "js-sha256": "*",
+ "js-sha256": "^0.9.0",
"text-encoding": "^0.7.0",
"ts-jest": "^28.0.5",
"ts-node": "^10.8.2",
diff --git a/packages/auth-client/src/index.test.ts b/packages/auth-client/src/index.test.ts
index bb7174c15..7c1525929 100644
--- a/packages/auth-client/src/index.test.ts
+++ b/packages/auth-client/src/index.test.ts
@@ -70,9 +70,14 @@ describe('Auth Client', () => {
expect(await test.isAuthenticated()).toBe(false);
expect(test.getIdentity().getPrincipal().isAnonymous()).toBe(true);
});
- it('should initialize an idleManager', async () => {
+ it('should not initialize an idleManager if the user is not logged in', async () => {
const test = await AuthClient.create();
+ expect(test.idleManager).not.toBeDefined();
+ });
+ it('should initialize an idleManager if an identity is passed', async () => {
+ const test = await AuthClient.create({ identity: await Ed25519KeyIdentity.generate() });
expect(test.idleManager).toBeDefined();
+ test.idleManager; //?
});
it('should be able to invalidate an identity after going idle', async () => {
// setup actor
@@ -141,14 +146,6 @@ describe('Auth Client', () => {
});
delete (window as any).location;
(window as any).location = { reload: jest.fn(), fetch };
- const mockFetch: jest.Mock = jest.fn();
-
- const canisterId = Principal.fromText('2chl6-4hpzw-vqaaa-aaaaa-c');
- const actorInterface = () => {
- return IDL.Service({
- greet: IDL.Func([IDL.Text], [IDL.Text]),
- });
- };
const storage: AuthClientStorage = {
remove: jest.fn(),
@@ -165,14 +162,14 @@ describe('Auth Client', () => {
});
// Test login flow
- await test.login({ identityProvider: 'http://localhost' });
+ const onSuccess = jest.fn();
+ test.login({ onSuccess });
+
+ idpMock.ready();
expect(storage.set).toBeCalled();
expect(storage.remove).not.toBeCalled();
- const httpAgent = new HttpAgent({ fetch: mockFetch, host: 'http://127.0.0.1:8000' });
- const actor = Actor.createActor(actorInterface, { canisterId, agent: httpAgent });
-
// simulate user being inactive for 10 minutes
jest.advanceTimersByTime(10 * 60 * 1000);
@@ -218,7 +215,8 @@ describe('Auth Client', () => {
});
// Test login flow
- await test.login({ identityProvider: 'http://localhost' });
+ await test.login();
+ idpMock.ready();
expect(storage.set).toBeCalled();
expect(storage.remove).not.toBeCalled();
@@ -232,6 +230,24 @@ describe('Auth Client', () => {
expect(window.location.reload).not.toBeCalled();
});
it('should not reload the page if a callback is provided', async () => {
+ setup({
+ onAuthRequest: () => {
+ // Send a valid request.
+ idpMock.send({
+ kind: 'authorize-client-success',
+ delegations: [
+ {
+ delegation: {
+ pubkey: Uint8Array.from([]),
+ expiration: BigInt(0),
+ },
+ signature: Uint8Array.from([]),
+ },
+ ],
+ userPublicKey: Uint8Array.from([]),
+ });
+ },
+ });
delete (window as any).location;
(window as any).location = { reload: jest.fn(), fetch };
const idleCb = jest.fn();
@@ -242,6 +258,9 @@ describe('Auth Client', () => {
},
});
+ test.login();
+ idpMock.ready();
+
// simulate user being inactive for 10 minutes
jest.advanceTimersByTime(10 * 60 * 1000);
@@ -325,6 +344,52 @@ describe('Auth Client', () => {
jest.advanceTimersByTime(30 * 60 * 1000);
expect(idleFn).not.toHaveBeenCalled();
});
+ it('should not set up an idle timer if the client is not logged in', async () => {
+ setup({
+ onAuthRequest: () => {
+ // Send a valid request.
+ idpMock.send({
+ kind: 'authorize-client-success',
+ delegations: [
+ {
+ delegation: {
+ pubkey: Uint8Array.from([]),
+ expiration: BigInt(0),
+ },
+ signature: Uint8Array.from([]),
+ },
+ ],
+ userPublicKey: Uint8Array.from([]),
+ });
+ },
+ });
+ delete (window as any).location;
+ (window as any).location = { reload: jest.fn(), fetch };
+
+ const storage: AuthClientStorage = {
+ remove: jest.fn(),
+ get: jest.fn(),
+ set: jest.fn(),
+ };
+
+ const test = await AuthClient.create({
+ storage,
+ idleOptions: {
+ idleTimeout: 1000,
+ },
+ });
+
+ expect(storage.set).toBeCalled();
+ expect(storage.remove).not.toBeCalled();
+
+ // simulate user being inactive for 10 minutes
+ jest.advanceTimersByTime(10 * 60 * 1000);
+
+ // Storage should not be cleared
+ expect(storage.remove).not.toBeCalled();
+ // Page should not be reloaded
+ expect(window.location.reload).not.toBeCalled();
+ });
});
describe('IdbStorage', () => {
@@ -527,7 +592,7 @@ describe('Auth Client login', () => {
const client = await AuthClient.create();
const onSuccess = jest.fn();
- await client.login({ onSuccess: onSuccess });
+ client.login({ onSuccess: onSuccess });
idpMock.ready();
diff --git a/packages/auth-client/src/index.ts b/packages/auth-client/src/index.ts
index 1dd3049fa..8625e9cc1 100644
--- a/packages/auth-client/src/index.ts
+++ b/packages/auth-client/src/index.ts
@@ -252,9 +252,14 @@ export class AuthClient {
key = null;
}
}
- const idleManager = options.idleOptions?.disableIdle
- ? undefined
- : IdleManager.create(options.idleOptions);
+ let idleManager: IdleManager | undefined = undefined;
+ if (options.idleOptions?.disableIdle) {
+ idleManager = undefined;
+ }
+ // if there is a delegation chain or provided identity, setup idleManager
+ else if (chain || options.identity) {
+ idleManager = IdleManager.create(options.idleOptions);
+ }
if (!key) {
// Create a new key (whether or not one was in storage).
@@ -270,7 +275,7 @@ export class AuthClient {
private _key: SignIdentity,
private _chain: DelegationChain | null,
private _storage: AuthClientStorage,
- public readonly idleManager: IdleManager | undefined,
+ public idleManager: IdleManager | undefined,
private _createOptions: AuthClientCreateOptions | undefined,
// A handle on the IdP window.
private _idpWindow?: Window,
@@ -317,6 +322,17 @@ export class AuthClient {
this._identity = DelegationIdentity.fromDelegation(key, this._chain);
this._idpWindow?.close();
+ if (!this.idleManager) {
+ const idleOptions = this._createOptions?.idleOptions;
+ this.idleManager = IdleManager.create(idleOptions);
+
+ if (!idleOptions?.onIdle && !idleOptions?.disableDefaultIdleCallback) {
+ this.idleManager?.registerCallback(() => {
+ this.logout();
+ location.reload();
+ });
+ }
+ }
onSuccess?.();
this._removeEventListener();
delete this._idpWindow;
diff --git a/packages/bls-verify/tsconfig.json b/packages/bls-verify/tsconfig.json
index f1fae3494..d6fb55d23 100644
--- a/packages/bls-verify/tsconfig.json
+++ b/packages/bls-verify/tsconfig.json
@@ -18,6 +18,6 @@
"strict": true,
"target": "es2017"
},
- "include": ["src/**/*"],
+ "include": ["src/**/*", "types/**/*", "amcl-js-3.0.0.tgz"],
"references": []
}
diff --git a/packages/bls-verify/types/amcl.d.ts b/packages/bls-verify/types/amcl.d.ts
new file mode 100644
index 000000000..5a858db82
--- /dev/null
+++ b/packages/bls-verify/types/amcl.d.ts
@@ -0,0 +1 @@
+declare module 'amcl-js';