feat(notifications): allow local debug register/refresh without JWT
When the Notification Debug Panel sends testMode: true and omits Authorization, skip requireAuth on /notifications/register and /refresh and scope devices under a synthetic local-test user id. Requests with a Bearer token or without testMode still use full JWT auth unchanged.
This commit is contained in:
@@ -1,16 +1,49 @@
|
||||
import type { NextFunction, Request, Response } from "express";
|
||||
import { Router } from "express";
|
||||
import { db } from "../db/fcmTokens.js";
|
||||
import { requireAuth } from "../middleware/auth.js";
|
||||
import { errorMessage, formatElapsedMs } from "../util/formatElapsed.js";
|
||||
import { maskToken } from "../util/maskToken.js";
|
||||
|
||||
/** Synthetic userId for unauthenticated local debug registrations (testMode). */
|
||||
const LOCAL_TEST_USER_ID = "__notification_local_test__";
|
||||
|
||||
function isNotificationLocalTestBypass(req: Request): boolean {
|
||||
if (req.headers.authorization?.startsWith("Bearer ")) {
|
||||
return false;
|
||||
}
|
||||
const body = req.body;
|
||||
return (
|
||||
body !== null &&
|
||||
typeof body === "object" &&
|
||||
(body as { testMode?: unknown }).testMode === true
|
||||
);
|
||||
}
|
||||
|
||||
async function requireAuthOrNotificationLocalTest(
|
||||
req: Request,
|
||||
res: Response,
|
||||
next: NextFunction
|
||||
): Promise<void> {
|
||||
if (isNotificationLocalTestBypass(req)) {
|
||||
req.did = LOCAL_TEST_USER_ID;
|
||||
console.log("[Auth] Local notification test bypass");
|
||||
next();
|
||||
return;
|
||||
}
|
||||
return requireAuth(req, res, next);
|
||||
}
|
||||
|
||||
export const notificationsRouter = Router();
|
||||
|
||||
notificationsRouter.get("/", (_req, res) => {
|
||||
res.json({ ok: true, resource: "notifications" });
|
||||
});
|
||||
|
||||
notificationsRouter.post("/refresh", requireAuth, async (req, res) => {
|
||||
notificationsRouter.post(
|
||||
"/refresh",
|
||||
requireAuthOrNotificationLocalTest,
|
||||
async (req, res) => {
|
||||
const started = Date.now();
|
||||
const userId = req.did;
|
||||
if (userId === undefined) {
|
||||
@@ -26,7 +59,9 @@ notificationsRouter.post("/refresh", requireAuth, async (req, res) => {
|
||||
const canonicalDeviceId =
|
||||
typeof deviceId === "string" ? deviceId.trim() : undefined;
|
||||
const token =
|
||||
typeof fcmToken === "string" && fcmToken.length > 0 ? fcmToken : undefined;
|
||||
typeof fcmToken === "string" && fcmToken.length > 0
|
||||
? fcmToken
|
||||
: undefined;
|
||||
|
||||
console.log(
|
||||
"[Refresh] Request received",
|
||||
@@ -76,9 +111,13 @@ notificationsRouter.post("/refresh", requireAuth, async (req, res) => {
|
||||
"deviceId=" + device.deviceId + ",",
|
||||
"token suffix=" + maskToken(device.fcmToken)
|
||||
);
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
notificationsRouter.post("/register", requireAuth, async (req, res) => {
|
||||
notificationsRouter.post(
|
||||
"/register",
|
||||
requireAuthOrNotificationLocalTest,
|
||||
async (req, res) => {
|
||||
const started = Date.now();
|
||||
const userId = req.did;
|
||||
if (userId === undefined) {
|
||||
@@ -178,4 +217,5 @@ notificationsRouter.post("/register", requireAuth, async (req, res) => {
|
||||
);
|
||||
res.sendStatus(500);
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user