fix(crypto): cover the WHOOP encrypted columns in key rotation

The rotation registry missed the per-user WHOOP credential columns and
the WhoopConnection token columns, so a key rotation would skip those
rows and leave them undecryptable once the operator drops the old key.
Add whoopClientIdEncrypted / whoopClientSecretEncrypted to the User
field list and a WhoopConnection accessToken / refreshToken pass.
This commit is contained in:
Marc-André Bombeck committed 2026-06-04 04:10:16 +02:00
1 parent 7036ff3e0c
commit 1b9f914b8b
1 file changed
+24
+24
View File
@@ -100,6 +100,8 @@ async function main() {
moodLogApiKeyEncrypted: true,
withingsClientIdEncrypted: true,
withingsClientSecretEncrypted: true,
whoopClientIdEncrypted: true,
whoopClientSecretEncrypted: true,
},
});
@@ -115,6 +117,8 @@ async function main() {
"moodLogApiKeyEncrypted",
"withingsClientIdEncrypted",
"withingsClientSecretEncrypted",
"whoopClientIdEncrypted",
"whoopClientSecretEncrypted",
];
for (const field of userFields) {
const r = await rotateField(
@@ -152,6 +156,26 @@ async function main() {
results.push(r);
}
// ───── WhoopConnection table (accessToken / refreshToken) ─────
const whoop = await prisma.whoopConnection.findMany({
select: { id: true, accessToken: true, refreshToken: true },
});
for (const field of ["accessToken", "refreshToken"] as const) {
const r = await rotateField(
"WhoopConnection",
field,
whoop,
(w) => w[field],
async (id, ciphertext) => {
await prisma.whoopConnection.update({
where: { id },
data: { [field]: ciphertext } as Record<string, string>,
});
},
);
results.push(r);
}
// ───── AppSettings table (singleton typically) ─────
const settings = await prisma.appSettings.findMany({
select: {