| import crypto from "crypto"; |
|
|
| |
| const COOKIE = "akis_auth"; |
| const MAX_AGE_DAYS = 30; |
|
|
| const PASSWORD = process.env.APP_PASSWORD || "admin"; |
| if (!process.env.APP_PASSWORD) { |
| console.warn( |
| "⚠️ APP_PASSWORD ayarlı değil — geçici şifre 'admin'. Üretimde .env veya ortam değişkeni ile mutlaka değiştirin." |
| ); |
| } |
| |
| const SECRET = process.env.SESSION_SECRET || "akis::" + PASSWORD; |
|
|
| const b64url = (buf) => |
| Buffer.from(buf).toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, ""); |
|
|
| function sign(payloadStr) { |
| return crypto.createHmac("sha256", SECRET).update(payloadStr).digest("base64") |
| .replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, ""); |
| } |
|
|
| function makeToken() { |
| const payload = b64url(JSON.stringify({ u: "admin", exp: Date.now() + MAX_AGE_DAYS * 864e5 })); |
| return `${payload}.${sign(payload)}`; |
| } |
|
|
| function verifyToken(token) { |
| if (!token || !token.includes(".")) return false; |
| const [payload, sig] = token.split("."); |
| const expected = sign(payload); |
| if (sig.length !== expected.length) return false; |
| if (!crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected))) return false; |
| try { |
| const data = JSON.parse(Buffer.from(payload.replace(/-/g, "+").replace(/_/g, "/"), "base64")); |
| return data.exp && data.exp > Date.now(); |
| } catch { |
| return false; |
| } |
| } |
|
|
| function passwordOk(input) { |
| const a = Buffer.from(String(input ?? "")); |
| const b = Buffer.from(PASSWORD); |
| if (a.length !== b.length) return false; |
| return crypto.timingSafeEqual(a, b); |
| } |
|
|
| function readCookie(req, name) { |
| const raw = req.headers.cookie; |
| if (!raw) return null; |
| for (const part of raw.split(";")) { |
| const i = part.indexOf("="); |
| if (i > -1 && part.slice(0, i).trim() === name) return decodeURIComponent(part.slice(i + 1).trim()); |
| } |
| return null; |
| } |
|
|
| function setAuthCookie(req, res) { |
| const secure = req.secure || req.headers["x-forwarded-proto"] === "https"; |
| res.setHeader("Set-Cookie", |
| `${COOKIE}=${makeToken()}; HttpOnly; SameSite=Lax; Path=/; Max-Age=${MAX_AGE_DAYS * 86400}${secure ? "; Secure" : ""}`); |
| } |
|
|
| export function clearAuthCookie(res) { |
| res.setHeader("Set-Cookie", `${COOKIE}=; HttpOnly; SameSite=Lax; Path=/; Max-Age=0`); |
| } |
|
|
| export function isAuthed(req) { |
| return verifyToken(readCookie(req, COOKIE)); |
| } |
|
|
| |
| export function requireApiAuth(req, res, next) { |
| if (isAuthed(req)) return next(); |
| res.status(401).json({ error: "Yetkisiz", auth: false }); |
| } |
|
|
| export function loginHandler(req, res) { |
| if (!passwordOk(req.body?.password)) { |
| return res.status(401).json({ error: "Şifre hatalı" }); |
| } |
| setAuthCookie(req, res); |
| res.json({ ok: true }); |
| } |
|
|
| export function logoutHandler(req, res) { |
| clearAuthCookie(res); |
| res.json({ ok: true }); |
| } |
|
|