@stratum-hq/lib 1.7.0 → 1.8.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.
Files changed (59) hide show
  1. package/README.md +29 -2
  2. package/dist/crypto.d.ts.map +1 -1
  3. package/dist/crypto.js +50 -10
  4. package/dist/crypto.js.map +1 -1
  5. package/dist/index.d.ts +7 -3
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +17 -1
  8. package/dist/index.js.map +1 -1
  9. package/dist/migrate-schemas.d.ts +4 -0
  10. package/dist/migrate-schemas.d.ts.map +1 -1
  11. package/dist/migrate-schemas.js +16 -6
  12. package/dist/migrate-schemas.js.map +1 -1
  13. package/dist/migrate.d.ts +24 -0
  14. package/dist/migrate.d.ts.map +1 -1
  15. package/dist/migrate.js +44 -6
  16. package/dist/migrate.js.map +1 -1
  17. package/dist/migration-sql.d.ts +25 -0
  18. package/dist/migration-sql.d.ts.map +1 -0
  19. package/dist/migration-sql.js +64 -0
  20. package/dist/migration-sql.js.map +1 -0
  21. package/dist/migrations/029_tenant_parent_cycle_guard.sql +2 -2
  22. package/dist/migrations/031_subtree_read_scope.sql +6 -6
  23. package/dist/migrations/032_control_role.sql +809 -0
  24. package/dist/migrations/033_api_keys_tenant_index.sql +14 -0
  25. package/dist/pinned-query.d.ts +29 -0
  26. package/dist/pinned-query.d.ts.map +1 -0
  27. package/dist/pinned-query.js +60 -0
  28. package/dist/pinned-query.js.map +1 -0
  29. package/dist/pool-helpers.d.ts +2 -0
  30. package/dist/pool-helpers.d.ts.map +1 -1
  31. package/dist/pool-helpers.js +17 -3
  32. package/dist/pool-helpers.js.map +1 -1
  33. package/dist/role-model.d.ts +178 -0
  34. package/dist/role-model.d.ts.map +1 -0
  35. package/dist/role-model.js +670 -0
  36. package/dist/role-model.js.map +1 -0
  37. package/dist/services/api-key-service.d.ts +12 -2
  38. package/dist/services/api-key-service.d.ts.map +1 -1
  39. package/dist/services/api-key-service.js +33 -9
  40. package/dist/services/api-key-service.js.map +1 -1
  41. package/dist/services/config-service.d.ts +15 -6
  42. package/dist/services/config-service.d.ts.map +1 -1
  43. package/dist/services/config-service.js +96 -50
  44. package/dist/services/config-service.js.map +1 -1
  45. package/dist/services/tenant-service.d.ts.map +1 -1
  46. package/dist/services/tenant-service.js +4 -4
  47. package/dist/services/tenant-service.js.map +1 -1
  48. package/dist/stratum-policies.d.ts +51 -0
  49. package/dist/stratum-policies.d.ts.map +1 -0
  50. package/dist/stratum-policies.js +217 -0
  51. package/dist/stratum-policies.js.map +1 -0
  52. package/dist/stratum-tables.d.ts.map +1 -1
  53. package/dist/stratum-tables.js +1 -0
  54. package/dist/stratum-tables.js.map +1 -1
  55. package/dist/stratum.d.ts +52 -7
  56. package/dist/stratum.d.ts.map +1 -1
  57. package/dist/stratum.js +75 -14
  58. package/dist/stratum.js.map +1 -1
  59. package/package.json +5 -5
