import express from 'express'; import fetch from 'node-fetch'; import { COOKIE_NAMES, getCsrfCookieOptions, generateToken } from '../utils/cookie-options.js'; export function createSessionRouter({ config, tokenStore }) { const router = express.Router(); async function probeChallonge(url, headers) { try { const resp = await fetch(url, { method: 'GET', headers }); const contentType = resp.headers.get('content-type') || ''; let bodyText = ''; try { bodyText = await resp.text(); } catch { bodyText = ''; } // Keep response small & safe const snippet = (bodyText || '').slice(0, 500); let json = null; if (contentType.includes('application/json')) { try { json = bodyText ? JSON.parse(bodyText) : null; } catch { json = null; } } return { ok: resp.ok, status: resp.status, contentType, snippet, json }; } catch (err) { return { ok: false, status: null, contentType: null, snippet: err?.message || 'probe failed', json: null }; } } // Ensure SID exists (sid middleware should run before this) router.get('/init', async (req, res) => { try { if (!req.sid) { return res.status(500).json({ error: 'SID middleware not configured' }); } await tokenStore.touchSession(req.sid); return res.json({ ok: true }); } catch (err) { return res.status(500).json({ error: err.message || 'Failed to init session', code: 'SESSION_INIT_FAILED' }); } }); // Issue/refresh CSRF token cookie router.get('/csrf', (req, res) => { const token = generateToken(24); res.cookie(COOKIE_NAMES.csrf, token, getCsrfCookieOptions(config)); res.json({ csrfToken: token }); }); // Dev helper: confirm which SID the browser is using and whether provider // credentials are present for that SID. Does not return secrets. router.get('/whoami', async (req, res) => { if (!req.sid) { return res.status(500).json({ error: 'SID middleware not configured' }); } const challonge = (await tokenStore.getProviderRecord(req.sid, 'challonge')) || {}; return res.json({ sid: req.sid, challonge: { hasApiKey: !!challonge.api_key?.token, hasUserOAuth: !!challonge.user_oauth?.access_token, userOAuthExpiresAt: challonge.user_oauth?.expires_at || null, hasClientCredentials: !!(challonge.client_credentials?.client_id && challonge.client_credentials?.client_secret), hasClientCredentialsToken: !!challonge.client_credentials?.access_token, clientCredentialsExpiresAt: challonge.client_credentials?.expires_at || null } }); }); // Dev-only: verify challonge upstream auth for this SID (no secrets returned) router.get('/challonge/verify', async (req, res) => { if (!req.sid) { return res.status(500).json({ error: 'SID middleware not configured' }); } const challonge = (await tokenStore.getProviderRecord(req.sid, 'challonge')) || {}; const base = 'https://api.challonge.com/v2.1/tournaments.json?page=1&per_page=1&state=pending'; const results = { sid: req.sid, endpoints: { userTournamentsSample: base, appTournamentsSample: 'https://api.challonge.com/v2.1/application/tournaments.json?page=1&per_page=1&state=pending' }, methods: { user_oauth: { present: !!challonge.user_oauth?.access_token, probe: null }, api_key: { present: !!challonge.api_key?.token, probe: null }, client_credentials: { present: !!challonge.client_credentials?.access_token, probe: null } } }; if (challonge.user_oauth?.access_token) { results.methods.user_oauth.probe = await probeChallonge(base, { Accept: 'application/json', 'Content-Type': 'application/vnd.api+json', authorization: `Bearer ${challonge.user_oauth.access_token}`, 'authorization-type': 'v2' }); } if (challonge.api_key?.token) { results.methods.api_key.probe = await probeChallonge(base, { Accept: 'application/json', 'Content-Type': 'application/vnd.api+json', authorization: challonge.api_key.token, 'authorization-type': 'v1' }); } if (challonge.client_credentials?.access_token) { results.methods.client_credentials.probe = await probeChallonge( results.endpoints.appTournamentsSample, { Accept: 'application/json', 'Content-Type': 'application/vnd.api+json', authorization: `Bearer ${challonge.client_credentials.access_token}`, 'authorization-type': 'v2' } ); } return res.json(results); }); return router; }