* For INSERT statements targeting a table with owner_email / org_id columns, * auto-inject the current user's email and org ID if not already present. * * Handles the explicit column list form: * INSERT INTO table (col1, col2) VALUES (val1, val2)
(sql: string, scoping: ScopingContext)
| 295 | * INSERT INTO table (col1, col2) VALUES (val1, val2) |
| 296 | */ |
| 297 | function injectOwnership(sql: string, scoping: ScopingContext): string { |
| 298 | if (!scoping.active) return sql; |
| 299 | |
| 300 | const upper = sql |
| 301 | .replace(/^\s*--[^\n]*\n/gm, "") |
| 302 | .replace(/\/\*[\s\S]*?\*\//g, "") |
| 303 | .trim() |
| 304 | .toUpperCase(); |
| 305 | if (!upper.startsWith("INSERT")) return sql; |
| 306 | |
| 307 | // Extract table name: INSERT INTO <table> ... |
| 308 | const match = sql.match(/INSERT\s+INTO\s+["']?(\w+)["']?/i); |
| 309 | if (!match) return sql; |
| 310 | |
| 311 | const tableName = match[1]; |
| 312 | |
| 313 | // Determine which columns to inject |
| 314 | const injections: { col: string; value: string }[] = []; |
| 315 | |
| 316 | if ( |
| 317 | scoping.userEmail && |
| 318 | scoping.ownerEmailTables.has(tableName) && |
| 319 | !/owner_email/i.test(sql) |
| 320 | ) { |
| 321 | injections.push({ |
| 322 | col: "owner_email", |
| 323 | value: `'${scoping.userEmail.replace(/'/g, "''")}'`, |
| 324 | }); |
| 325 | } |
| 326 | |
| 327 | if ( |
| 328 | scoping.orgId && |
| 329 | scoping.orgIdTables.has(tableName) && |
| 330 | !/org_id/i.test(sql) |
| 331 | ) { |
| 332 | injections.push({ |
| 333 | col: "org_id", |
| 334 | value: `'${scoping.orgId.replace(/'/g, "''")}'`, |
| 335 | }); |
| 336 | } |
| 337 | |
| 338 | if (injections.length === 0) return sql; |
| 339 | |
| 340 | // Try to inject into explicit column list: INSERT INTO t (cols) VALUES (vals) |
| 341 | const colListMatch = sql.match( |
| 342 | /(INSERT\s+INTO\s+["']?\w+["']?\s*)\(([^)]+)\)(\s*VALUES\s*)\(([^)]+)\)/i, |
| 343 | ); |
| 344 | if (colListMatch) { |
| 345 | const [, prefix, cols, valueKeyword, vals] = colListMatch; |
| 346 | const extraCols = injections.map((i) => i.col).join(", "); |
| 347 | const extraVals = injections.map((i) => i.value).join(", "); |
| 348 | return `${prefix}(${cols}, ${extraCols})${valueKeyword}(${vals}, ${extraVals})`; |
| 349 | } |
| 350 | |
| 351 | return sql; |
| 352 | } |
| 353 | |
| 354 | function escapeSqlString(value: string): string { |