mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-07 04:12:04 +00:00
fix(whoop): refuse a profile without a user id instead of storing "undefined"
String(profile.user_id) turned a missing id into the literal "undefined", so every such connection would have looked like one WHOOP account and the unique account id would have refused the second record. The callback now treats it like a failed exchange (reason=token), as the Polar callback already does for a token body without x_user_id.
This commit is contained in:
1 parent
5306ba7614
commit
b42b0d5fee
2 files changed
+27
No files matched your search
@@ -175,6 +175,24 @@ describe("GET /api/whoop/callback custom-scheme redirect", () => {
|
||||
expect(connUpsert).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("refuses a profile without a user id instead of storing a shared placeholder", async () => {
|
||||
stateDelete.mockResolvedValue({
|
||||
userId: "u1",
|
||||
expiresAt: new Date(Date.now() + 60_000),
|
||||
returnScheme: null,
|
||||
});
|
||||
const { fetchProfile } = await import("@/lib/whoop/client");
|
||||
vi.mocked(fetchProfile).mockResolvedValueOnce({} as never);
|
||||
|
||||
const res = await GET(makeReq("nonce-noid"));
|
||||
|
||||
expect(res.headers.get("location")).toBe(
|
||||
"https://app.example/settings/integrations?whoop=error&reason=token",
|
||||
);
|
||||
expect(connFindUnique).not.toHaveBeenCalled();
|
||||
expect(connUpsert).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("maps a concurrent WHOOP identity P2002 to the safe owner-conflict redirect", async () => {
|
||||
stateDelete.mockResolvedValue({
|
||||
userId: "local-user",
|
||||
|
||||
@@ -204,6 +204,15 @@ export const GET = apiHandler(async (request: NextRequest) => {
|
||||
|
||||
const tokens = await whoopOAuth.exchange(code, creds);
|
||||
const profile = await fetchProfile(tokens.access_token);
|
||||
// An off-spec profile without `user_id` would store the string
|
||||
// "undefined" as the account id: every such connection would then look
|
||||
// like one WHOOP account, and the check below would refuse the second.
|
||||
if (
|
||||
typeof profile.user_id !== "number" ||
|
||||
!Number.isFinite(profile.user_id)
|
||||
) {
|
||||
return outcomeRedirect(returnScheme, "error", "token");
|
||||
}
|
||||
const whoopUserId = String(profile.user_id);
|
||||
const expiresAt = new Date(Date.now() + tokens.expires_in * 1000);
|
||||
const owner = await prisma.whoopConnection.findUnique({
|
||||
|
||||
Reference in new issue
Block a user