security: remove hardcoded database credentials and auth secrets
- Replace hardcoded DB_PASSWORD 'dwroller2025' with process.env.DB_PASSWORD - Replace hardcoded GM_SECRET 'bongo' with process.env.GM_SECRET - Replace hardcoded GM_PASSWORD with process.env.GM_PASSWORD - Replace hardcoded PLAYER_PASSWORD '1234' with process.env.PLAYER_PASSWORD - Update .env.example to document required environment variables - Apply changes to all backend routes, database modules, and React components - Update test files to use environment variables for credentials - Ensure .env remains in .gitignore for production safety This fix addresses critical security vulnerabilities where database credentials and authentication secrets were exposed in source code.
This commit is contained in:
@@ -1,2 +1,10 @@
|
||||
PORT=5000
|
||||
MONGO_URI=mongodb://localhost:27017/deathwatch
|
||||
|
||||
# Database credentials - CHANGE THESE IN PRODUCTION
|
||||
DB_PASSWORD=your_secure_database_password_here
|
||||
|
||||
# Authentication secrets - CHANGE THESE IN PRODUCTION
|
||||
GM_SECRET=your_secure_gm_secret_here
|
||||
GM_PASSWORD=your_secure_gm_password_here
|
||||
PLAYER_PASSWORD=your_secure_player_password_here
|
||||
|
||||
@@ -10,13 +10,14 @@ function logToFile(...args) {
|
||||
const existingGm = db.prepare('SELECT * FROM players WHERE name = ?').get('gm');
|
||||
|
||||
if (!existingGm) {
|
||||
// Create GM user with password 'bongo'
|
||||
// Create GM user with password from environment variable
|
||||
const gmPassword = process.env.GM_PASSWORD || 'defaultpassword';
|
||||
const stmt = db.prepare(`
|
||||
INSERT INTO players (name, pw, pw_hash, tab_info)
|
||||
INSERT INTO players (name, pw, pw_hash, tab_info)
|
||||
VALUES (?, ?, ?, ?)
|
||||
`);
|
||||
|
||||
stmt.run('gm', 'bongo', 'bongo', JSON.stringify({
|
||||
stmt.run('gm', gmPassword, gmPassword, JSON.stringify({
|
||||
rp: 999999,
|
||||
inventory: [],
|
||||
renown: 'None'
|
||||
@@ -26,13 +27,14 @@ if (!existingGm) {
|
||||
console.log('Created GM user');
|
||||
} else {
|
||||
// Update GM user password if needed
|
||||
const gmPassword = process.env.GM_PASSWORD || 'defaultpassword';
|
||||
const stmt = db.prepare(`
|
||||
UPDATE players
|
||||
UPDATE players
|
||||
SET pw = ?, pw_hash = ?
|
||||
WHERE name = 'gm'
|
||||
`);
|
||||
|
||||
stmt.run('bongo', 'bongo');
|
||||
stmt.run(gmPassword, gmPassword);
|
||||
|
||||
logToFile('Updated GM user');
|
||||
console.log('Updated GM user');
|
||||
|
||||
+1
-1
@@ -17,7 +17,7 @@ function logToFile(...args) {
|
||||
const dbConfig = {
|
||||
host: 'localhost',
|
||||
user: 'deathwatch',
|
||||
password: 'dwroller2025',
|
||||
password: process.env.DB_PASSWORD || 'defaultpassword',
|
||||
database: 'deathwatch',
|
||||
waitForConnections: true,
|
||||
connectionLimit: 10,
|
||||
|
||||
@@ -11,7 +11,7 @@ const sqliteDbPath = path.join(__dirname, 'sqlite', 'deathwatch.db');
|
||||
const mariadbConfig = {
|
||||
host: 'localhost',
|
||||
user: 'deathwatch',
|
||||
password: 'dwroller2025',
|
||||
password: process.env.DB_PASSWORD || 'defaultpassword',
|
||||
database: 'deathwatch'
|
||||
};
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ function logToFile(...args) {
|
||||
}
|
||||
|
||||
// Express middleware to require a valid sessionId in req.headers['x-session-id'] or req.body.sessionId
|
||||
// Accepts a GM bypass header 'x-gm-secret' matching process.env.GM_PASSWORD or 'bongo' for local convenience
|
||||
// Accepts a GM bypass header 'x-gm-secret' matching process.env.GM_SECRET
|
||||
module.exports = async function requireSession(req, res, next) {
|
||||
try {
|
||||
// Ensure req.body is always an object before any access
|
||||
@@ -16,7 +16,7 @@ module.exports = async function requireSession(req, res, next) {
|
||||
|
||||
// GM bypass
|
||||
const gmSecret = req.headers['x-gm-secret'] || (req.query && req.query.gmSecret) || (req.body && req.body.gmSecret);
|
||||
const gmPassword = process.env.GM_PASSWORD || 'bongo';
|
||||
const gmPassword = process.env.GM_SECRET || 'defaultsecret';
|
||||
if (gmSecret && String(gmSecret) === String(gmPassword)) {
|
||||
logToFile('SESSION: GM bypass accepted', req.method, req.originalUrl);
|
||||
req.session = { data: { playerName: 'GM' }, playerName: 'GM' };
|
||||
|
||||
@@ -158,7 +158,8 @@ router.post('/reload', async (req, res) => {
|
||||
try {
|
||||
// Check for GM secret
|
||||
const gmSecret = req.headers['x-gm-secret'];
|
||||
if (gmSecret !== 'bongo') {
|
||||
const expectedGmSecret = process.env.GM_SECRET || 'defaultsecret';
|
||||
if (gmSecret !== expectedGmSecret) {
|
||||
return res.status(403).json({ error: 'Unauthorized' });
|
||||
}
|
||||
|
||||
|
||||
@@ -14,12 +14,14 @@ router.post('/login', async (req, res) => {
|
||||
|
||||
// Special handling for GM user
|
||||
if (name.toLowerCase() === 'gm') {
|
||||
if (password !== 'bongo') {
|
||||
const gmPassword = process.env.GM_PASSWORD || 'defaultpassword';
|
||||
if (password !== gmPassword) {
|
||||
return res.status(401).json({ error: 'Invalid password' });
|
||||
}
|
||||
} else {
|
||||
// For regular players, use password '1234'
|
||||
if (password !== '1234') {
|
||||
// For regular players, use environment variable or default
|
||||
const playerPassword = process.env.PLAYER_PASSWORD || 'defaultpassword';
|
||||
if (password !== playerPassword) {
|
||||
return res.status(401).json({ error: 'Invalid password' });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -199,7 +199,8 @@ router.get('/stats', async (req, res) => {
|
||||
router.post('/reload', async (req, res) => {
|
||||
try {
|
||||
const gmSecret = req.headers['x-gm-secret'];
|
||||
if (gmSecret !== 'bongo') return res.status(403).json({ error: 'Unauthorized' });
|
||||
const expectedGmSecret = process.env.GM_SECRET || 'defaultsecret';
|
||||
if (gmSecret !== expectedGmSecret) return res.status(403).json({ error: 'Unauthorized' });
|
||||
|
||||
const allRules = await getAllRules();
|
||||
const totalRules = allRules.length;
|
||||
|
||||
@@ -18,7 +18,7 @@ const { playerHelpers } = require('../sqlite-db');
|
||||
fs.writeFileSync(beforePath, JSON.stringify(player, null, 2), 'utf8');
|
||||
console.log('Backup written:', beforePath);
|
||||
|
||||
const plain = '1234';
|
||||
const plain = process.env.PLAYER_PASSWORD || 'defaultpassword';
|
||||
const hash = await bcrypt.hash(plain, 10);
|
||||
const ok = playerHelpers.update(name, { name, rollerInfo: player.rollerInfo || {}, shopInfo: player.shopInfo || {}, tabInfo: player.tabInfo || {}, pw: '', pwHash: hash });
|
||||
if (!ok) {
|
||||
@@ -31,5 +31,5 @@ const { playerHelpers } = require('../sqlite-db');
|
||||
console.log('Updated player:', name, 'pwHash set. After backup:', afterPath);
|
||||
console.log(JSON.stringify({ name: updated.name, pwHashPresent: !!updated.pwHash, _id: updated._id }, null, 2));
|
||||
}
|
||||
console.log('All done. Password for andreas and chris set to "1234" (hashed).');
|
||||
console.log('All done. Password for andreas and chris set to environment default (hashed).');
|
||||
})();
|
||||
|
||||
+2
-1
@@ -126,7 +126,8 @@ try {
|
||||
app.post('/api/gmkit/upload', express.json({ limit: '20mb' }), (req, res) => {
|
||||
try {
|
||||
const gmSecret = req.headers['x-gm-secret'];
|
||||
if (gmSecret !== 'bongo') return res.status(403).json({ error: 'Unauthorized' });
|
||||
const expectedGmSecret = process.env.GM_SECRET || 'defaultsecret';
|
||||
if (gmSecret !== expectedGmSecret) return res.status(403).json({ error: 'Unauthorized' });
|
||||
const { name, b64 } = req.body || {};
|
||||
if (!name || !b64) return res.status(400).json({ error: 'Missing name or b64 body' });
|
||||
if (!fs.existsSync(gmkitDir)) fs.mkdirSync(gmkitDir, { recursive: true });
|
||||
|
||||
@@ -1,17 +1,18 @@
|
||||
const { db, playerHelpers } = require('./sqlite-db');
|
||||
|
||||
// Update all player passwords to '1234'
|
||||
// Update all player passwords to environment default
|
||||
function updateAllPasswords() {
|
||||
try {
|
||||
// First check the table structure
|
||||
const columns = db.prepare("PRAGMA table_info(players)").all();
|
||||
console.log('Table columns:', columns.map(c => c.name));
|
||||
|
||||
|
||||
// Update only the pw column (pwHash might not exist)
|
||||
const defaultPassword = process.env.PLAYER_PASSWORD || 'defaultpassword';
|
||||
const updateStmt = db.prepare('UPDATE players SET pw = ?');
|
||||
const result = updateStmt.run('1234');
|
||||
|
||||
console.log(`Updated ${result.changes} player passwords to '1234'`);
|
||||
const result = updateStmt.run(defaultPassword);
|
||||
|
||||
console.log(`Updated ${result.changes} player passwords to environment default`);
|
||||
|
||||
// Verify the changes
|
||||
const players = playerHelpers.getAll();
|
||||
|
||||
+1
-1
@@ -335,7 +335,7 @@ function App() {
|
||||
{players && players.length > 0 ? players.map(player => (
|
||||
<button
|
||||
key={player.name}
|
||||
onClick={() => {setLoginName(player.name); setLoginPw('1234');}}
|
||||
onClick={() => {setLoginName(player.name); setLoginPw(process.env.REACT_APP_PLAYER_PASSWORD || 'defaultpassword');}}
|
||||
className="px-2 py-1 rounded bg-blue-700/30 text-blue-200 hover:bg-blue-600/40 transition-colors"
|
||||
>
|
||||
{player.name}
|
||||
|
||||
@@ -115,11 +115,11 @@ export default function BestiaryTab(){
|
||||
setIsRefreshing(true)
|
||||
try {
|
||||
// First try to reload the database
|
||||
const reloadResponse = await fetch('/api/bestiary/reload', {
|
||||
const reloadResponse = await fetch('/api/bestiary/reload', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'x-gm-secret': 'bongo'
|
||||
'x-gm-secret': process.env.REACT_APP_GM_SECRET || 'defaultsecret'
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ export default function PlayerManagement({ authedPlayer, sessionId }) {
|
||||
function buildHeaders(extra = {}) {
|
||||
const headers = { 'Content-Type': 'application/json' };
|
||||
if (sessionId) headers['x-session-id'] = sessionId;
|
||||
if (authedPlayer === 'gm') headers['x-gm-secret'] = 'bongo';
|
||||
if (authedPlayer === 'gm') headers['x-gm-secret'] = process.env.REACT_APP_GM_SECRET || 'defaultsecret';
|
||||
return { ...headers, ...extra };
|
||||
}
|
||||
|
||||
@@ -84,8 +84,9 @@ export default function PlayerManagement({ authedPlayer, sessionId }) {
|
||||
async function gmAddOrUpdatePlayer(name, rp, pw) {
|
||||
console.log('PlayerManagement: gmAddOrUpdatePlayer', { name, rp, pwProvided: !!pw });
|
||||
try {
|
||||
const resPost = await axios.post('/api/players/gm/add-or-update',
|
||||
{ name, requisitionPoints: parseInt(rp), password: pw || '1234' },
|
||||
const defaultPassword = process.env.REACT_APP_PLAYER_PASSWORD || 'defaultpassword';
|
||||
const resPost = await axios.post('/api/players/gm/add-or-update',
|
||||
{ name, requisitionPoints: parseInt(rp), password: pw || defaultPassword },
|
||||
{ headers: buildHeaders() }
|
||||
);
|
||||
console.log('PlayerManagement: gmAddOrUpdatePlayer POST response', resPost.status, resPost.data);
|
||||
@@ -142,8 +143,9 @@ export default function PlayerManagement({ authedPlayer, sessionId }) {
|
||||
async function gmResetPlayerPw(name, pw) {
|
||||
console.log('PlayerManagement: gmResetPlayerPw', { name, pwProvided: !!pw });
|
||||
try {
|
||||
const res = await axios.post('/api/players/gm/reset-password',
|
||||
{ playerName: name, newPassword: pw || '1234' },
|
||||
const defaultPassword = process.env.REACT_APP_PLAYER_PASSWORD || 'defaultpassword';
|
||||
const res = await axios.post('/api/players/gm/reset-password',
|
||||
{ playerName: name, newPassword: pw || defaultPassword },
|
||||
{ headers: buildHeaders() }
|
||||
);
|
||||
console.log('PlayerManagement: gmResetPlayerPw response', res.status, res.data);
|
||||
@@ -201,15 +203,16 @@ export default function PlayerManagement({ authedPlayer, sessionId }) {
|
||||
<input
|
||||
className="rounded border border-slate-600 bg-slate-800 px-3 py-2 text-white placeholder-slate-400 text-sm"
|
||||
type="password"
|
||||
placeholder="Password (default: 1234)"
|
||||
value={pw}
|
||||
onChange={e => setPw(e.target.value)}
|
||||
placeholder="Password (use environment default)"
|
||||
value={pw}
|
||||
onChange={e => setPw(e.target.value)}
|
||||
/>
|
||||
<button
|
||||
<button
|
||||
className="rounded bg-green-600 hover:bg-green-500 px-4 py-2 text-white text-sm font-medium transition-colors"
|
||||
onClick={() => {
|
||||
if (name.trim()) {
|
||||
onAdd(name.trim(), rp, pw || '1234');
|
||||
const defaultPassword = process.env.REACT_APP_PLAYER_PASSWORD || 'defaultpassword';
|
||||
onAdd(name.trim(), rp, pw || defaultPassword);
|
||||
setName('');
|
||||
setRp('50');
|
||||
setPw('');
|
||||
@@ -340,17 +343,17 @@ export default function PlayerManagement({ authedPlayer, sessionId }) {
|
||||
|
||||
return (
|
||||
<div className="flex items-center gap-2 w-full">
|
||||
<input
|
||||
<input
|
||||
className="rounded border border-slate-600 bg-slate-800 px-2 py-1 text-white placeholder-slate-400 text-sm flex-1 min-w-0"
|
||||
type="password"
|
||||
placeholder="New password (default: 1234)"
|
||||
value={pw}
|
||||
onChange={e => setPw(e.target.value)}
|
||||
type="password"
|
||||
placeholder="New password (use environment default)"
|
||||
value={pw}
|
||||
onChange={e => setPw(e.target.value)}
|
||||
/>
|
||||
<button
|
||||
<button
|
||||
className="rounded bg-orange-600 hover:bg-orange-500 px-3 py-1 text-white text-xs font-medium transition-colors whitespace-nowrap"
|
||||
onClick={() => {
|
||||
onReset(name, pw || '1234');
|
||||
onReset(name, pw || process.env.REACT_APP_PLAYER_PASSWORD || 'defaultpassword');
|
||||
setPw('');
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -9,7 +9,7 @@ const STORAGE_SHOP_PLAYERS = 'dw:shop:players:v1';
|
||||
|
||||
const RANK_ORDER = ['None','Respected','Distinguished','Famed','Hero'];
|
||||
|
||||
const GM_PASSWORD = 'bongo';
|
||||
const GM_PASSWORD = process.env.REACT_APP_GM_SECRET || 'defaultsecret';
|
||||
|
||||
function safeGet(key) {
|
||||
try {
|
||||
|
||||
@@ -22,7 +22,7 @@ function RulesTab({ authedPlayer, sessionId }) {
|
||||
|
||||
const buildHeaders = () => {
|
||||
const headers = { 'x-session-id': sessionId || '' };
|
||||
if (authedPlayer === 'gm') headers['x-gm-secret'] = 'bongo';
|
||||
if (authedPlayer === 'gm') headers['x-gm-secret'] = process.env.REACT_APP_GM_SECRET || 'defaultsecret';
|
||||
return headers;
|
||||
};
|
||||
|
||||
|
||||
@@ -86,9 +86,10 @@ describe('Login Functionality', () => {
|
||||
const passwordInput = screen.getByPlaceholderText(/password/i);
|
||||
const loginButton = screen.getByRole('button', { name: /login|enter/i });
|
||||
|
||||
// Fill in login form with GM credentials
|
||||
// Fill in login form with GM credentials (test credentials)
|
||||
const testGmPassword = process.env.GM_PASSWORD || 'defaultpassword';
|
||||
fireEvent.change(nameInput, { target: { value: 'gm' } });
|
||||
fireEvent.change(passwordInput, { target: { value: 'bongo' } });
|
||||
fireEvent.change(passwordInput, { target: { value: testGmPassword } });
|
||||
|
||||
// Click login button
|
||||
fireEvent.click(loginButton);
|
||||
@@ -99,7 +100,7 @@ describe('Login Functionality', () => {
|
||||
'/api/players/login',
|
||||
{
|
||||
name: 'gm',
|
||||
password: 'bongo'
|
||||
password: testGmPassword
|
||||
}
|
||||
);
|
||||
});
|
||||
@@ -157,8 +158,9 @@ describe('Login Functionality', () => {
|
||||
const passwordInput = screen.getByPlaceholderText(/password/i);
|
||||
const loginButton = screen.getByRole('button', { name: /login|enter/i });
|
||||
|
||||
const testPlayerPassword = process.env.PLAYER_PASSWORD || 'defaultpassword';
|
||||
fireEvent.change(nameInput, { target: { value: 'nonexistent' } });
|
||||
fireEvent.change(passwordInput, { target: { value: '1234' } });
|
||||
fireEvent.change(passwordInput, { target: { value: testPlayerPassword } });
|
||||
fireEvent.click(loginButton);
|
||||
|
||||
await waitFor(() => {
|
||||
|
||||
@@ -72,7 +72,7 @@ describe('PlayerManagement Component', () => {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'x-session-id': mockSessionId,
|
||||
'x-gm-secret': 'bongo'
|
||||
'x-gm-secret': process.env.GM_SECRET || 'defaultsecret'
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -126,7 +126,7 @@ describe('PlayerManagement Component', () => {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'x-session-id': mockSessionId,
|
||||
'x-gm-secret': 'bongo'
|
||||
'x-gm-secret': process.env.GM_SECRET || 'defaultsecret'
|
||||
}
|
||||
}
|
||||
);
|
||||
@@ -159,7 +159,7 @@ describe('PlayerManagement Component', () => {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'x-session-id': mockSessionId,
|
||||
'x-gm-secret': 'bongo'
|
||||
'x-gm-secret': process.env.GM_SECRET || 'defaultsecret'
|
||||
}
|
||||
}
|
||||
);
|
||||
@@ -192,7 +192,7 @@ describe('PlayerManagement Component', () => {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'x-session-id': mockSessionId,
|
||||
'x-gm-secret': 'bongo'
|
||||
'x-gm-secret': process.env.GM_SECRET || 'defaultsecret'
|
||||
}
|
||||
}
|
||||
);
|
||||
@@ -225,7 +225,7 @@ describe('PlayerManagement Component', () => {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'x-session-id': mockSessionId,
|
||||
'x-gm-secret': 'bongo'
|
||||
'x-gm-secret': process.env.GM_SECRET || 'defaultsecret'
|
||||
}
|
||||
}
|
||||
);
|
||||
@@ -257,7 +257,7 @@ describe('PlayerManagement Component', () => {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'x-session-id': mockSessionId,
|
||||
'x-gm-secret': 'bongo'
|
||||
'x-gm-secret': process.env.GM_SECRET || 'defaultsecret'
|
||||
}
|
||||
}
|
||||
);
|
||||
@@ -289,7 +289,7 @@ describe('PlayerManagement Component', () => {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'x-session-id': mockSessionId,
|
||||
'x-gm-secret': 'bongo'
|
||||
'x-gm-secret': process.env.GM_SECRET || 'defaultsecret'
|
||||
}
|
||||
}
|
||||
);
|
||||
@@ -318,7 +318,7 @@ describe('PlayerManagement Component', () => {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'x-session-id': mockSessionId,
|
||||
'x-gm-secret': 'bongo'
|
||||
'x-gm-secret': process.env.GM_SECRET || 'defaultsecret'
|
||||
}
|
||||
}
|
||||
);
|
||||
@@ -356,7 +356,7 @@ describe('PlayerManagement Component', () => {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'x-session-id': mockSessionId,
|
||||
'x-gm-secret': 'bongo'
|
||||
'x-gm-secret': process.env.GM_SECRET || 'defaultsecret'
|
||||
}
|
||||
}
|
||||
);
|
||||
@@ -393,7 +393,7 @@ describe('PlayerManagement Component', () => {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'x-session-id': mockSessionId,
|
||||
'x-gm-secret': 'bongo'
|
||||
'x-gm-secret': process.env.GM_SECRET || 'defaultsecret'
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
+2
-2
@@ -6,7 +6,7 @@ async function testRulesAPI() {
|
||||
|
||||
// Test search endpoint
|
||||
const searchResponse = await axios.get('http://localhost:5000/api/rules/search?q=combat', {
|
||||
headers: { 'x-gm-secret': 'bongo' }
|
||||
headers: { 'x-gm-secret': process.env.GM_SECRET || 'defaultsecret' }
|
||||
});
|
||||
|
||||
console.log('Search results:', searchResponse.data);
|
||||
@@ -14,7 +14,7 @@ async function testRulesAPI() {
|
||||
|
||||
// Test stats endpoint
|
||||
const statsResponse = await axios.get('http://localhost:5000/api/rules/stats', {
|
||||
headers: { 'x-gm-secret': 'bongo' }
|
||||
headers: { 'x-gm-secret': process.env.GM_SECRET || 'defaultsecret' }
|
||||
});
|
||||
|
||||
console.log('Stats:', statsResponse.data);
|
||||
|
||||
@@ -4,7 +4,8 @@ const { execSync } = require('child_process');
|
||||
describe('GM flow (create / update / login / delete)', () => {
|
||||
const name = 'gmtest';
|
||||
const baseURL = process.env.API_BASE || 'http://localhost:5000';
|
||||
const gmHeaders = `-H "x-gm-secret: ${process.env.GM_PASSWORD || 'bongo'}"`;
|
||||
const gmHeaders = `-H "x-gm-secret: ${process.env.GM_SECRET || 'defaultsecret'}"`;
|
||||
const testPassword = process.env.PLAYER_PASSWORD || 'defaultpassword';
|
||||
|
||||
const curl = (method, url, data = null, headers = '') => {
|
||||
const command = `curl -X ${method} ${headers} -H "Content-Type: application/json" ${data ? `-d '${JSON.stringify(data)}'` : ''} ${url}`;
|
||||
@@ -36,7 +37,7 @@ describe('GM flow (create / update / login / delete)', () => {
|
||||
}
|
||||
|
||||
// create
|
||||
const createRes = curl('POST', `${baseURL}/api/players`, { name, rp: 10, pw: '1234' }, gmHeaders);
|
||||
const createRes = curl('POST', `${baseURL}/api/players`, { name, rp: 10, pw: testPassword }, gmHeaders);
|
||||
expect(createRes.status).toBe(201);
|
||||
expect(createRes.data.name).toBe(name);
|
||||
|
||||
|
||||
@@ -5,7 +5,8 @@ describe('Player flow (login, update sheet, gear/spend RP)', () => {
|
||||
const name = 'testplayer';
|
||||
const baseURL = process.env.API_BASE || 'http://localhost:5000';
|
||||
let sessionId;
|
||||
const gmHeaders = `-H "x-gm-secret: ${process.env.GM_PASSWORD || 'bongo'}"`;
|
||||
const gmHeaders = `-H "x-gm-secret: ${process.env.GM_SECRET || 'defaultsecret'}"`;
|
||||
const testPassword = process.env.PLAYER_PASSWORD || 'defaultpassword';
|
||||
|
||||
const curl = (method, url, data = null, headers = '') => {
|
||||
const command = `curl -X ${method} ${headers} -H "Content-Type: application/json" ${data ? `-d '${JSON.stringify(data)}'` : ''} ${url}`;
|
||||
@@ -37,12 +38,12 @@ describe('Player flow (login, update sheet, gear/spend RP)', () => {
|
||||
}
|
||||
|
||||
// create test player
|
||||
const create = curl('POST', `${baseURL}/api/players`, { name, rp: 10, pw: '1234' }, gmHeaders);
|
||||
const create = curl('POST', `${baseURL}/api/players`, { name, rp: 10, pw: testPassword }, gmHeaders);
|
||||
expect(create.status).toBe(201);
|
||||
expect(create.data.name).toBe(name);
|
||||
|
||||
|
||||
// login as player
|
||||
const login = curl('POST', `${baseURL}/api/players/login`, { name, password: '1234' });
|
||||
const login = curl('POST', `${baseURL}/api/players/login`, { name, password: testPassword });
|
||||
expect(login.status).toBe(200);
|
||||
expect(login.data.sessionId).toBeTruthy();
|
||||
sessionId = login.data.sessionId;
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ const path = require('path');
|
||||
|
||||
describe('Rules endpoints', () => {
|
||||
const baseURL = process.env.API_BASE || 'http://localhost:5000';
|
||||
const gmHeaders = `-H "x-gm-secret: ${process.env.GM_PASSWORD || 'bongo'}"`;
|
||||
const gmHeaders = `-H "x-gm-secret: ${process.env.GM_SECRET || 'defaultsecret'}"`;
|
||||
|
||||
const curl = (method, url, data = null, headers = '') => {
|
||||
const command = `curl -s -X ${method} ${headers} -H "Content-Type: application/json" ${data ? `-d '${JSON.stringify(data)}'` : ''} ${url}`;
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@ const { execSync } = require('child_process');
|
||||
|
||||
describe('Shop endpoints (public and protected)', () => {
|
||||
const baseURL = process.env.API_BASE || 'http://localhost:5000';
|
||||
const gmHeaders = `-H "x-gm-secret: ${process.env.GM_PASSWORD || 'bongo'}"`;
|
||||
const gmHeaders = `-H "x-gm-secret: ${process.env.GM_SECRET || 'defaultsecret'}"`;
|
||||
const mockPlayer = 'shoptestplayer';
|
||||
|
||||
const curl = (method, url, data = null, headers = '') => {
|
||||
|
||||
Reference in New Issue
Block a user