This repository has no description
Something went wrong. Try again.
TypeScript
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267// SPDX-License-Identifier: AGPL-3.0-or-later
import {beforeEach, describe, expect, test} from 'vitest';import type {TestAccount} from '../../auth/tests/AuthTestUtils';import {createTestAccount, setUserACLs} from '../../auth/tests/AuthTestUtils';import {type ApiTestHarness, createApiTestHarness} from '../../test/ApiTestHarness';import {HTTP_STATUS} from '../../test/TestConstants';import {createBuilder} from '../../test/TestRequestBuilder';
interface AdminApiKey { keyId: string; key: string; name: string; acls: Array<string>; token: string;}
async function createAdminApiKey( harness: ApiTestHarness, account: TestAccount, name: string, acls: Array<string>, expiresInDays: number | null,): Promise<AdminApiKey> { const data = await createBuilder<{ key_id: string; key: string; name: string; acls: Array<string>; }>(harness, `${account.token}`) .post('/admin/api-keys') .body({ name, acls, ...(expiresInDays !== null ? {expires_in_days: expiresInDays} : {}), }) .expect(HTTP_STATUS.OK) .execute(); return { keyId: data.key_id, key: data.key, name: data.name, acls: data.acls, token: `Admin ${data.key}`, };}
async function createAdminApiKeyWithDefaultACLs( harness: ApiTestHarness, account: TestAccount, name: string,): Promise<AdminApiKey> { return await createAdminApiKey(harness, account, name, ['audit_log:view', 'user:lookup', 'guild:lookup'], null);}
async function listAdminApiKeys(harness: ApiTestHarness, token: string): Promise<Array<Record<string, unknown>>> { return await createBuilder<Array<Record<string, unknown>>>(harness, `${token}`) .get('/admin/api-keys') .expect(HTTP_STATUS.OK) .execute();}
async function revokeAdminApiKey(harness: ApiTestHarness, token: string, keyId: string): Promise<void> { await createBuilder(harness, `${token}`) .delete(`/admin/api-keys/${keyId}`) .body(null) .expect(HTTP_STATUS.OK) .execute();}
describe('Admin API Key Authentication', () => { let harness: ApiTestHarness; beforeEach(async () => { harness = await createApiTestHarness(); }); test('valid key authenticates successfully', async () => { const admin = await createTestAccount(harness); await setUserACLs(harness, admin, [ 'admin:authenticate', 'admin_api_key:manage', 'audit_log:view', 'user:lookup', 'guild:lookup', ]); const apiKey = await createAdminApiKeyWithDefaultACLs(harness, admin, 'Auth Test Key'); await createBuilder(harness, apiKey.token) .post('/admin/users/lookup') .body({ user_ids: [admin.userId], }) .expect(HTTP_STATUS.OK) .execute(); }); test('invalid key is rejected', async () => { await createTestAccount(harness); await createBuilder(harness, 'Admin invalid_key_12345') .post('/admin/users/lookup') .body({ user_ids: ['123456789'], }) .expect(HTTP_STATUS.UNAUTHORIZED) .execute(); }); test('revoked key is rejected', async () => { const admin = await createTestAccount(harness); await setUserACLs(harness, admin, [ 'admin:authenticate', 'admin_api_key:manage', 'audit_log:view', 'user:lookup', 'guild:lookup', ]); const apiKey = await createAdminApiKeyWithDefaultACLs(harness, admin, 'Revoke Test Key'); await revokeAdminApiKey(harness, admin.token, apiKey.keyId); await createBuilder(harness, apiKey.token) .post('/admin/users/lookup') .body({ user_ids: [admin.userId], }) .expect(HTTP_STATUS.UNAUTHORIZED) .execute(); }); test('wrong prefix is rejected', async () => { const admin = await createTestAccount(harness); await setUserACLs(harness, admin, [ 'admin:authenticate', 'admin_api_key:manage', 'audit_log:view', 'user:lookup', 'guild:lookup', ]); const apiKey = await createAdminApiKeyWithDefaultACLs(harness, admin, 'Prefix Test Key'); await createBuilder(harness, `Bearer ${apiKey.key}`) .post('/admin/users/lookup') .body({ user_ids: [admin.userId], }) .expect(HTTP_STATUS.UNAUTHORIZED) .execute(); }); test('missing prefix is rejected', async () => { const admin = await createTestAccount(harness); await setUserACLs(harness, admin, [ 'admin:authenticate', 'admin_api_key:manage', 'audit_log:view', 'user:lookup', 'guild:lookup', ]); const apiKey = await createAdminApiKeyWithDefaultACLs(harness, admin, 'No Prefix Test Key'); await createBuilder(harness, apiKey.key) .post('/admin/users/lookup') .body({ user_ids: [admin.userId], }) .expect(HTTP_STATUS.UNAUTHORIZED) .execute(); }); test('case sensitive prefix', async () => { const admin = await createTestAccount(harness); await setUserACLs(harness, admin, [ 'admin:authenticate', 'admin_api_key:manage', 'audit_log:view', 'user:lookup', 'guild:lookup', ]); const apiKey = await createAdminApiKeyWithDefaultACLs(harness, admin, 'Case Test Key'); await createBuilder(harness, `admin ${apiKey.key}`) .post('/admin/users/lookup') .body({ user_ids: [admin.userId], }) .expect(HTTP_STATUS.UNAUTHORIZED) .execute(); }); test('empty key is rejected', async () => { await createTestAccount(harness); await createBuilder(harness, 'Admin ') .post('/admin/users/lookup') .body({ user_ids: ['123456789'], }) .expect(HTTP_STATUS.UNAUTHORIZED) .execute(); }); test('cannot authenticate to user endpoints', async () => { const admin = await createTestAccount(harness); await setUserACLs(harness, admin, [ 'admin:authenticate', 'admin_api_key:manage', 'audit_log:view', 'user:lookup', 'guild:lookup', ]); const apiKey = await createAdminApiKeyWithDefaultACLs(harness, admin, 'User Endpoint Test Key'); await createBuilder(harness, apiKey.token).get('/users/@me').expect(HTTP_STATUS.UNAUTHORIZED).execute(); }); test('cannot authenticate to bot endpoints', async () => { const admin = await createTestAccount(harness); await setUserACLs(harness, admin, [ 'admin:authenticate', 'admin_api_key:manage', 'audit_log:view', 'user:lookup', 'guild:lookup', ]); const apiKey = await createAdminApiKeyWithDefaultACLs(harness, admin, 'Bot Endpoint Test Key'); await createBuilder(harness, `Bot ${apiKey.key}`).get('/users/@me').expect(HTTP_STATUS.UNAUTHORIZED).execute(); }); test('updates last_used_at timestamp', async () => { const admin = await createTestAccount(harness); await setUserACLs(harness, admin, [ 'admin:authenticate', 'admin_api_key:manage', 'audit_log:view', 'user:lookup', 'guild:lookup', ]); const apiKey = await createAdminApiKeyWithDefaultACLs(harness, admin, 'Last Used Test Key'); const keys = await listAdminApiKeys(harness, admin.token); expect(keys).toHaveLength(1); expect(keys[0]!.last_used_at).toBeNull(); await createBuilder(harness, apiKey.token) .post('/admin/users/lookup') .body({ user_ids: [admin.userId], }) .execute(); const keysAfter = await listAdminApiKeys(harness, admin.token); expect(keysAfter).toHaveLength(1); expect(keysAfter[0]!.last_used_at).not.toBeNull(); }); test('multiple keys for same user all work', async () => { const admin = await createTestAccount(harness); await setUserACLs(harness, admin, ['admin:authenticate', 'admin_api_key:manage', 'user:lookup']); const key1 = await createAdminApiKey(harness, admin, 'Key 1', ['admin:authenticate', 'user:lookup'], null); const key2 = await createAdminApiKey(harness, admin, 'Key 2', ['admin:authenticate', 'user:lookup'], null); const key3 = await createAdminApiKey(harness, admin, 'Key 3', ['admin:authenticate', 'user:lookup'], null); for (const key of [key1, key2, key3]) { await createBuilder(harness, key.token) .post('/admin/users/lookup') .body({ user_ids: [admin.userId], }) .expect(HTTP_STATUS.OK) .execute(); } const keys = await listAdminApiKeys(harness, admin.token); expect(keys).toHaveLength(3); }); test('different users can use same key if creator has permissions', async () => { const admin1 = await createTestAccount(harness); const admin2 = await createTestAccount(harness); await setUserACLs(harness, admin1, ['admin:authenticate', 'admin_api_key:manage', 'user:lookup']); await setUserACLs(harness, admin2, ['admin:authenticate', 'user:lookup']); const key1 = await createAdminApiKey(harness, admin1, 'Admin 1 Key', ['admin:authenticate', 'user:lookup'], null); await createBuilder(harness, key1.token) .post('/admin/users/lookup') .body({ user_ids: [admin2.userId], }) .expect(HTTP_STATUS.OK) .execute(); });});