Files
HealthLog/src/lib/nightscout/credentials.ts
T
Marc-André Bombeck f95da50ba0 fix(01-07): enforce exact Nightscout origins
- move private-host authority to the server-owned exact-origin policy
- preserve stable redacted policy failures through connect and sync
2026-07-29 13:57:07 +02:00

48 lines
1.6 KiB
TypeScript

/**
* Per-user Nightscout connection credentials (v1.17.0).
*
* Unlike WHOOP / Fitbit (OAuth, with a dedicated `*Connection` row), Nightscout
* is a URL + token the user pastes once. Both are stored encrypted on `User`
* (`nightscoutUrlEncrypted` / `nightscoutTokenEncrypted`) via the fail-closed
* `*Encrypted` convention; the private-host opt-in is the plaintext boolean
* `nightscoutAllowPrivateHost`. This helper is the single read+decrypt path the
* sync + status + connect surfaces share.
*/
import { prisma } from "@/lib/db";
import { decrypt } from "@/lib/crypto";
export interface NightscoutCredentials {
baseUrl: string;
token: string;
/** @deprecated Compatibility/display metadata; never egress authority. */
allowPrivateHost: boolean;
}
/**
* Fetch and decrypt the user's Nightscout connection. Returns null when the
* URL is not configured (a token-less, fully-public instance still stores a
* URL, so the URL is the configured-marker, not the token).
*/
export async function getUserNightscoutCredentials(
userId: string,
): Promise<NightscoutCredentials | null> {
const user = await prisma.user.findUnique({
where: { id: userId },
select: {
nightscoutUrlEncrypted: true,
nightscoutTokenEncrypted: true,
nightscoutAllowPrivateHost: true,
},
});
if (!user?.nightscoutUrlEncrypted) return null;
return {
baseUrl: decrypt(user.nightscoutUrlEncrypted),
token: user.nightscoutTokenEncrypted
? decrypt(user.nightscoutTokenEncrypted)
: "",
allowPrivateHost: user.nightscoutAllowPrivateHost,
};
}