mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-24 07:53:09 +00:00
fix(oauth): purge tokens whose refresh token expired a month ago
Every refresh writes a new oauth_tokens row and nothing ever deleted the old ones, so an MCP client refreshing hourly grew the table, and every backup with it, without end. A nightly job now deletes tokens whose refresh token expired more than 30 days ago, leaves first, and keeps any row a live chain still points at for replay detection. Also types the backup's per-entry store flag.
This commit is contained in:
@@ -352,6 +352,35 @@ export class OauthTokensRepository extends TrekRepository<OauthTokens> {
|
||||
return rows.map((r) => r.id);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Retention
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Delete tokens whose refresh token expired before `cutoffIso`, oldest
|
||||
* generation first. A row is only deleted once no other token names it as
|
||||
* parent: `parent_token_id` has no ON DELETE action, and a token still in a
|
||||
* live chain is what replay detection walks. Each pass removes the current
|
||||
* leaves, so a whole expired chain goes over a few passes; `maxPasses`
|
||||
* bounds a chain that is still growing. Returns the number deleted.
|
||||
*/
|
||||
async deleteExpiredBefore(cutoffIso: string, maxPasses = 50): Promise<number> {
|
||||
let total = 0;
|
||||
for (let pass = 0; pass < maxPasses; pass++) {
|
||||
const result = await this.kysely<OauthTokensKyselyDB>()
|
||||
.deleteFrom('oauth_tokens')
|
||||
.where('refresh_token_expires_at', '<', cutoffIso)
|
||||
.where('id', 'not in', (eb) =>
|
||||
eb.selectFrom('oauth_tokens as child').select('child.parent_token_id').where('child.parent_token_id', 'is not', null),
|
||||
)
|
||||
.executeTakeFirst();
|
||||
const deleted = Number(result.numDeletedRows ?? 0);
|
||||
total += deleted;
|
||||
if (deleted === 0) break;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// OA19 — chain-wide revoke
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user