File size: 2,843 Bytes
5ef6e9d | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 | import { Router } from "express";
import { db, configTable, geminiAccountsTable } from "@workspace/db";
import { eq, sql } from "drizzle-orm";
import { OTP_KEY, SITE_CONFIG_KEYS } from "./admin";
const router = Router();
const TOKEN_KEY = "geminigen_bearer_token";
const REFRESH_TOKEN_KEY = "geminigen_refresh_token";
router.post("/receive-tokens", async (req, res) => {
const { otp, access_token, refresh_token, label } = req.body as {
otp?: string;
access_token?: string;
refresh_token?: string;
label?: string;
};
if (!otp || !access_token) {
return res.status(400).json({ error: "otp ε access_token ηΊεΏ
ε‘«" });
}
const row = await db
.select()
.from(configTable)
.where(eq(configTable.key, OTP_KEY))
.limit(1);
if (!row.length) {
return res.status(401).json({ error: "OTP η‘ζζε·²ιζοΌθ«ιζ°η’ηζΈη±€" });
}
const [storedOtp, expiresAtStr] = row[0].value.split(":");
const expiresAt = Number(expiresAtStr);
if (storedOtp !== otp || Date.now() > expiresAt) {
return res.status(401).json({ error: "OTP η‘ζζε·²ιζοΌθ«ιζ°η’ηζΈη±€" });
}
// Delete OTP (one-time use)
await db.delete(configTable).where(eq(configTable.key, OTP_KEY));
if (label) {
// Save to pool as a new account
await db.insert(geminiAccountsTable).values({
label: label.trim(),
bearerToken: access_token,
refreshToken: refresh_token || null,
isActive: true,
});
return res.json({ success: true, message: `εΈ³ζΆγ${label}γε·²ε ε
₯ Token ζ± οΌ` });
}
// Legacy: save as single token in config
await db
.insert(configTable)
.values({ key: TOKEN_KEY, value: access_token, updatedAt: new Date() })
.onConflictDoUpdate({ target: configTable.key, set: { value: access_token, updatedAt: new Date() } });
if (refresh_token) {
await db
.insert(configTable)
.values({ key: REFRESH_TOKEN_KEY, value: refresh_token, updatedAt: new Date() })
.onConflictDoUpdate({ target: configTable.key, set: { value: refresh_token, updatedAt: new Date() } });
}
return res.json({ success: true, message: "Token ε·²ζεεζ₯οΌ" });
});
// ββ Public site config (logo, Google Ads) βββββββββββββββββββββββββββββββββββββ
const PUBLIC_SITE_KEYS = ["logo_url", "site_name", "google_ads_enabled", "google_ads_client", "google_ads_slot"];
router.get("/site-config", async (_req, res) => {
const rows = await db
.select()
.from(configTable)
.where(sql`${configTable.key} = ANY(ARRAY[${sql.raw(PUBLIC_SITE_KEYS.map(k => `'${k}'`).join(","))}]::text[])`);
const config: Record<string, string> = {};
for (const row of rows) config[row.key] = row.value;
res.json(config);
});
export default router;
|