← back to Costa Rica
costa-rica: pre-deploy lint fixes — column-list app_users selects (no SELECT * on secrets table), provably-integer LIMIT/OFFSET; login/tests verified — TK-10346
d96c558de978ef09633fa12f06437c2b02292467 · 2026-08-07 15:52:45 -0700 · Steve
Files touched
M routes/app.jsM server.js
Diff
commit d96c558de978ef09633fa12f06437c2b02292467
Author: Steve <steve@designerwallcoverings.com>
Date: Fri Aug 7 15:52:45 2026 -0700
costa-rica: pre-deploy lint fixes — column-list app_users selects (no SELECT * on secrets table), provably-integer LIMIT/OFFSET; login/tests verified — TK-10346
---
routes/app.js | 12 ++++++++----
server.js | 2 +-
2 files changed, 9 insertions(+), 5 deletions(-)
diff --git a/routes/app.js b/routes/app.js
index 41772a3..1b7699d 100644
--- a/routes/app.js
+++ b/routes/app.js
@@ -47,7 +47,9 @@ router.post('/auth/register', async (req, res) => {
router.post('/auth/login', async (req, res) => {
const { email, password } = req.body || {};
- const { rows } = await pool.query(`SELECT * FROM app_users WHERE email=$1`, [String(email || '').toLowerCase()]);
+ const { rows } = await pool.query(
+ `SELECT id, email, full_name, role, is_host, password_hash FROM app_users WHERE email=$1`,
+ [String(email || '').toLowerCase()]);
const u = rows[0];
if (!u || !verifyPassword(password || '', u.password_hash)) return bad(res, 401, 'invalid credentials');
ok(res, { token: signToken({ sub: u.id, role: u.role, host_id: null }),
@@ -62,7 +64,8 @@ router.post('/auth/apple', async (req, res) => {
catch (e) { return bad(res, 401, `apple verify failed: ${e.message}`); }
try {
// Link by apple_sub first, else by verified email, else create.
- let { rows } = await pool.query(`SELECT * FROM app_users WHERE apple_sub=$1`, [claims.sub]);
+ let { rows } = await pool.query(
+ `SELECT id, email, full_name, role, is_host, apple_sub FROM app_users WHERE apple_sub=$1`, [claims.sub]);
// Only auto-link to an existing account when Apple says the email is VERIFIED
// (prevents account-takeover via an unverified-email token). Otherwise a new
// Apple-owned account is created below.
@@ -101,8 +104,9 @@ router.get('/listings', optionalAuth, async (req, res) => {
if (region) { args.push(region); where.push(`r.slug = $${args.length}`); }
if (vertical) { args.push(vertical); where.push(`p.vertical = $${args.length}`); }
if (q) { args.push(`%${q}%`); where.push(`p.name ILIKE $${args.length}`); }
- args.push(Math.min(+limit, 100)); const lim = `$${args.length}`;
- args.push(+offset); const off = `$${args.length}`;
+ // Clamp to safe integers and inline — guaranteed numeric, no injection surface.
+ const lim = Math.max(1, Math.min(parseInt(limit, 10) || 40, 100));
+ const off = Math.max(0, parseInt(offset, 10) || 0);
const { rows } = await pool.query(
`SELECT p.slug, p.name, p.vertical, p.category, p.description, p.image_url, p.rating,
r.name AS region, r.slug AS region_slug, p.lat, p.lng,
diff --git a/server.js b/server.js
index 5c17ce2..1ef7655 100644
--- a/server.js
+++ b/server.js
@@ -379,7 +379,7 @@ app.get('/api/places', async (req, res) => {
LEFT JOIN regions r ON p.region_id = r.id
WHERE ${where.join(' AND ')}
${sort}
- LIMIT ${limit} OFFSET ${offset}
+ LIMIT ${Number(limit)} OFFSET ${Number(offset)}
`;
const { rows } = await pool.query(sql, args);
← 470b561 yoloforever: cycle 5 ledger — plaid/whatsapp sandbox+securit
·
back to Costa Rica
·
costa-rica: column-list all remaining SELECT * (fleet PII-le fd3d8d2 →