ldap-rest 1.1.0 → 1.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.
Files changed (97) hide show
  1. package/bin/index.mjs +8 -7
  2. package/dist/abstract/ldapFlat.js +1 -1
  3. package/dist/abstract/plugin.js +1 -1
  4. package/dist/abstract/twakePlugin.js +1 -1
  5. package/dist/bin/index.js +1 -1
  6. package/dist/config/args.js +1 -1
  7. package/dist/config/schema.js +1 -1
  8. package/dist/lib/changeContext.js +1 -1
  9. package/dist/lib/entitySchema/validator.js +1 -0
  10. package/dist/lib/expressFormatedResponses.js +1 -1
  11. package/dist/lib/health.js +1 -0
  12. package/dist/lib/instanceProviders.js +1 -1
  13. package/dist/lib/ldapActions.js +1 -1
  14. package/dist/lib/metrics.js +1 -0
  15. package/dist/lib/requestContext.js +1 -1
  16. package/dist/lib/shutdown.js +1 -0
  17. package/dist/lib/staticFiles.js +1 -0
  18. package/dist/lib/storage/store.js +1 -1
  19. package/dist/lib/utils.js +1 -1
  20. package/dist/logger/winston.js +1 -1
  21. package/dist/plugins/auth/crowdsec.js +1 -1
  22. package/dist/plugins/auth/openidconnect.js +1 -1
  23. package/dist/plugins/demo/helloworld.js +1 -1
  24. package/dist/plugins/ldap/bulkImport.js +1 -1
  25. package/dist/plugins/ldap/flatGeneric.js +1 -1
  26. package/dist/plugins/ldap/groups.js +1 -1
  27. package/dist/plugins/ldap/organizations.js +1 -1
  28. package/dist/plugins/metrics.js +1 -0
  29. package/dist/plugins/rabbitmq.js +1 -1
  30. package/dist/plugins/scim/scim.js +1 -1
  31. package/dist/plugins/static.js +1 -1
  32. package/dist/plugins/storage/file.js +1 -1
  33. package/dist/plugins/storage/postgres.js +1 -1
  34. package/dist/plugins/storage/valkey.js +1 -1
  35. package/dist/plugins/storage.js +1 -1
  36. package/dist/plugins/twake/calendar.js +1 -1
  37. package/dist/plugins/twake/clouderyProvision.js +1 -1
  38. package/dist/plugins/twake/cozyProvision.js +1 -1
  39. package/dist/plugins/twake/drive.js +1 -1
  40. package/dist/plugins/twake/james.js +1 -1
  41. package/dist/plugins/twake/migrationProxy.js +1 -0
  42. package/dist/plugins/weblogs.js +1 -1
  43. package/dist/src/abstract/ldapFlat.d.ts +3 -13
  44. package/dist/src/abstract/plugin.d.ts +20 -0
  45. package/dist/src/abstract/twakePlugin.d.ts +23 -1
  46. package/dist/src/bin/index.d.ts +46 -1
  47. package/dist/src/config/args.d.ts +12 -1
  48. package/dist/src/lib/changeContext.d.ts +11 -0
  49. package/dist/src/lib/entitySchema/validator.d.ts +64 -0
  50. package/dist/src/lib/expressFormatedResponses.d.ts +19 -0
  51. package/dist/src/lib/health.d.ts +63 -0
  52. package/dist/src/lib/instanceProviders.d.ts +4 -0
  53. package/dist/src/lib/ldapActions.d.ts +28 -0
  54. package/dist/src/lib/metrics.d.ts +44 -0
  55. package/dist/src/lib/requestContext.d.ts +40 -0
  56. package/dist/src/lib/shutdown.d.ts +20 -0
  57. package/dist/src/lib/staticFiles.d.ts +33 -0
  58. package/dist/src/lib/storage/store.d.ts +8 -0
  59. package/dist/src/lib/utils.d.ts +9 -0
  60. package/dist/src/logger/winston.d.ts +4 -0
  61. package/dist/src/plugins/ldap/groups.d.ts +18 -3
  62. package/dist/src/plugins/ldap/organizations.d.ts +3 -5
  63. package/dist/src/plugins/metrics.d.ts +17 -0
  64. package/dist/src/plugins/rabbitmq.d.ts +37 -1
  65. package/dist/src/plugins/static.d.ts +12 -0
  66. package/dist/src/plugins/storage/file.d.ts +4 -0
  67. package/dist/src/plugins/storage/postgres.d.ts +7 -14
  68. package/dist/src/plugins/storage/valkey.d.ts +2 -15
  69. package/dist/src/plugins/storage.d.ts +8 -0
  70. package/dist/src/plugins/twake/drive.d.ts +8 -0
  71. package/dist/src/plugins/twake/james.d.ts +2 -0
  72. package/dist/src/plugins/twake/migrationProxy.d.ts +71 -0
  73. package/docs/client-development/api/reference.md +5 -9
  74. package/docs/client-development/api/rest-api.md +4 -10
  75. package/docs/client-development/schemas/README.md +60 -21
  76. package/docs/plugin-development/README.md +15 -13
  77. package/docs/plugin-development/dependencies.md +8 -0
  78. package/docs/plugin-development/hooks.md +1 -1
  79. package/docs/usage/README.md +1 -0
  80. package/docs/usage/configuration.md +49 -11
  81. package/docs/usage/operations.md +193 -0
  82. package/docs/usage/plugins/README.md +2 -0
  83. package/docs/usage/plugins/auth/authz-per-branch.md +2 -1
  84. package/docs/usage/plugins/integrations/README.md +8 -4
  85. package/docs/usage/plugins/integrations/mail-migration.md +102 -0
  86. package/docs/usage/plugins/integrations/scim.md +4 -2
  87. package/docs/usage/plugins/ldap/bulk-import.md +3 -1
  88. package/docs/usage/plugins/ldap/flat-generic.md +5 -2
  89. package/docs/usage/plugins/ldap/on-change.md +2 -1
  90. package/docs/usage/plugins/ldap/organizations.md +7 -7
  91. package/docs/usage/plugins/utilities/metrics.md +21 -0
  92. package/docs/usage/plugins/utilities/static.md +16 -8
  93. package/docs/usage/plugins/utilities/storage.md +7 -0
  94. package/docs/usage/plugins/utilities/weblogs.md +51 -30
  95. package/docs/usage/upgrading.md +71 -0
  96. package/package.json +11 -2
  97. package/static/schemas/example/README.md +1 -0
@@ -30,10 +30,18 @@
30
30
  import DmPlugin from '../abstract/plugin';
31
31
  import type { DM } from '../bin';
32
32
  import type Store from '../lib/storage/store';
33
+ import type { HealthStatus } from '../lib/health';
33
34
  export default class Storage extends DmPlugin {
34
35
  name: string;
35
36
  store: Store;
36
37
  constructor(server: DM);
38
+ close(): Promise<void>;
39
+ /** Set while the backend fails the probe, so the reason is logged once */
40
+ private degraded;
41
+ /** Counts the probes: only the latest says what the log lines say */
42
+ private probes;
43
+ /** The backend's own answer; a backend that cannot answer is degraded */
44
+ health(): Promise<HealthStatus>;
37
45
  /**
38
46
  * Release the single-instance hold.
39
47
  *
@@ -1,3 +1,11 @@
1
+ /**
2
+ * Twake Drive Plugin
3
+ *
4
+ * Synchronizes LDAP user changes with Twake Drive via Admin API.
5
+ * Propagates email address, display name, and disk quota changes.
6
+ *
7
+ * @see https://docs.cozy.io/en/cozy-stack/admin/
8
+ */
1
9
  import TwakePlugin from '../../abstract/twakePlugin';
2
10
  import { type Role } from '../../abstract/plugin';
3
11
  import type { DM } from '../../bin';
@@ -1,5 +1,6 @@
1
1
  import type { Express } from 'express';
2
2
  import TwakePlugin from '../../abstract/twakePlugin';
3
+ import type { HealthStatus } from '../../lib/health';
3
4
  import { type Role } from '../../abstract/plugin';
4
5
  import type { DM } from '../../bin';
5
6
  import type { AttributeValue } from '../../lib/ldapActions';
@@ -22,6 +23,7 @@ export default class James extends TwakePlugin {
22
23
  onLdapChange: string;
23
24
  ldapGroups: string;
24
25
  };
26
+ health(): Promise<HealthStatus>;
25
27
  private quotaAttr;
26
28
  private aliasAttr;
27
29
  private mailboxTypeAttr;
@@ -0,0 +1,71 @@
1
+ /**
2
+ * @module plugins/twake/migrationProxy
3
+ *
4
+ * Keeps the migrated-users list of the Twake Mail migration proxy in step
5
+ * with the accounts of the directory: an account created during the
6
+ * migration has no mailbox on the old system, so the proxy has to route it
7
+ * to the new one from its first login, and the addresses of a migrated
8
+ * account have to follow it.
9
+ *
10
+ * See `docs/usage/plugins/integrations/mail-migration.md`.
11
+ */
12
+ import type { Express } from 'express';
13
+ import TwakePlugin from '../../abstract/twakePlugin';
14
+ import { type Role } from '../../abstract/plugin';
15
+ import type { DM } from '../../bin';
16
+ import type { Hooks } from '../../hooks';
17
+ import type { HealthStatus } from '../../lib/health';
18
+ /**
19
+ * @openapi
20
+ * components:
21
+ * schemas:
22
+ * MailMigrationStatus:
23
+ * type: object
24
+ * required: [migrated]
25
+ * properties:
26
+ * migrated:
27
+ * type: boolean
28
+ * description: Whether the proxy routes the user to the new backend
29
+ */
30
+ export default class MigrationProxy extends TwakePlugin {
31
+ name: string;
32
+ roles: Role[];
33
+ dependencies: {
34
+ onLdapChange: string;
35
+ };
36
+ private readonly branches;
37
+ private readonly aliasAttr;
38
+ /** The work on one entry waits for the work before it */
39
+ private readonly queues;
40
+ constructor(server: DM);
41
+ health(): Promise<HealthStatus>;
42
+ api(app: Express): void;
43
+ hooks: Hooks;
44
+ /**
45
+ * One entry at a time: two writes close together would otherwise race to
46
+ * the proxy, the second reading a list the first has not written yet
47
+ */
48
+ private inOrder;
49
+ /**
50
+ * The address the entry logs in with, and the ones that reach it, each
51
+ * once: an alias repeating the mail would otherwise be put and taken off
52
+ * in the same breath
53
+ */
54
+ private addresses;
55
+ /**
56
+ * An entry gaining its address is put on the list with all of them, one
57
+ * losing it is taken off; one keeping it has its addresses follow it when
58
+ * the proxy says it is migrated, and is left to the migration otherwise.
59
+ * The proxy folds usernames to lower case, so a change of case is none.
60
+ */
61
+ private follow;
62
+ private userUrl;
63
+ private call;
64
+ /**
65
+ * `HEAD /migratedUsers/{user}`: 204 when migrated, 404 otherwise. With
66
+ * `retry`, an answer of {@link PROXY_UNAVAILABLE} is asked again as a
67
+ * write would be; throws once the proxy has not said
68
+ */
69
+ isMigrated(address: string, retry?: boolean): Promise<boolean>;
70
+ private getMigrationStatus;
71
+ }
@@ -93,11 +93,13 @@ Complete technical reference for the LDAP-Rest REST API including detailed speci
93
93
  | 500 | Internal Server Error | Server-side failure | LDAP connection issues, database errors, plugin failures |
94
94
  | 503 | Service Unavailable | Server temporarily unavailable | LDAP server down, maintenance mode |
95
95
 
96
- **Example 500 Response:**
96
+ **Example 500 Response** (the failure is in the server's logs; `message`
97
+ names it only when the server runs with `--debug`):
97
98
 
98
99
  ```json
99
100
  {
100
- "error": "LDAP bind error"
101
+ "error": "Internal Server Error",
102
+ "message": "An error occurred"
101
103
  }
102
104
  ```
103
105
 
@@ -805,13 +807,7 @@ Failed to fetch
805
807
 
806
808
  #### Problem: LDAP Connection Failed
807
809
 
808
- **Error:**
809
-
810
- ```json
811
- {
812
- "error": "LDAP bind error"
813
- }
814
- ```
810
+ **Error:** a 500 answer, with `LDAP bind error` in the server's logs.
815
811
 
816
812
  **Checklist:**
817
813
 
@@ -1335,19 +1335,13 @@ no `limit` was given —
1335
1335
 
1336
1336
  #### 500 Internal Server Error
1337
1337
 
1338
- **LDAP Connection Error:**
1338
+ The failure is in the server's logs, not in the response; the message names
1339
+ it only when the server runs with `--debug`:
1339
1340
 
1340
1341
  ```json
1341
1342
  {
1342
- "error": "LDAP bind error"
1343
- }
1344
- ```
1345
-
1346
- **General Server Error:**
1347
-
1348
- ```json
1349
- {
1350
- "error": "Internal server error: <details>"
1343
+ "error": "Internal Server Error",
1344
+ "message": "An error occurred"
1351
1345
  }
1352
1346
  ```
1353
1347
 
@@ -169,7 +169,10 @@ This will be replaced with the actual LDAP base at runtime (e.g., `ou=users,dc=e
169
169
 
170
170
  ## Attribute Types
171
171
 
172
- LDAP-Rest supports three main attribute types: `string`, `array`, and `pointer`.
172
+ LDAP-Rest supports three main attribute types: `string`, `array`, and `pointer`,
173
+ plus `number`, `integer`, `boolean` and `date` for single values. What a
174
+ client sends has to have the shape of the type, see
175
+ [what a value must look like](#what-a-value-must-look-like).
173
176
 
174
177
  ### String Type
175
178
 
@@ -337,7 +340,7 @@ Complete reference for all attribute properties.
337
340
 
338
341
  | Property | Type | Applies To | Description | Example |
339
342
  | ---------- | --------------- | ------------------- | ------------------------------------------------------------------------------------- | ----------------------------------- |
340
- | `type` | string | All | Attribute data type: `"string"`, `"array"`, `"pointer"`, `"number"`, `"integer"` | `"string"` |
343
+ | `type` | string | All | `"string"`, `"array"`, `"pointer"`, `"number"`, `"integer"`, `"boolean"`, `"date"` | `"string"` |
341
344
  | `required` | boolean | All | Whether the attribute must be present | `true` |
342
345
  | `fixed` | boolean | All | Whether the attribute value cannot be changed after creation | `true` |
343
346
  | `role` | string/string[] | String | Semantic role, or roles, for special handling (see [Semantic Roles](#semantic-roles)) | `"identifier"` |
@@ -364,6 +367,32 @@ Defines the data type of the attribute. Supported values:
364
367
  - `"pointer"`: Reference to another LDAP entry (DN)
365
368
  - `"number"`: Numeric value (integer or float)
366
369
  - `"integer"`: Integer value only
370
+ - `"boolean"`: `true` or `false`, stored as `TRUE` / `FALSE`
371
+ - `"date"`: LDAP generalized time, as text
372
+
373
+ #### What a value must look like
374
+
375
+ A single-valued attribute takes one value, an `array` a list. A list of one
376
+ value stands for that value and one value for a list of one, so what a read
377
+ answers, one value where the attribute holds one, can be sent back as is;
378
+ two values or more for a single-valued attribute are refused. Each element
379
+ of an `array` follows `items.type`, text without `items`. A `number` or
380
+ `integer` is a JSON number or its text (`42`, `"42"`), a `boolean` a JSON
381
+ boolean or the directory's `TRUE` / `FALSE`; anything else for them, and
382
+ anything but text for a `string`, `date` or `pointer`, is refused; an
383
+ attribute with `normalize` takes any text, read after validation. In a
384
+ `replace`, `null` or `[]` clears an attribute; in an `add` or on a creation
385
+ they are refused as no value. A `delete` naming the attribute, or naming it
386
+ with no value, removes it, unless it is `required`; naming values removes
387
+ those, every value it holds included, as the server does not read what
388
+ remains, and `''` names no value. An empty string sent as a value is
389
+ checked against `test`, refused for a pointer, and missing for a `required`
390
+ attribute. Every refusal answers 400 with the attribute's name.
391
+
392
+ Every entity route applies these rules; `test/lib/entitySchema.contract.test.ts`
393
+ asserts them on a flat entity, a group and an organization alike. In the
394
+ server they are enforced by `EntityValidator` (`src/lib/entitySchema/validator.ts`)
395
+ alone: ESLint refuses the import of the schema helpers anywhere else.
367
396
 
368
397
  #### `required` (Optional, default: `false`)
369
398
 
@@ -674,13 +703,8 @@ Common validation patterns:
674
703
 
675
704
  ### Type Validation
676
705
 
677
- Attribute values must match their declared type:
678
-
679
- - **String**: Single text value
680
- - **Array**: Multiple values (may be empty unless required)
681
- - **Number**: Numeric value (integer or float)
682
- - **Integer**: Integer value only
683
- - **Pointer**: Valid DN string
706
+ Attribute values must have the shape of their declared type, see
707
+ [what a value must look like](#what-a-value-must-look-like).
684
708
 
685
709
  ### Fixed Attributes
686
710
 
@@ -780,6 +804,7 @@ twake/
780
804
  ```bash
781
805
  npx ldap-rest \
782
806
  --ldap-base 'dc=example,dc=com' \
807
+ --ldap-dn 'cn=admin,dc=example,dc=com' --ldap-pwd secret \
783
808
  --plugin core/ldap/flatGeneric \
784
809
  --ldap-flat-schema ./static/schemas/twake/users.json \
785
810
  --plugin core/ldap/groups \
@@ -842,6 +867,7 @@ ad/
842
867
  ```bash
843
868
  npx ldap-rest \
844
869
  --ldap-base 'dc=example,dc=com' \
870
+ --ldap-dn 'cn=admin,dc=example,dc=com' --ldap-pwd secret \
845
871
  --plugin core/ldap/flatGeneric \
846
872
  --ldap-flat-schema ./static/schemas/ad/users.json \
847
873
  --plugin core/ldap/groups \
@@ -910,6 +936,7 @@ standard/
910
936
  ```bash
911
937
  npx ldap-rest \
912
938
  --ldap-base 'dc=example,dc=com' \
939
+ --ldap-dn 'cn=admin,dc=example,dc=com' --ldap-pwd secret \
913
940
  --plugin core/ldap/flatGeneric \
914
941
  --ldap-flat-schema ./static/schemas/standard/users.json \
915
942
  --plugin core/ldap/groups \
@@ -1055,6 +1082,7 @@ Save your schema and reference it when starting LDAP-Rest:
1055
1082
  ```bash
1056
1083
  npx ldap-rest \
1057
1084
  --ldap-base 'dc=example,dc=com' \
1085
+ --ldap-dn 'cn=admin,dc=example,dc=com' --ldap-pwd secret \
1058
1086
  --plugin core/ldap/flatGeneric \
1059
1087
  --ldap-flat-schema ./path/to/custom-users.json
1060
1088
  ```
@@ -1131,18 +1159,29 @@ it with a 500.
1131
1159
  ### Served Schemas
1132
1160
 
1133
1161
  `core/static` serves the merged schema. The configuration API gives each
1134
- entity its merged schema inline (`schema`) and, with `core/static`, a
1135
- `schemaUrl` made of the file path from its first `schemas` directory:
1136
- `/etc/ldap-rest/schemas/users.json` gets `/static/schemas/users.json`.
1137
- `core/static` serves a configured schema file at that URL even when it is
1138
- outside `--static-path`, and before a shipped schema of the same URL:
1139
- `/etc/ldap-rest/schemas/twake/users.json` is what
1140
- `/static/schemas/twake/users.json` returns. An option left at its default
1141
- does not count: without `--group-schema`, a `--static-path` of your own
1142
- still serves its `schemas/twake/groups.json`. If two configured files get
1143
- the same URL, the first one is served there and a warning names the other.
1144
- A file outside any `schemas` directory has no `schemaUrl`; its schema is
1145
- still inline.
1162
+ entity its merged schema inline (`schema`) and, where a static plugin's
1163
+ schema routes serve that very file, its `schemaUrl`, under the plugin's own
1164
+ `--static-name`:
1165
+
1166
+ - a schema file of the configuration gets the file path from its first
1167
+ `schemas` directory, `/etc/ldap-rest/schemas/users.json` getting
1168
+ `/static/schemas/users.json`. `core/static` serves it at that URL even
1169
+ when it is outside `--static-path`, and before a shipped schema of the
1170
+ same URL: `/etc/ldap-rest/schemas/twake/users.json` is what
1171
+ `/static/schemas/twake/users.json` returns. If two configured files get
1172
+ the same URL, the first one is served there and a warning names the
1173
+ other;
1174
+ - a file the `schemas/` directory of `--static-path` holds, that directory
1175
+ being a link or not, gets its path in it, if it is named `.json`.
1176
+
1177
+ An option left at its default does not count as configured: without
1178
+ `--group-schema`, a `--static-path` of your own still serves its
1179
+ `schemas/twake/groups.json`, and no `schemaUrl` is given unless that file is
1180
+ the package's, through a link. A static plugin loaded under another name, or with a
1181
+ `static_name` of its own, is asked as well, the one registered as `static`
1182
+ first. A file no static plugin serves merged has no `schemaUrl`, one
1183
+ express.static would send as it stands included (outside `schemas/`, or not
1184
+ named `.json`); its schema is still inline.
1146
1185
 
1147
1186
  ---
1148
1187
 
@@ -61,20 +61,22 @@ export default class MyPlugin extends DmPlugin {
61
61
  - **this.config**: Complete configuration object
62
62
  - **this.logger**: Winston logger instance
63
63
  - **this.registeredHooks**: Access to global hook registry
64
+ - **this.fetch**: `fetch` timed into the
65
+ [outbound metrics](../usage/operations.md#metrics) under the plugin's
66
+ name; the lint refuses a bare `fetch` or `node-fetch` under `src`, and a
67
+ plugin with a `fetch` member of its own has to rename it
64
68
 
65
69
  ### Error Handling and Server Resilience
66
70
 
67
- LDAP-Rest includes robust error handling to ensure the server remains operational even when plugins encounter errors:
68
-
69
- #### Global Error Handling
70
-
71
- The server automatically catches and handles:
72
-
73
- - **Uncaught exceptions** in plugin code
74
- - **Unhandled promise rejections**
75
- - **Errors in async route handlers**
76
-
77
- All errors are logged with full stack traces without crashing the server.
71
+ An error a route handler or a hook throws is logged with its stack; the
72
+ request is answered with a 5xx when the hook ran before the operation, and
73
+ the server keeps serving. An exception nothing catches, in a timer or an
74
+ event handler, is not: the binary shuts down and exits with 1, and a
75
+ promise rejection nothing handles is logged and counted, see
76
+ [shutdown](../usage/operations.md#shutdown); a host assembling the server
77
+ chooses with `exitOnCrash()`. A plugin holding a connection, a timer or a
78
+ queue implements `close()`, see
79
+ [for plugin authors](../usage/operations.md#for-plugin-authors).
78
80
 
79
81
  #### Using asyncHandler
80
82
 
@@ -175,7 +177,7 @@ export default class WebhookNotifier extends DmPlugin {
175
177
  // Private methods
176
178
  private async sendWebhook(event: string, data: unknown): Promise<void> {
177
179
  try {
178
- await fetch(this.config.webhook_url as string, {
180
+ await this.fetch(this.config.webhook_url as string, {
179
181
  method: 'POST',
180
182
  headers: { 'Content-Type': 'application/json' },
181
183
  body: JSON.stringify({ event, data }),
@@ -1153,7 +1155,7 @@ export default class NotificationPlugin extends DmPlugin {
1153
1155
  const timeoutId = setTimeout(() => controller.abort(), this.webhookTimeout);
1154
1156
 
1155
1157
  try {
1156
- const response = await fetch(this.webhookUrl, {
1158
+ const response = await this.fetch(this.webhookUrl, {
1157
1159
  method: 'POST',
1158
1160
  headers: {
1159
1161
  'Content-Type': 'application/json',
@@ -204,6 +204,14 @@ overrides builds a second instance, and it needs a name of its own.
204
204
  - **Consumes Hooks**: (Hooks provided by `onLdapChange`)
205
205
  - **Notes**: Synchronizes LDAP users/groups with Apache James mail server
206
206
 
207
+ #### `migrationProxy` (twake/migrationProxy)
208
+
209
+ - **Dependencies**:
210
+ - `onLdapChange: 'core/ldap/onChange'` ⚠️ **Required**
211
+ - **Provides Hooks**: None
212
+ - **Consumes Hooks**: `onLdapEntryChange` (provided by `onLdapChange`)
213
+ - **Notes**: Keeps the migrated-users list of the Twake Mail migration proxy, see [mail-migration](../usage/plugins/integrations/mail-migration.md)
214
+
207
215
  #### `calendar` (twake/calendar)
208
216
 
209
217
  - **Dependencies**:
@@ -9,7 +9,7 @@ those typed in [hooks.ts](../../src/hooks.ts), which is the reference.
9
9
 
10
10
  ## [LDAP](../../src/lib/ldapActions.ts) hooks
11
11
 
12
- - **ldapopts**: called before any ldapsearch to modify search options
12
+ - **ldapsearchopts**: called before any ldapsearch to modify search options
13
13
  - **ldapsearchresult**: called after any ldapsearch to modify search result
14
14
  - **ldapaddrequest**: called before any ldapadd
15
15
  - **ldapadddone**: launched once an ldapadd has written the entry, not awaited
@@ -88,4 +88,5 @@ The system will:
88
88
  - **[Plugins](plugins/README.md)** - Choose and configure plugins
89
89
  - **[Upgrading](upgrading.md)** - What to check before deploying a new version
90
90
  - **[Directory audit](directory-audit.md)** - What a schema would refuse in an existing directory
91
+ - **[Operations](operations.md)** - Health and readiness probes
91
92
  - **[Troubleshooting](troubleshooting.md)** - Problem resolution
@@ -39,17 +39,20 @@ All LDAP-Rest configuration options.
39
39
  - [core/auth/trustedProxy](#coreauthtrustedproxy)
40
40
  - [Twake Integration Plugins](#twake-integration-plugins)
41
41
  - [core/twake/james](#coretwakejames)
42
+ - [core/twake/migrationProxy](#coretwakemigrationproxy)
42
43
  - [core/twake/calendar](#coretwakecalendar)
43
44
  - [core/twake/applicativeAccounts](#coretwakeapplicativeaccounts)
44
45
  - [core/twake/appAccountsConsistency](#coretwakeappaccountsconsistency)
45
46
  - [Utility Plugins](#utility-plugins)
46
47
  - [core/static](#corestatic)
47
48
  - [core/weblogs](#coreweblogs)
49
+ - [core/metrics](#coremetrics)
48
50
  - [core/storage](#corestorage)
49
51
  - [core/configApi](#coreconfigapi)
50
52
  - [Configuration File](#configuration-file)
51
53
  - [LDAP Failover](#ldap-failover)
52
54
  - [Log Levels (`--log-level`)](#log-levels---log-level)
55
+ - [Logger (`--logger`)](#logger---logger)
53
56
 
54
57
  ## Environment Variables
55
58
 
@@ -148,15 +151,18 @@ to keep the default.
148
151
 
149
152
  ## General Options
150
153
 
151
- | CLI | Plural | Env | Default | Description |
152
- | ---------------- | ---------------- | ----------------- | ---------------- | ------------------------------------------- |
153
- | `--port` | | `DM_PORT` | `8081` | Listen port |
154
- | `--plugin` | `--plugins` | `DM_PLUGINS` | `[]` | Plugins to load |
155
- | `--log-level` | | `DM_LOG_LEVEL` | `notice` | Log level: error, warn, notice, info, debug |
156
- | `--logger` | | `DM_LOGGER` | `console` | Logger type |
157
- | `--api-prefix` | | `DM_API_PREFIX` | `/api` | API URL prefix |
158
- | `--mail-domain` | `--mail-domains` | `DM_MAIL_DOMAIN` | `[]` | Mail domains |
159
- | `--schemas-path` | | `DM_SCHEMAS_PATH` | `static/schemas` | Path to JSON schemas |
154
+ | CLI | Plural | Env | Default | Description |
155
+ | -------------------- | ---------------- | --------------------- | ---------------- | ------------------------------------------------------------------------------------------------- |
156
+ | `--port` | | `DM_PORT` | `8081` | Listen port |
157
+ | `--shutdown-timeout` | | `DM_SHUTDOWN_TIMEOUT` | `20000` | How long a stop may take, in ms, see [shutdown](operations.md#shutdown) |
158
+ | `--plugin` | `--plugins` | `DM_PLUGINS` | `[]` | Plugins to load |
159
+ | `--log-level` | | `DM_LOG_LEVEL` | `notice` | Log level: error, warn, notice, info, debug |
160
+ | `--logger` | | `DM_LOGGER` | `console` | `console` or `file`, see [Logger](#logger---logger) |
161
+ | `--log-file` | | `DM_LOG_FILE` | `error.log` | File `--logger file` writes to |
162
+ | `--debug` | | `DM_DEBUG` | `false` | Name the failure in the 5xx answers of the error middleware and `serverError`; not for production |
163
+ | `--api-prefix` | | `DM_API_PREFIX` | `/api` | API URL prefix |
164
+ | `--mail-domain` | `--mail-domains` | `DM_MAIL_DOMAIN` | `[]` | Mail domains |
165
+ | `--schemas-path` | | `DM_SCHEMAS_PATH` | `static/schemas` | Path to JSON schemas |
160
166
 
161
167
  A schema file named by an option may extend another one, shipped or not, and
162
168
  hold only the differences:
@@ -167,8 +173,8 @@ hold only the differences:
167
173
  | CLI | Plural | Env | Default | Description |
168
174
  | ---------------------------- | ---------------- | ------------------------ | ---------------------------------- | ------------------------------------------- |
169
175
  | `--ldap-url` | `--ldap-urls` | `DM_LDAP_URL` | `ldap://localhost` | LDAP server URL(s) |
170
- | `--ldap-dn` | | `DM_LDAP_DN` | `cn=admin,dc=example,dc=com` | Bind DN |
171
- | `--ldap-pwd` | | `DM_LDAP_PWD` | `admin` | Password |
176
+ | `--ldap-dn` | | `DM_LDAP_DN` | | Bind DN (required) |
177
+ | `--ldap-pwd` | | `DM_LDAP_PWD` | | Password (required) |
172
178
  | `--ldap-base` | | `DM_LDAP_BASE` | | Base DN for searches (required) |
173
179
  | `--ldap-user-main-attribute` | | `DM_LDAP_USER_ATTRIBUTE` | `uid` | User identifier attribute |
174
180
  | `--ldap-cache-max` | | `DM_LDAP_CACHE_MAX` | `1000` | Max cache entries |
@@ -493,6 +499,19 @@ whichever of the two names it selects. A value other than `req.user` or
493
499
 
494
500
  The wait before each retry grows with the attempt, so the total wait is `--james-retry-delay` × n(n−1)/2 for n attempts: 10 s with the defaults, 190 s with 20 attempts.
495
501
 
502
+ #### `core/twake/migrationProxy`
503
+
504
+ Keeps the migrated-users list of the Twake Mail migration proxy in step with the accounts, [details](plugins/integrations/mail-migration.md).
505
+
506
+ | CLI | Plural | Env | Default | Description |
507
+ | ---------------------------------- | ---------------------------- | ----------------------------------- | ------- | ---------------------------------------------------------------- |
508
+ | `--migration-proxy-url` | | `DM_MIGRATION_PROXY_URL` | | Webadmin URL of the proxy (required) |
509
+ | `--migration-proxy-token` | | `DM_MIGRATION_PROXY_TOKEN` | | Bearer token |
510
+ | `--migration-proxy-branch` | `--migration-proxy-branches` | `DM_MIGRATION_PROXY_BRANCHES` | `[]` | Branches whose entries are followed, `;`-separated (required) |
511
+ | `--migration-proxy-concurrency` | | `DM_MIGRATION_PROXY_CONCURRENCY` | `10` | Calls to the proxy at once |
512
+ | `--migration-proxy-retry-attempts` | | `DM_MIGRATION_PROXY_RETRY_ATTEMPTS` | `5` | Attempts in all of a call the proxy answers 500, 502, 503 or 504 |
513
+ | `--migration-proxy-retry-delay` | | `DM_MIGRATION_PROXY_RETRY_DELAY` | `1000` | Base retry delay (ms), growing with the attempt |
514
+
496
515
  #### `core/twake/calendar`
497
516
 
498
517
  Formerly `core/twake/calendarResources`, still accepted as a deprecated alias.
@@ -675,6 +694,15 @@ See [security headers](plugins/utilities/static.md#security-headers).
675
694
 
676
695
  Web access logging plugin. No configuration options - just add the plugin to enable access logs.
677
696
 
697
+ #### `core/metrics`
698
+
699
+ Prometheus metrics on a port of their own, see
700
+ [metrics](operations.md#metrics).
701
+
702
+ | CLI | Env | Default | Description |
703
+ | ---------------- | ----------------- | ------- | ---------------------------------------------------------- |
704
+ | `--metrics-port` | `DM_METRICS_PORT` | `9464` | Port `GET /metrics` is served on; keep it off the internet |
705
+
678
706
  #### `core/storage`
679
707
 
680
708
  Keyed storage with a deadline, for the plugins that need to keep something —
@@ -743,3 +771,13 @@ The system will:
743
771
  | `debug` | Everything, including debug output |
744
772
 
745
773
  The `notice` level is ideal for production as it shows web access logs without flooding with general info messages.
774
+
775
+ ## Logger _(`--logger`)_
776
+
777
+ | Logger | Output |
778
+ | --------- | ---------------------------------------------------------------------------------------------------- |
779
+ | `console` | One JSON object per line on standard output (errors and warnings on standard error) |
780
+ | `file` | Text lines appended to `--log-file` (`DM_LOG_FILE`), `error.log` in the working directory by default |
781
+
782
+ An empty value is `console`. Any other value, or `file` with an empty
783
+ `--log-file`, stops the server at startup.