mirror of
https://github.com/darkwire/darkwire.io.git
synced 2025-07-18 10:49:02 +00:00
164 lines
4.0 KiB
JavaScript
164 lines
4.0 KiB
JavaScript
import dotenv from 'dotenv';
|
|
import http from 'http';
|
|
import https from 'https';
|
|
import Koa from 'koa';
|
|
import { Server } from 'socket.io';
|
|
import KoaBody from 'koa-body';
|
|
import cors from 'kcors';
|
|
import Router from 'koa-router';
|
|
import crypto from 'crypto';
|
|
import koaStatic from 'koa-static';
|
|
import koaSend from 'koa-send';
|
|
|
|
import Socket from './socket.js';
|
|
import mailer from './utils/mailer.js';
|
|
import { pollForInactiveRooms } from './inactive_rooms.js';
|
|
import getStore from './store/index.js';
|
|
|
|
dotenv.config();
|
|
|
|
const env = process.env.NODE_ENV || 'development';
|
|
|
|
const app = new Koa();
|
|
const PORT = process.env.PORT || 3001;
|
|
|
|
const router = new Router();
|
|
const koaBody = new KoaBody();
|
|
|
|
const appName = process.env.HEROKU_APP_NAME;
|
|
const isReviewApp = /-pr-/.test(appName);
|
|
const siteURL = process.env.SITE_URL;
|
|
|
|
const store = getStore();
|
|
|
|
if ((siteURL || env === 'development') && !isReviewApp) {
|
|
app.use(
|
|
cors({
|
|
origin: env === 'development' ? '*' : siteURL,
|
|
allowMethods: ['GET', 'HEAD', 'POST'],
|
|
credentials: true,
|
|
}),
|
|
);
|
|
}
|
|
|
|
router.post('/abuse/:roomId', koaBody, async ctx => {
|
|
let { roomId } = ctx.params;
|
|
|
|
roomId = roomId.trim();
|
|
|
|
if (process.env.ABUSE_FROM_EMAIL_ADDRESS && process.env.ABUSE_TO_EMAIL_ADDRESS) {
|
|
const abuseForRoomExists = await store.get('abuse', roomId);
|
|
if (!abuseForRoomExists) {
|
|
mailer.send({
|
|
from: process.env.ABUSE_FROM_EMAIL_ADDRESS,
|
|
to: process.env.ABUSE_TO_EMAIL_ADDRESS,
|
|
subject: 'Darkwire Abuse Notification',
|
|
text: `Room ID: ${roomId}`,
|
|
});
|
|
}
|
|
}
|
|
|
|
await store.inc('abuse', roomId);
|
|
|
|
ctx.status = 200;
|
|
});
|
|
|
|
app.use(router.routes());
|
|
|
|
const apiHost = process.env.API_HOST;
|
|
const cspDefaultSrc = `'self'${apiHost ? ` https://${apiHost} wss://${apiHost}` : ''}`;
|
|
|
|
function setStaticFileHeaders(ctx) {
|
|
ctx.set({
|
|
'strict-transport-security': 'max-age=31536000',
|
|
'Content-Security-Policy': `default-src ${cspDefaultSrc} 'unsafe-inline'; img-src 'self' data:;`,
|
|
'X-Frame-Options': 'deny',
|
|
'X-XSS-Protection': '1; mode=block',
|
|
'X-Content-Type-Options': 'nosniff',
|
|
'Referrer-Policy': 'no-referrer',
|
|
'Feature-Policy': "geolocation 'none'; vr 'none'; payment 'none'; microphone 'none'",
|
|
});
|
|
}
|
|
|
|
const clientDistDirectory = process.env.CLIENT_DIST_DIRECTORY;
|
|
if (clientDistDirectory) {
|
|
app.use(async (ctx, next) => {
|
|
setStaticFileHeaders(ctx);
|
|
await koaStatic(clientDistDirectory, {
|
|
maxage: ctx.req.url === '/' ? 60 * 1000 : 365 * 24 * 60 * 60 * 1000, // one minute in ms for html doc, one year for css, js, etc
|
|
})(ctx, next);
|
|
});
|
|
|
|
app.use(async ctx => {
|
|
setStaticFileHeaders(ctx);
|
|
await koaSend(ctx, 'index.html', { root: clientDistDirectory });
|
|
});
|
|
} else {
|
|
app.use(async ctx => {
|
|
ctx.body = { ready: true };
|
|
});
|
|
}
|
|
|
|
const protocol = (process.env.PROTOCOL || 'http') === 'http' ? http : https;
|
|
|
|
const httpServer = protocol.createServer(app.callback());
|
|
|
|
const io = new Server(httpServer, {
|
|
pingInterval: 20000,
|
|
pingTimeout: 60000,
|
|
maxHttpBufferSize: 5 * 1e8,
|
|
cors: {
|
|
origin: true,
|
|
credentials: true,
|
|
},
|
|
});
|
|
|
|
// Only use socket adapter if store has one
|
|
if (store.hasSocketAdapter) {
|
|
io.adapter(store.getSocketAdapter());
|
|
}
|
|
|
|
|
|
const roomHashSecret = process.env.ROOM_HASH_SECRET || crypto.randomBytes(256).toString('hex');
|
|
|
|
|
|
const getRoomIdHash = id => {
|
|
if (env === 'development') {
|
|
return id;
|
|
}
|
|
|
|
if (roomHashSecret) {
|
|
return crypto.createHmac('sha256', roomHashSecret).update(id).digest('hex');
|
|
}
|
|
|
|
return crypto.createHash('sha256').update(id).digest('hex');
|
|
};
|
|
|
|
io.on('connection', async socket => {
|
|
const roomId = socket.handshake.query.roomId;
|
|
|
|
const roomIdHash = getRoomIdHash(roomId);
|
|
|
|
let room = await store.get('rooms', roomIdHash);
|
|
room = JSON.parse(room || '{}');
|
|
|
|
new Socket({
|
|
roomIdOriginal: roomId,
|
|
roomId: roomIdHash,
|
|
socket,
|
|
room,
|
|
});
|
|
});
|
|
|
|
export const getIO = () => io;
|
|
|
|
const init = async () => {
|
|
httpServer.listen(PORT, () => {
|
|
console.log(`Darkwire is online at port ${PORT}`);
|
|
});
|
|
|
|
pollForInactiveRooms();
|
|
};
|
|
|
|
init();
|