refactor: merge auth into account prefix (/account/register, /account/email)
This commit is contained in:
parent
fd4af848bc
commit
a22112dc77
|
|
@ -119,7 +119,7 @@
|
||||||
document.getElementById('register-btn').addEventListener('click', async () => {
|
document.getElementById('register-btn').addEventListener('click', async () => {
|
||||||
setLoading('register-btn', true, 'Creating...');
|
setLoading('register-btn', true, 'Creating...');
|
||||||
try {
|
try {
|
||||||
const res = await fetch(`${API}/auth/register`, {
|
const res = await fetch(`${API}/account/register`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify({}),
|
body: JSON.stringify({}),
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ import { cors } from "@elysiajs/cors";
|
||||||
import { swagger } from "@elysiajs/swagger";
|
import { swagger } from "@elysiajs/swagger";
|
||||||
import { checks } from "./routes/checks";
|
import { checks } from "./routes/checks";
|
||||||
import { monitors } from "./routes/monitors";
|
import { monitors } from "./routes/monitors";
|
||||||
import { auth, account } from "./routes/auth";
|
import { account } from "./routes/auth";
|
||||||
import { internal } from "./routes/internal";
|
import { internal } from "./routes/internal";
|
||||||
import { dashboard } from "./routes/dashboard";
|
import { dashboard } from "./routes/dashboard";
|
||||||
import { migrate } from "./db";
|
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" } } }))
|
.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 } })
|
.get("/", () => ({ name: "PingQL", version: "0.1.0", docs: "/docs", dashboard: "/dashboard" }), { detail: { hide: true } })
|
||||||
.use(dashboard)
|
.use(dashboard)
|
||||||
.use(auth)
|
|
||||||
.use(account)
|
.use(account)
|
||||||
.use(monitors)
|
.use(monitors)
|
||||||
.use(checks)
|
.use(checks)
|
||||||
|
|
|
||||||
|
|
@ -2,14 +2,12 @@ import { Elysia, t } from "elysia";
|
||||||
import { randomBytes, createHash } from "crypto";
|
import { randomBytes, createHash } from "crypto";
|
||||||
import sql from "../db";
|
import sql from "../db";
|
||||||
|
|
||||||
// Generate a memorable 16-digit account key: XXXX-XXXX-XXXX-XXXX
|
|
||||||
function generateAccountKey(): string {
|
function generateAccountKey(): string {
|
||||||
const bytes = randomBytes(8);
|
const bytes = randomBytes(8);
|
||||||
const hex = bytes.toString("hex").toUpperCase();
|
const hex = bytes.toString("hex").toUpperCase();
|
||||||
return `${hex.slice(0, 4)}-${hex.slice(4, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}`;
|
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) {
|
export function requireAuth(app: Elysia) {
|
||||||
return app.derive(async ({ headers, error }) => {
|
return app.derive(async ({ headers, error }) => {
|
||||||
const key = headers["authorization"]?.replace("Bearer ", "").trim();
|
const key = headers["authorization"]?.replace("Bearer ", "").trim();
|
||||||
|
|
@ -23,8 +21,28 @@ export function requireAuth(app: Elysia) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const account = new Elysia({ prefix: "/account" })
|
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)
|
.use(requireAuth)
|
||||||
// Update email (post-registration or settings)
|
|
||||||
.post("/email", async ({ accountId, body }) => {
|
.post("/email", async ({ accountId, body }) => {
|
||||||
const emailHash = body.email
|
const emailHash = body.email
|
||||||
? createHash("sha256").update(body.email.toLowerCase().trim()).digest("hex")
|
? 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"] },
|
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"] },
|
|
||||||
});
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue