Skip to content

Commit a899991

Browse files
araujoguijuanarbol
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 af00ddc commit a899991

4 files changed

Lines changed: 694 additions & 0 deletions

File tree

doc/api/sqlite.md

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

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

311386
<!-- YAML
@@ -833,6 +908,182 @@ resolution handler passed to [`database.applyChangeset()`][]. See also
833908
</tr>
834909
</table>
835910

911+
#### Authorization constants
912+
913+
The following constants are used with the [`database.setAuthorizer()`][] method.
914+
915+
##### Authorization result codes
916+
917+
One of the following constants must be returned from the authorizer callback
918+
function passed to [`database.setAuthorizer()`][].
919+
920+
<table>
921+
<tr>
922+
<th>Constant</th>
923+
<th>Description</th>
924+
</tr>
925+
<tr>
926+
<td><code>SQLITE_OK</code></td>
927+
<td>Allow the operation to proceed normally.</td>
928+
</tr>
929+
<tr>
930+
<td><code>SQLITE_DENY</code></td>
931+
<td>Deny the operation and cause an error to be returned.</td>
932+
</tr>
933+
<tr>
934+
<td><code>SQLITE_IGNORE</code></td>
935+
<td>Ignore the operation and continue as if it had never been requested.</td>
936+
</tr>
937+
</table>
938+
939+
##### Authorization action codes
940+
941+
The following constants are passed as the first argument to the authorizer
942+
callback function to indicate what type of operation is being authorized.
943+
944+
<table>
945+
<tr>
946+
<th>Constant</th>
947+
<th>Description</th>
948+
</tr>
949+
<tr>
950+
<td><code>SQLITE_CREATE_INDEX</code></td>
951+
<td>Create an index</td>
952+
</tr>
953+
<tr>
954+
<td><code>SQLITE_CREATE_TABLE</code></td>
955+
<td>Create a table</td>
956+
</tr>
957+
<tr>
958+
<td><code>SQLITE_CREATE_TEMP_INDEX</code></td>
959+
<td>Create a temporary index</td>
960+
</tr>
961+
<tr>
962+
<td><code>SQLITE_CREATE_TEMP_TABLE</code></td>
963+
<td>Create a temporary table</td>
964+
</tr>
965+
<tr>
966+
<td><code>SQLITE_CREATE_TEMP_TRIGGER</code></td>
967+
<td>Create a temporary trigger</td>
968+
</tr>
969+
<tr>
970+
<td><code>SQLITE_CREATE_TEMP_VIEW</code></td>
971+
<td>Create a temporary view</td>
972+
</tr>
973+
<tr>
974+
<td><code>SQLITE_CREATE_TRIGGER</code></td>
975+
<td>Create a trigger</td>
976+
</tr>
977+
<tr>
978+
<td><code>SQLITE_CREATE_VIEW</code></td>
979+
<td>Create a view</td>
980+
</tr>
981+
<tr>
982+
<td><code>SQLITE_DELETE</code></td>
983+
<td>Delete from a table</td>
984+
</tr>
985+
<tr>
986+
<td><code>SQLITE_DROP_INDEX</code></td>
987+
<td>Drop an index</td>
988+
</tr>
989+
<tr>
990+
<td><code>SQLITE_DROP_TABLE</code></td>
991+
<td>Drop a table</td>
992+
</tr>
993+
<tr>
994+
<td><code>SQLITE_DROP_TEMP_INDEX</code></td>
995+
<td>Drop a temporary index</td>
996+
</tr>
997+
<tr>
998+
<td><code>SQLITE_DROP_TEMP_TABLE</code></td>
999+
<td>Drop a temporary table</td>
1000+
</tr>
1001+
<tr>
1002+
<td><code>SQLITE_DROP_TEMP_TRIGGER</code></td>
1003+
<td>Drop a temporary trigger</td>
1004+
</tr>
1005+
<tr>
1006+
<td><code>SQLITE_DROP_TEMP_VIEW</code></td>
1007+
<td>Drop a temporary view</td>
1008+
</tr>
1009+
<tr>
1010+
<td><code>SQLITE_DROP_TRIGGER</code></td>
1011+
<td>Drop a trigger</td>
1012+
</tr>
1013+
<tr>
1014+
<td><code>SQLITE_DROP_VIEW</code></td>
1015+
<td>Drop a view</td>
1016+
</tr>
1017+
<tr>
1018+
<td><code>SQLITE_INSERT</code></td>
1019+
<td>Insert into a table</td>
1020+
</tr>
1021+
<tr>
1022+
<td><code>SQLITE_PRAGMA</code></td>
1023+
<td>Execute a PRAGMA statement</td>
1024+
</tr>
1025+
<tr>
1026+
<td><code>SQLITE_READ</code></td>
1027+
<td>Read from a table</td>
1028+
</tr>
1029+
<tr>
1030+
<td><code>SQLITE_SELECT</code></td>
1031+
<td>Execute a SELECT statement</td>
1032+
</tr>
1033+
<tr>
1034+
<td><code>SQLITE_TRANSACTION</code></td>
1035+
<td>Begin, commit, or rollback a transaction</td>
1036+
</tr>
1037+
<tr>
1038+
<td><code>SQLITE_UPDATE</code></td>
1039+
<td>Update a table</td>
1040+
</tr>
1041+
<tr>
1042+
<td><code>SQLITE_ATTACH</code></td>
1043+
<td>Attach a database</td>
1044+
</tr>
1045+
<tr>
1046+
<td><code>SQLITE_DETACH</code></td>
1047+
<td>Detach a database</td>
1048+
</tr>
1049+
<tr>
1050+
<td><code>SQLITE_ALTER_TABLE</code></td>
1051+
<td>Alter a table</td>
1052+
</tr>
1053+
<tr>
1054+
<td><code>SQLITE_REINDEX</code></td>
1055+
<td>Reindex</td>
1056+
</tr>
1057+
<tr>
1058+
<td><code>SQLITE_ANALYZE</code></td>
1059+
<td>Analyze the database</td>
1060+
</tr>
1061+
<tr>
1062+
<td><code>SQLITE_CREATE_VTABLE</code></td>
1063+
<td>Create a virtual table</td>
1064+
</tr>
1065+
<tr>
1066+
<td><code>SQLITE_DROP_VTABLE</code></td>
1067+
<td>Drop a virtual table</td>
1068+
</tr>
1069+
<tr>
1070+
<td><code>SQLITE_FUNCTION</code></td>
1071+
<td>Use a function</td>
1072+
</tr>
1073+
<tr>
1074+
<td><code>SQLITE_SAVEPOINT</code></td>
1075+
<td>Create, release, or rollback a savepoint</td>
1076+
</tr>
1077+
<tr>
1078+
<td><code>SQLITE_COPY</code></td>
1079+
<td>Copy data (legacy)</td>
1080+
</tr>
1081+
<tr>
1082+
<td><code>SQLITE_RECURSIVE</code></td>
1083+
<td>Recursive query</td>
1084+
</tr>
1085+
</table>
1086+
8361087
[Changesets and Patchsets]: https://www.sqlite.org/sessionintro.html#changesets_and_patchsets
8371088
[Constants Passed To The Conflict Handler]: https://www.sqlite.org/session/c_changeset_conflict.html
8381089
[Constants Returned From The Conflict Handler]: https://www.sqlite.org/session/c_changeset_abort.html
@@ -844,6 +1095,7 @@ resolution handler passed to [`database.applyChangeset()`][]. See also
8441095
[`SQLITE_DIRECTONLY`]: https://www.sqlite.org/c3ref/c_deterministic.html
8451096
[`SQLITE_MAX_FUNCTION_ARG`]: https://www.sqlite.org/limits.html#max_function_arg
8461097
[`database.applyChangeset()`]: #databaseapplychangesetchangeset-options
1098+
[`database.setAuthorizer()`]: #databasesetauthorizercallback
8471099
[`sqlite3_backup_finish()`]: https://www.sqlite.org/c3ref/backup_finish.html#sqlite3backupfinish
8481100
[`sqlite3_backup_init()`]: https://www.sqlite.org/c3ref/backup_finish.html#sqlite3backupinit
8491101
[`sqlite3_backup_step()`]: https://www.sqlite.org/c3ref/backup_finish.html#sqlite3backupstep
@@ -863,6 +1115,7 @@ resolution handler passed to [`database.applyChangeset()`][]. See also
8631115
[`sqlite3_last_insert_rowid()`]: https://www.sqlite.org/c3ref/last_insert_rowid.html
8641116
[`sqlite3_load_extension()`]: https://www.sqlite.org/c3ref/load_extension.html
8651117
[`sqlite3_prepare_v2()`]: https://www.sqlite.org/c3ref/prepare.html
1118+
[`sqlite3_set_authorizer()`]: https://sqlite.org/c3ref/set_authorizer.html
8661119
[`sqlite3_sql()`]: https://www.sqlite.org/c3ref/expanded_sql.html
8671120
[`sqlite3changeset_apply()`]: https://www.sqlite.org/session/sqlite3changeset_apply.html
8681121
[`sqlite3session_attach()`]: https://www.sqlite.org/session/sqlite3session_attach.html

0 commit comments

Comments
 (0)