Merge branch 'main' into fix/gro-485-oobe-staff-middleware
This commit is contained in:
@@ -24,11 +24,11 @@ describe("encryptSecret / decryptSecret", () => {
|
||||
expect(decrypted).toBe(plaintext);
|
||||
});
|
||||
|
||||
it("produces output in iv:ciphertext:authTag format", () => {
|
||||
it("produces output in salt:iv:ciphertext:authTag format", () => {
|
||||
const encrypted = encryptSecret("test");
|
||||
const parts = encrypted.split(":");
|
||||
|
||||
expect(parts).toHaveLength(3);
|
||||
expect(parts).toHaveLength(4);
|
||||
// Each part should be valid base64
|
||||
parts.forEach((part) => {
|
||||
expect(() => Buffer.from(part, "base64")).not.toThrow();
|
||||
@@ -62,11 +62,12 @@ describe("encryptSecret / decryptSecret", () => {
|
||||
|
||||
it("throws when decrypting invalid format (wrong number of parts)", () => {
|
||||
const encrypted = encryptSecret("test");
|
||||
// Replace the last ":authTag" part by matching colon + non-colon chars at the end
|
||||
const invalid = encrypted.replace(/:[^:]+$/, "");
|
||||
// Replace the last two parts with a single part to create a 2-part string
|
||||
// This can't be parsed as either legacy (3 parts) or new (4 parts) format
|
||||
const invalid = encrypted.replace(/:[^:]+$/, "").replace(/:[^:]+$/, "");
|
||||
|
||||
expect(() => decryptSecret(invalid)).toThrow(
|
||||
"Invalid encrypted value format: expected iv:ciphertext:authTag"
|
||||
"Invalid encrypted value format: expected salt:iv:ciphertext:authTag or iv:ciphertext:authTag"
|
||||
);
|
||||
});
|
||||
|
||||
@@ -93,4 +94,4 @@ describe("encryptSecret / decryptSecret", () => {
|
||||
|
||||
expect(decrypted).toBe(plaintext);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -167,7 +167,6 @@ api.route("/impersonation", impersonationRouter);
|
||||
api.route("/admin/settings", settingsRouter);
|
||||
api.route("/admin/auth-provider", authProviderRouter);
|
||||
api.route("/admin/seed", adminSeedRouter);
|
||||
api.route("/admin/auth-provider", authProviderRouter);
|
||||
api.route("/search", searchRouter);
|
||||
|
||||
const port = Number(process.env.PORT ?? 3000);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { MiddlewareHandler } from "hono";
|
||||
import { eq, getDb, staff } from "@groombook/db";
|
||||
import { and, eq, getDb, isNull, staff } from "@groombook/db";
|
||||
|
||||
export type StaffRole = "groomer" | "receptionist" | "manager";
|
||||
export type StaffRow = typeof staff.$inferSelect;
|
||||
@@ -90,6 +90,25 @@ export const resolveStaffMiddleware: MiddlewareHandler<AppEnv> = async (
|
||||
.from(staff)
|
||||
.where(eq(staff.oidcSub, jwt.sub));
|
||||
if (!fallbackRow) {
|
||||
// Auto-link: staff record exists with matching email but no userId — link it now
|
||||
if (jwt.email) {
|
||||
const [linkedStaff] = await db
|
||||
.select()
|
||||
.from(staff)
|
||||
.where(and(eq(staff.email, jwt.email), isNull(staff.userId)));
|
||||
if (linkedStaff) {
|
||||
await db
|
||||
.update(staff)
|
||||
.set({ userId: jwt.sub })
|
||||
.where(eq(staff.id, linkedStaff.id));
|
||||
console.log(
|
||||
`[rbac] Auto-linked staff ${linkedStaff.id} to Better-Auth user ${jwt.sub} via email ${jwt.email}`
|
||||
);
|
||||
c.set("staff", linkedStaff);
|
||||
await next();
|
||||
return;
|
||||
}
|
||||
}
|
||||
return c.json(
|
||||
{ error: "Forbidden: no staff record found for authenticated user" },
|
||||
403
|
||||
|
||||
Reference in New Issue
Block a user