diff --git a/.env.example b/.env.example index 0ae165b..1b247d9 100644 --- a/.env.example +++ b/.env.example @@ -2,7 +2,6 @@ # Port the server listens on (client must connect to this) PORT=5055 -ADMIN_PORT=5056 # Logging: error, warn, info, verbose, debug, silly LOG_LEVEL=info @@ -13,7 +12,3 @@ RECNET_VERIFY_URL= # SQLite DB file SQLITE_FILE=./helium.db - -# Admin basic auth (optional) -ADMIN_USER=admin -ADMIN_PASS=changeme diff --git a/README.md b/README.md index 511ab74..2d611fa 100644 --- a/README.md +++ b/README.md @@ -7,28 +7,24 @@ What I added in this commit: - Protocol stub (src/protocol.js) — where Rec Room / Photon packet parsing should be implemented - Auth helpers (src/auth.js) for Steam/RecNet token verification (placeholders that call configured endpoints) - SQLite persistence (src/storage.js) -- Admin console (src/admin.js) with basic auth and endpoints to list connections and broadcast messages - Logger and test client - package.json with dependencies Environment variables (set in .env): - PORT (default 5055) — WebSocket server port -- ADMIN_PORT (default 5056) — Admin HTTP server port - LOG_LEVEL — winston log level (info/debug/...) - STEAM_WEB_API_KEY — Steam Web API key (if you plan to use Steam verification) - RECNET_VERIFY_URL — RecNet verification endpoint to POST { token } - SQLITE_FILE — path for the SQLite DB file (default ./helium.db) -- ADMIN_USER / ADMIN_PASS — optional Basic auth for admin console How to run: 1. Copy `.env.example` to `.env` and fill in the variables you need. 2. npm install 3. npm start -4. Admin console: http://localhost:5056 (use basic auth if ADMIN_USER/ADMIN_PASS set) Notes about Photon & Rec Room: - The client uses Photon; this skeleton provides a WebSocket entry point you can use for reverse engineering and testing. Photon traffic is binary and has its own framing — you'll need to implement Photon protocol handling inside src/protocol.js (or add a UDP/TCP transport if Photon expects that). -- You said you can replace Photon keys and localhost yourself — good. Put the Photon server host/port to point to this process and replace any required AppId/AppVersion in the client. +- You said you can replace Photon keys & localhost yourself — point the client at this process and replace any required AppId/AppVersion in the client. Next steps I can take after you confirm: - Implement Photon framing and basic handshake to accept a 2023 Rec Room client (requires packet captures or protocol docs). diff --git a/package.json b/package.json index 1cb9c39..bd92101 100644 --- a/package.json +++ b/package.json @@ -5,16 +5,13 @@ "main": "src/index.js", "scripts": { "start": "node src/index.js", - "dev": "nodemon src/index.js", - "admin": "node src/admin.js" + "dev": "nodemon src/index.js" }, "dependencies": { "ws": "^8.13.0", "dotenv": "^16.0.0", "winston": "^3.8.0", - "express": "^4.18.2", "axios": "^1.4.0", - "sqlite3": "^5.1.6", - "basic-auth": "^2.0.1" + "sqlite3": "^5.1.6" } } diff --git a/src/admin.js b/src/admin.js index d30bebb..405c107 100644 --- a/src/admin.js +++ b/src/admin.js @@ -1,50 +1,5 @@ -const express = require('express'); -const basicAuth = require('basic-auth'); -const logger = require('./logger'); +// The admin console was intentionally removed from the project per repository owner request. +// If you need to restore it later, re-add an admin HTTP server (e.g., using express) and +// provide ADMIN_USER / ADMIN_PASS environment variables for basic auth. -let serverInstance; - -function ensureAuth(req, res, next) { - if (!process.env.ADMIN_USER || !process.env.ADMIN_PASS) return next(); - const user = basicAuth(req); - if (!user || user.name !== process.env.ADMIN_USER || user.pass !== process.env.ADMIN_PASS) { - res.set('WWW-Authenticate', 'Basic realm="HeliumRecAdmin"'); - return res.status(401).send('Authentication required'); - } - return next(); -} - -function start({ port = 5056, getConnections }) { - const app = express(); - app.use(express.json()); - - app.get('/health', (req, res) => res.json({ ok: true })); - - app.use(ensureAuth); - - app.get('/connections', (req, res) => { - const conns = []; - const map = getConnections(); - map.forEach((v, k) => { - conns.push({ id: k, user: v.user, connectedAt: v.connectedAt, remote: v.ws?._meta?.remote }); - }); - res.json(conns); - }); - - app.post('/broadcast', (req, res) => { - const { message } = req.body || {}; - if (!message) return res.status(400).json({ error: 'message required' }); - const map = getConnections(); - let sent = 0; - map.forEach((v) => { - try { v.ws.send(typeof message === 'string' ? message : JSON.stringify(message)); sent++; } catch (e) { logger.warn('broadcast failed', e.message); } - }); - res.json({ sent }); - }); - - serverInstance = app.listen(port, () => logger.info(`Admin console listening on http://0.0.0.0:${port}`)); -} - -function stop() { if (serverInstance) serverInstance.close(); } - -module.exports = { start, stop }; +module.exports = {}; diff --git a/src/index.js b/src/index.js index 97bbf2e..f696738 100644 --- a/src/index.js +++ b/src/index.js @@ -8,16 +8,28 @@ const logger = require('./logger'); const protocol = require('./protocol'); const auth = require('./auth'); const storage = require('./storage'); -const admin = require('./admin'); const PORT = process.env.PORT || 5055; -const ADMIN_PORT = process.env.ADMIN_PORT || 5056; (async () => { await storage.init(); // Start WebSocket server on its own HTTP server so we can inspect req.url - const server = http.createServer(); + const server = http.createServer((req, res) => { + // Provide a minimal informational page for HTTP GETs so browsers don't see "Cannot GET /" + if (req.method === 'GET' && (req.url === '/' || req.url === '/index.html')) { + res.writeHead(200, { 'Content-Type': 'text/html' }); + res.end(` +

HeliumRecServer

+

This port is a WebSocket endpoint. Connect using a WebSocket client.

+

Server listens on ws://0.0.0.0:${PORT}

+ `); + return; + } + // leave other requests to return 404 + res.writeHead(404); res.end('Not Found'); + }); + const wss = new WebSocket.Server({ noServer: true }); const connections = new Map(); // key -> { ws, user } @@ -79,7 +91,4 @@ const ADMIN_PORT = process.env.ADMIN_PORT || 5056; }); server.listen(PORT, () => logger.info(`HeliumRecServer WebSocket listening on ws://0.0.0.0:${PORT}`)); - - // Start admin console (HTTP) bound to ADMIN_PORT - admin.start({ port: ADMIN_PORT, getConnections: () => connections }); })();