@@ -0,0 +1,64 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ROLE_NAME = exports.STRATUM_CONTROL_ROLE = void 0;
4
+ exports.assertRoleName = assertRoleName;
5
+ exports.migrationSql = migrationSql;
6
+ exports.isSuperuser = isSuperuser;
7
+ exports.setControlRole = setControlRole;
8
+ exports.setApplyControlRole = setApplyControlRole;
9
+ /** The default name of the NOLOGIN control role (migration 032). */
10
+ exports.STRATUM_CONTROL_ROLE = "stratum_control";
11
+ /** A role name Stratum accepts: a plain lowercase identifier. */
12
+ exports.ROLE_NAME = /^[a-z_][a-z0-9_]{0,62}$/;
13
+ /** Throws when `role` is not a plain lowercase identifier. */
14
+ function assertRoleName(role, what) {
15
+ if (!exports.ROLE_NAME.test(role)) {
16
+ throw new Error(`[stratum] Invalid ${what} '${role}': use lowercase letters, digits and underscores`);
17
+ }
18
+ }
19
+ // Migrations 029 and 031 created their helper functions with
20
+ // `SET app.bypass_rls = 'on'` (and `SET app.tenant_scope = ''`) clauses.
21
+ // PostgreSQL lets only a superuser, or a role granted SET on the parameter,
22
+ // put a custom setting in a function, so a fresh install by a role that is
23
+ // not a superuser stopped at 029. For such a role the runner drops the
24
+ // clauses from these two files. Migration 032 re-creates both functions
25
+ // without them (SECURITY DEFINER, owned by the control role) when it applies
26
+ // the control role, in the same run or later through
27
+ // stratum_apply_control_role(). Until then the functions see what their
28
+ // caller sees, which can only narrow what they return. A superuser runs the
29
+ // files as they are.
30
+ const SUPERSEDED_SET_CLAUSES = new Set(["029_tenant_parent_cycle_guard.sql", "031_subtree_read_scope.sql"]);
31
+ const APP_SET_CLAUSE = /^SET app\.[a-z_]+ = '[^']*'\n/gm;
32
+ /** The SQL to run for one migration file. */
33
+ function migrationSql(name, sql, superuser) {
34
+ if (superuser || !SUPERSEDED_SET_CLAUSES.has(name))
35
+ return sql;
36
+ return sql.replace(APP_SET_CLAUSE, "");
37
+ }
38
+ /** Whether the role of `client` is a superuser. */
39
+ async function isSuperuser(client) {
40
+ const res = await client.query("SELECT rolsuper FROM pg_catalog.pg_roles WHERE rolname = current_user");
41
+ return res.rows[0]?.rolsuper === true;
42
+ }
43
+ /**
44
+ * Sets stratum.control_role for the current transaction, which migration 032
45
+ * reads. Without a name the setting stays as the session has it.
46
+ */
47
+ async function setControlRole(client, controlRole) {
48
+ if (controlRole === undefined)
49
+ return;
50
+ await client.query("SELECT pg_catalog.set_config('stratum.control_role', $1, true)", [controlRole]);
51
+ }
52
+ /**
53
+ * Sets stratum.apply_control_role = 'on' for the current transaction when
54
+ * `apply` is true. Migration 032 grants the control role to the migrating
55
+ * login only with this opt-in (or when the login is a superuser or already a
56
+ * member), because that login must be the library's admin login and never
57
+ * the application's.
58
+ */
59
+ async function setApplyControlRole(client, apply) {
60
+ if (!apply)
61
+ return;
62
+ await client.query("SELECT pg_catalog.set_config('stratum.apply_control_role', 'on', true)");
63
+ }
64
+ //# sourceMappingURL=migration-sql.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migration-sql.js","sourceRoot":"","sources":["../src/migration-sql.ts"],"names":[],"mappings":";;;AASA,wCAIC;AAiBD,oCAGC;AAGD,kCAKC;AAMD,wCAGC;AASD,kDAGC;AA5DD,oEAAoE;AACvD,QAAA,oBAAoB,GAAG,iBAAiB,CAAC;AAEtD,iEAAiE;AACpD,QAAA,SAAS,GAAG,yBAAyB,CAAC;AAEnD,8DAA8D;AAC9D,SAAgB,cAAc,CAAC,IAAY,EAAE,IAAY;IACvD,IAAI,CAAC,iBAAS,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAC1B,MAAM,IAAI,KAAK,CAAC,qBAAqB,IAAI,KAAK,IAAI,kDAAkD,CAAC,CAAC;IACxG,CAAC;AACH,CAAC;AAED,6DAA6D;AAC7D,yEAAyE;AACzE,4EAA4E;AAC5E,2EAA2E;AAC3E,uEAAuE;AACvE,wEAAwE;AACxE,6EAA6E;AAC7E,qDAAqD;AACrD,wEAAwE;AACxE,4EAA4E;AAC5E,qBAAqB;AACrB,MAAM,sBAAsB,GAAG,IAAI,GAAG,CAAC,CAAC,mCAAmC,EAAE,4BAA4B,CAAC,CAAC,CAAC;AAC5G,MAAM,cAAc,GAAG,iCAAiC,CAAC;AAEzD,6CAA6C;AAC7C,SAAgB,YAAY,CAAC,IAAY,EAAE,GAAW,EAAE,SAAkB;IACxE,IAAI,SAAS,IAAI,CAAC,sBAAsB,CAAC,GAAG,CAAC,IAAI,CAAC;QAAE,OAAO,GAAG,CAAC;IAC/D,OAAO,GAAG,CAAC,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC;AACzC,CAAC;AAED,mDAAmD;AAC5C,KAAK,UAAU,WAAW,CAAC,MAA+B;IAC/D,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,KAAK,CAC5B,uEAAuE,CACxE,CAAC;IACF,OAAO,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,QAAQ,KAAK,IAAI,CAAC;AACxC,CAAC;AAED;;;GAGG;AACI,KAAK,UAAU,cAAc,CAAC,MAAqB,EAAE,WAA+B;IACzF,IAAI,WAAW,KAAK,SAAS;QAAE,OAAO;IACtC,MAAM,MAAM,CAAC,KAAK,CAAC,gEAAgE,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC;AACtG,CAAC;AAED;;;;;;GAMG;AACI,KAAK,UAAU,mBAAmB,CAAC,MAAqB,EAAE,KAA0B;IACzF,IAAI,CAAC,KAAK;QAAE,OAAO;IACnB,MAAM,MAAM,CAAC,KAAK,CAAC,wEAAwE,CAAC,CAAC;AAC/F,CAAC"}
@@ -48,9 +48,9 @@ END;
48
48
  $$ language 'plpgsql';
