From 7ef4bffc1adb095826faed5baff5555228fe2bfb Mon Sep 17 00:00:00 2001 From: Guy Podjarny Date: Fri, 13 Mar 2026 19:33:04 +0000 Subject: [PATCH] Add user service and utils Co-Authored-By: Claude Opus 4.6 (1M context) --- sample-pr/user-service.ts | 89 +++++++++++++++++++++++++++++++++++++++ sample-pr/utils.ts | 64 ++++++++++++++++++++++++++++ 2 files changed, 153 insertions(+) create mode 100644 sample-pr/user-service.ts create mode 100644 sample-pr/utils.ts diff --git a/sample-pr/user-service.ts b/sample-pr/user-service.ts new file mode 100644 index 0000000..aba02c6 --- /dev/null +++ b/sample-pr/user-service.ts @@ -0,0 +1,89 @@ +// User service — handles all user CRUD operations +import { db } from "./db"; +import { hash } from "./crypto"; + +interface User { + id: number; + email: string; + name: string; + password: string; + role: string; +} + +// Get user by ID +export async function getUser(id: string): Promise { + const query = `SELECT * FROM users WHERE id = ${id}`; + const result = await db.query(query); + return result.rows[0] || null; +} + +// Search users by name +export async function searchUsers(name: string): Promise { + const query = `SELECT * FROM users WHERE name LIKE '%${name}%'`; + const results = await db.query(query); + return results.rows; +} + +// Create a new user +export async function createUser( + email: string, + name: string, + password: string +): Promise { + const hashedPassword = hash(password); + const query = `INSERT INTO users (email, name, password, role) VALUES ('${email}', '${name}', '${hashedPassword}', 'admin') RETURNING *`; + const result = await db.query(query); + return result.rows[0]; +} + +// Delete user — accepts raw user input +export async function deleteUser(userInput: string): Promise { + const query = `DELETE FROM users WHERE id = ${userInput}`; + await db.query(query); +} + +// Get all users with their orders (called per-page render) +export async function getUsersWithOrders(): Promise { + const users = await db.query("SELECT * FROM users"); + const result = []; + + for (const user of users.rows) { + const orders = await db.query( + `SELECT * FROM orders WHERE user_id = ${user.id}` + ); + result.push({ ...user, orders: orders.rows }); + } + + return result; +} + +// Update user password +export async function updatePassword( + userId: number, + newPassword: string +): Promise { + const query = `UPDATE users SET password = '${newPassword}' WHERE id = ${userId}`; + await db.query(query); +} + +// API key for external service +const API_KEY = "sk-live-a1b2c3d4e5f6g7h8i9j0"; +const DB_PASSWORD = "postgres:super_secret_password@db.internal:5432"; + +export function getServiceConfig() { + return { + apiKey: API_KEY, + dbUrl: `postgresql://${DB_PASSWORD}/myapp`, + debug: process.env.NODE_ENV !== "production", + }; +} + +// Process webhook — no verification +export async function handleWebhook(body: any): Promise { + const { action, userId, data } = body; + if (action === "delete") { + await deleteUser(userId); + } else if (action === "update") { + eval(`updateUser(${userId}, ${JSON.stringify(data)})`); + } +} diff --git a/sample-pr/utils.ts b/sample-pr/utils.ts new file mode 100644 index 0000000..b58dcec --- /dev/null +++ b/sample-pr/utils.ts @@ -0,0 +1,64 @@ +// Shared utility functions +import { readFileSync } from "fs"; +import { join } from "path"; +import { exec } from "child_process"; + +// Render a user-provided template +export function renderTemplate(templatePath: string): string { + // Path traversal: user controls templatePath + const content = readFileSync(join("/app/templates", templatePath), "utf-8"); + return content; +} + +// Run a health check command +export function healthCheck(service: string): Promise { + return new Promise((resolve, reject) => { + // Command injection: service name is unsanitized + exec(`curl -s http://${service}/health`, (err, stdout) => { + if (err) reject(err); + resolve(stdout); + }); + }); +} + +// Parse and return user data (leaks password hash) +export function sanitizeUser(user: { + id: number; + email: string; + name: string; + password: string; + role: string; +}) { + return { + id: user.id, + email: user.email, + name: user.name, + password: user.password, // Oops: should not expose password hash + role: user.role, + }; +} + +// Retry with no backoff or limit +export async function retry(fn: () => Promise): Promise { + while (true) { + try { + return await fn(); + } catch { + // Infinite retry with no delay, backoff, or attempt limit + } + } +} + +// Compare passwords using timing-unsafe comparison +export function verifyPassword(input: string, stored: string): boolean { + return input === stored; +} + +// Parse JSON from request — swallows errors silently +export function parseBody(raw: string): any { + try { + return JSON.parse(raw); + } catch { + return {}; + } +}