From 57b828f15c44b0c415a47a2de6c391273747cf54 Mon Sep 17 00:00:00 2001 From: dreamhunter2333 Date: Mon, 24 Aug 2026 00:36:49 +0800 Subject: [PATCH] fix: bind user role token to account --- e2e/tests/api/user-send-mail.spec.ts | 54 +++++++++++++++++++++++++--- worker/src/worker.ts | 7 ++-- 2 files changed, 54 insertions(+), 7 deletions(-) diff --git a/e2e/tests/api/user-send-mail.spec.ts b/e2e/tests/api/user-send-mail.spec.ts index ef57fe0..dd9ba9b 100644 --- a/e2e/tests/api/user-send-mail.spec.ts +++ b/e2e/tests/api/user-send-mail.spec.ts @@ -282,7 +282,7 @@ test.describe('User send mail API', () => { test('applies unlimited balance from the user role access token', async ({ request }) => { const addresses: Awaited>[] = []; - let userId: number | undefined; + const userIds: number[] = []; let originalUserSettings: Record | undefined; try { @@ -300,7 +300,7 @@ test.describe('User send mail API', () => { expect(enableUserRes.ok()).toBe(true); const user = await createUser(request); - userId = user.userId; + userIds.push(user.userId); const address = await createTestAddress(request, 'user-send-role-'); addresses.push(address); await bindAddress(request, user.jwt, address.jwt); @@ -355,11 +355,55 @@ test.describe('User send mail API', () => { ); expect(sendRes.ok()).toBe(true); expect((await getAddressSender(request, address.address)).balance).toBe(0); + + const otherUser = await createUser(request); + userIds.push(otherUser.userId); + const otherAddress = await createTestAddress(request, 'user-send-other-'); + addresses.push(otherAddress); + await bindAddress(request, otherUser.jwt, otherAddress.jwt); + const otherAccessRes = await request.post( + `${WORKER_URL}/user_api/address/${otherAddress.address_id}/request_send_mail_access`, + { headers: { 'x-user-token': otherUser.jwt } }, + ); + expect(otherAccessRes.ok()).toBe(true); + const otherSender = await getAddressSender(request, otherAddress.address); + await updateAddressSender(request, { + address: otherAddress.address, + address_id: otherSender.id, + balance: 0, + enabled: true, + }); + + const mixedHeaders = { + 'x-user-token': otherUser.jwt, + 'x-user-access-token': accessToken, + }; + const otherSettingsRes = await request.get( + `${WORKER_URL}/user_api/address/${otherAddress.address_id}/settings`, + { headers: mixedHeaders }, + ); + expect(otherSettingsRes.ok()).toBe(true); + expect((await otherSettingsRes.json()).send_balance).toBe(0); + + const otherSendRes = await request.post( + `${WORKER_URL}/user_api/address/${otherAddress.address_id}/send_mail`, + { + headers: mixedHeaders, + data: { + to_mail: 'recipient@test.example.com', + subject: `Mismatched role token ${Date.now()}`, + content: 'This message must not be sent', + is_html: false, + }, + }, + ); + expect(otherSendRes.status()).toBe(400); + expect(await otherSendRes.text()).toContain('No balance'); } finally { await Promise.allSettled(addresses.map((address) => deleteAddress(request, address.jwt))); - if (userId !== undefined) { - await request.delete(`${WORKER_URL}/admin/users/${userId}`); - } + await Promise.allSettled(userIds.map((userId) => ( + request.delete(`${WORKER_URL}/admin/users/${userId}`) + ))); if (originalUserSettings) { await request.post(`${WORKER_URL}/admin/user_settings`, { data: originalUserSettings, diff --git a/worker/src/worker.ts b/worker/src/worker.ts index 9f4d47f..65bbdbb 100644 --- a/worker/src/worker.ts +++ b/worker/src/worker.ts @@ -126,7 +126,8 @@ const checkUserPayload = async ( } const checkoutUserRolePayload = async ( - c: Context + c: Context, + userId?: number ): Promise => { try { const token = c.req.raw.headers.get("x-user-access-token"); @@ -139,6 +140,7 @@ const checkoutUserRolePayload = async ( return; } if (typeof payload?.user_role !== "string") return; + if (userId !== undefined && payload.user_id !== userId) return; c.set("userRolePayload", payload.user_role); } catch (e) { console.error(e); @@ -207,7 +209,8 @@ app.use('/user_api/*', async (c, next) => { c.req.path.startsWith("/user_api/bind_address") || c.req.path.startsWith("/user_api/address/") ) { - await checkoutUserRolePayload(c); + const { user_id } = c.get("userPayload"); + await checkoutUserRolePayload(c, user_id); } if (c.req.path.startsWith('/user_api/bind_address') && c.req.method === 'POST'