50 lines
1.6 KiB
JavaScript
50 lines
1.6 KiB
JavaScript
require('dotenv').config({ path: require('path').join(__dirname, '..', '.env') });
|
|
|
|
const express = require('express');
|
|
const path = require('path');
|
|
const crypto = require('crypto');
|
|
|
|
const app = express();
|
|
const PORT = process.env.PORT || 3000;
|
|
const UPLOADS_DIR = process.env.UPLOADS_DIR || path.join(__dirname, '..', 'uploads');
|
|
|
|
// 10mb limit needed for base64-encoded screenshot payloads
|
|
app.use(express.json({ limit: '10mb' }));
|
|
|
|
// Auth middleware for protected API routes
|
|
function requireAuth(req, res, next) {
|
|
const password = (process.env.SHOWCASE_PASSWORD || '').trim();
|
|
if (!password) return next(); // not configured, skip
|
|
|
|
const auth = req.headers['authorization'] || '';
|
|
const token = auth.startsWith('Bearer ') ? auth.slice(7) : '';
|
|
const expected = crypto.createHmac('sha256', password).update('showcase-session').digest('hex');
|
|
|
|
if (token !== expected) {
|
|
return res.status(401).json({ error: 'Unauthorized' });
|
|
}
|
|
next();
|
|
}
|
|
|
|
// Auth route (public)
|
|
app.use('/api/auth', require('./routes/auth').router);
|
|
|
|
// Protected API routes
|
|
app.use('/api/apps', requireAuth, require('./routes/apps'));
|
|
app.use('/api/ads', requireAuth, require('./routes/upload'));
|
|
app.use('/api/ads', requireAuth, require('./routes/ads'));
|
|
|
|
// Serve uploaded HTML files
|
|
app.use('/uploads', express.static(UPLOADS_DIR));
|
|
|
|
// Serve React build in production
|
|
const publicDir = path.join(__dirname, '..', 'public');
|
|
app.use(express.static(publicDir));
|
|
app.get('*', (_req, res) => {
|
|
res.sendFile(path.join(publicDir, 'index.html'));
|
|
});
|
|
|
|
app.listen(PORT, () => {
|
|
console.log(`Playable Showcase running on http://localhost:${PORT}`);
|
|
});
|