This commit is contained in:
1 parent
8efd032cc6
commit
df38dccbf1
735 files changed
+128321
-120870
No files matched your search
+52
-45
@@ -1,7 +1,7 @@
|
||||
import { createHash, randomBytes } from "node:crypto";
|
||||
import { prisma } from "@/lib/prisma";
|
||||
import { personalTokenScope, USER_TOKENABLE_TYPE } from "@/lib/auth/personal-token-scope";
|
||||
import { personalTokenScope } from "@/lib/auth/personal-token-scope";
|
||||
import { databaseUserId } from "@/lib/auth/session-user";
|
||||
import { prisma } from "@/lib/prisma";
|
||||
|
||||
/**
|
||||
* Bearer-token auth for the public REST API, backed by personal_access_tokens
|
||||
@@ -10,55 +10,62 @@ import { databaseUserId } from "@/lib/auth/session-user";
|
||||
* Sanctum "{id}|{plaintext}" form) as `Authorization: Bearer …`.
|
||||
*/
|
||||
function hashToken(raw: string): string {
|
||||
return createHash("sha256").update(raw).digest("hex");
|
||||
return createHash("sha256").update(raw).digest("hex");
|
||||
}
|
||||
|
||||
/** Resolve the user id behind a Bearer token, or null. */
|
||||
export async function bearerUserId(req: Request): Promise<number | null> {
|
||||
const header = req.headers.get("authorization") ?? "";
|
||||
const m = header.match(/^Bearer\s+(.+)$/i);
|
||||
if (!m) return null;
|
||||
let raw = m[1].trim();
|
||||
const pipe = raw.indexOf("|");
|
||||
if (pipe >= 0) raw = raw.slice(pipe + 1); // Sanctum "{id}|{token}"
|
||||
if (!raw) return null;
|
||||
const header = req.headers.get("authorization") ?? "";
|
||||
const m = header.match(/^Bearer\s+(.+)$/i);
|
||||
if (!m) return null;
|
||||
let raw = m[1].trim();
|
||||
const pipe = raw.indexOf("|");
|
||||
if (pipe >= 0) raw = raw.slice(pipe + 1); // Sanctum "{id}|{token}"
|
||||
if (!raw) return null;
|
||||
|
||||
try {
|
||||
const row = await prisma.personalAccessTokens.findFirst({
|
||||
where: {
|
||||
token: hashToken(raw),
|
||||
OR: [{ expiresAt: null }, { expiresAt: { gt: new Date() } }],
|
||||
},
|
||||
select: { id: true, tokenableId: true },
|
||||
});
|
||||
if (!row) return null;
|
||||
// Best-effort last-used stamp (don't fail the request if it errors).
|
||||
prisma.personalAccessTokens
|
||||
.update({ where: { id: row.id }, data: { lastUsedAt: new Date() }, select: { id: true } })
|
||||
.catch(() => {});
|
||||
return databaseUserId(row.tokenableId);
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
const row = await prisma.personalAccessTokens.findFirst({
|
||||
where: {
|
||||
token: hashToken(raw),
|
||||
OR: [{ expiresAt: null }, { expiresAt: { gt: new Date() } }],
|
||||
},
|
||||
select: { id: true, tokenableId: true },
|
||||
});
|
||||
if (!row) return null;
|
||||
// Best-effort last-used stamp (don't fail the request if it errors).
|
||||
prisma.personalAccessTokens
|
||||
.update({
|
||||
where: { id: row.id },
|
||||
data: { lastUsedAt: new Date() },
|
||||
select: { id: true },
|
||||
})
|
||||
.catch(() => {});
|
||||
return databaseUserId(row.tokenableId);
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/** Mint a new token for a user. Returns the plaintext (shown once). */
|
||||
export async function issueToken(userId: number, name = "api"): Promise<string | null> {
|
||||
const plaintext = randomBytes(32).toString("hex");
|
||||
try {
|
||||
await prisma.personalAccessTokens.create({
|
||||
data: {
|
||||
...personalTokenScope(userId),
|
||||
name: name.slice(0, 100),
|
||||
token: hashToken(plaintext),
|
||||
abilities: '["*"]',
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
},
|
||||
select: { id: true },
|
||||
});
|
||||
return plaintext;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
export async function issueToken(
|
||||
userId: number,
|
||||
name = "api",
|
||||
): Promise<string | null> {
|
||||
const plaintext = randomBytes(32).toString("hex");
|
||||
try {
|
||||
await prisma.personalAccessTokens.create({
|
||||
data: {
|
||||
...personalTokenScope(userId),
|
||||
name: name.slice(0, 100),
|
||||
token: hashToken(plaintext),
|
||||
abilities: '["*"]',
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
},
|
||||
select: { id: true },
|
||||
});
|
||||
return plaintext;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user