From 70d848f1591f58e493a1ee095390df94d5f18f15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Kol=C3=A1rik?= Date: Wed, 18 Dec 2024 15:12:36 +0100 Subject: [PATCH] misc: send usernames to APM --- src/lib/http/auth.ts | 11 +++++++---- src/lib/http/middleware/authenticate.ts | 11 ++++++----- test/tests/unit/auth.test.ts | 17 +++++++++++++++++ 3 files changed, 30 insertions(+), 9 deletions(-) diff --git a/src/lib/http/auth.ts b/src/lib/http/auth.ts index 87903e7b..eb6a5371 100644 --- a/src/lib/http/auth.ts +++ b/src/lib/http/auth.ts @@ -13,7 +13,8 @@ const logger = scopedLogger('auth'); const TOKEN_TTL = 2 * 60 * 1000; export type Token = { - user_created?: string, + user_created: string | null, + user_github_username: string | null, value: string, expire: Date | null, scopes: string[], @@ -85,8 +86,10 @@ export class Auth { } async fetchTokens (filter: Partial = {}) { - const rows = await this.sql(GP_TOKENS_TABLE).where(filter) - .select([ 'user_created', 'value', 'expire', 'origins', 'date_last_used', 'scopes' ]); + const rows = await this.sql(GP_TOKENS_TABLE) + .leftJoin(USERS_TABLE, 'user_created', `${USERS_TABLE}.id`) + .where(filter) + .select([ 'user_created', 'value', 'expire', 'origins', 'date_last_used', 'scopes', 'github_username as user_github_username' ]); const tokens: Token[] = rows.map(row => ({ ...row, @@ -127,7 +130,7 @@ export class Auth { } await this.updateLastUsedDate(token); - return { userId: token.user_created, scopes: token.scopes, hashedToken: token.value }; + return { userId: token.user_created, username: token.user_github_username, scopes: token.scopes, hashedToken: token.value }; } private async updateLastUsedDate (token: Token) { diff --git a/src/lib/http/middleware/authenticate.ts b/src/lib/http/middleware/authenticate.ts index 7a79b34b..7b42632e 100644 --- a/src/lib/http/middleware/authenticate.ts +++ b/src/lib/http/middleware/authenticate.ts @@ -12,6 +12,7 @@ type SessionCookiePayload = { role?: string; app_access?: number; admin_access?: number; + github_username?: string; }; export const authenticate = (): ExtendedMiddleware => { @@ -38,15 +39,15 @@ export const authenticate = (): ExtendedMiddleware => { return; } - ctx.state.user = { id: result.userId, scopes: result.scopes, authMode: 'token', hashedToken: result.hashedToken }; - apmAgent.setUserContext({ id: result.userId || 'anonymous-token' }); + ctx.state.user = { id: result.userId, username: result.username, scopes: result.scopes, authMode: 'token', hashedToken: result.hashedToken }; + apmAgent.setUserContext({ id: result.userId || 'anonymous-token', username: result.username || 'anonymous-token' }); } else if (sessionCookie) { try { const result = await jwtVerify(sessionCookie, sessionKey); if (result.payload.id && result.payload.app_access) { - ctx.state.user = { id: result.payload.id, authMode: 'cookie' }; - apmAgent.setUserContext({ id: result.payload.id }); + ctx.state.user = { id: result.payload.id, username: result.payload.github_username || null, authMode: 'cookie' }; + apmAgent.setUserContext({ id: result.payload.id, username: result.payload.github_username || `ID(${result.payload.id})` }); } } catch {} } @@ -56,4 +57,4 @@ export const authenticate = (): ExtendedMiddleware => { }; export type AuthenticateOptions = { session: { cookieName: string, cookieSecret: string } }; -export type AuthenticateState = { user?: { id: string | undefined, scopes?: string[], hashedToken?: string, authMode: 'cookie' | 'token' } }; +export type AuthenticateState = { user?: { id: string | null, username: string | null, scopes?: string[], hashedToken?: string, authMode: 'cookie' | 'token' } }; diff --git a/test/tests/unit/auth.test.ts b/test/tests/unit/auth.test.ts index 37a349c7..8e2ae103 100644 --- a/test/tests/unit/auth.test.ts +++ b/test/tests/unit/auth.test.ts @@ -11,8 +11,14 @@ describe('Auth', () => { update: updateStub, select: selectStub, }); + const leftJoinStub = sandbox.stub().returns({ + where: whereStub, + update: updateStub, + select: selectStub, + }); const sqlStub = sandbox.stub().returns({ where: whereStub, + leftJoin: leftJoinStub, }) as sinon.SinonStub & {raw: any}; beforeEach(() => { @@ -29,6 +35,7 @@ describe('Auth', () => { selectStub.onCall(1).resolves([{ value: '/bSluuDrAPX9zIiZZ/hxEKARwOg+e//EdJgCFpmApbg=', user_created: 'user1', + user_github_username: 'gh_user1', }]); selectStub.onCall(2).resolves([]); @@ -39,6 +46,7 @@ describe('Auth', () => { const user1 = await auth.validate('hf2fnprguymlgliirdk7qv23664c2xcr', 'https://jsdelivr.com'); expect(user1).to.deep.equal({ userId: 'user1', + username: 'gh_user1', scopes: [], hashedToken: '/bSluuDrAPX9zIiZZ/hxEKARwOg+e//EdJgCFpmApbg=', }); @@ -46,9 +54,11 @@ describe('Auth', () => { const user2 = await auth.validate('vumzijbzihrskmc2hj34yw22batpibmt', 'https://jsdelivr.com'); expect(user2).to.equal(null); + // should work without a username too selectStub.onCall(3).resolves([{ value: '8YZ2pZoGQxfOeEGvUUkagX1yizZckq3weL+IN0chvU0=', user_created: 'user2', + user_github_username: null, }]); selectStub.onCall(4).resolves([]); @@ -60,6 +70,7 @@ describe('Auth', () => { const user2afterSync = await auth.validate('vumzijbzihrskmc2hj34yw22batpibmt', 'https://jsdelivr.com'); expect(user2afterSync).to.deep.equal({ userId: 'user2', + username: null, scopes: [], hashedToken: '8YZ2pZoGQxfOeEGvUUkagX1yizZckq3weL+IN0chvU0=', }); @@ -73,6 +84,7 @@ describe('Auth', () => { selectStub.resolves([{ value: '/bSluuDrAPX9zIiZZ/hxEKARwOg+e//EdJgCFpmApbg=', user_created: 'user1', + user_github_username: 'gh_user1', }]); await auth.syncTokens(); @@ -84,6 +96,7 @@ describe('Auth', () => { expect(user).to.deep.equal({ userId: 'user1', + username: 'gh_user1', scopes: [], hashedToken: '/bSluuDrAPX9zIiZZ/hxEKARwOg+e//EdJgCFpmApbg=', }); @@ -97,6 +110,7 @@ describe('Auth', () => { selectStub.resolves([{ value: '/bSluuDrAPX9zIiZZ/hxEKARwOg+e//EdJgCFpmApbg=', user_created: 'user1', + user_github_username: 'gh_user1', }]); const user = await auth.validate('hf2fnprguymlgliirdk7qv23664c2xcr', 'https://jsdelivr.com'); @@ -106,6 +120,7 @@ describe('Auth', () => { expect(user).to.deep.equal({ userId: 'user1', + username: 'gh_user1', scopes: [], hashedToken: '/bSluuDrAPX9zIiZZ/hxEKARwOg+e//EdJgCFpmApbg=', }); @@ -119,6 +134,7 @@ describe('Auth', () => { selectStub.resolves([{ value: '/bSluuDrAPX9zIiZZ/hxEKARwOg+e//EdJgCFpmApbg=', user_created: 'user1', + user_github_username: 'gh_user1', date_last_used: new Date(), }]); @@ -136,6 +152,7 @@ describe('Auth', () => { selectStub.resolves([{ value: '/bSluuDrAPX9zIiZZ/hxEKARwOg+e//EdJgCFpmApbg=', user_created: 'user1', + user_github_username: 'gh_user1', }]); await auth.validate('hf2fnprguymlgliirdk7qv23664c2xcr', 'https://jsdelivr.com');