Files
Skunk-casino/server.js

137 lines
5.2 KiB
JavaScript

const express = require('express');
const pg = require('pg');
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
const socketIo = require('socket.io');
const http = require('http');
const cors = require('cors');
const bodyParser = require('body-parser');
const dotenv = require('dotenv');
dotenv.config();
const app = express();
const server = http.createServer(app);
const io = socketIo(server);
app.use(cors());
app.use(bodyParser.json());
app.use(express.static('public'));
const pool = new pg.Pool({
user: process.env.POSTGRES_USER,
host: process.env.POSTGRES_HOST,
database: process.env.POSTGRES_DB,
password: process.env.POSTGRES_PASSWORD,
port: 5432,
});
// Auth middleware
const authenticate = (req, res, next) => {
const token = req.headers.authorization?.split(' ')[1];
if (!token) return res.status(401).json({ error: 'Unauthorized' });
try {
const decoded = jwt.verify(token, process.env.SECRET_KEY);
req.user = decoded;
next();
} catch (err) {
res.status(401).json({ error: 'Invalid token' });
}
};
const isAdmin = (req, res, next) => {
if (req.user.role !== 'admin') return res.status(403).json({ error: 'Forbidden' });
next();
};
// Routes: Auth
app.post('/api/signup', async (req, res) => {
const { username, password, email, promoCode } = req.body;
const hashedPw = await bcrypt.hash(password, 10);
try {
const result = await pool.query('INSERT INTO users (username, password, email) VALUES ($1, $2, $3) RETURNING id', [username, hashedPw, email]);
let bonus = 0;
if (promoCode) {
const promo = await pool.query('SELECT * FROM promo_codes WHERE code = $1 AND used = FALSE', [promoCode]);
if (promo.rows[0]) {
bonus = promo.rows[0].value;
await pool.query('UPDATE promo_codes SET used = TRUE, user_id = $1 WHERE id = $2', [result.rows[0].id, promo.rows[0].id]);
await pool.query('UPDATE users SET balance = balance + $1 WHERE id = $2', [bonus, result.rows[0].id]);
}
}
res.json({ message: 'User created', bonus });
} catch (err) {
res.status(500).json({ error: err.message });
}
});
app.post('/api/login', async (req, res) => {
const { username, password } = req.body;
try {
const user = await pool.query('SELECT * FROM users WHERE username = $1', [username]);
if (!user.rows[0] || !(await bcrypt.compare(password, user.rows[0].password))) {
return res.status(401).json({ error: 'Invalid credentials' });
}
const token = jwt.sign({ id: user.rows[0].id, role: user.rows[0].role }, process.env.SECRET_KEY, { expiresIn: '1h' });
res.json({ token, balance: user.rows[0].balance });
} catch (err) {
res.status(500).json({ error: err.message });
}
});
// Games API (example for bet/result)
app.post('/api/bet', authenticate, async (req, res) => {
const { gameId, amount } = req.body;
try {
const game = await pool.query('SELECT * FROM games WHERE id = $1 AND enabled = TRUE', [gameId]);
if (!game.rows[0] || amount < game.rows[0].min_bet || amount > game.rows[0].max_bet) {
return res.status(400).json({ error: 'Invalid bet' });
}
const user = await pool.query('SELECT balance FROM users WHERE id = $1', [req.user.id]);
if (user.rows[0].balance < amount) return res.status(400).json({ error: 'Insufficient balance' });
// Simulate result (fake, based on win_probability)
const win = Math.random() * 100 < game.rows[0].win_probability;
const payout = win ? amount * 2 : -amount; // Simple 2x win example; customize per game
await pool.query('UPDATE users SET balance = balance + $1 WHERE id = $2', [payout, req.user.id]);
await pool.query('INSERT INTO transactions (user_id, type, amount) VALUES ($1, $2, $3)', [req.user.id, win ? 'win' : 'loss', Math.abs(payout)]);
res.json({ win, payout, newBalance: user.rows[0].balance + payout });
} catch (err) {
res.status(500).json({ error: err.message });
}
});
// Admin Routes
app.get('/api/admin/users', authenticate, isAdmin, async (req, res) => {
const users = await pool.query('SELECT id, username, email, balance, role FROM users');
res.json(users.rows);
});
app.put('/api/admin/user/:id', authenticate, isAdmin, async (req, res) => {
const { balance, role } = req.body;
await pool.query('UPDATE users SET balance = $1, role = $2 WHERE id = $3', [balance, role, req.params.id]);
res.json({ message: 'User updated' });
});
// Similar routes for promo codes, games, stats (e.g., sum wins/losses)
app.get('/api/admin/stats', authenticate, isAdmin, async (req, res) => {
const wins = await pool.query("SELECT SUM(amount) FROM transactions WHERE type = 'win'");
const losses = await pool.query("SELECT SUM(amount) FROM transactions WHERE type = 'loss'");
res.json({ totalWins: wins.rows[0].sum || 0, totalLosses: losses.rows[0].sum || 0 });
});
// Socket.io for multiplayer/chat
io.on('connection', (socket) => {
console.log('User connected');
socket.on('joinGame', (gameId) => {
socket.join(gameId);
// Broadcast messages/bets; integrate with Diablo-Lounge multiplayer logic
});
socket.on('chatMessage', (msg) => {
io.to(msg.gameId).emit('message', msg);
});
// Add more for real-time game updates (e.g., card deals)
});
server.listen(process.env.PORT, () => console.log(`Server running on port ${process.env.PORT}`));