49
49
 
50
50
  DO $pin$ BEGIN
51
- EXECUTE format(
51
+ EXECUTE pg_catalog.format(
52
52
  'ALTER FUNCTION refuse_tenant_parent_cycle() SET search_path = pg_catalog, %I',
53
- current_schema()
53
+ pg_catalog.current_schema()
54
54
  );
55
55
  END $pin$;
56
56
 
@@ -106,9 +106,9 @@ AS $$
106
106
  $$;
107
107
 
108
108
  DO $pin$ BEGIN
109
- EXECUTE format(
109
+ EXECUTE pg_catalog.format(
110
110
  'ALTER FUNCTION stratum_subtree_tenant_ids() SET search_path = pg_catalog, %I, pg_temp',
111
- current_schema()
111
+ pg_catalog.current_schema()
112
112
  );
113
113
  END $pin$;
114
114
 
@@ -255,9 +255,9 @@ END;
255
255
  $$ language 'plpgsql';
256
256
 
257
257
  DO $pin$ BEGIN
258
- EXECUTE format(
258
+ EXECUTE pg_catalog.format(
259
259
  'ALTER FUNCTION refuse_tenant_tree_column_change() SET search_path = pg_catalog, %I, pg_temp',
260
- current_schema()
260
+ pg_catalog.current_schema()
261
261
  );
262
262
  END $pin$;
263
263
 
@@ -300,8 +300,8 @@ END;
300
300
  $$ language 'plpgsql';
301
301
 
302
302
  DO $pin$ BEGIN
303
- EXECUTE format(
303
+ EXECUTE pg_catalog.format(
304
304
  'ALTER FUNCTION refuse_tenant_parent_cycle() SET search_path = pg_catalog, %I, pg_temp',
305
- current_schema()
305
+ pg_catalog.current_schema()
306
306
  );
307
307
  END $pin$;