mirror of
https://github.com/Such-Software/wownerogue.git
synced 2026-11-14 11:03:53 +01:00
fix(auth): resolve Smirk challenge parameter types
This commit is contained in:
+13
-7
@@ -10,6 +10,16 @@ const { verifyNip98Event } = require('../utils/nip98');
|
||||
const AUTH_WINDOW_MS = 60 * 1000;
|
||||
const AUTH_RATE_MAX_KEYS = 10000;
|
||||
|
||||
// Shared with the real PostgreSQL lifecycle check so parameter inference is exercised
|
||||
// against the migrated schema, rather than accepted only by query mocks.
|
||||
const challengeInsertQuery = `
|
||||
INSERT INTO smirk_challenges (challenge, socket_id, user_id)
|
||||
SELECT $1::varchar(64), $2::varchar(255), id
|
||||
FROM users
|
||||
WHERE id = $3 AND socket_id = $2 AND anon_token = $4
|
||||
RETURNING id
|
||||
`;
|
||||
|
||||
/**
|
||||
* The host a NIP-98 auth event must be signed for.
|
||||
*
|
||||
@@ -260,13 +270,7 @@ router.post('/api/auth/smirk/challenge', challengeRateLimit, asyncHandler(async
|
||||
|
||||
// Store a stable user binding as well as the current socket. The user binding is what
|
||||
// prevents a public Tavern/Match socket id from being used to attach an attacker's key.
|
||||
const inserted = await db.query(`
|
||||
INSERT INTO smirk_challenges (challenge, socket_id, user_id)
|
||||
SELECT $1, $2, id
|
||||
FROM users
|
||||
WHERE id = $3 AND socket_id = $2 AND anon_token = $4
|
||||
RETURNING id
|
||||
`, [challenge, socketId, session.userId, session.token]);
|
||||
const inserted = await db.query(challengeInsertQuery, [challenge, socketId, session.userId, session.token]);
|
||||
if (inserted.rows.length !== 1) throw unauthorized();
|
||||
|
||||
// Opportunistic cleanup of expired and long-used challenges.
|
||||
@@ -470,3 +474,5 @@ router.get('/api/auth/smirk/status', asyncHandler(async (req, res) => {
|
||||
|
||||
return router;
|
||||
};
|
||||
|
||||
module.exports.challengeInsertQuery = challengeInsertQuery;
|
||||
|
||||
@@ -12,6 +12,7 @@ const path = require('node:path');
|
||||
const { promisify } = require('node:util');
|
||||
const { Client } = require('pg');
|
||||
const { chromium } = require('playwright-core');
|
||||
const { challengeInsertQuery } = require('../routes/auth');
|
||||
|
||||
const execFile = promisify(childProcess.execFile);
|
||||
const ROOT = path.resolve(__dirname, '../..');
|
||||
@@ -143,6 +144,7 @@ function classifyStartupFailure(output) {
|
||||
|
||||
function classifyHarnessFailure(error, phase) {
|
||||
const sqlStateCodes = {
|
||||
'42P08': 'DATABASE_PARAMETER_TYPE_CONFLICT',
|
||||
'42P01': 'DATABASE_TABLE_UNDEFINED',
|
||||
'42703': 'DATABASE_COLUMN_UNDEFINED',
|
||||
'42883': 'DATABASE_FUNCTION_UNDEFINED',
|
||||
@@ -370,6 +372,19 @@ async function main() {
|
||||
throw error;
|
||||
});
|
||||
|
||||
// PREPARE checks the route's actual parameter inference without generating a
|
||||
// challenge, activating Smirk, or passing any authentication values to PostgreSQL.
|
||||
phase = 'auth-query-compile';
|
||||
const authDb = new Client({ host: socketDir, port: dbPort, database: dbName, user: dbUser,
|
||||
connectionTimeoutMillis: 2000, statement_timeout: 5000, lock_timeout: 2000 });
|
||||
try {
|
||||
await authDb.connect();
|
||||
await authDb.query(`PREPARE showcase_smirk_challenge AS ${challengeInsertQuery}`);
|
||||
await authDb.query('DEALLOCATE showcase_smirk_challenge');
|
||||
} finally {
|
||||
await authDb.end();
|
||||
}
|
||||
|
||||
phase = 'browser-setup';
|
||||
browser = await chromium.launch({ headless: true });
|
||||
for (const role of ROLES) {
|
||||
|
||||
Reference in New Issue
Block a user