|
6 | 6 | } from '@icp-sdk/core/identity'; |
7 | 7 | import { Principal } from '@icp-sdk/core/principal'; |
8 | 8 | import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; |
| 9 | +import { SessionGoneError } from '../../src/client/app-delegation-source.ts'; |
9 | 10 | import { AuthClient } from '../../src/client/auth-client.ts'; |
10 | 11 | import { |
11 | 12 | APP_PENDING_SLOT, |
@@ -604,17 +605,43 @@ describe('AuthClient signIn', () => { |
604 | 605 | await expect(client.signIn()).rejects.toThrow('connection failed'); |
605 | 606 | }); |
606 | 607 |
|
| 608 | + it('fails the sign-in when the session granted has nothing left to mint against', async () => { |
| 609 | + const credentialStorage = new MemoryCredentialStorage(); |
| 610 | + const stateStorage = new MemoryStateStorage(); |
| 611 | + const client = new AuthClient({ |
| 612 | + credentialStorage, |
| 613 | + stateStorage, |
| 614 | + idleOptions: { disableIdle: true }, |
| 615 | + }); |
| 616 | + handleSignIn(FakeTransport.last()); |
| 617 | + |
| 618 | + // One millisecond of session: the fixture takes the chain's life from the |
| 619 | + // requested ceiling. Nothing can be minted against it, so an identity built |
| 620 | + // around it could never sign. |
| 621 | + await expect(client.signIn({ maxTimeToLive: 1_000_000n })).rejects.toThrow(SessionGoneError); |
| 622 | + |
| 623 | + // And nothing is recorded. Reporting a sign-in that cannot make a call would |
| 624 | + // have the application render a signed-in page and fail on its first request, |
| 625 | + // which is the outcome this refusal exists to avoid. |
| 626 | + expect(stateStorage.get()).toBeNull(); |
| 627 | + expect(await credentialStorage.get(APP_SLOT)).toBeNull(); |
| 628 | + }); |
| 629 | + |
607 | 630 | it('asks for a session, carrying maxTimeToLive and no targets', async () => { |
608 | 631 | const client = new AuthClient(); |
609 | 632 | const transport = FakeTransport.last(); |
610 | 633 | handleSignIn(transport); |
611 | 634 |
|
612 | | - await client.signIn({ maxTimeToLive: 1_000_000n }); |
| 635 | + // An hour, in nanoseconds. The value only has to survive onto the wire, but |
| 636 | + // the fixture derives the session's own life from it — so a token number here |
| 637 | + // would build a session already too short to mint against, which is a |
| 638 | + // different outcome and not the one this test is about. |
| 639 | + await client.signIn({ maxTimeToLive: 3_600_000_000_000n }); |
613 | 640 |
|
614 | 641 | const req = transport.requests[0]; |
615 | 642 | expect(req.method).toBe('ii_session_delegation'); |
616 | 643 | expect(req.params?.sessionPublicKey).toEqual(expect.any(String)); |
617 | | - expect(req.params?.maxTimeToLive).toBe('1000000'); |
| 644 | + expect(req.params?.maxTimeToLive).toBe('3600000000000'); |
618 | 645 | // A session chain is restricted to Internet Identity, so an application has |
619 | 646 | // no targets to ask for: what it may call is decided by the delegations |
620 | 647 | // minted from the session, not by the session itself. |
|
0 commit comments