From 91cb44d2443f50f9f465b965430e5e46cf18cb91 Mon Sep 17 00:00:00 2001 From: Jonas Lochmann Date: Mon, 15 Jun 2026 02:00:00 +0200 Subject: [PATCH] add expiry tolerance if not dryRun to the admin premium unlock api --- docs/api/admin.md | 4 +++- src/api/admin.ts | 2 +- src/util/identity-token.ts | 9 ++++++--- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/docs/api/admin.md b/docs/api/admin.md index 2ede89d..a80d0cb 100644 --- a/docs/api/admin.md +++ b/docs/api/admin.md @@ -100,7 +100,9 @@ request properties: ``purchaseToken``, ``purchaseId`` and ``dryRun`` - ``purchasetoken`` is a string which the client shows at the purchase screen - ``purchaseId`` is the ID that is used at the bill -- ``dryRun`` is a boolean; setting true will skip the actual unlocking +- ``dryRun`` is a boolean + - setting true will skip the actual unlocking + - false will add a four week tolerance to the token expiry to permit checking now and unlocking later - ``type`` is a string and must be ``year``, ``month`` or ``unpaid14`` ### response diff --git a/src/api/admin.ts b/src/api/admin.ts index b980b07..884211d 100644 --- a/src/api/admin.ts +++ b/src/api/admin.ts @@ -156,7 +156,7 @@ export const createAdminRouter = ({ database, websocket, eventHandler }: { throw new BadRequest() } - const tokenContent = await verifyIdentitifyToken(purchaseToken) + const tokenContent = await verifyIdentitifyToken(purchaseToken, dryRun) if (tokenContent.purpose !== 'purchase') { res.json({ ok: false, error: 'token invalid', detail: 'wrong purpose' }) diff --git a/src/util/identity-token.ts b/src/util/identity-token.ts index fb147a3..87bf35b 100644 --- a/src/util/identity-token.ts +++ b/src/util/identity-token.ts @@ -1,6 +1,6 @@ /* * server component for the TimeLimit App - * Copyright (C) 2019 - 2022 Jonas Lochmann + * Copyright (C) 2019 - 2026 Jonas Lochmann * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as @@ -33,12 +33,15 @@ export async function createIdentityToken({ purpose, familyId, userId, mail }: I .join('\n') } -export async function verifyIdentitifyToken(token: string): Promise { +export async function verifyIdentitifyToken(token: string, dryRun: boolean): Promise { try { const { payload } = await jwtVerify( Buffer.from(token, 'base64').toString('ascii'), getSignSecret(), - { algorithms: ['HS512'] } + { + algorithms: ['HS512'], + clockTolerance: dryRun ? 0 : '4w', + } ) if (!isIdentityTokenPayload(payload)) throw new BadPayloadException()