const express = require('express') const Database = require('better-sqlite3') const path = require('path') const fs = require('fs') const dataDir = path.join(process.cwd(), 'data') if (!fs.existsSync(dataDir)) fs.mkdirSync(dataDir, { recursive: true }) const dbPath = path.join(dataDir, 'dlt_draws.db') const db = new Database(dbPath) // Initialize Tables db.exec(`CREATE TABLE IF NOT EXISTS draws ( issue TEXT PRIMARY KEY, date TEXT, front TEXT, back TEXT, pool INTEGER DEFAULT 0, created_at TEXT DEFAULT (datetime('now')) );`) // Auth Helpers const readCookieCfg = () => { const cfgPath = path.join(process.cwd(), 'public', 'tools', 'dlt_draws', 'assets', 'auth_config.json') let name = 'dlt_draws_gate' let maxAge = 90 * 24 * 3600 * 1000 try { if (fs.existsSync(cfgPath)) { const cfg = JSON.parse(fs.readFileSync(cfgPath, 'utf-8')) if (cfg.cookieName) name = String(cfg.cookieName) const days = Number(cfg.max_age_days || 0) if (Number.isFinite(days) && days > 0) maxAge = Math.min(days, 365) * 24 * 3600 * 1000 } } catch {} return { name, maxAge } } const parseCookie = (cookieStr) => { const out = {} String(cookieStr || '').split(/;\s*/).forEach(p => { const idx = p.indexOf('='); if (idx > 0) out[p.slice(0, idx)] = decodeURIComponent(p.slice(idx + 1)) }) return out } const checkAuth = (req, res, next) => { try { const cookies = parseCookie(req.headers.cookie || '') const { name, maxAge } = readCookieCfg() if (cookies[name] === '1' || cookies['nav_gate'] === '1') { res.cookie(name, '1', { httpOnly: true, sameSite: 'lax', maxAge }) return next() } } catch {} return res.status(401).json({ error: 'unauthorized' }) } // Helpers const pad2 = (n) => String(n).padStart(2, '0') const arrToCsv = (arr) => (Array.isArray(arr) ? arr : String(arr).split(/[,,\s]+/).filter(Boolean)) .map((x) => pad2(parseInt(x, 10))) .join(',') const csvToArr = (csv) => String(csv).split(/[,,\s]+/).filter(Boolean).map((x) => parseInt(x, 10)) const bindRoutes = (app) => { // Routes prefixed with /api/dlt app.get('/auth/handshake', (req, res) => { try { const cookies = parseCookie(req.headers.cookie || '') const { name } = readCookieCfg() if (cookies[name] === '1' || cookies['nav_gate'] === '1') return res.json({ ok: true }) return res.status(401).json({ error: 'unauthorized' }) } catch (e) { res.status(500).json({ ok: false, error: String(e.message || e) }) } }) app.get('/auth/token', (req, res) => { const cookies = parseCookie(req.headers.cookie || '') const { name } = readCookieCfg() if (cookies[name] === '1' || cookies['nav_gate'] === '1') return res.json({ ok: true }) return res.status(401).json({ error: 'unauthorized' }) }) app.get('/api/dlt/health', (req, res) => res.json({ status: 'ok' })) app.get('/api/dlt/draws', checkAuth, (req, res) => { const limit = Math.max(0, parseInt(req.query.limit || '0', 10) || 0) const base = `SELECT issue, date, front, back, pool FROM draws ORDER BY CAST(issue AS INTEGER) ASC` const sql = limit ? `${base} LIMIT ?` : base try { const rows = db.prepare(sql).all(limit ? [limit] : []) res.json(rows.map((r) => ({ issue: r.issue, date: r.date, front: csvToArr(r.front), back: csvToArr(r.back), pool: r.pool || 0 }))) } catch (err) { res.status(500).json({ error: err.message }) } }) app.post('/api/dlt/draws/merge', checkAuth, (req, res) => { const items = Array.isArray(req.body.rows) ? req.body.rows : [] if (!items.length) return res.status(400).json({ error: 'rows empty' }) let inserted = 0 try { const insert = db.transaction((rows) => { let count = 0 const stmt = db.prepare('INSERT OR IGNORE INTO draws(issue,date,front,back,pool) VALUES (?,?,?,?,?)') for (const it of rows) { const issue = String(it.issue || '').trim() const date = String(it.date || '').trim() const front = arrToCsv(it.front || it.frontArr || []) const back = arrToCsv(it.back || it.backArr || []) const pool = Number(it.pool || 0) if (!issue || csvToArr(front).length !== 5 || csvToArr(back).length !== 2) continue const info = stmt.run(issue, date, front, back, pool) count += info.changes } return count }) inserted = insert(items) res.json({ inserted }) } catch (err) { res.status(500).json({ error: err.message }) } }) app.post('/api/dlt/draws/clear', checkAuth, (req, res) => { try { db.prepare('DELETE FROM draws').run() res.json({ cleared: true }) } catch (err) { res.status(500).json({ error: err.message }) } }) } module.exports = { bindRoutes }