refactor: merge auth into account prefix (/account/register, /account/email)

This commit is contained in:
M1 2026-03-16 13:37:20 +04:00
parent fd4af848bc
commit a22112dc77
3 changed files with 23 additions and 28 deletions

View File

@ -119,7 +119,7 @@
document.getElementById('register-btn').addEventListener('click', async () => {
setLoading('register-btn', true, 'Creating...');
try {
const res = await fetch(`${API}/auth/register`, {
const res = await fetch(`${API}/account/register`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({}),

View File

@ -3,7 +3,7 @@ import { cors } from "@elysiajs/cors";
import { swagger } from "@elysiajs/swagger";
import { checks } from "./routes/checks";
import { monitors } from "./routes/monitors";
import { auth, account } from "./routes/auth";
import { account } from "./routes/auth";
import { internal } from "./routes/internal";
import { dashboard } from "./routes/dashboard";
import { migrate } from "./db";
@ -15,7 +15,6 @@ const app = new Elysia()
.use(swagger({ path: "/docs", documentation: { info: { title: "PingQL API", version: "0.1.0" } } }))
.get("/", () => ({ name: "PingQL", version: "0.1.0", docs: "/docs", dashboard: "/dashboard" }), { detail: { hide: true } })
.use(dashboard)
.use(auth)
.use(account)
.use(monitors)
.use(checks)

View File

@ -2,14 +2,12 @@ import { Elysia, t } from "elysia";
import { randomBytes, createHash } from "crypto";
import sql from "../db";
// Generate a memorable 16-digit account key: XXXX-XXXX-XXXX-XXXX
function generateAccountKey(): string {
const bytes = randomBytes(8);
const hex = bytes.toString("hex").toUpperCase();
return `${hex.slice(0, 4)}-${hex.slice(4, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}`;
}
// Middleware: validate account key from Authorization header
export function requireAuth(app: Elysia) {
return app.derive(async ({ headers, error }) => {
const key = headers["authorization"]?.replace("Bearer ", "").trim();
@ -23,8 +21,28 @@ export function requireAuth(app: Elysia) {
}
export const account = new Elysia({ prefix: "/account" })
// Create account
.post("/register", async ({ body }) => {
const key = generateAccountKey();
const emailHash = body.email
? createHash("sha256").update(body.email.toLowerCase().trim()).digest("hex")
: null;
await sql`INSERT INTO accounts (id, email_hash) VALUES (${key}, ${emailHash})`;
return {
key,
...(body.email ? { email_registered: true } : { email_registered: false }),
};
}, {
body: t.Object({
email: t.Optional(t.String({ format: "email", description: "Optional. Used for recovery and alerts." })),
}),
detail: { summary: "Create account", tags: ["account"] },
})
// Update email
.use(requireAuth)
// Update email (post-registration or settings)
.post("/email", async ({ accountId, body }) => {
const emailHash = body.email
? createHash("sha256").update(body.email.toLowerCase().trim()).digest("hex")
@ -37,25 +55,3 @@ export const account = new Elysia({ prefix: "/account" })
}),
detail: { summary: "Update account email", tags: ["account"] },
});
export const auth = new Elysia({ prefix: "/auth" })
// Create a new account — no email required
.post("/register", async ({ body }) => {
const key = generateAccountKey();
const emailHash = body.email
? createHash("sha256").update(body.email.toLowerCase().trim()).digest("hex")
: null;
await sql`INSERT INTO accounts (id, email_hash) VALUES (${key}, ${emailHash})`;
return {
key,
message: "Save this key — it's your only credential. We don't store it.",
...(body.email ? { email_registered: true } : { email_registered: false }),
};
}, {
body: t.Object({
email: t.Optional(t.String({ format: "email", description: "Optional. Only used for account recovery." })),
}),
detail: { summary: "Create account", tags: ["auth"] },
});