Gate bot logic on full account authentication
This commit is contained in:
1 parent
4db6de8bf5
commit
2fd92bf82c
22 files changed
+635
-65
No files matched your search
@@ -0,0 +1,104 @@
|
||||
import { describe, expect, it, vi } from 'vitest';
|
||||
import { AccountAuthContext } from '../src/services/account-auth-context.js';
|
||||
import { createMockLogger } from './mockLogger.js';
|
||||
|
||||
describe('AccountAuthContext', () => {
|
||||
it('fails closed until Reddit and Matrix resolve to one authenticated account', async () => {
|
||||
const auth = new AccountAuthContext(createMockLogger());
|
||||
const authenticate = vi.fn().mockResolvedValue({
|
||||
accountId: '@t2_account:reddit.com',
|
||||
redditUsername: 'account',
|
||||
matrixUserId: '@t2_account:reddit.com',
|
||||
});
|
||||
auth.setAuthenticator(authenticate);
|
||||
|
||||
expect(auth.isFullyAuthenticated()).toBe(false);
|
||||
expect(auth.getSnapshot().status).toBe('login-required');
|
||||
|
||||
await expect(auth.ensureFullyAuthenticated()).resolves.toBe(true);
|
||||
|
||||
expect(auth.isFullyAuthenticated()).toBe(true);
|
||||
expect(auth.getSnapshot()).toMatchObject({
|
||||
status: 'authenticated',
|
||||
accountId: '@t2_account:reddit.com',
|
||||
});
|
||||
});
|
||||
|
||||
it('coalesces concurrent authentication checks globally', async () => {
|
||||
const auth = new AccountAuthContext(createMockLogger());
|
||||
let resolveAuth: ((account: {
|
||||
accountId: string;
|
||||
redditUsername: string;
|
||||
matrixUserId: string;
|
||||
}) => void) | undefined;
|
||||
const authenticate = vi.fn(() => new Promise((resolve) => { resolveAuth = resolve; }));
|
||||
auth.setAuthenticator(authenticate);
|
||||
|
||||
const first = auth.ensureFullyAuthenticated();
|
||||
const second = auth.ensureFullyAuthenticated();
|
||||
await vi.waitFor(() => expect(authenticate).toHaveBeenCalledOnce());
|
||||
resolveAuth?.({
|
||||
accountId: '@t2_account:reddit.com',
|
||||
redditUsername: 'account',
|
||||
matrixUserId: '@t2_account:reddit.com',
|
||||
});
|
||||
|
||||
await expect(Promise.all([first, second])).resolves.toEqual([true, true]);
|
||||
});
|
||||
|
||||
it('invalidates the whole account context when either login layer expires', async () => {
|
||||
const auth = new AccountAuthContext(createMockLogger());
|
||||
auth.markAuthenticated({
|
||||
accountId: '@t2_account:reddit.com',
|
||||
redditUsername: 'account',
|
||||
matrixUserId: '@t2_account:reddit.com',
|
||||
});
|
||||
|
||||
auth.invalidate('matrix token rejected');
|
||||
|
||||
expect(auth.isFullyAuthenticated()).toBe(false);
|
||||
expect(auth.getSnapshot()).toMatchObject({
|
||||
status: 'login-required',
|
||||
accountId: null,
|
||||
reason: 'matrix token rejected',
|
||||
});
|
||||
});
|
||||
|
||||
it('fails closed when the authentication lease expires', () => {
|
||||
let now = 1_000;
|
||||
const auth = new AccountAuthContext(createMockLogger(), {
|
||||
leaseMs: 100,
|
||||
retryDelayMs: 1_000,
|
||||
now: () => now,
|
||||
});
|
||||
auth.markAuthenticated({
|
||||
accountId: '@t2_account:reddit.com',
|
||||
redditUsername: 'account',
|
||||
matrixUserId: '@t2_account:reddit.com',
|
||||
});
|
||||
|
||||
now = 1_101;
|
||||
|
||||
expect(auth.isFullyAuthenticated()).toBe(false);
|
||||
expect(auth.getSnapshot().status).toBe('login-required');
|
||||
});
|
||||
|
||||
it('throttles failed global authentication checks', async () => {
|
||||
let now = 1_000;
|
||||
const auth = new AccountAuthContext(createMockLogger(), {
|
||||
leaseMs: 100,
|
||||
retryDelayMs: 1_000,
|
||||
now: () => now,
|
||||
});
|
||||
const authenticate = vi.fn().mockResolvedValue(null);
|
||||
auth.setAuthenticator(authenticate);
|
||||
|
||||
await expect(auth.ensureFullyAuthenticated()).resolves.toBe(false);
|
||||
await expect(auth.ensureFullyAuthenticated()).resolves.toBe(false);
|
||||
expect(authenticate).toHaveBeenCalledOnce();
|
||||
|
||||
now = 2_001;
|
||||
await auth.ensureFullyAuthenticated();
|
||||
expect(authenticate).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user