@nest-boot/row-level-security 7.0.0 → 7.2.0
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/dist/enums/row-level-security-role.enum.d.ts +7 -0
- package/dist/enums/row-level-security-role.enum.js +12 -0
- package/dist/enums/row-level-security-role.enum.js.map +1 -0
- package/dist/index.d.ts +3 -2
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/index.spec.js +6 -14
- package/dist/index.spec.js.map +1 -1
- package/dist/interfaces/index.d.ts +0 -1
- package/dist/interfaces/index.js +0 -1
- package/dist/interfaces/index.js.map +1 -1
- package/dist/interfaces/policy-options.interface.d.ts +2 -2
- package/dist/interfaces/policy-sql-options.interface.d.ts +2 -2
- package/dist/row-level-security-driver.d.ts +15 -0
- package/dist/row-level-security-driver.js +136 -0
- package/dist/row-level-security-driver.js.map +1 -0
- package/dist/row-level-security-driver.spec.js +267 -0
- package/dist/row-level-security-driver.spec.js.map +1 -0
- package/dist/row-level-security-migration-generator.d.ts +1 -0
- package/dist/row-level-security-migration-generator.js +39 -8
- package/dist/row-level-security-migration-generator.js.map +1 -1
- package/dist/row-level-security-migration-generator.spec.js +181 -10
- package/dist/row-level-security-migration-generator.spec.js.map +1 -1
- package/dist/row-level-security-migration.d.ts +2 -4
- package/dist/row-level-security-migration.js +9 -7
- package/dist/row-level-security-migration.js.map +1 -1
- package/dist/row-level-security-migration.spec.js +7 -16
- package/dist/row-level-security-migration.spec.js.map +1 -1
- package/dist/row-level-security.d.ts +29 -0
- package/dist/row-level-security.js +69 -0
- package/dist/row-level-security.js.map +1 -0
- package/dist/row-level-security.spec.js +52 -0
- package/dist/row-level-security.spec.js.map +1 -0
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/dist/utils/create-policy-bootstrap-sql-statements.d.ts +1 -1
- package/dist/utils/create-policy-bootstrap-sql-statements.js +1 -7
- package/dist/utils/create-policy-bootstrap-sql-statements.js.map +1 -1
- package/dist/utils/create-policy-privilege-down-sql-statements.d.ts +8 -0
- package/dist/utils/create-policy-privilege-down-sql-statements.js +93 -0
- package/dist/utils/create-policy-privilege-down-sql-statements.js.map +1 -0
- package/dist/utils/create-policy-role-sql-statements.d.ts +6 -0
- package/dist/utils/create-policy-role-sql-statements.js +48 -0
- package/dist/utils/create-policy-role-sql-statements.js.map +1 -0
- package/dist/utils/create-policy-up-sql-statements.js +8 -2
- package/dist/utils/create-policy-up-sql-statements.js.map +1 -1
- package/dist/utils/create-row-level-security-transaction-setup.d.ts +20 -0
- package/dist/utils/create-row-level-security-transaction-setup.js +53 -0
- package/dist/utils/create-row-level-security-transaction-setup.js.map +1 -0
- package/dist/utils/index.d.ts +2 -3
- package/dist/utils/index.js +2 -3
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/policy-migration-sql.spec.js +125 -7
- package/dist/utils/policy-migration-sql.spec.js.map +1 -1
- package/package.json +4 -4
- package/dist/interfaces/row-level-security-options.interface.d.ts +0 -18
- package/dist/interfaces/row-level-security-options.interface.js +0 -3
- package/dist/interfaces/row-level-security-options.interface.js.map +0 -1
- package/dist/row-level-security-context.d.ts +0 -14
- package/dist/row-level-security-context.js +0 -38
- package/dist/row-level-security-context.js.map +0 -1
- package/dist/row-level-security-context.spec.js +0 -29
- package/dist/row-level-security-context.spec.js.map +0 -1
- package/dist/row-level-security-entity-manager.d.ts +0 -22
- package/dist/row-level-security-entity-manager.js +0 -135
- package/dist/row-level-security-entity-manager.js.map +0 -1
- package/dist/row-level-security-entity-manager.spec.js +0 -200
- package/dist/row-level-security-entity-manager.spec.js.map +0 -1
- package/dist/tsconfig.tsbuildinfo +0 -1
- package/dist/utils/default-row-level-security-options.d.ts +0 -3
- package/dist/utils/default-row-level-security-options.js +0 -9
- package/dist/utils/default-row-level-security-options.js.map +0 -1
- package/dist/utils/get-row-level-security-options.d.ts +0 -8
- package/dist/utils/get-row-level-security-options.js +0 -9
- package/dist/utils/get-row-level-security-options.js.map +0 -1
- package/dist/utils/policy-sql-options.d.ts +0 -12
- package/dist/utils/policy-sql-options.js +0 -3
- package/dist/utils/policy-sql-options.js.map +0 -1
- package/dist/utils/row-level-security-options-state.d.ts +0 -4
- package/dist/utils/row-level-security-options-state.js +0 -8
- package/dist/utils/row-level-security-options-state.js.map +0 -1
- package/dist/utils/set-row-level-security-options.d.ts +0 -3
- package/dist/utils/set-row-level-security-options.js +0 -13
- package/dist/utils/set-row-level-security-options.js.map +0 -1
- /package/dist/{row-level-security-context.spec.d.ts → row-level-security-driver.spec.d.ts} +0 -0
- /package/dist/{row-level-security-entity-manager.spec.d.ts → row-level-security.spec.d.ts} +0 -0
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"row-level-security-options.interface.js","sourceRoot":"","sources":["../../src/interfaces/row-level-security-options.interface.ts"],"names":[],"mappings":""}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { RowLevelSecurityContextValue, SnakeCase } from "./utils/row-level-security-context-builder.types";
|
|
2
|
-
/** Request-scoped row-level security role and context helpers. */
|
|
3
|
-
export declare class RowLevelSecurityContext {
|
|
4
|
-
/** Stores the database role that should be applied to the next RLS transaction. */
|
|
5
|
-
static setRole(role: string): void;
|
|
6
|
-
/** Reads the request-scoped database role, if one is active. */
|
|
7
|
-
static getRole(): string | undefined;
|
|
8
|
-
/** Stores a context value that will be converted to a PostgreSQL setting. */
|
|
9
|
-
static set<S extends string>(key: SnakeCase<S>, value: RowLevelSecurityContextValue): void;
|
|
10
|
-
/** Reads a request-scoped context value by key. */
|
|
11
|
-
static get<S extends string>(key: SnakeCase<S>): RowLevelSecurityContextValue;
|
|
12
|
-
/** Returns all request-scoped context entries for RLS transaction setup. */
|
|
13
|
-
static entries(): [string, RowLevelSecurityContextValue][];
|
|
14
|
-
}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.RowLevelSecurityContext = void 0;
|
|
4
|
-
const request_context_1 = require("@nest-boot/request-context");
|
|
5
|
-
const ROW_LEVEL_SECURITY_CONTEXT = Symbol("ROW_LEVEL_SECURITY_CONTEXT");
|
|
6
|
-
const ROW_LEVEL_SECURITY_ROLE = Symbol("ROW_LEVEL_SECURITY_ROLE");
|
|
7
|
-
/** Request-scoped row-level security role and context helpers. */
|
|
8
|
-
class RowLevelSecurityContext {
|
|
9
|
-
/** Stores the database role that should be applied to the next RLS transaction. */
|
|
10
|
-
static setRole(role) {
|
|
11
|
-
request_context_1.RequestContext.set(ROW_LEVEL_SECURITY_ROLE, role);
|
|
12
|
-
}
|
|
13
|
-
/** Reads the request-scoped database role, if one is active. */
|
|
14
|
-
static getRole() {
|
|
15
|
-
return request_context_1.RequestContext.isActive()
|
|
16
|
-
? request_context_1.RequestContext.get(ROW_LEVEL_SECURITY_ROLE)
|
|
17
|
-
: undefined;
|
|
18
|
-
}
|
|
19
|
-
/** Stores a context value that will be converted to a PostgreSQL setting. */
|
|
20
|
-
static set(key, value) {
|
|
21
|
-
const context = request_context_1.RequestContext.getOrSet(ROW_LEVEL_SECURITY_CONTEXT, new Map());
|
|
22
|
-
context.set(key, value);
|
|
23
|
-
}
|
|
24
|
-
/** Reads a request-scoped context value by key. */
|
|
25
|
-
static get(key) {
|
|
26
|
-
return request_context_1.RequestContext.isActive()
|
|
27
|
-
? request_context_1.RequestContext.get(ROW_LEVEL_SECURITY_CONTEXT)?.get(key)
|
|
28
|
-
: undefined;
|
|
29
|
-
}
|
|
30
|
-
/** Returns all request-scoped context entries for RLS transaction setup. */
|
|
31
|
-
static entries() {
|
|
32
|
-
return request_context_1.RequestContext.isActive()
|
|
33
|
-
? Array.from(request_context_1.RequestContext.get(ROW_LEVEL_SECURITY_CONTEXT) ?? [])
|
|
34
|
-
: [];
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
exports.RowLevelSecurityContext = RowLevelSecurityContext;
|
|
38
|
-
//# sourceMappingURL=row-level-security-context.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"row-level-security-context.js","sourceRoot":"","sources":["../src/row-level-security-context.ts"],"names":[],"mappings":";;;AAAA,gEAA4D;AAS5D,MAAM,0BAA0B,GAAG,MAAM,CAAC,4BAA4B,CAAC,CAAC;AACxE,MAAM,uBAAuB,GAAG,MAAM,CAAC,yBAAyB,CAAC,CAAC;AAElE,kEAAkE;AAClE,MAAa,uBAAuB;IAClC,mFAAmF;IACnF,MAAM,CAAC,OAAO,CAAC,IAAY;QACzB,gCAAc,CAAC,GAAG,CAAC,uBAAuB,EAAE,IAAI,CAAC,CAAC;IACpD,CAAC;IAED,gEAAgE;IAChE,MAAM,CAAC,OAAO;QACZ,OAAO,gCAAc,CAAC,QAAQ,EAAE;YAC9B,CAAC,CAAC,gCAAc,CAAC,GAAG,CAAS,uBAAuB,CAAC;YACrD,CAAC,CAAC,SAAS,CAAC;IAChB,CAAC;IAED,6EAA6E;IAC7E,MAAM,CAAC,GAAG,CACR,GAAiB,EACjB,KAAmC;QAEnC,MAAM,OAAO,GAAG,gCAAc,CAAC,QAAQ,CACrC,0BAA0B,EAC1B,IAAI,GAAG,EAAE,CACV,CAAC;QAEF,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IAC1B,CAAC;IAED,mDAAmD;IACnD,MAAM,CAAC,GAAG,CACR,GAAiB;QAEjB,OAAO,gCAAc,CAAC,QAAQ,EAAE;YAC9B,CAAC,CAAC,gCAAc,CAAC,GAAG,CAChB,0BAA0B,CAC3B,EAAE,GAAG,CAAC,GAAG,CAAC;YACb,CAAC,CAAC,SAAS,CAAC;IAChB,CAAC;IAED,4EAA4E;IAC5E,MAAM,CAAC,OAAO;QACZ,OAAO,gCAAc,CAAC,QAAQ,EAAE;YAC9B,CAAC,CAAC,KAAK,CAAC,IAAI,CACR,gCAAc,CAAC,GAAG,CAChB,0BAA0B,CAC3B,IAAI,EAAE,CACR;YACH,CAAC,CAAC,EAAE,CAAC;IACT,CAAC;CACF;AA/CD,0DA+CC"}
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const request_context_1 = require("@nest-boot/request-context");
|
|
4
|
-
const row_level_security_context_1 = require("./row-level-security-context");
|
|
5
|
-
describe("RowLevelSecurityContext", () => {
|
|
6
|
-
it("stores the database role in RequestContext", async () => {
|
|
7
|
-
await request_context_1.RequestContext.run(new request_context_1.RequestContext({ type: "http" }), () => {
|
|
8
|
-
row_level_security_context_1.RowLevelSecurityContext.setRole("authenticated");
|
|
9
|
-
expect(row_level_security_context_1.RowLevelSecurityContext.getRole()).toBe("authenticated");
|
|
10
|
-
});
|
|
11
|
-
});
|
|
12
|
-
it("stores policy context values in RequestContext", async () => {
|
|
13
|
-
await request_context_1.RequestContext.run(new request_context_1.RequestContext({ type: "http" }), () => {
|
|
14
|
-
row_level_security_context_1.RowLevelSecurityContext.set("tenant_id", "42");
|
|
15
|
-
row_level_security_context_1.RowLevelSecurityContext.set("user_id", 7);
|
|
16
|
-
expect(row_level_security_context_1.RowLevelSecurityContext.get("tenant_id")).toBe("42");
|
|
17
|
-
expect(row_level_security_context_1.RowLevelSecurityContext.entries()).toEqual([
|
|
18
|
-
["tenant_id", "42"],
|
|
19
|
-
["user_id", 7],
|
|
20
|
-
]);
|
|
21
|
-
});
|
|
22
|
-
});
|
|
23
|
-
it("returns empty values when RequestContext is inactive", () => {
|
|
24
|
-
expect(row_level_security_context_1.RowLevelSecurityContext.getRole()).toBeUndefined();
|
|
25
|
-
expect(row_level_security_context_1.RowLevelSecurityContext.get("tenant_id")).toBeUndefined();
|
|
26
|
-
expect(row_level_security_context_1.RowLevelSecurityContext.entries()).toEqual([]);
|
|
27
|
-
});
|
|
28
|
-
});
|
|
29
|
-
//# sourceMappingURL=row-level-security-context.spec.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"row-level-security-context.spec.js","sourceRoot":"","sources":["../src/row-level-security-context.spec.ts"],"names":[],"mappings":";;AAAA,gEAA4D;AAE5D,6EAAuE;AAEvE,QAAQ,CAAC,yBAAyB,EAAE,GAAG,EAAE;IACvC,EAAE,CAAC,4CAA4C,EAAE,KAAK,IAAI,EAAE;QAC1D,MAAM,gCAAc,CAAC,GAAG,CAAC,IAAI,gCAAc,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,GAAG,EAAE;YAClE,oDAAuB,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;YAEjD,MAAM,CAAC,oDAAuB,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;QAClE,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gDAAgD,EAAE,KAAK,IAAI,EAAE;QAC9D,MAAM,gCAAc,CAAC,GAAG,CAAC,IAAI,gCAAc,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,GAAG,EAAE;YAClE,oDAAuB,CAAC,GAAG,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;YAC/C,oDAAuB,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;YAE1C,MAAM,CAAC,oDAAuB,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC5D,MAAM,CAAC,oDAAuB,CAAC,OAAO,EAAE,CAAC,CAAC,OAAO,CAAC;gBAChD,CAAC,WAAW,EAAE,IAAI,CAAC;gBACnB,CAAC,SAAS,EAAE,CAAC,CAAC;aACf,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sDAAsD,EAAE,GAAG,EAAE;QAC9D,MAAM,CAAC,oDAAuB,CAAC,OAAO,EAAE,CAAC,CAAC,aAAa,EAAE,CAAC;QAC1D,MAAM,CAAC,oDAAuB,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,aAAa,EAAE,CAAC;QACjE,MAAM,CAAC,oDAAuB,CAAC,OAAO,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IACxD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { CountOptions, Cursor, DeleteOptions, EntityData, EntityManager, EntityName, FilterQuery, FindAllOptions, FindByCursorOptions, FindOneOptions, FindOneOrFailOptions, FindOptions, Loaded, NativeInsertUpdateOptions, NoInfer, PopulatePath, Primary, RequiredEntityData, TransactionOptions, UpdateOptions, UpsertManyOptions, UpsertOptions } from "@mikro-orm/postgresql";
|
|
2
|
-
/**
|
|
3
|
-
* MikroORM entity manager that wraps database operations in transactions with
|
|
4
|
-
* transaction-local PostgreSQL role and context settings.
|
|
5
|
-
*/
|
|
6
|
-
export declare class RowLevelSecurityEntityManager extends EntityManager {
|
|
7
|
-
transactional<T>(cb: (em: this) => T | Promise<T>, options?: TransactionOptions): Promise<T>;
|
|
8
|
-
find<Entity extends object, Hint extends string = never, Fields extends string = PopulatePath.ALL, Excludes extends string = never>(entityName: EntityName<Entity>, where: FilterQuery<NoInfer<Entity>>, options?: FindOptions<Entity, Hint, Fields, Excludes>): Promise<Loaded<Entity, Hint, Fields, Excludes>[]>;
|
|
9
|
-
findAll<Entity extends object, Hint extends string = never, Fields extends string = "*", Excludes extends string = never>(entityName: EntityName<Entity>, options?: FindAllOptions<NoInfer<Entity>, Hint, Fields, Excludes>): Promise<Loaded<Entity, Hint, Fields, Excludes>[]>;
|
|
10
|
-
findOne<Entity extends object, Hint extends string = never, Fields extends string = "*", Excludes extends string = never>(entityName: EntityName<Entity>, where: FilterQuery<NoInfer<Entity>>, options?: FindOneOptions<Entity, Hint, Fields, Excludes>): Promise<Loaded<Entity, Hint, Fields, Excludes> | null>;
|
|
11
|
-
findOneOrFail<Entity extends object, Hint extends string = never, Fields extends string = "*", Excludes extends string = never>(entityName: EntityName<Entity>, where: FilterQuery<NoInfer<Entity>>, options?: FindOneOrFailOptions<Entity, Hint, Fields, Excludes>): Promise<Loaded<Entity, Hint, Fields, Excludes>>;
|
|
12
|
-
findAndCount<Entity extends object, Hint extends string = never, Fields extends string = PopulatePath.ALL, Excludes extends string = never>(entityName: EntityName<Entity>, where: FilterQuery<NoInfer<Entity>>, options?: FindOptions<Entity, Hint, Fields, Excludes>): Promise<[Loaded<Entity, Hint, Fields, Excludes>[], number]>;
|
|
13
|
-
findByCursor<Entity extends object, Hint extends string = never, Fields extends string = "*", Excludes extends string = never, IncludeCount extends boolean = true>(entityName: EntityName<Entity>, where: FilterQuery<NoInfer<Entity>>, options: FindByCursorOptions<Entity, Hint, Fields, Excludes, IncludeCount>): Promise<Cursor<Entity, Hint, Fields, Excludes, IncludeCount>>;
|
|
14
|
-
count<Entity extends object, Hint extends string = never>(entityName: EntityName<Entity>, where?: FilterQuery<NoInfer<Entity>>, options?: CountOptions<Entity, Hint>): Promise<number>;
|
|
15
|
-
insert<Entity extends object>(entityNameOrEntity: EntityName<Entity> | Entity, data?: RequiredEntityData<Entity> | Entity, options?: NativeInsertUpdateOptions<Entity>): Promise<Primary<Entity>>;
|
|
16
|
-
insertMany<Entity extends object>(entityNameOrEntities: EntityName<Entity> | Entity[], data?: RequiredEntityData<Entity>[] | Entity[], options?: NativeInsertUpdateOptions<Entity>): Promise<Primary<Entity>[]>;
|
|
17
|
-
nativeUpdate<Entity extends object>(entityName: EntityName<Entity>, where: FilterQuery<NoInfer<Entity>>, data: EntityData<Entity>, options?: UpdateOptions<Entity>): Promise<number>;
|
|
18
|
-
nativeDelete<Entity extends object>(entityName: EntityName<Entity>, where: FilterQuery<NoInfer<Entity>>, options?: DeleteOptions<Entity>): Promise<number>;
|
|
19
|
-
upsert<Entity extends object, Fields extends string = any>(entityNameOrEntity: EntityName<Entity> | Entity, data?: EntityData<Entity> | NoInfer<Entity>, options?: UpsertOptions<Entity, Fields>): Promise<Entity>;
|
|
20
|
-
upsertMany<Entity extends object, Fields extends string = any>(entityNameOrEntity: EntityName<Entity> | Entity[], data?: (EntityData<Entity> | NoInfer<Entity>)[], options?: UpsertManyOptions<Entity, Fields>): Promise<Entity[]>;
|
|
21
|
-
flush(): Promise<void>;
|
|
22
|
-
}
|
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.RowLevelSecurityEntityManager = void 0;
|
|
4
|
-
const postgresql_1 = require("@mikro-orm/postgresql");
|
|
5
|
-
const row_level_security_context_1 = require("./row-level-security-context");
|
|
6
|
-
const assert_snake_case_1 = require("./utils/assert-snake-case");
|
|
7
|
-
const get_row_level_security_options_1 = require("./utils/get-row-level-security-options");
|
|
8
|
-
const row_level_security_context_builder_1 = require("./utils/row-level-security-context-builder");
|
|
9
|
-
/**
|
|
10
|
-
* MikroORM entity manager that wraps database operations in transactions with
|
|
11
|
-
* transaction-local PostgreSQL role and context settings.
|
|
12
|
-
*/
|
|
13
|
-
class RowLevelSecurityEntityManager extends postgresql_1.EntityManager {
|
|
14
|
-
async transactional(cb, options) {
|
|
15
|
-
const rowLevelSecurityOptions = (0, get_row_level_security_options_1.getRowLevelSecurityOptions)();
|
|
16
|
-
if (rowLevelSecurityOptions.shouldApply &&
|
|
17
|
-
!(await rowLevelSecurityOptions.shouldApply())) {
|
|
18
|
-
return await super.transactional(cb, options);
|
|
19
|
-
}
|
|
20
|
-
return await super.transactional(async (em) => {
|
|
21
|
-
const knex = em.getTransactionContext();
|
|
22
|
-
if (!knex) {
|
|
23
|
-
throw new Error("Transaction context is not available. Ensure you are calling this method within a transaction.");
|
|
24
|
-
}
|
|
25
|
-
const builder = new row_level_security_context_builder_1.RowLevelSecurityContextBuilder();
|
|
26
|
-
const role = row_level_security_context_1.RowLevelSecurityContext.getRole() ??
|
|
27
|
-
((await rowLevelSecurityOptions.isAuthenticated?.())
|
|
28
|
-
? (rowLevelSecurityOptions.authenticatedRole ?? "authenticated")
|
|
29
|
-
: (rowLevelSecurityOptions.anonymousRole ?? "anonymous"));
|
|
30
|
-
const context = await rowLevelSecurityOptions.getContext?.();
|
|
31
|
-
appendContext(builder, context);
|
|
32
|
-
appendContext(builder, row_level_security_context_1.RowLevelSecurityContext.entries());
|
|
33
|
-
(0, assert_snake_case_1.assertSnakeCase)(role, "Row level security database role");
|
|
34
|
-
await knex.raw([
|
|
35
|
-
/* SQL */ `SET LOCAL ROLE ${role};`,
|
|
36
|
-
builder.entries().length > 0 ? builder.toSQL() : "",
|
|
37
|
-
]
|
|
38
|
-
.filter(Boolean)
|
|
39
|
-
.join("\n"));
|
|
40
|
-
return await cb(em);
|
|
41
|
-
}, options);
|
|
42
|
-
}
|
|
43
|
-
find(entityName, where, options) {
|
|
44
|
-
if (this.isInTransaction()) {
|
|
45
|
-
return super.find(entityName, where, options);
|
|
46
|
-
}
|
|
47
|
-
return this.transactional((em) => em.find(entityName, where, options));
|
|
48
|
-
}
|
|
49
|
-
findAll(entityName, options) {
|
|
50
|
-
if (this.isInTransaction()) {
|
|
51
|
-
return super.findAll(entityName, options);
|
|
52
|
-
}
|
|
53
|
-
return this.transactional((em) => em.findAll(entityName, options));
|
|
54
|
-
}
|
|
55
|
-
findOne(entityName, where, options) {
|
|
56
|
-
if (this.isInTransaction()) {
|
|
57
|
-
return super.findOne(entityName, where, options);
|
|
58
|
-
}
|
|
59
|
-
return this.transactional((em) => em.findOne(entityName, where, options));
|
|
60
|
-
}
|
|
61
|
-
findOneOrFail(entityName, where, options) {
|
|
62
|
-
if (this.isInTransaction()) {
|
|
63
|
-
return super.findOneOrFail(entityName, where, options);
|
|
64
|
-
}
|
|
65
|
-
return this.transactional((em) => em.findOneOrFail(entityName, where, options));
|
|
66
|
-
}
|
|
67
|
-
findAndCount(entityName, where, options) {
|
|
68
|
-
if (this.isInTransaction()) {
|
|
69
|
-
return super.findAndCount(entityName, where, options);
|
|
70
|
-
}
|
|
71
|
-
return this.transactional((em) => em.findAndCount(entityName, where, options));
|
|
72
|
-
}
|
|
73
|
-
findByCursor(entityName, where, options) {
|
|
74
|
-
if (this.isInTransaction()) {
|
|
75
|
-
return super.findByCursor(entityName, where, options);
|
|
76
|
-
}
|
|
77
|
-
return this.transactional((em) => em.findByCursor(entityName, where, options));
|
|
78
|
-
}
|
|
79
|
-
count(entityName, where, options) {
|
|
80
|
-
if (this.isInTransaction()) {
|
|
81
|
-
return super.count(entityName, where, options);
|
|
82
|
-
}
|
|
83
|
-
return this.transactional((em) => em.count(entityName, where, options));
|
|
84
|
-
}
|
|
85
|
-
insert(entityNameOrEntity, data, options) {
|
|
86
|
-
if (this.isInTransaction()) {
|
|
87
|
-
return super.insert(entityNameOrEntity, data, options);
|
|
88
|
-
}
|
|
89
|
-
return this.transactional((em) => em.insert(entityNameOrEntity, data, options));
|
|
90
|
-
}
|
|
91
|
-
// @ts-expect-error - MikroORM type duplication/deep mapped type collision
|
|
92
|
-
insertMany(entityNameOrEntities, data, options) {
|
|
93
|
-
if (this.isInTransaction()) {
|
|
94
|
-
return super.insertMany(entityNameOrEntities, data, options);
|
|
95
|
-
}
|
|
96
|
-
return this.transactional((em) => em.insertMany(entityNameOrEntities, data, options));
|
|
97
|
-
}
|
|
98
|
-
nativeUpdate(entityName, where, data, options) {
|
|
99
|
-
if (this.isInTransaction()) {
|
|
100
|
-
return super.nativeUpdate(entityName, where, data, options);
|
|
101
|
-
}
|
|
102
|
-
return this.transactional((em) => em.nativeUpdate(entityName, where, data, options));
|
|
103
|
-
}
|
|
104
|
-
nativeDelete(entityName, where, options) {
|
|
105
|
-
if (this.isInTransaction()) {
|
|
106
|
-
return super.nativeDelete(entityName, where, options);
|
|
107
|
-
}
|
|
108
|
-
return this.transactional((em) => em.nativeDelete(entityName, where, options));
|
|
109
|
-
}
|
|
110
|
-
upsert(entityNameOrEntity, data, options) {
|
|
111
|
-
if (this.isInTransaction()) {
|
|
112
|
-
return super.upsert(entityNameOrEntity, data, options);
|
|
113
|
-
}
|
|
114
|
-
return this.transactional((em) => em.upsert(entityNameOrEntity, data, options));
|
|
115
|
-
}
|
|
116
|
-
upsertMany(entityNameOrEntity, data, options) {
|
|
117
|
-
if (this.isInTransaction()) {
|
|
118
|
-
return super.upsertMany(entityNameOrEntity, data, options);
|
|
119
|
-
}
|
|
120
|
-
return this.transactional((em) => em.upsertMany(entityNameOrEntity, data, options));
|
|
121
|
-
}
|
|
122
|
-
flush() {
|
|
123
|
-
if (this.isInTransaction()) {
|
|
124
|
-
return super.flush();
|
|
125
|
-
}
|
|
126
|
-
return this.transactional((em) => em.flush());
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
exports.RowLevelSecurityEntityManager = RowLevelSecurityEntityManager;
|
|
130
|
-
function appendContext(builder, context) {
|
|
131
|
-
for (const [key, value] of context ?? []) {
|
|
132
|
-
builder.set(key, value);
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
//# sourceMappingURL=row-level-security-entity-manager.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"row-level-security-entity-manager.js","sourceRoot":"","sources":["../src/row-level-security-entity-manager.ts"],"names":[],"mappings":";;;AAAA,sDAwB+B;AAE/B,6EAAuE;AACvE,iEAA4D;AAC5D,2FAAoF;AACpF,mGAA4F;AAG5F;;;GAGG;AACH,MAAa,6BAA8B,SAAQ,0BAAa;IAC9D,KAAK,CAAC,aAAa,CACjB,EAAgC,EAChC,OAA4B;QAE5B,MAAM,uBAAuB,GAAG,IAAA,2DAA0B,GAAE,CAAC;QAE7D,IACE,uBAAuB,CAAC,WAAW;YACnC,CAAC,CAAC,MAAM,uBAAuB,CAAC,WAAW,EAAE,CAAC,EAC9C,CAAC;YACD,OAAO,MAAM,KAAK,CAAC,aAAa,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;QAChD,CAAC;QAED,OAAO,MAAM,KAAK,CAAC,aAAa,CAAC,KAAK,EAAE,EAAE,EAAE,EAAE;YAC5C,MAAM,IAAI,GAAG,EAAE,CAAC,qBAAqB,EAAQ,CAAC;YAE9C,IAAI,CAAC,IAAI,EAAE,CAAC;gBACV,MAAM,IAAI,KAAK,CACb,gGAAgG,CACjG,CAAC;YACJ,CAAC;YAED,MAAM,OAAO,GAAG,IAAI,mEAA8B,EAAE,CAAC;YACrD,MAAM,IAAI,GACR,oDAAuB,CAAC,OAAO,EAAE;gBACjC,CAAC,CAAC,MAAM,uBAAuB,CAAC,eAAe,EAAE,EAAE,CAAC;oBAClD,CAAC,CAAC,CAAC,uBAAuB,CAAC,iBAAiB,IAAI,eAAe,CAAC;oBAChE,CAAC,CAAC,CAAC,uBAAuB,CAAC,aAAa,IAAI,WAAW,CAAC,CAAC,CAAC;YAC9D,MAAM,OAAO,GAAG,MAAM,uBAAuB,CAAC,UAAU,EAAE,EAAE,CAAC;YAE7D,aAAa,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;YAChC,aAAa,CAAC,OAAO,EAAE,oDAAuB,CAAC,OAAO,EAAE,CAAC,CAAC;YAE1D,IAAA,mCAAe,EAAC,IAAI,EAAE,kCAAkC,CAAC,CAAC;YAC1D,MAAM,IAAI,CAAC,GAAG,CACZ;gBACE,SAAS,CAAC,kBAAkB,IAAI,GAAG;gBACnC,OAAO,CAAC,OAAO,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE;aACpD;iBACE,MAAM,CAAC,OAAO,CAAC;iBACf,IAAI,CAAC,IAAI,CAAC,CACd,CAAC;YAEF,OAAO,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC;QACtB,CAAC,EAAE,OAAO,CAAC,CAAC;IACd,CAAC;IAED,IAAI,CAMF,UAA8B,EAC9B,KAAmC,EACnC,OAAqD;QAErD,IAAI,IAAI,CAAC,eAAe,EAAE,EAAE,CAAC;YAC3B,OAAO,KAAK,CAAC,IAAI,CAAC,UAAU,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;QAChD,CAAC;QAED,OAAO,IAAI,CAAC,aAAa,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,UAAU,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC;IACzE,CAAC;IAED,OAAO,CAML,UAA8B,EAC9B,OAAiE;QAEjE,IAAI,IAAI,CAAC,eAAe,EAAE,EAAE,CAAC;YAC3B,OAAO,KAAK,CAAC,OAAO,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;QAC5C,CAAC;QAED,OAAO,IAAI,CAAC,aAAa,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC;IACrE,CAAC;IAED,OAAO,CAML,UAA8B,EAC9B,KAAmC,EACnC,OAAwD;QAExD,IAAI,IAAI,CAAC,eAAe,EAAE,EAAE,CAAC;YAC3B,OAAO,KAAK,CAAC,OAAO,CAAC,UAAU,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;QACnD,CAAC;QAED,OAAO,IAAI,CAAC,aAAa,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,UAAU,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC;IAC5E,CAAC;IAED,aAAa,CAMX,UAA8B,EAC9B,KAAmC,EACnC,OAA8D;QAE9D,IAAI,IAAI,CAAC,eAAe,EAAE,EAAE,CAAC;YAC3B,OAAO,KAAK,CAAC,aAAa,CAAC,UAAU,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;QACzD,CAAC;QAED,OAAO,IAAI,CAAC,aAAa,CAAC,CAAC,EAAE,EAAE,EAAE,CAC/B,EAAE,CAAC,aAAa,CAAC,UAAU,EAAE,KAAK,EAAE,OAAO,CAAC,CAC7C,CAAC;IACJ,CAAC;IAED,YAAY,CAMV,UAA8B,EAC9B,KAAmC,EACnC,OAAqD;QAErD,IAAI,IAAI,CAAC,eAAe,EAAE,EAAE,CAAC;YAC3B,OAAO,KAAK,CAAC,YAAY,CAAC,UAAU,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;QACxD,CAAC;QAED,OAAO,IAAI,CAAC,aAAa,CAAC,CAAC,EAAE,EAAE,EAAE,CAC/B,EAAE,CAAC,YAAY,CAAC,UAAU,EAAE,KAAK,EAAE,OAAO,CAAC,CAC5C,CAAC;IACJ,CAAC;IAED,YAAY,CAOV,UAA8B,EAC9B,KAAmC,EACnC,OAA0E;QAE1E,IAAI,IAAI,CAAC,eAAe,EAAE,EAAE,CAAC;YAC3B,OAAO,KAAK,CAAC,YAAY,CAAC,UAAU,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;QACxD,CAAC;QAED,OAAO,IAAI,CAAC,aAAa,CAAC,CAAC,EAAE,EAAE,EAAE,CAC/B,EAAE,CAAC,YAAY,CAAC,UAAU,EAAE,KAAK,EAAE,OAAO,CAAC,CAC5C,CAAC;IACJ,CAAC;IAED,KAAK,CACH,UAA8B,EAC9B,KAAoC,EACpC,OAAoC;QAEpC,IAAI,IAAI,CAAC,eAAe,EAAE,EAAE,CAAC;YAC3B,OAAO,KAAK,CAAC,KAAK,CAAC,UAAU,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;QACjD,CAAC;QAED,OAAO,IAAI,CAAC,aAAa,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,UAAU,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC;IAC1E,CAAC;IAED,MAAM,CACJ,kBAA+C,EAC/C,IAA0C,EAC1C,OAA2C;QAE3C,IAAI,IAAI,CAAC,eAAe,EAAE,EAAE,CAAC;YAC3B,OAAO,KAAK,CAAC,MAAM,CAAC,kBAAkB,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;QACzD,CAAC;QAED,OAAO,IAAI,CAAC,aAAa,CAAC,CAAC,EAAE,EAAE,EAAE,CAC/B,EAAE,CAAC,MAAM,CAAC,kBAAkB,EAAE,IAAI,EAAE,OAAO,CAAC,CAC7C,CAAC;IACJ,CAAC;IAED,0EAA0E;IAC1E,UAAU,CACR,oBAAmD,EACnD,IAA8C,EAC9C,OAA2C;QAE3C,IAAI,IAAI,CAAC,eAAe,EAAE,EAAE,CAAC;YAC3B,OAAO,KAAK,CAAC,UAAU,CACrB,oBAA2B,EAC3B,IAAW,EACX,OAAO,CACD,CAAC;QACX,CAAC;QAED,OAAO,IAAI,CAAC,aAAa,CACvB,CAAC,EAAE,EAAE,EAAE,CACL,EAAE,CAAC,UAAU,CAAC,oBAA2B,EAAE,IAAW,EAAE,OAAO,CAAQ,CAC1E,CAAC;IACJ,CAAC;IAED,YAAY,CACV,UAA8B,EAC9B,KAAmC,EACnC,IAAwB,EACxB,OAA+B;QAE/B,IAAI,IAAI,CAAC,eAAe,EAAE,EAAE,CAAC;YAC3B,OAAO,KAAK,CAAC,YAAY,CAAC,UAAU,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;QAC9D,CAAC;QAED,OAAO,IAAI,CAAC,aAAa,CAAC,CAAC,EAAE,EAAE,EAAE,CAC/B,EAAE,CAAC,YAAY,CAAC,UAAU,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,CAAC,CAClD,CAAC;IACJ,CAAC;IAED,YAAY,CACV,UAA8B,EAC9B,KAAmC,EACnC,OAA+B;QAE/B,IAAI,IAAI,CAAC,eAAe,EAAE,EAAE,CAAC;YAC3B,OAAO,KAAK,CAAC,YAAY,CAAC,UAAU,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;QACxD,CAAC;QAED,OAAO,IAAI,CAAC,aAAa,CAAC,CAAC,EAAE,EAAE,EAAE,CAC/B,EAAE,CAAC,YAAY,CAAC,UAAU,EAAE,KAAK,EAAE,OAAO,CAAC,CAC5C,CAAC;IACJ,CAAC;IAED,MAAM,CACJ,kBAA+C,EAC/C,IAA2C,EAC3C,OAAuC;QAEvC,IAAI,IAAI,CAAC,eAAe,EAAE,EAAE,CAAC;YAC3B,OAAO,KAAK,CAAC,MAAM,CAAC,kBAAkB,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;QACzD,CAAC;QAED,OAAO,IAAI,CAAC,aAAa,CAAC,CAAC,EAAE,EAAE,EAAE,CAC/B,EAAE,CAAC,MAAM,CAAC,kBAAkB,EAAE,IAAI,EAAE,OAAO,CAAC,CAC7C,CAAC;IACJ,CAAC;IAED,UAAU,CACR,kBAAiD,EACjD,IAA+C,EAC/C,OAA2C;QAE3C,IAAI,IAAI,CAAC,eAAe,EAAE,EAAE,CAAC;YAC3B,OAAO,KAAK,CAAC,UAAU,CAAC,kBAAkB,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;QAC7D,CAAC;QAED,OAAO,IAAI,CAAC,aAAa,CAAC,CAAC,EAAE,EAAE,EAAE,CAC/B,EAAE,CAAC,UAAU,CAAC,kBAAkB,EAAE,IAAI,EAAE,OAAO,CAAC,CACjD,CAAC;IACJ,CAAC;IAED,KAAK;QACH,IAAI,IAAI,CAAC,eAAe,EAAE,EAAE,CAAC;YAC3B,OAAO,KAAK,CAAC,KAAK,EAAE,CAAC;QACvB,CAAC;QAED,OAAO,IAAI,CAAC,aAAa,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,CAAC;IAChD,CAAC;CACF;AA1QD,sEA0QC;AAED,SAAS,aAAa,CACpB,OAAuC,EACvC,OAEa;IAEb,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,OAAO,IAAI,EAAE,EAAE,CAAC;QACzC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IAC1B,CAAC;AACH,CAAC"}
|
|
@@ -1,200 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const postgresql_1 = require("@mikro-orm/postgresql");
|
|
4
|
-
const request_context_1 = require("@nest-boot/request-context");
|
|
5
|
-
const row_level_security_context_1 = require("./row-level-security-context");
|
|
6
|
-
const row_level_security_entity_manager_1 = require("./row-level-security-entity-manager");
|
|
7
|
-
const set_row_level_security_options_1 = require("./utils/set-row-level-security-options");
|
|
8
|
-
describe("RowLevelSecurityEntityManager", () => {
|
|
9
|
-
afterEach(() => {
|
|
10
|
-
jest.restoreAllMocks();
|
|
11
|
-
(0, set_row_level_security_options_1.setRowLevelSecurityOptions)();
|
|
12
|
-
});
|
|
13
|
-
it("sets authenticated row level security transaction context", async () => {
|
|
14
|
-
const rawSql = [];
|
|
15
|
-
mockSuperTransactional(rawSql);
|
|
16
|
-
const result = await request_context_1.RequestContext.run(new request_context_1.RequestContext({ type: "http" }), async () => {
|
|
17
|
-
(0, set_row_level_security_options_1.setRowLevelSecurityOptions)({
|
|
18
|
-
authenticatedRole: "app_authenticated",
|
|
19
|
-
isAuthenticated: () => true,
|
|
20
|
-
getContext: () => [["tenant_id", "42"]],
|
|
21
|
-
});
|
|
22
|
-
return await callTransactional();
|
|
23
|
-
});
|
|
24
|
-
expect(result).toBe("transaction-result");
|
|
25
|
-
expect(rawSql).toEqual([
|
|
26
|
-
"SET LOCAL ROLE app_authenticated;\nSELECT set_config('app.tenant_id', '42', true);",
|
|
27
|
-
]);
|
|
28
|
-
});
|
|
29
|
-
it("omits context SQL when no row level security context values are present", async () => {
|
|
30
|
-
const rawSql = [];
|
|
31
|
-
mockSuperTransactional(rawSql);
|
|
32
|
-
await request_context_1.RequestContext.run(new request_context_1.RequestContext({ type: "http" }), async () => {
|
|
33
|
-
await callTransactional();
|
|
34
|
-
});
|
|
35
|
-
expect(rawSql).toEqual(["SET LOCAL ROLE anonymous;"]);
|
|
36
|
-
});
|
|
37
|
-
it("throws when a transaction context is unavailable", async () => {
|
|
38
|
-
jest
|
|
39
|
-
.spyOn(postgresql_1.EntityManager.prototype, "transactional")
|
|
40
|
-
.mockImplementation(async (cb) => {
|
|
41
|
-
return await cb({
|
|
42
|
-
getTransactionContext: () => undefined,
|
|
43
|
-
});
|
|
44
|
-
});
|
|
45
|
-
await expect(request_context_1.RequestContext.run(new request_context_1.RequestContext({ type: "http" }), callTransactional)).rejects.toThrow("Transaction context is not available");
|
|
46
|
-
});
|
|
47
|
-
it("uses the anonymous role when no user is present", async () => {
|
|
48
|
-
const rawSql = [];
|
|
49
|
-
mockSuperTransactional(rawSql);
|
|
50
|
-
await request_context_1.RequestContext.run(new request_context_1.RequestContext({ type: "http" }), async () => {
|
|
51
|
-
(0, set_row_level_security_options_1.setRowLevelSecurityOptions)({
|
|
52
|
-
anonymousRole: "app_anonymous",
|
|
53
|
-
getContext: () => [["tenant_id", "42"]],
|
|
54
|
-
});
|
|
55
|
-
await callTransactional();
|
|
56
|
-
});
|
|
57
|
-
expect(rawSql).toEqual([
|
|
58
|
-
"SET LOCAL ROLE app_anonymous;\nSELECT set_config('app.tenant_id', '42', true);",
|
|
59
|
-
]);
|
|
60
|
-
});
|
|
61
|
-
it("uses the default authenticated role when the tenant authentication marker is present", async () => {
|
|
62
|
-
const rawSql = [];
|
|
63
|
-
mockSuperTransactional(rawSql);
|
|
64
|
-
await request_context_1.RequestContext.run(new request_context_1.RequestContext({ type: "http" }), async () => {
|
|
65
|
-
(0, set_row_level_security_options_1.setRowLevelSecurityOptions)({
|
|
66
|
-
isAuthenticated: () => true,
|
|
67
|
-
getContext: () => [["tenant_id", "42"]],
|
|
68
|
-
});
|
|
69
|
-
await callTransactional();
|
|
70
|
-
});
|
|
71
|
-
expect(rawSql).toEqual([
|
|
72
|
-
"SET LOCAL ROLE authenticated;\nSELECT set_config('app.tenant_id', '42', true);",
|
|
73
|
-
]);
|
|
74
|
-
});
|
|
75
|
-
it("uses the request context role when one is set", async () => {
|
|
76
|
-
const rawSql = [];
|
|
77
|
-
mockSuperTransactional(rawSql);
|
|
78
|
-
await request_context_1.RequestContext.run(new request_context_1.RequestContext({ type: "http" }), async () => {
|
|
79
|
-
row_level_security_context_1.RowLevelSecurityContext.setRole("service_role");
|
|
80
|
-
row_level_security_context_1.RowLevelSecurityContext.set("tenant_id", "42");
|
|
81
|
-
await callTransactional();
|
|
82
|
-
});
|
|
83
|
-
expect(rawSql).toEqual([
|
|
84
|
-
"SET LOCAL ROLE service_role;\nSELECT set_config('app.tenant_id', '42', true);",
|
|
85
|
-
]);
|
|
86
|
-
});
|
|
87
|
-
it("sets additional row level security context values from RequestContext", async () => {
|
|
88
|
-
const rawSql = [];
|
|
89
|
-
mockSuperTransactional(rawSql);
|
|
90
|
-
await request_context_1.RequestContext.run(new request_context_1.RequestContext({ type: "http" }), async () => {
|
|
91
|
-
(0, set_row_level_security_options_1.setRowLevelSecurityOptions)({
|
|
92
|
-
getContext: () => [["tenant_id", "42"]],
|
|
93
|
-
});
|
|
94
|
-
row_level_security_context_1.RowLevelSecurityContext.set("user_id", "7");
|
|
95
|
-
await callTransactional();
|
|
96
|
-
});
|
|
97
|
-
expect(rawSql).toEqual([
|
|
98
|
-
"SET LOCAL ROLE anonymous;\nSELECT set_config('app.tenant_id', '42', true),set_config('app.user_id', '7', true);",
|
|
99
|
-
]);
|
|
100
|
-
});
|
|
101
|
-
it("uses the default anonymous role when the tenant authentication marker is absent", async () => {
|
|
102
|
-
const rawSql = [];
|
|
103
|
-
mockSuperTransactional(rawSql);
|
|
104
|
-
await request_context_1.RequestContext.run(new request_context_1.RequestContext({ type: "http" }), async () => {
|
|
105
|
-
(0, set_row_level_security_options_1.setRowLevelSecurityOptions)({
|
|
106
|
-
getContext: () => [["tenant_id", "42"]],
|
|
107
|
-
});
|
|
108
|
-
await callTransactional();
|
|
109
|
-
});
|
|
110
|
-
expect(rawSql).toEqual([
|
|
111
|
-
"SET LOCAL ROLE anonymous;\nSELECT set_config('app.tenant_id', '42', true);",
|
|
112
|
-
]);
|
|
113
|
-
});
|
|
114
|
-
it("delegates without tenant SQL when shouldApply returns false", async () => {
|
|
115
|
-
const rawSql = [];
|
|
116
|
-
const transactionalSpy = mockSuperTransactional(rawSql);
|
|
117
|
-
(0, set_row_level_security_options_1.setRowLevelSecurityOptions)({
|
|
118
|
-
shouldApply: () => false,
|
|
119
|
-
});
|
|
120
|
-
const result = await callTransactional();
|
|
121
|
-
expect(result).toBe("transaction-result");
|
|
122
|
-
expect(rawSql).toEqual([]);
|
|
123
|
-
expect(transactionalSpy).toHaveBeenCalledTimes(1);
|
|
124
|
-
});
|
|
125
|
-
it("rejects unsafe database role names", async () => {
|
|
126
|
-
const rawSql = [];
|
|
127
|
-
mockSuperTransactional(rawSql);
|
|
128
|
-
(0, set_row_level_security_options_1.setRowLevelSecurityOptions)({
|
|
129
|
-
authenticatedRole: "app.authenticated",
|
|
130
|
-
isAuthenticated: () => true,
|
|
131
|
-
});
|
|
132
|
-
await expect(request_context_1.RequestContext.run(new request_context_1.RequestContext({ type: "http" }), callTransactional)).rejects.toThrow("Row level security database role must be snake_case");
|
|
133
|
-
});
|
|
134
|
-
it.each(getDelegatedMethodCases())("wraps %s in a row level security transaction when outside a transaction", async (methodName, args, result) => {
|
|
135
|
-
const delegatedMethod = jest.fn(() => Promise.resolve(result));
|
|
136
|
-
const transactional = jest.fn(async (cb) => {
|
|
137
|
-
return await cb({
|
|
138
|
-
[methodName]: delegatedMethod,
|
|
139
|
-
});
|
|
140
|
-
});
|
|
141
|
-
const entityManager = {
|
|
142
|
-
isInTransaction: () => false,
|
|
143
|
-
transactional,
|
|
144
|
-
};
|
|
145
|
-
const actual = await row_level_security_entity_manager_1.RowLevelSecurityEntityManager.prototype[methodName].call(entityManager, ...args);
|
|
146
|
-
expect(actual).toBe(result);
|
|
147
|
-
expect(transactional).toHaveBeenCalledTimes(1);
|
|
148
|
-
expect(delegatedMethod.mock.calls[0]?.slice(0, args.length)).toEqual(args);
|
|
149
|
-
});
|
|
150
|
-
it.each(getDelegatedMethodCases())("delegates %s directly when already inside a transaction", async (methodName, args, result) => {
|
|
151
|
-
const superMethod = jest
|
|
152
|
-
.spyOn(postgresql_1.EntityManager.prototype, methodName)
|
|
153
|
-
.mockResolvedValue(result);
|
|
154
|
-
const entityManager = {
|
|
155
|
-
isInTransaction: () => true,
|
|
156
|
-
};
|
|
157
|
-
const actual = await row_level_security_entity_manager_1.RowLevelSecurityEntityManager.prototype[methodName].call(entityManager, ...args);
|
|
158
|
-
expect(actual).toBe(result);
|
|
159
|
-
expect(superMethod.mock.calls[0]?.slice(0, args.length)).toEqual(args);
|
|
160
|
-
});
|
|
161
|
-
});
|
|
162
|
-
function mockSuperTransactional(rawSql) {
|
|
163
|
-
return jest
|
|
164
|
-
.spyOn(postgresql_1.EntityManager.prototype, "transactional")
|
|
165
|
-
.mockImplementation(async (cb) => {
|
|
166
|
-
const em = {
|
|
167
|
-
getTransactionContext: () => ({
|
|
168
|
-
raw: (sql) => {
|
|
169
|
-
rawSql.push(sql);
|
|
170
|
-
return Promise.resolve();
|
|
171
|
-
},
|
|
172
|
-
}),
|
|
173
|
-
};
|
|
174
|
-
return await cb(em);
|
|
175
|
-
});
|
|
176
|
-
}
|
|
177
|
-
async function callTransactional() {
|
|
178
|
-
return await row_level_security_entity_manager_1.RowLevelSecurityEntityManager.prototype.transactional.call({}, () => "transaction-result");
|
|
179
|
-
}
|
|
180
|
-
function getDelegatedMethodCases() {
|
|
181
|
-
class Entity {
|
|
182
|
-
}
|
|
183
|
-
return [
|
|
184
|
-
["find", [Entity, { id: "1" }, { limit: 1 }], [{ id: "1" }]],
|
|
185
|
-
["findAll", [Entity, { limit: 1 }], [{ id: "1" }]],
|
|
186
|
-
["findOne", [Entity, { id: "1" }], { id: "1" }],
|
|
187
|
-
["findOneOrFail", [Entity, { id: "1" }], { id: "1" }],
|
|
188
|
-
["findAndCount", [Entity, { id: "1" }], [[{ id: "1" }], 1]],
|
|
189
|
-
["findByCursor", [Entity, {}, { first: 10 }], { items: [] }],
|
|
190
|
-
["count", [Entity, { active: true }], 1],
|
|
191
|
-
["insert", [Entity, { name: "one" }], "1"],
|
|
192
|
-
["insertMany", [Entity, [{ name: "one" }]], ["1"]],
|
|
193
|
-
["nativeUpdate", [Entity, { id: "1" }, { name: "one" }], 1],
|
|
194
|
-
["nativeDelete", [Entity, { id: "1" }], 1],
|
|
195
|
-
["upsert", [Entity, { id: "1", name: "one" }], { id: "1" }],
|
|
196
|
-
["upsertMany", [Entity, [{ id: "1", name: "one" }]], [{ id: "1" }]],
|
|
197
|
-
["flush", [], undefined],
|
|
198
|
-
];
|
|
199
|
-
}
|
|
200
|
-
//# sourceMappingURL=row-level-security-entity-manager.spec.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"row-level-security-entity-manager.spec.js","sourceRoot":"","sources":["../src/row-level-security-entity-manager.spec.ts"],"names":[],"mappings":"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"}
|