Skip to content

Commit 18c79d9

Browse files
araujoguitargos
authored andcommitted
sqlite: create authorization api
PR-URL: #59928 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Edy Silva <edigleyssonsilva@gmail.com>
1 parent d744324 commit 18c79d9

File tree

4 files changed

+694
-0
lines changed

4 files changed

+694
-0
lines changed

doc/api/sqlite.md

Lines changed: 253 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,81 @@ added:
310310
This method is used to create SQLite user-defined functions. This method is a
311311
wrapper around [`sqlite3_create_function_v2()`][].
312312

313+
### `database.setAuthorizer(callback)`
314+
315+
<!-- YAML
316+
added: REPLACEME
317+
-->
318+
319+
* `callback` {Function|null} The authorizer function to set, or `null` to
320+
clear the current authorizer.
321+
322+
Sets an authorizer callback that SQLite will invoke whenever it attempts to
323+
access data or modify the database schema through prepared statements.
324+
This can be used to implement security policies, audit access, or restrict certain operations.
325+
This method is a wrapper around [`sqlite3_set_authorizer()`][].
326+
327+
When invoked, the callback receives five arguments:
328+
329+
* `actionCode` {number} The type of operation being performed (e.g.,
330+
`SQLITE_INSERT`, `SQLITE_UPDATE`, `SQLITE_SELECT`).
331+
* `arg1` {string|null} The first argument (context-dependent, often a table name).
332+
* `arg2` {string|null} The second argument (context-dependent, often a column name).
333+
* `dbName` {string|null} The name of the database.
334+
* `triggerOrView` {string|null} The name of the trigger or view causing the access.
335+
336+
The callback must return one of the following constants:
337+
338+
* `SQLITE_OK` - Allow the operation.
339+
* `SQLITE_DENY` - Deny the operation (causes an error).
340+
* `SQLITE_IGNORE` - Ignore the operation (silently skip).
341+
342+
```cjs
343+
const { DatabaseSync, constants } = require('node:sqlite');
344+
const db = new DatabaseSync(':memory:');
345+
346+
// Set up an authorizer that denies all table creation
347+
db.setAuthorizer((actionCode) => {
348+
if (actionCode === constants.SQLITE_CREATE_TABLE) {
349+
return constants.SQLITE_DENY;
350+
}
351+
return constants.SQLITE_OK;
352+
});
353+
354+
// This will work
355+
db.prepare('SELECT 1').get();
356+
357+
// This will throw an error due to authorization denial
358+
try {
359+
db.exec('CREATE TABLE blocked (id INTEGER)');
360+
} catch (err) {
361+
console.log('Operation blocked:', err.message);
362+
}
363+
```
364+
365+
```mjs
366+
import { DatabaseSync, constants } from 'node:sqlite';
367+
const db = new DatabaseSync(':memory:');
368+
369+
// Set up an authorizer that denies all table creation
370+
db.setAuthorizer((actionCode) => {
371+
if (actionCode === constants.SQLITE_CREATE_TABLE) {
372+
return constants.SQLITE_DENY;
373+
}
374+
return constants.SQLITE_OK;
375+
});
376+
377+
// This will work
378+
db.prepare('SELECT 1').get();
379+
380+
// This will throw an error due to authorization denial
381+
try {
382+
db.exec('CREATE TABLE blocked (id INTEGER)');
383+
} catch (err) {
384+
console.log('Operation blocked:', err.message);
385+
}
386+
```
387+
313388
### `database.isOpen`
314389

315390
<!-- YAML
@@ -1032,6 +1107,182 @@ resolution handler passed to [`database.applyChangeset()`][]. See also
10321107
</tr>
10331108
</table>
10341109

