mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-07 04:12:04 +00:00
fix(garmin): compare the cached token's key in memory, drop an unused export
This commit is contained in:
1 parent
de47cb7b31
commit
5dd6453773
2 files changed
+11
-11
No files matched your search
@@ -160,7 +160,7 @@ test.describe("Settings → Export & Import", () => {
|
|||||||
).toContainText("2/12");
|
).toContainText("2/12");
|
||||||
await expect(
|
await expect(
|
||||||
page.getByTestId("report-group-row-cardio-export"),
|
page.getByTestId("report-group-row-cardio-export"),
|
||||||
).toContainText("2/15");
|
).toContainText("2/16");
|
||||||
await expect(
|
await expect(
|
||||||
page.getByTestId("report-group-row-mobility-export"),
|
page.getByTestId("report-group-row-mobility-export"),
|
||||||
).toContainText("0/11");
|
).toContainText("0/11");
|
||||||
|
|||||||
+10
-10
@@ -19,7 +19,6 @@
|
|||||||
* Egress goes through `safeFetch` to two fixed hosts (global and China), so
|
* Egress goes through `safeFetch` to two fixed hosts (global and China), so
|
||||||
* there is no user-supplied host to pin. Answers are read with a byte cap.
|
* there is no user-supplied host to pin. Answers are read with a byte cap.
|
||||||
*/
|
*/
|
||||||
import { createHash } from "node:crypto";
|
|
||||||
|
|
||||||
import { getEvent } from "@/lib/logging/context";
|
import { getEvent } from "@/lib/logging/context";
|
||||||
import { shiftDateKey } from "@/lib/tz/format";
|
import { shiftDateKey } from "@/lib/tz/format";
|
||||||
@@ -39,8 +38,6 @@ export const GARMIN_HOSTS = {
|
|||||||
|
|
||||||
export type GarminRegion = keyof typeof GARMIN_HOSTS;
|
export type GarminRegion = keyof typeof GARMIN_HOSTS;
|
||||||
|
|
||||||
export const GARMIN_REGIONS = Object.keys(GARMIN_HOSTS) as GarminRegion[];
|
|
||||||
|
|
||||||
export function isGarminRegion(value: unknown): value is GarminRegion {
|
export function isGarminRegion(value: unknown): value is GarminRegion {
|
||||||
return value === "global" || value === "china";
|
return value === "global" || value === "china";
|
||||||
}
|
}
|
||||||
@@ -258,7 +255,8 @@ export async function exchangeGarminKey(
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface CachedToken extends GarminToken {
|
interface CachedToken extends GarminToken {
|
||||||
fingerprint: string;
|
/** The key and service the token was bought with; a pasted key misses. */
|
||||||
|
keyRef: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Process-local token cache, per account. Never persisted. */
|
/** Process-local token cache, per account. Never persisted. */
|
||||||
@@ -270,8 +268,10 @@ export function clearGarminTokenCache(userId?: string): void {
|
|||||||
else tokenCache.delete(userId);
|
else tokenCache.delete(userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
function keyFingerprint(apiKey: string, region: GarminRegion): string {
|
// Compared in memory only, like the key the session already holds. A hash
|
||||||
return createHash("sha256").update(`${region}\n${apiKey}`).digest("hex");
|
// would add nothing here and reads as a password digest to a scanner.
|
||||||
|
function keyRefFor(apiKey: string, region: GarminRegion): string {
|
||||||
|
return `${region}\n${apiKey}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type GarminQuery = Record<
|
export type GarminQuery = Record<
|
||||||
@@ -290,7 +290,7 @@ export class GarminSession {
|
|||||||
private readonly apiKey: string;
|
private readonly apiKey: string;
|
||||||
private readonly region: GarminRegion;
|
private readonly region: GarminRegion;
|
||||||
private readonly transport: GarminTransport;
|
private readonly transport: GarminTransport;
|
||||||
private readonly fingerprint: string;
|
private readonly keyRef: string;
|
||||||
/** The key's expiry, once a token revealed it. */
|
/** The key's expiry, once a token revealed it. */
|
||||||
learnedKeyExpiresAt: number | null = null;
|
learnedKeyExpiresAt: number | null = null;
|
||||||
/** Number of key exchanges this session made (for the record and tests). */
|
/** Number of key exchanges this session made (for the record and tests). */
|
||||||
@@ -308,7 +308,7 @@ export class GarminSession {
|
|||||||
this.apiKey = opts.apiKey;
|
this.apiKey = opts.apiKey;
|
||||||
this.region = opts.region;
|
this.region = opts.region;
|
||||||
this.transport = opts.transport ?? {};
|
this.transport = opts.transport ?? {};
|
||||||
this.fingerprint = keyFingerprint(opts.apiKey, opts.region);
|
this.keyRef = keyRefFor(opts.apiKey, opts.region);
|
||||||
}
|
}
|
||||||
|
|
||||||
private now(): number {
|
private now(): number {
|
||||||
@@ -321,7 +321,7 @@ export class GarminSession {
|
|||||||
if (
|
if (
|
||||||
!force &&
|
!force &&
|
||||||
cached &&
|
cached &&
|
||||||
cached.fingerprint === this.fingerprint &&
|
cached.keyRef === this.keyRef &&
|
||||||
this.now() < cached.refreshAt
|
this.now() < cached.refreshAt
|
||||||
) {
|
) {
|
||||||
return cached.value;
|
return cached.value;
|
||||||
@@ -336,7 +336,7 @@ export class GarminSession {
|
|||||||
if (fresh.keyExpiresAt !== null) {
|
if (fresh.keyExpiresAt !== null) {
|
||||||
this.learnedKeyExpiresAt = fresh.keyExpiresAt;
|
this.learnedKeyExpiresAt = fresh.keyExpiresAt;
|
||||||
}
|
}
|
||||||
tokenCache.set(this.userId, { ...fresh, fingerprint: this.fingerprint });
|
tokenCache.set(this.userId, { ...fresh, keyRef: this.keyRef });
|
||||||
return fresh.value;
|
return fresh.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user