@proteinjs/db 1.50.0 → 1.50.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +11 -0
- package/dist/src/auth/TableAuth.d.ts +2 -0
- package/dist/src/auth/TableAuth.d.ts.map +1 -1
- package/dist/src/auth/TableAuth.js +24 -2
- package/dist/src/auth/TableAuth.js.map +1 -1
- package/dist/test/TableAuthIdentity.test.js +85 -0
- package/dist/test/TableAuthIdentity.test.js.map +1 -1
- package/package.json +2 -2
- package/src/auth/TableAuth.ts +26 -2
- package/test/TableAuthIdentity.test.ts +95 -2
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,17 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## [1.50.1](https://github.com/proteinjs/db/compare/@proteinjs/db@1.50.0...@proteinjs/db@1.50.1) (2026-09-30)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Bug Fixes
|
|
10
|
+
|
|
11
|
+
* **db:** an undeclared db door mirrors the declared service door — the RPC runs both, so a service write door with no db mirror admitted the caller at the gate and refused them behind it ([35a3621](https://github.com/proteinjs/db/commit/35a362170d92b521b9104f8349f2e27d7bec98b8))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
6
17
|
# [1.50.0](https://github.com/proteinjs/db/compare/@proteinjs/db@1.49.1...@proteinjs/db@1.50.0) (2026-09-29)
|
|
7
18
|
|
|
8
19
|
|
|
@@ -63,6 +63,8 @@ export declare class TableAuth {
|
|
|
63
63
|
*/
|
|
64
64
|
canDelete(table: Table<any>, api?: 'db' | 'service'): void;
|
|
65
65
|
private canAccess;
|
|
66
|
+
/** The service block's door for `operation`, as the RPC gate reads it; a table with no service block declares none. */
|
|
67
|
+
private allowsServiceDoor;
|
|
66
68
|
/** One identity against the current user; undefined (nothing declared) is not a grant. */
|
|
67
69
|
private allows;
|
|
68
70
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TableAuth.d.ts","sourceRoot":"","sources":["../../../src/auth/TableAuth.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC;AAEjC;;;;;;;GAOG;AACH,MAAM,MAAM,kBAAkB,GAAG;IAAE,UAAU,EAAE,MAAM,CAAA;CAAE,CAAC;AAExD,MAAM,MAAM,QAAQ,GAAG,QAAQ,GAAG,eAAe,GAAG,MAAM,EAAE,GAAG,kBAAkB,CAAC;AAKlF;;;GAGG;AACH,MAAM,MAAM,mBAAmB,GAAG;IAChC,GAAG,CAAC,EAAE,QAAQ,CAAC;IACf,KAAK,CAAC,EAAE,QAAQ,CAAC;IACjB,MAAM,CAAC,EAAE,QAAQ,CAAC;IAClB,MAAM,CAAC,EAAE,QAAQ,CAAC;IAClB,MAAM,CAAC,EAAE,QAAQ,CAAC;CACnB,CAAC;AAEF;;;;;GAKG;AACH,qBAAa,cAAe,SAAQ,KAAK;gBAC3B,OAAO,EAAE,MAAM;CAI5B;AAED;;GAEG;AACH,qBAAa,SAAS;IACpB;;;;;;;;;OASG;IACH,UAAU,CACR,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EACjB,SAAS,EAAE,OAAO,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,EACnD,GAAG,GAAE,IAAI,GAAG,SAAgB,GAC3B,OAAO;IAQV;;;;;;OAMG;IACH,cAAc,CAAC,QAAQ,EAAE,QAAQ,GAAG,SAAS,GAAG,OAAO;IAQvD,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EAAE,GAAG,GAAE,IAAI,GAAG,SAAgB,GAAG,IAAI;IAM/D,SAAS,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EAAE,GAAG,GAAE,IAAI,GAAG,SAAgB,GAAG,IAAI;IAMhE,SAAS,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EAAE,GAAG,GAAE,IAAI,GAAG,SAAgB,GAAG,IAAI;IAMhE;;;OAGG;IACH,SAAS,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EAAE,GAAG,GAAE,IAAI,GAAG,SAAgB,GAAG,IAAI;IAUhE,OAAO,CAAC,SAAS;
|
|
1
|
+
{"version":3,"file":"TableAuth.d.ts","sourceRoot":"","sources":["../../../src/auth/TableAuth.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC;AAEjC;;;;;;;GAOG;AACH,MAAM,MAAM,kBAAkB,GAAG;IAAE,UAAU,EAAE,MAAM,CAAA;CAAE,CAAC;AAExD,MAAM,MAAM,QAAQ,GAAG,QAAQ,GAAG,eAAe,GAAG,MAAM,EAAE,GAAG,kBAAkB,CAAC;AAKlF;;;GAGG;AACH,MAAM,MAAM,mBAAmB,GAAG;IAChC,GAAG,CAAC,EAAE,QAAQ,CAAC;IACf,KAAK,CAAC,EAAE,QAAQ,CAAC;IACjB,MAAM,CAAC,EAAE,QAAQ,CAAC;IAClB,MAAM,CAAC,EAAE,QAAQ,CAAC;IAClB,MAAM,CAAC,EAAE,QAAQ,CAAC;CACnB,CAAC;AAEF;;;;;GAKG;AACH,qBAAa,cAAe,SAAQ,KAAK;gBAC3B,OAAO,EAAE,MAAM;CAI5B;AAED;;GAEG;AACH,qBAAa,SAAS;IACpB;;;;;;;;;OASG;IACH,UAAU,CACR,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EACjB,SAAS,EAAE,OAAO,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,EACnD,GAAG,GAAE,IAAI,GAAG,SAAgB,GAC3B,OAAO;IAQV;;;;;;OAMG;IACH,cAAc,CAAC,QAAQ,EAAE,QAAQ,GAAG,SAAS,GAAG,OAAO;IAQvD,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EAAE,GAAG,GAAE,IAAI,GAAG,SAAgB,GAAG,IAAI;IAM/D,SAAS,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EAAE,GAAG,GAAE,IAAI,GAAG,SAAgB,GAAG,IAAI;IAMhE,SAAS,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EAAE,GAAG,GAAE,IAAI,GAAG,SAAgB,GAAG,IAAI;IAMhE;;;OAGG;IACH,SAAS,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EAAE,GAAG,GAAE,IAAI,GAAG,SAAgB,GAAG,IAAI;IAUhE,OAAO,CAAC,SAAS;IAmCjB,uHAAuH;IACvH,OAAO,CAAC,iBAAiB;IASzB,0FAA0F;IAC1F,OAAO,CAAC,MAAM;CAef"}
|
|
@@ -119,8 +119,30 @@ var TableAuth = /** @class */ (function () {
|
|
|
119
119
|
}
|
|
120
120
|
// Within a declared block an undeclared operation stays closed to everyone (the block is
|
|
121
121
|
// the whole declaration) — `allows` reads undefined as false, so the two doors are exactly
|
|
122
|
-
// the ones the table wrote down
|
|
123
|
-
|
|
122
|
+
// the ones the table wrote down...
|
|
123
|
+
if (this.allows(tableAuth.all) || this.allows(tableAuth[operation])) {
|
|
124
|
+
return true;
|
|
125
|
+
}
|
|
126
|
+
// ...except that a db door the block leaves UNDECLARED mirrors the door the table's SERVICE
|
|
127
|
+
// block declares for the same operation. The RPC runs both doors — the service gate
|
|
128
|
+
// (TableServiceAuth), then the inner Db's db-api re-check as the calling user — so a service
|
|
129
|
+
// door with no db mirror admitted the caller at the gate and refused them behind it, in the
|
|
130
|
+
// gate's own words ("db doors mirror service doors" was a rule tables hand-copied; the owner
|
|
131
|
+
// derives it). One-way: a service block that omits the door keeps the lock (the session /
|
|
132
|
+
// audit-trail pattern — no write door on either api, break-glass included), and a table with
|
|
133
|
+
// no service block keeps its db block as written.
|
|
134
|
+
return api === 'db' && tableAuth.all === undefined && tableAuth[operation] === undefined
|
|
135
|
+
? this.allowsServiceDoor(table, operation)
|
|
136
|
+
: false;
|
|
137
|
+
};
|
|
138
|
+
/** The service block's door for `operation`, as the RPC gate reads it; a table with no service block declares none. */
|
|
139
|
+
TableAuth.prototype.allowsServiceDoor = function (table, operation) {
|
|
140
|
+
var _a;
|
|
141
|
+
var serviceAuth = (_a = table.auth) === null || _a === void 0 ? void 0 : _a.service;
|
|
142
|
+
if (!serviceAuth || Object.keys(serviceAuth).length == 0) {
|
|
143
|
+
return false;
|
|
144
|
+
}
|
|
145
|
+
return this.allows(serviceAuth.all) || this.allows(serviceAuth[operation]);
|
|
124
146
|
};
|
|
125
147
|
/** One identity against the current user; undefined (nothing declared) is not a grant. */
|
|
126
148
|
TableAuth.prototype.allows = function (identity) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TableAuth.js","sourceRoot":"","sources":["../../../src/auth/TableAuth.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;AAAA,kDAAgD;AAChD,8CAAoD;AAepD,IAAM,oBAAoB,GAAG,UAAC,QAA8B;IAC1D,OAAA,CAAC,CAAC,QAAQ,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,OAAO,QAAQ,CAAC,UAAU,KAAK,QAAQ;AAAjH,CAAiH,CAAC;AAcpH;;;;;GAKG;AACH;IAAoC,kCAAK;IACvC,wBAAY,OAAe;QAA3B,YACE,kBAAM,OAAO,CAAC,SAEf;QADC,KAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC;;IAC/B,CAAC;IACH,qBAAC;AAAD,CAAC,AALD,CAAoC,KAAK,GAKxC;AALY,wCAAc;AAO3B;;GAEG;AACH;IAAA;
|
|
1
|
+
{"version":3,"file":"TableAuth.js","sourceRoot":"","sources":["../../../src/auth/TableAuth.ts"],"names":[],"mappings":"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"}
|
|
@@ -107,4 +107,89 @@ describe('TableAuth operation doors keep their declared-block semantics', functi
|
|
|
107
107
|
expect(new TableAuth_1.TableAuth().canPerform(new QueryOnlyTable(), 'insert')).toBe(false);
|
|
108
108
|
});
|
|
109
109
|
});
|
|
110
|
+
/**
|
|
111
|
+
* The RPC runs BOTH doors — the service gate (`TableServiceAuth`) and then the inner `Db`'s
|
|
112
|
+
* db-api re-check as the calling user — so a db door a table leaves UNDECLARED mirrors the door
|
|
113
|
+
* its service block declares for the same operation. "db doors mirror service doors" was a rule
|
|
114
|
+
* tables hand-copied; the owner derives it now: fifteen consumer tables opened `['admin']` writes
|
|
115
|
+
* on the service api over a query-only db block, and every one refused the admin at the inner
|
|
116
|
+
* check in the gate's own words — the gate admitted them, the re-check behind it did not, two
|
|
117
|
+
* verdicts for one caller. One-way: a service block that omits the door keeps the lock (the
|
|
118
|
+
* session / audit-trail pattern — no write door on either api, break-glass included), and a table
|
|
119
|
+
* with no service block keeps its db block as written (the pin above).
|
|
120
|
+
*/
|
|
121
|
+
var ReadOpenWriteAdminTable = /** @class */ (function (_super) {
|
|
122
|
+
__extends(ReadOpenWriteAdminTable, _super);
|
|
123
|
+
function ReadOpenWriteAdminTable() {
|
|
124
|
+
var _this = _super !== null && _super.apply(this, arguments) || this;
|
|
125
|
+
_this.name = 'identity_read_open_write_admin_test';
|
|
126
|
+
_this.auth = {
|
|
127
|
+
db: { query: 'authenticated' },
|
|
128
|
+
service: { query: 'authenticated', insert: ['admin'], update: ['admin'], delete: ['admin'] },
|
|
129
|
+
};
|
|
130
|
+
_this.columns = (0, Record_1.withRecordColumns)({ title: new Columns_1.StringColumn('title') });
|
|
131
|
+
return _this;
|
|
132
|
+
}
|
|
133
|
+
return ReadOpenWriteAdminTable;
|
|
134
|
+
}(Table_1.Table));
|
|
135
|
+
var LockedLedgerTable = /** @class */ (function (_super) {
|
|
136
|
+
__extends(LockedLedgerTable, _super);
|
|
137
|
+
function LockedLedgerTable() {
|
|
138
|
+
var _this = _super !== null && _super.apply(this, arguments) || this;
|
|
139
|
+
_this.name = 'identity_locked_ledger_test';
|
|
140
|
+
_this.auth = {
|
|
141
|
+
db: { query: { permission: 'ledger' } },
|
|
142
|
+
service: { query: { permission: 'ledger' } },
|
|
143
|
+
};
|
|
144
|
+
_this.columns = (0, Record_1.withRecordColumns)({ title: new Columns_1.StringColumn('title') });
|
|
145
|
+
return _this;
|
|
146
|
+
}
|
|
147
|
+
return LockedLedgerTable;
|
|
148
|
+
}(Table_1.Table));
|
|
149
|
+
describe('TableAuth — an undeclared db door mirrors the declared service door', function () {
|
|
150
|
+
beforeEach(function () {
|
|
151
|
+
setMapping({ ledger: ['ledger'] });
|
|
152
|
+
});
|
|
153
|
+
afterEach(function () {
|
|
154
|
+
user_auth_1.UserAuth.userRepo = undefined;
|
|
155
|
+
user_auth_1.UserAuth.permissionRolesMapping = undefined;
|
|
156
|
+
});
|
|
157
|
+
test("an admin's write clears the ['admin'] service door AND the db-api re-check behind it", function () {
|
|
158
|
+
setUser(['admin']);
|
|
159
|
+
var table = new ReadOpenWriteAdminTable();
|
|
160
|
+
expect(function () { return new TableAuth_1.TableAuth().canUpdate(table, 'service'); }).not.toThrow();
|
|
161
|
+
expect(function () { return new TableAuth_1.TableAuth().canUpdate(table); }).not.toThrow();
|
|
162
|
+
expect(function () { return new TableAuth_1.TableAuth().canInsert(table); }).not.toThrow();
|
|
163
|
+
expect(function () { return new TableAuth_1.TableAuth().canDelete(table); }).not.toThrow();
|
|
164
|
+
expect(new TableAuth_1.TableAuth().canPerform(table, 'update', 'db')).toBe(true);
|
|
165
|
+
});
|
|
166
|
+
test('a signed-in non-admin is refused by name on both apis; the read door stays open', function () {
|
|
167
|
+
setUser(['ledger']);
|
|
168
|
+
var table = new ReadOpenWriteAdminTable();
|
|
169
|
+
expect(function () { return new TableAuth_1.TableAuth().canUpdate(table, 'service'); }).toThrow('User is not authorized to update records in table: identity_read_open_write_admin_test');
|
|
170
|
+
expect(function () { return new TableAuth_1.TableAuth().canUpdate(table); }).toThrow('User is not authorized to update records in table: identity_read_open_write_admin_test');
|
|
171
|
+
expect(function () { return new TableAuth_1.TableAuth().canQuery(table); }).not.toThrow();
|
|
172
|
+
});
|
|
173
|
+
test('a guest is refused every door', function () {
|
|
174
|
+
setGuest();
|
|
175
|
+
var table = new ReadOpenWriteAdminTable();
|
|
176
|
+
expect(function () { return new TableAuth_1.TableAuth().canQuery(table); }).toThrow('User is not authorized to query table: identity_read_open_write_admin_test');
|
|
177
|
+
expect(function () { return new TableAuth_1.TableAuth().canUpdate(table); }).toThrow();
|
|
178
|
+
expect(function () { return new TableAuth_1.TableAuth().canInsert(table, 'service'); }).toThrow();
|
|
179
|
+
});
|
|
180
|
+
test('one-way: a service block that omits the door keeps the lock on both apis, break-glass included', function () {
|
|
181
|
+
setUser(['admin']);
|
|
182
|
+
var table = new LockedLedgerTable();
|
|
183
|
+
expect(new TableAuth_1.TableAuth().canPerform(table, 'update', 'service')).toBe(false);
|
|
184
|
+
expect(new TableAuth_1.TableAuth().canPerform(table, 'update', 'db')).toBe(false);
|
|
185
|
+
expect(function () { return new TableAuth_1.TableAuth().canUpdate(table); }).toThrow('User is not authorized to update records in table: identity_locked_ledger_test');
|
|
186
|
+
expect(function () { return new TableAuth_1.TableAuth().canInsert(table, 'service'); }).toThrow();
|
|
187
|
+
expect(function () { return new TableAuth_1.TableAuth().canQuery(table); }).not.toThrow();
|
|
188
|
+
});
|
|
189
|
+
test('a table with no service block keeps its db block as written — admin included', function () {
|
|
190
|
+
setUser(['admin']);
|
|
191
|
+
expect(new TableAuth_1.TableAuth().canPerform(new QueryOnlyTable(), 'update', 'db')).toBe(false);
|
|
192
|
+
expect(function () { return new TableAuth_1.TableAuth().canUpdate(new QueryOnlyTable()); }).toThrow('User is not authorized to update records in table: identity_query_only_test');
|
|
193
|
+
});
|
|
194
|
+
});
|
|
110
195
|
//# sourceMappingURL=TableAuthIdentity.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TableAuthIdentity.test.js","sourceRoot":"","sources":["../../test/TableAuthIdentity.test.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAAA,kDAAgD;AAChD,sCAAqC;AACrC,wCAA0D;AAC1D,0CAA8C;AAC9C,mDAAkD;
|
|
1
|
+
{"version":3,"file":"TableAuthIdentity.test.js","sourceRoot":"","sources":["../../test/TableAuthIdentity.test.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@proteinjs/db",
|
|
3
|
-
"version": "1.50.
|
|
3
|
+
"version": "1.50.1",
|
|
4
4
|
"main": "./dist/generated/index.js",
|
|
5
5
|
"types": "./dist/generated/index.d.ts",
|
|
6
6
|
"exports": {
|
|
@@ -66,5 +66,5 @@
|
|
|
66
66
|
"ts-jest": "29.1.1",
|
|
67
67
|
"typescript": "5.2.2"
|
|
68
68
|
},
|
|
69
|
-
"gitHead": "
|
|
69
|
+
"gitHead": "a324a92e60161ddf69fec4e17b646882fe830f85"
|
|
70
70
|
}
|
package/src/auth/TableAuth.ts
CHANGED
|
@@ -132,8 +132,32 @@ export class TableAuth {
|
|
|
132
132
|
|
|
133
133
|
// Within a declared block an undeclared operation stays closed to everyone (the block is
|
|
134
134
|
// the whole declaration) — `allows` reads undefined as false, so the two doors are exactly
|
|
135
|
-
// the ones the table wrote down
|
|
136
|
-
|
|
135
|
+
// the ones the table wrote down...
|
|
136
|
+
if (this.allows(tableAuth.all) || this.allows(tableAuth[operation])) {
|
|
137
|
+
return true;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// ...except that a db door the block leaves UNDECLARED mirrors the door the table's SERVICE
|
|
141
|
+
// block declares for the same operation. The RPC runs both doors — the service gate
|
|
142
|
+
// (TableServiceAuth), then the inner Db's db-api re-check as the calling user — so a service
|
|
143
|
+
// door with no db mirror admitted the caller at the gate and refused them behind it, in the
|
|
144
|
+
// gate's own words ("db doors mirror service doors" was a rule tables hand-copied; the owner
|
|
145
|
+
// derives it). One-way: a service block that omits the door keeps the lock (the session /
|
|
146
|
+
// audit-trail pattern — no write door on either api, break-glass included), and a table with
|
|
147
|
+
// no service block keeps its db block as written.
|
|
148
|
+
return api === 'db' && tableAuth.all === undefined && tableAuth[operation] === undefined
|
|
149
|
+
? this.allowsServiceDoor(table, operation)
|
|
150
|
+
: false;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/** The service block's door for `operation`, as the RPC gate reads it; a table with no service block declares none. */
|
|
154
|
+
private allowsServiceDoor(table: Table<any>, operation: 'query' | 'insert' | 'update' | 'delete'): boolean {
|
|
155
|
+
const serviceAuth = table.auth?.service;
|
|
156
|
+
if (!serviceAuth || Object.keys(serviceAuth).length == 0) {
|
|
157
|
+
return false;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return this.allows(serviceAuth.all) || this.allows(serviceAuth[operation]);
|
|
137
161
|
}
|
|
138
162
|
|
|
139
163
|
/** One identity against the current user; undefined (nothing declared) is not a grant. */
|
|
@@ -11,8 +11,9 @@ import { TableAuth } from '../src/auth/TableAuth';
|
|
|
11
11
|
* - each identity form resolves against the current user; 'admin' is break-glass throughout;
|
|
12
12
|
* - an UNDECLARED identity is admin-only (default-deny made explicit), never open;
|
|
13
13
|
* - it fails CLOSED when no user can be resolved;
|
|
14
|
-
* - the operation doors (`canPerform`)
|
|
15
|
-
*
|
|
14
|
+
* - the operation doors (`canPerform`) keep the declared-block semantics: within a declared block
|
|
15
|
+
* an undeclared operation stays closed to everyone, admin included — unless the table's SERVICE
|
|
16
|
+
* block names that door, which the db door then mirrors (the last describe).
|
|
16
17
|
*
|
|
17
18
|
* `UserAuth` reads from a static repo; tests stub it directly per identity — no server needed.
|
|
18
19
|
*/
|
|
@@ -113,3 +114,95 @@ describe('TableAuth operation doors keep their declared-block semantics', () =>
|
|
|
113
114
|
expect(new TableAuth().canPerform(new QueryOnlyTable(), 'insert')).toBe(false);
|
|
114
115
|
});
|
|
115
116
|
});
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* The RPC runs BOTH doors — the service gate (`TableServiceAuth`) and then the inner `Db`'s
|
|
120
|
+
* db-api re-check as the calling user — so a db door a table leaves UNDECLARED mirrors the door
|
|
121
|
+
* its service block declares for the same operation. "db doors mirror service doors" was a rule
|
|
122
|
+
* tables hand-copied; the owner derives it now: fifteen consumer tables opened `['admin']` writes
|
|
123
|
+
* on the service api over a query-only db block, and every one refused the admin at the inner
|
|
124
|
+
* check in the gate's own words — the gate admitted them, the re-check behind it did not, two
|
|
125
|
+
* verdicts for one caller. One-way: a service block that omits the door keeps the lock (the
|
|
126
|
+
* session / audit-trail pattern — no write door on either api, break-glass included), and a table
|
|
127
|
+
* with no service block keeps its db block as written (the pin above).
|
|
128
|
+
*/
|
|
129
|
+
class ReadOpenWriteAdminTable extends Table<Doc> {
|
|
130
|
+
public name = 'identity_read_open_write_admin_test';
|
|
131
|
+
public auth: Table<Doc>['auth'] = {
|
|
132
|
+
db: { query: 'authenticated' },
|
|
133
|
+
service: { query: 'authenticated', insert: ['admin'], update: ['admin'], delete: ['admin'] },
|
|
134
|
+
};
|
|
135
|
+
public columns = withRecordColumns<Doc>({ title: new StringColumn('title') });
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
class LockedLedgerTable extends Table<Doc> {
|
|
139
|
+
public name = 'identity_locked_ledger_test';
|
|
140
|
+
public auth: Table<Doc>['auth'] = {
|
|
141
|
+
db: { query: { permission: 'ledger' } },
|
|
142
|
+
service: { query: { permission: 'ledger' } },
|
|
143
|
+
};
|
|
144
|
+
public columns = withRecordColumns<Doc>({ title: new StringColumn('title') });
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
describe('TableAuth — an undeclared db door mirrors the declared service door', () => {
|
|
148
|
+
beforeEach(() => {
|
|
149
|
+
setMapping({ ledger: ['ledger'] });
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
afterEach(() => {
|
|
153
|
+
(UserAuth as any).userRepo = undefined;
|
|
154
|
+
(UserAuth as any).permissionRolesMapping = undefined;
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
test("an admin's write clears the ['admin'] service door AND the db-api re-check behind it", () => {
|
|
158
|
+
setUser(['admin']);
|
|
159
|
+
const table = new ReadOpenWriteAdminTable();
|
|
160
|
+
expect(() => new TableAuth().canUpdate(table, 'service')).not.toThrow();
|
|
161
|
+
expect(() => new TableAuth().canUpdate(table)).not.toThrow();
|
|
162
|
+
expect(() => new TableAuth().canInsert(table)).not.toThrow();
|
|
163
|
+
expect(() => new TableAuth().canDelete(table)).not.toThrow();
|
|
164
|
+
expect(new TableAuth().canPerform(table, 'update', 'db')).toBe(true);
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
test('a signed-in non-admin is refused by name on both apis; the read door stays open', () => {
|
|
168
|
+
setUser(['ledger']);
|
|
169
|
+
const table = new ReadOpenWriteAdminTable();
|
|
170
|
+
expect(() => new TableAuth().canUpdate(table, 'service')).toThrow(
|
|
171
|
+
'User is not authorized to update records in table: identity_read_open_write_admin_test'
|
|
172
|
+
);
|
|
173
|
+
expect(() => new TableAuth().canUpdate(table)).toThrow(
|
|
174
|
+
'User is not authorized to update records in table: identity_read_open_write_admin_test'
|
|
175
|
+
);
|
|
176
|
+
expect(() => new TableAuth().canQuery(table)).not.toThrow();
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
test('a guest is refused every door', () => {
|
|
180
|
+
setGuest();
|
|
181
|
+
const table = new ReadOpenWriteAdminTable();
|
|
182
|
+
expect(() => new TableAuth().canQuery(table)).toThrow(
|
|
183
|
+
'User is not authorized to query table: identity_read_open_write_admin_test'
|
|
184
|
+
);
|
|
185
|
+
expect(() => new TableAuth().canUpdate(table)).toThrow();
|
|
186
|
+
expect(() => new TableAuth().canInsert(table, 'service')).toThrow();
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
test('one-way: a service block that omits the door keeps the lock on both apis, break-glass included', () => {
|
|
190
|
+
setUser(['admin']);
|
|
191
|
+
const table = new LockedLedgerTable();
|
|
192
|
+
expect(new TableAuth().canPerform(table, 'update', 'service')).toBe(false);
|
|
193
|
+
expect(new TableAuth().canPerform(table, 'update', 'db')).toBe(false);
|
|
194
|
+
expect(() => new TableAuth().canUpdate(table)).toThrow(
|
|
195
|
+
'User is not authorized to update records in table: identity_locked_ledger_test'
|
|
196
|
+
);
|
|
197
|
+
expect(() => new TableAuth().canInsert(table, 'service')).toThrow();
|
|
198
|
+
expect(() => new TableAuth().canQuery(table)).not.toThrow();
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
test('a table with no service block keeps its db block as written — admin included', () => {
|
|
202
|
+
setUser(['admin']);
|
|
203
|
+
expect(new TableAuth().canPerform(new QueryOnlyTable(), 'update', 'db')).toBe(false);
|
|
204
|
+
expect(() => new TableAuth().canUpdate(new QueryOnlyTable())).toThrow(
|
|
205
|
+
'User is not authorized to update records in table: identity_query_only_test'
|
|
206
|
+
);
|
|
207
|
+
});
|
|
208
|
+
});
|