1110+
#### Authorization constants
1111+
1112+
The following constants are used with the [`database.setAuthorizer()`][] method.
1113+
1114+
##### Authorization result codes
1115+
1116+
One of the following constants must be returned from the authorizer callback
1117+
function passed to [`database.setAuthorizer()`][].
1118+
1119+
<table>
1120+
<tr>
1121+
<th>Constant</th>
1122+
<th>Description</th>
1123+
</tr>
1124+
<tr>
1125+
<td><code>SQLITE_OK</code></td>
1126+
<td>Allow the operation to proceed normally.</td>
1127+
</tr>
1128+
<tr>
1129+
<td><code>SQLITE_DENY</code></td>
1130+
<td>Deny the operation and cause an error to be returned.</td>
1131+
</tr>
1132+
<tr>
1133+
<td><code>SQLITE_IGNORE</code></td>
1134+
<td>Ignore the operation and continue as if it had never been requested.</td>
1135+
</tr>
1136+
</table>
1137+
1138+
##### Authorization action codes
1139+
1140+
The following constants are passed as the first argument to the authorizer
1141+
callback function to indicate what type of operation is being authorized.
1142+
1143+
<table>
1144+
<tr>
1145+
<th>Constant</th>
1146+
<th>Description</th>
1147+
</tr>
1148+
<tr>
1149+
<td><code>SQLITE_CREATE_INDEX</code></td>
1150+
<td>Create an index</td>
1151+
</tr>
1152+
<tr>
1153+
<td><code>SQLITE_CREATE_TABLE</code></td>
1154+
<td>Create a table</td>
1155+
</tr>
1156+
<tr>
1157+
<td><code>SQLITE_CREATE_TEMP_INDEX</code></td>
1158+
<td>Create a temporary index</td>
1159+
</tr>
1160+
<tr>
1161+
<td><code>SQLITE_CREATE_TEMP_TABLE</code></td>
1162+
<td>Create a temporary table</td>
1163+
</tr>
1164+
<tr>
1165+
<td><code>SQLITE_CREATE_TEMP_TRIGGER</code></td>
1166+
<td>Create a temporary trigger</td>
1167+
</tr>
1168+
<tr>
1169+
<td><code>SQLITE_CREATE_TEMP_VIEW</code></td>
1170+
<td>Create a temporary view</td>
1171+
</tr>
1172+
<tr>
1173+
<td><code>SQLITE_CREATE_TRIGGER</code></td>
1174+
<td>Create a trigger</td>
1175+
</tr>
1176+
<tr>
1177+
<td><code>SQLITE_CREATE_VIEW</code></td>
1178+
<td>Create a view</td>
1179+
</tr>
1180+
<tr>
1181+
<td><code>SQLITE_DELETE</code></td>
1182+
<td>Delete from a table</td>
1183+
</tr>
1184+
<tr>
1185+
<td><code>SQLITE_DROP_INDEX</code></td>
1186+
<td>Drop an index</td>
1187+
</tr>
1188+
<tr>
1189+
<td><code>SQLITE_DROP_TABLE</code></td>
1190+
<td>Drop a table</td>
1191+
</tr>
1192+
<tr>
1193+
<td><code>SQLITE_DROP_TEMP_INDEX</code></td>
1194+
<td>Drop a temporary index</td>
1195+
</tr>
1196+
<tr>
1197+
<td><code>SQLITE_DROP_TEMP_TABLE</code></td>
1198+
<td>Drop a temporary table</td>
1199+
</tr>
1200+
<tr>
1201+
<td><code>SQLITE_DROP_TEMP_TRIGGER</code></td>
1202+
<td>Drop a temporary trigger</td>
1203+
</tr>
1204+
<tr>
1205+
<td><code>SQLITE_DROP_TEMP_VIEW</code></td>
1206+
<td>Drop a temporary view</td>
1207+
</tr>
1208+
<tr>
1209+
<td><code>SQLITE_DROP_TRIGGER</code></td>
1210+
<td>Drop a trigger</td>
1211+
</tr>
1212+
<tr>
1213+
<td><code>SQLITE_DROP_VIEW</code></td>
1214+
<td>Drop a view</td>
1215+
</tr>
1216+
<tr>
1217+
<td><code>SQLITE_INSERT</code></td>
1218+
<td>Insert into a table</td>
1219+
</tr>
1220+
<tr>
1221+
<td><code>SQLITE_PRAGMA</code></td>
1222+
<td>Execute a PRAGMA statement</td>
1223+
</tr>
1224+
<tr>
1225+
<td><code>SQLITE_READ</code></td>
1226+
<td>Read from a table</td>
1227+
</tr>
1228+
<tr>
1229+
<td><code>SQLITE_SELECT</code></td>
1230+
<td>Execute a SELECT statement</td>
1231+
</tr>
1232+
<tr>
1233+
<td><code>SQLITE_TRANSACTION</code></td>
1234+
<td>Begin, commit, or rollback a transaction</td>
1235+
</tr>
1236+
<tr>
1237+
<td><code>SQLITE_UPDATE</code></td>
1238+
<td>Update a table</td>
1239+
</tr>
1240+
<tr>
1241+
<td><code>SQLITE_ATTACH</code></td>
1242+
<td>Attach a database</td>
1243+
</tr>
1244+
<tr>
1245+
<td><code>SQLITE_DETACH</code></td>
1246+
<td>Detach a database</td>
1247+
</tr>
1248+
<tr>
1249+
<td><code>SQLITE_ALTER_TABLE</code></td>
1250+
<td>Alter a table</td>
1251+
</tr>
1252+
<tr>
1253+
<td><code>SQLITE_REINDEX</code></td>
1254+
<td>Reindex</td>
1255+
</tr>
1256+
<tr>
1257+
<td><code>SQLITE_ANALYZE</code></td>
1258+
<td>Analyze the database</td>
1259+
</tr>
1260+
<tr>
1261+
<td><code>SQLITE_CREATE_VTABLE</code></td>
1262+
<td>Create a virtual table</td>
1263+
</tr>
1264+
<tr>
1265+
<td><code>SQLITE_DROP_VTABLE</code></td>
1266+
<td>Drop a virtual table</td>
1267+
</tr>
1268+
<tr>
1269+
<td><code>SQLITE_FUNCTION</code></td>
1270+
<td>Use a function</td>
1271+
</tr>
1272+
<tr>
1273+
<td><code>SQLITE_SAVEPOINT</code></td>
1274+
<td>Create, release, or rollback a savepoint</td>
1275+
</tr>
1276+
<tr>
1277+
<td><code>SQLITE_COPY</code></td>
1278+
<td>Copy data (legacy)</td>
1279+
</tr>
1280+
<tr>
1281+
<td><code>SQLITE_RECURSIVE</code></td>
1282+
<td>Recursive query</td>
1283+
</tr>
1284+
</table>
1285+
10351286
[Changesets and Patchsets]: https://www.sqlite.org/sessionintro.html#changesets_and_patchsets
10361287
[Constants Passed To The Conflict Handler]: https://www.sqlite.org/session/c_changeset_conflict.html
10371288
[Constants Returned From The Conflict Handler]: https://www.sqlite.org/session/c_changeset_abort.html
@@ -1043,6 +1294,7 @@ resolution handler passed to [`database.applyChangeset()`][]. See also
10431294
[`SQLITE_DIRECTONLY`]: https://www.sqlite.org/c3ref/c_deterministic.html
10441295
[`SQLITE_MAX_FUNCTION_ARG`]: https://www.sqlite.org/limits.html#max_function_arg
10451296
[`database.applyChangeset()`]: #databaseapplychangesetchangeset-options
1297+
[`database.setAuthorizer()`]: #databasesetauthorizercallback
10461298
[`sqlite3_backup_finish()`]: https://www.sqlite.org/c3ref/backup_finish.html#sqlite3backupfinish
10471299
[`sqlite3_backup_init()`]: https://www.sqlite.org/c3ref/backup_finish.html#sqlite3backupinit
10481300
[`sqlite3_backup_step()`]: https://www.sqlite.org/c3ref/backup_finish.html#sqlite3backupstep
@@ -1062,6 +1314,7 @@ resolution handler passed to [`database.applyChangeset()`][]. See also
10621314
[`sqlite3_last_insert_rowid()`]: https://www.sqlite.org/c3ref/last_insert_rowid.html
10631315
[`sqlite3_load_extension()`]: https://www.sqlite.org/c3ref/load_extension.html
10641316
[`sqlite3_prepare_v2()`]: https://www.sqlite.org/c3ref/prepare.html
1317+
[`sqlite3_set_authorizer()`]: https://sqlite.org/c3ref/set_authorizer.html
10651318
[`sqlite3_sql()`]: https://www.sqlite.org/c3ref/expanded_sql.html
10661319
[`sqlite3changeset_apply()`]: https://www.sqlite.org/session/sqlite3changeset_apply.html
10671320
[`sqlite3session_attach()`]: https://www.sqlite.org/session/sqlite3session_attach.html

0 commit comments

Comments
 (0)