ldap-rest 1.2.1 → 2.0.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/bin/sync-james.mjs +13 -2
- package/dist/abstract/ldapFlat.js +1 -1
- package/dist/abstract/plugin.js +1 -1
- package/dist/abstract/twakePlugin.js +1 -1
- package/dist/bin/index.js +1 -1
- package/dist/config/args.js +1 -1
- package/dist/config/options.js +1 -0
- package/dist/config/schema.js +1 -1
- package/dist/lib/auth/base.js +1 -1
- package/dist/lib/authz/base.js +1 -1
- package/dist/lib/entitySchema/validator.js +1 -1
- package/dist/lib/errors.js +1 -1
- package/dist/lib/expressFormatedResponses.js +1 -1
- package/dist/lib/health.js +1 -1
- package/dist/lib/hookBus.js +1 -0
- package/dist/lib/instanceProviders.js +1 -1
- package/dist/lib/ldap/callerView.js +1 -0
- package/dist/lib/ldap/pool.js +1 -0
- package/dist/lib/ldap/schema.js +1 -0
- package/dist/lib/ldap/searchCache.js +1 -0
- package/dist/lib/ldapActions.js +1 -1
- package/dist/lib/ldapSchema.js +1 -1
- package/dist/lib/parseConfig.js +1 -1
- package/dist/lib/route.js +1 -0
- package/dist/lib/schemaFile.js +1 -1
- package/dist/lib/services/index.js +1 -0
- package/dist/lib/storage/store.js +1 -1
- package/dist/lib/utils.js +1 -1
- package/dist/lib/version.js +1 -0
- package/dist/logger/winston.js +1 -1
- package/dist/plugins/auth/auth.options.js +1 -0
- package/dist/plugins/auth/authzDynamic.js +1 -1
- package/dist/plugins/auth/authzLinid1.js +1 -1
- package/dist/plugins/auth/authzPerBranch.js +1 -1
- package/dist/plugins/auth/authzPerRoute.js +1 -1
- package/dist/plugins/auth/authzScope.js +1 -1
- package/dist/plugins/auth/crowdsec.js +1 -1
- package/dist/plugins/auth/fake.js +1 -1
- package/dist/plugins/auth/hmac.js +1 -1
- package/dist/plugins/auth/llng.js +1 -1
- package/dist/plugins/auth/openidconnect.js +1 -1
- package/dist/plugins/auth/rateLimit.js +1 -1
- package/dist/plugins/auth/token.js +1 -1
- package/dist/plugins/auth/totp.js +1 -1
- package/dist/plugins/auth/trustedProxy.js +1 -1
- package/dist/plugins/bcl.js +1 -1
- package/dist/plugins/bcl.options.js +1 -0
- package/dist/plugins/configApi.js +1 -1
- package/dist/plugins/demo/helloworld.js +1 -1
- package/dist/plugins/ldap/accountLifecycle.js +1 -1
- package/dist/plugins/ldap/bulkImport.js +1 -1
- package/dist/plugins/ldap/departmentSync.js +1 -1
- package/dist/plugins/ldap/enterpriseRules.js +1 -1
- package/dist/plugins/ldap/externalUsersInGroups.js +1 -1
- package/dist/plugins/ldap/flatGeneric.js +1 -1
- package/dist/plugins/ldap/groups.js +1 -1
- package/dist/plugins/ldap/ldap.options.js +1 -0
- package/dist/plugins/ldap/onChange.js +1 -1
- package/dist/plugins/ldap/organizations.js +1 -1
- package/dist/plugins/ldap/passwordPolicy.js +1 -1
- package/dist/plugins/ldap/raw.js +1 -1
- package/dist/plugins/ldap/trash.js +1 -1
- package/dist/plugins/metrics.js +1 -1
- package/dist/plugins/metrics.options.js +1 -0
- package/dist/plugins/rabbitmq.js +1 -1
- package/dist/plugins/rabbitmq.options.js +1 -0
- package/dist/plugins/scim/baseResolver.js +1 -1
- package/dist/plugins/scim/bulk.js +1 -1
- package/dist/plugins/scim/discovery.js +1 -1
- package/dist/plugins/scim/errors.js +1 -1
- package/dist/plugins/scim/filter.js +1 -1
- package/dist/plugins/scim/groups.js +1 -1
- package/dist/plugins/scim/mapping.js +1 -1
- package/dist/plugins/scim/patch.js +1 -1
- package/dist/plugins/scim/scim.js +1 -1
- package/dist/plugins/scim/scim.options.js +1 -0
- package/dist/plugins/scim/users.js +1 -1
- package/dist/plugins/static.js +1 -1
- package/dist/plugins/static.options.js +1 -0
- package/dist/plugins/storage/file.js +1 -1
- package/dist/plugins/storage/ldap.js +1 -1
- package/dist/plugins/storage/postgres.js +1 -1
- package/dist/plugins/storage/valkey.js +1 -1
- package/dist/plugins/storage.js +1 -1
- package/dist/plugins/storage.options.js +1 -0
- package/dist/plugins/twake/appAccounts.options.js +1 -0
- package/dist/plugins/twake/appAccountsApi.js +1 -1
- package/dist/plugins/twake/appAccountsConsistency.js +1 -1
- package/dist/plugins/twake/calendar.js +1 -1
- package/dist/plugins/twake/calendar.options.js +1 -0
- package/dist/plugins/twake/calendarResources.js +1 -1
- package/dist/plugins/twake/cloudery.options.js +1 -0
- package/dist/plugins/twake/clouderyProvision.js +1 -1
- package/dist/plugins/twake/cozy.options.js +1 -0
- package/dist/plugins/twake/cozyProvision.js +1 -1
- package/dist/plugins/twake/drive.js +1 -1
- package/dist/plugins/twake/drive.options.js +1 -0
- package/dist/plugins/twake/groups.js +1 -1
- package/dist/plugins/twake/instances.js +1 -1
- package/dist/plugins/twake/james.js +1 -1
- package/dist/plugins/twake/james.options.js +1 -0
- package/dist/plugins/twake/lifecycleAttributes.js +1 -1
- package/dist/plugins/twake/lifecycleEvents.js +1 -1
- package/dist/plugins/twake/migrationProxy.js +1 -1
- package/dist/plugins/twake/migrationProxy.options.js +1 -0
- package/dist/plugins/twake/spaces.js +1 -1
- package/dist/plugins/twake/tombstone.js +1 -1
- package/dist/plugins/twake/twakeGroups.options.js +1 -0
- package/dist/plugins/twake/twakeInstances.options.js +1 -0
- package/dist/plugins/twake/twakeLifecycle.options.js +1 -0
- package/dist/plugins/twake/twakeSpaces.options.js +1 -0
- package/dist/plugins/twake/twakeTombstone.options.js +1 -0
- package/dist/plugins/weblogs.js +1 -1
- package/dist/src/abstract/ldapFlat.d.ts +41 -10
- package/dist/src/abstract/plugin.d.ts +31 -5
- package/dist/src/abstract/twakePlugin.d.ts +14 -4
- package/dist/src/bin/index.d.ts +35 -4
- package/dist/src/config/args.d.ts +2 -4
- package/dist/src/config/options.d.ts +104 -0
- package/dist/src/config/schema.d.ts +50 -1
- package/dist/src/hooks.d.ts +60 -22
- package/dist/src/lib/authz/base.d.ts +4 -51
- package/dist/src/lib/authz/composition.d.ts +2 -2
- package/dist/src/lib/entitySchema/validator.d.ts +63 -6
- package/dist/src/lib/errors.d.ts +57 -1
- package/dist/src/lib/expressFormatedResponses.d.ts +49 -7
- package/dist/src/lib/hookBus.d.ts +226 -0
- package/dist/src/lib/instanceProviders.d.ts +0 -8
- package/dist/src/lib/ldap/callerView.d.ts +45 -0
- package/dist/src/lib/ldap/pool.d.ts +108 -0
- package/dist/src/lib/ldap/schema.d.ts +157 -0
- package/dist/src/lib/ldap/searchCache.d.ts +112 -0
- package/dist/src/lib/ldapActions.d.ts +26 -256
- package/dist/src/lib/parseConfig.d.ts +31 -2
- package/dist/src/lib/route.d.ts +99 -0
- package/dist/src/lib/services/index.d.ts +56 -0
- package/dist/src/lib/utils.d.ts +100 -36
- package/dist/src/lib/version.d.ts +12 -0
- package/dist/src/plugins/auth/auth.options.d.ts +88 -0
- package/dist/src/plugins/auth/authzDynamic.d.ts +10 -1
- package/dist/src/plugins/auth/authzLinid1.d.ts +6 -0
- package/dist/src/plugins/auth/authzPerBranch.d.ts +9 -0
- package/dist/src/plugins/auth/authzPerRoute.d.ts +3 -0
- package/dist/src/plugins/auth/authzScope.d.ts +23 -14
- package/dist/src/plugins/auth/crowdsec.d.ts +5 -0
- package/dist/src/plugins/auth/fake.d.ts +3 -0
- package/dist/src/plugins/auth/hmac.d.ts +4 -0
- package/dist/src/plugins/auth/llng.d.ts +4 -0
- package/dist/src/plugins/auth/openidconnect.d.ts +7 -0
- package/dist/src/plugins/auth/rateLimit.d.ts +4 -0
- package/dist/src/plugins/auth/token.d.ts +3 -0
- package/dist/src/plugins/auth/totp.d.ts +5 -0
- package/dist/src/plugins/auth/trustedProxy.d.ts +4 -0
- package/dist/src/plugins/bcl.d.ts +3 -0
- package/dist/src/plugins/bcl.options.d.ts +8 -0
- package/dist/src/plugins/configApi.d.ts +24 -5
- package/dist/src/plugins/demo/helloworld.d.ts +8 -19
- package/dist/src/plugins/ldap/accountLifecycle.d.ts +17 -0
- package/dist/src/plugins/ldap/bulkImport.d.ts +6 -76
- package/dist/src/plugins/ldap/departmentSync.d.ts +1 -0
- package/dist/src/plugins/ldap/enterpriseRules.d.ts +8 -15
- package/dist/src/plugins/ldap/externalUsersInGroups.d.ts +4 -0
- package/dist/src/plugins/ldap/flatGeneric.d.ts +4 -0
- package/dist/src/plugins/ldap/groups.d.ts +27 -11
- package/dist/src/plugins/ldap/ldap.options.d.ts +75 -0
- package/dist/src/plugins/ldap/onChange.d.ts +10 -2
- package/dist/src/plugins/ldap/organizations.d.ts +16 -0
- package/dist/src/plugins/ldap/passwordPolicy.d.ts +35 -3
- package/dist/src/plugins/ldap/raw.d.ts +50 -19
- package/dist/src/plugins/ldap/trash.d.ts +6 -0
- package/dist/src/plugins/metrics.d.ts +3 -0
- package/dist/src/plugins/metrics.options.d.ts +8 -0
- package/dist/src/plugins/rabbitmq.d.ts +3 -0
- package/dist/src/plugins/rabbitmq.options.d.ts +8 -0
- package/dist/src/plugins/scim/baseResolver.d.ts +2 -1
- package/dist/src/plugins/scim/bulk.d.ts +6 -7
- package/dist/src/plugins/scim/discovery.d.ts +3 -0
- package/dist/src/plugins/scim/errors.d.ts +2 -1
- package/dist/src/plugins/scim/groups.d.ts +6 -4
- package/dist/src/plugins/scim/mapping.d.ts +16 -3
- package/dist/src/plugins/scim/scim.d.ts +37 -3
- package/dist/src/plugins/scim/scim.options.d.ts +35 -0
- package/dist/src/plugins/scim/types.d.ts +2 -0
- package/dist/src/plugins/scim/users.d.ts +6 -7
- package/dist/src/plugins/static.d.ts +9 -0
- package/dist/src/plugins/static.options.d.ts +13 -0
- package/dist/src/plugins/storage.d.ts +12 -1
- package/dist/src/plugins/storage.options.d.ts +16 -0
- package/dist/src/plugins/twake/appAccounts.options.d.ts +13 -0
- package/dist/src/plugins/twake/appAccountsApi.d.ts +18 -0
- package/dist/src/plugins/twake/appAccountsConsistency.d.ts +8 -0
- package/dist/src/plugins/twake/calendar.d.ts +25 -2
- package/dist/src/plugins/twake/calendar.options.d.ts +19 -0
- package/dist/src/plugins/twake/cloudery.options.d.ts +26 -0
- package/dist/src/plugins/twake/clouderyProvision.d.ts +18 -0
- package/dist/src/plugins/twake/cozy.options.d.ts +23 -0
- package/dist/src/plugins/twake/cozyProvision.d.ts +14 -0
- package/dist/src/plugins/twake/drive.d.ts +7 -0
- package/dist/src/plugins/twake/drive.options.d.ts +15 -0
- package/dist/src/plugins/twake/groups.d.ts +29 -1
- package/dist/src/plugins/twake/instances.d.ts +74 -10
- package/dist/src/plugins/twake/james.d.ts +17 -0
- package/dist/src/plugins/twake/james.options.d.ts +21 -0
- package/dist/src/plugins/twake/lifecycleAttributes.d.ts +13 -2
- package/dist/src/plugins/twake/lifecycleEvents.d.ts +12 -0
- package/dist/src/plugins/twake/migrationProxy.d.ts +11 -11
- package/dist/src/plugins/twake/migrationProxy.options.d.ts +16 -0
- package/dist/src/plugins/twake/spaces.d.ts +30 -0
- package/dist/src/plugins/twake/tombstone.d.ts +25 -16
- package/dist/src/plugins/twake/twakeGroups.options.d.ts +20 -0
- package/dist/src/plugins/twake/twakeInstances.options.d.ts +43 -0
- package/dist/src/plugins/twake/twakeLifecycle.options.d.ts +21 -0
- package/dist/src/plugins/twake/twakeSpaces.options.d.ts +19 -0
- package/dist/src/plugins/twake/twakeTombstone.options.d.ts +17 -0
- package/docs/README.md +17 -2
- package/docs/client-development/api/rest-api.md +13 -3
- package/docs/client-development/schemas/README.md +96 -32
- package/docs/development/contracts.md +109 -0
- package/docs/plugin-development/README.md +53 -95
- package/docs/plugin-development/dependencies.md +24 -8
- package/docs/plugin-development/hooks.md +143 -23
- package/docs/plugin-development/openapi.md +14 -1
- package/docs/plugin-development/options.md +136 -0
- package/docs/plugin-development/routes.md +152 -0
- package/docs/plugin-development/services.md +95 -0
- package/docs/plugin-development/testing.md +3 -3
- package/docs/usage/configuration.md +18 -11
- package/docs/usage/operations.md +28 -4
- package/docs/usage/plugins/integrations/instances.md +11 -3
- package/docs/usage/plugins/integrations/lifecycle-events.md +4 -1
- package/docs/usage/plugins/integrations/scim.md +20 -18
- package/docs/usage/plugins/integrations/tombstone.md +10 -6
- package/docs/usage/plugins/ldap/enterprise-rules.md +10 -1
- package/docs/usage/plugins/ldap/flat-generic.md +11 -0
- package/docs/usage/plugins/ldap/groups.md +4 -1
- package/docs/usage/plugins/ldap/password-policy.md +7 -0
- package/docs/usage/plugins/ldap/raw.md +17 -1
- package/docs/usage/upgrading.md +253 -0
- package/package.json +372 -286
- package/static/browser/ldap-browser/LdapBrowser.js +8 -6
- package/static/browser/ldap-browser/LdapBrowser.js.map +1 -1
- package/static/browser/ldap-browser/api/RawApiClient.js +2 -0
- package/static/browser/ldap-browser/api/RawApiClient.js.map +1 -1
- package/static/browser/ldap-browser/components/EntryTree.js +9 -5
- package/static/browser/ldap-browser/components/EntryTree.js.map +1 -1
- package/static/browser/ldap-browser/components/EntryView.js +2 -0
- package/static/browser/ldap-browser/components/EntryView.js.map +1 -1
- package/static/browser/ldap-browser/schema.js +3 -2
- package/static/browser/ldap-browser/schema.js.map +1 -1
- package/static/browser/ldap-browser.esm.js +27 -18
- package/static/browser/ldap-browser.esm.js.map +1 -1
- package/static/browser/ldap-browser.js +27 -18
- package/static/browser/ldap-browser.js.map +1 -1
- package/static/browser/ldap-browser.min.js +1 -1
- package/static/browser/ldap-browser.min.js.map +1 -1
- package/static/browser/ldap-group-editor/LdapGroupEditor.js +8 -6
- package/static/browser/ldap-group-editor/LdapGroupEditor.js.map +1 -1
- package/static/browser/ldap-group-editor/api/GroupApiClient.js +1 -0
- package/static/browser/ldap-group-editor/api/GroupApiClient.js.map +1 -1
- package/static/browser/ldap-group-editor/components/CreateGroupModal.js +5 -1
- package/static/browser/ldap-group-editor/components/CreateGroupModal.js.map +1 -1
- package/static/browser/ldap-group-editor/components/GroupPropertyEditor.js +6 -3
- package/static/browser/ldap-group-editor/components/GroupPropertyEditor.js.map +1 -1
- package/static/browser/ldap-group-editor/components/GroupTree.js +6 -3
- package/static/browser/ldap-group-editor/components/GroupTree.js.map +1 -1
- package/static/browser/ldap-group-editor/components/MoveGroupModal.js +6 -3
- package/static/browser/ldap-group-editor/components/MoveGroupModal.js.map +1 -1
- package/static/browser/ldap-group-editor.esm.js +32 -16
- package/static/browser/ldap-group-editor.esm.js.map +1 -1
- package/static/browser/ldap-group-editor.js +32 -16
- package/static/browser/ldap-group-editor.js.map +1 -1
- package/static/browser/ldap-group-editor.min.js +1 -1
- package/static/browser/ldap-group-editor.min.js.map +1 -1
- package/static/browser/ldap-resource-editor/api/ResourceApiClient.js +3 -0
- package/static/browser/ldap-resource-editor/api/ResourceApiClient.js.map +1 -1
- package/static/browser/ldap-resource-editor/cache/CacheManager.js +3 -1
- package/static/browser/ldap-resource-editor/cache/CacheManager.js.map +1 -1
- package/static/browser/ldap-tree-viewer/LdapTreeViewer.js +6 -1
- package/static/browser/ldap-tree-viewer/LdapTreeViewer.js.map +1 -1
- package/static/browser/ldap-tree-viewer/api/LdapApiClient.js +2 -0
- package/static/browser/ldap-tree-viewer/api/LdapApiClient.js.map +1 -1
- package/static/browser/ldap-tree-viewer/components/TreeNode.js +4 -0
- package/static/browser/ldap-tree-viewer/components/TreeNode.js.map +1 -1
- package/static/browser/ldap-tree-viewer/components/TreeRoot.js +3 -0
- package/static/browser/ldap-tree-viewer/components/TreeRoot.js.map +1 -1
- package/static/browser/ldap-tree-viewer/store/Store.js +3 -1
- package/static/browser/ldap-tree-viewer/store/Store.js.map +1 -1
- package/static/browser/ldap-tree-viewer.esm.js +18 -2
- package/static/browser/ldap-tree-viewer.esm.js.map +1 -1
- package/static/browser/ldap-tree-viewer.js +18 -2
- package/static/browser/ldap-tree-viewer.js.map +1 -1
- package/static/browser/ldap-tree-viewer.min.js +1 -1
- package/static/browser/ldap-tree-viewer.min.js.map +1 -1
- package/static/browser/ldap-unit-editor/LdapUnitEditor.js +7 -5
- package/static/browser/ldap-unit-editor/LdapUnitEditor.js.map +1 -1
- package/static/browser/ldap-unit-editor/api/UnitApiClient.js +1 -0
- package/static/browser/ldap-unit-editor/api/UnitApiClient.js.map +1 -1
- package/static/browser/ldap-unit-editor/components/MoveUnitModal.js +7 -4
- package/static/browser/ldap-unit-editor/components/MoveUnitModal.js.map +1 -1
- package/static/browser/ldap-unit-editor/components/UnitPropertyEditor.js +7 -4
- package/static/browser/ldap-unit-editor/components/UnitPropertyEditor.js.map +1 -1
- package/static/browser/ldap-unit-editor/components/UnitTree.js +6 -3
- package/static/browser/ldap-unit-editor/components/UnitTree.js.map +1 -1
- package/static/browser/ldap-unit-editor.esm.js +28 -16
- package/static/browser/ldap-unit-editor.esm.js.map +1 -1
- package/static/browser/ldap-unit-editor.js +28 -16
- package/static/browser/ldap-unit-editor.js.map +1 -1
- package/static/browser/ldap-unit-editor.min.js +1 -1
- package/static/browser/ldap-unit-editor.min.js.map +1 -1
- package/static/browser/ldap-user-editor/LdapUserEditor.js +9 -7
- package/static/browser/ldap-user-editor/LdapUserEditor.js.map +1 -1
- package/static/browser/ldap-user-editor/api/UserApiClient.js +2 -0
- package/static/browser/ldap-user-editor/api/UserApiClient.js.map +1 -1
- package/static/browser/ldap-user-editor/cache/CacheManager.js +3 -1
- package/static/browser/ldap-user-editor/cache/CacheManager.js.map +1 -1
- package/static/browser/ldap-user-editor/components/MoveUserModal.js +7 -4
- package/static/browser/ldap-user-editor/components/MoveUserModal.js.map +1 -1
- package/static/browser/ldap-user-editor/components/PointerField.js +6 -1
- package/static/browser/ldap-user-editor/components/PointerField.js.map +1 -1
- package/static/browser/ldap-user-editor/components/UserEditor.js +10 -5
- package/static/browser/ldap-user-editor/components/UserEditor.js.map +1 -1
- package/static/browser/ldap-user-editor/components/UserList.js +8 -4
- package/static/browser/ldap-user-editor/components/UserList.js.map +1 -1
- package/static/browser/ldap-user-editor/components/UserTree.js +7 -3
- package/static/browser/ldap-user-editor/components/UserTree.js.map +1 -1
- package/static/browser/ldap-user-editor.esm.js +55 -30
- package/static/browser/ldap-user-editor.esm.js.map +1 -1
- package/static/browser/ldap-user-editor.js +55 -30
- package/static/browser/ldap-user-editor.js.map +1 -1
- package/static/browser/ldap-user-editor.min.js +1 -1
- package/static/browser/ldap-user-editor.min.js.map +1 -1
- package/static/browser/shared/components/DisposableComponent.js +3 -5
- package/static/browser/shared/components/DisposableComponent.js.map +1 -1
- package/static/browser/shared/components/Modal.js +2 -1
- package/static/browser/shared/components/Modal.js.map +1 -1
- package/static/browser/shared/components/StatusMessage.js +3 -2
- package/static/browser/shared/components/StatusMessage.js.map +1 -1
- package/static/browser/shared/utils/form.js.map +1 -1
- package/static/browser/shared/utils/hmac.js +1 -0
- package/static/browser/shared/utils/hmac.js.map +1 -1
- package/static/browser/shared/utils/totp.js +1 -0
- package/static/browser/shared/utils/totp.js.map +1 -1
- package/static/browser/shared.esm.js +9 -8
- package/static/browser/shared.esm.js.map +1 -1
- package/static/browser/shared.js +9 -8
- package/static/browser/shared.js.map +1 -1
- package/static/browser/shared.min.js +1 -1
- package/static/browser/shared.min.js.map +1 -1
- package/static/schemas/ad/groups.json +1 -1
- package/static/schemas/ad/users.json +3 -3
- package/static/schemas/example/organizations.json +2 -2
- package/static/schemas/example/users.json +2 -2
- package/static/schemas/obm/users.json +2 -2
- package/static/schemas/standard/groups.json +1 -1
- package/static/schemas/standard/users.json +2 -2
- package/static/schemas/twake/groups.json +4 -4
- package/static/schemas/twake/teamMailboxes.json +3 -3
- package/static/schemas/twake/users.json +7 -7
|
@@ -66,7 +66,7 @@ A complete schema consists of two main sections: entity metadata and attribute d
|
|
|
66
66
|
},
|
|
67
67
|
"mail": {
|
|
68
68
|
"type": "string",
|
|
69
|
-
"test": "^[^@\\s]+@[^@\\s]
|
|
69
|
+
"test": "^[^@\\s]+@[^@\\s.]+(\\.[^@\\s.]+)+$",
|
|
70
70
|
"required": false,
|
|
71
71
|
"role": "primaryEmail"
|
|
72
72
|
},
|
|
@@ -74,7 +74,7 @@ A complete schema consists of two main sections: entity metadata and attribute d
|
|
|
74
74
|
"type": "array",
|
|
75
75
|
"items": {
|
|
76
76
|
"type": "string",
|
|
77
|
-
"test": "^[^@\\s]+@[^@\\s]
|
|
77
|
+
"test": "^[^@\\s]+@[^@\\s.]+(\\.[^@\\s.]+)+$"
|
|
78
78
|
},
|
|
79
79
|
"required": false,
|
|
80
80
|
"role": "emailAliases"
|
|
@@ -197,7 +197,7 @@ Simple text values.
|
|
|
197
197
|
},
|
|
198
198
|
"mail": {
|
|
199
199
|
"type": "string",
|
|
200
|
-
"test": "^[^@\\s]+@[^@\\s]
|
|
200
|
+
"test": "^[^@\\s]+@[^@\\s.]+(\\.[^@\\s.]+)+$",
|
|
201
201
|
"required": false,
|
|
202
202
|
"role": "primaryEmail"
|
|
203
203
|
},
|
|
@@ -237,7 +237,7 @@ Multi-valued attributes containing multiple items of the same type.
|
|
|
237
237
|
"type": "array",
|
|
238
238
|
"items": {
|
|
239
239
|
"type": "string",
|
|
240
|
-
"test": "^[^@\\s]+@[^@\\s]
|
|
240
|
+
"test": "^[^@\\s]+@[^@\\s.]+(\\.[^@\\s.]+)+$"
|
|
241
241
|
},
|
|
242
242
|
"required": false,
|
|
243
243
|
"role": "emailAliases"
|
|
@@ -338,19 +338,20 @@ Complete reference for all attribute properties.
|
|
|
338
338
|
|
|
339
339
|
### Attribute Properties Table
|
|
340
340
|
|
|
341
|
-
| Property
|
|
342
|
-
|
|
|
343
|
-
| `type`
|
|
344
|
-
| `required`
|
|
345
|
-
| `fixed`
|
|
346
|
-
| `role`
|
|
347
|
-
| `test`
|
|
348
|
-
| `
|
|
349
|
-
| `
|
|
350
|
-
| `
|
|
351
|
-
| `
|
|
352
|
-
| `
|
|
353
|
-
| `
|
|
341
|
+
| Property | Type | Applies To | Description | Example |
|
|
342
|
+
| ----------- | --------------- | ------------------- | ------------------------------------------------------------------------------------- | ----------------------------------- |
|
|
343
|
+
| `type` | string | All | `"string"`, `"array"`, `"pointer"`, `"number"`, `"integer"`, `"boolean"`, `"date"` | `"string"` |
|
|
344
|
+
| `required` | boolean | All | Whether the attribute must be present | `true` |
|
|
345
|
+
| `fixed` | boolean | All | Whether the attribute value cannot be changed after creation | `true` |
|
|
346
|
+
| `role` | string/string[] | String | Semantic role, or roles, for special handling (see [Semantic Roles](#semantic-roles)) | `"identifier"` |
|
|
347
|
+
| `test` | string/regex | String, Array items | Regular expression for validation | `"^[a-zA-Z0-9._-]{1,255}$"` |
|
|
348
|
+
| `maxLength` | number | String, Array items | Longest value accepted, in characters; a longer one is refused before `test` (4096) | `255` |
|
|
349
|
+
| `branch` | string[] | Pointer | LDAP branches where referenced entries exist | `["ou=users,dc=example,dc=com"]` |
|
|
350
|
+
| `ui` | object | Pointer | UI configuration for pointer selection (future feature) | `{}` |
|
|
351
|
+
| `hint` | text | String, Array items | What a valid value looks like, shown under the field and quoted in refusals | `"Expected pattern 999 9999"` |
|
|
352
|
+
| `group` | text | All | Form section the attribute is shown in | `"Mailbox Settings"` |
|
|
353
|
+
| `default` | any | All | Default value for new entries | `["top", "person"]` |
|
|
354
|
+
| `items` | object | Array | Schema for array element validation | `{"type": "string", "test": "..."}` |
|
|
354
355
|
|
|
355
356
|
A _text_ is a plain string or a map keyed by language tag,
|
|
356
357
|
`{ "en": "Mailbox Settings", "fr": "Paramètres de messagerie" }`, picked as
|
|
@@ -378,16 +379,40 @@ answers, one value where the attribute holds one, can be sent back as is;
|
|
|
378
379
|
two values or more for a single-valued attribute are refused. Each element
|
|
379
380
|
of an `array` follows `items.type`, text without `items`. A `number` or
|
|
380
381
|
`integer` is a JSON number or its text (`42`, `"42"`), a `boolean` a JSON
|
|
381
|
-
boolean or the directory's `TRUE` / `FALSE
|
|
382
|
+
boolean or the directory's `TRUE` / `FALSE`. A JSON number is judged on the
|
|
383
|
+
text written for it, what the directory is sent: `1e21` and `1e-7` are
|
|
384
|
+
written `1e+21` and `1e-7`, so they are refused like that text, and a whole
|
|
385
|
+
number beyond 2⁵³ is refused whatever the type, as the JSON parser has
|
|
386
|
+
already lost its digits. Anything else for them, and
|
|
382
387
|
anything but text for a `string`, `date` or `pointer`, is refused; an
|
|
383
388
|
attribute with `normalize` takes any text, read after validation. In a
|
|
384
389
|
`replace`, `null` or `[]` clears an attribute; in an `add` or on a creation
|
|
385
|
-
they are refused as no value
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
390
|
+
they are refused as no value when the schema declares the attribute. A
|
|
391
|
+
`null` under a name the schema does not declare — and, for an entity without
|
|
392
|
+
a schema, under any name — is dropped from a creation and from an `add`, as
|
|
393
|
+
if the key were left out, and clears the attribute in a `replace`. A
|
|
394
|
+
`delete` naming the attribute, or naming it with no value, removes it,
|
|
395
|
+
unless it is `required`; naming values removes those, every value it holds
|
|
396
|
+
included, as the server does not read what remains, and `''` names no
|
|
397
|
+
value. An empty string sent as a value is checked against `test`, refused
|
|
398
|
+
for a pointer, and missing for a `required` attribute. Every refusal answers
|
|
399
|
+
400 with the attribute's name.
|
|
400
|
+
|
|
401
|
+
#### What an attribute may be called
|
|
402
|
+
|
|
403
|
+
A name is read as the directory reads it: case and the `;binary` option do
|
|
404
|
+
not change the attribute it names, so `Cn`, `CN` and `cn;binary` all name
|
|
405
|
+
`cn`. Each key the schema declares is written under the schema's spelling —
|
|
406
|
+
`Cn` becomes `cn`, `L;binary` becomes `l;binary` — before any check, so that
|
|
407
|
+
a `required` attribute counts as present wherever it was sent, and a `fixed`
|
|
408
|
+
one is written once, at its default. The attribute's type is read the same
|
|
409
|
+
way when a value is converted, so a boolean sent as `pwdReset;binary` is
|
|
410
|
+
written `TRUE`.
|
|
411
|
+
|
|
412
|
+
Two keys of an entry or of one part of a change naming one attribute are
|
|
413
|
+
refused; the option does not make them two, so `l` and `l;binary` are
|
|
414
|
+
refused together. A name the schema does not declare is left as sent, and a
|
|
415
|
+
strict schema refuses it.
|
|
391
416
|
|
|
392
417
|
Every entity route applies these rules; `test/lib/entitySchema.contract.test.ts`
|
|
393
418
|
asserts them on a flat entity, a group and an organization alike. In the
|
|
@@ -451,7 +476,10 @@ Assigns semantic meaning to attributes for special handling by the application.
|
|
|
451
476
|
|
|
452
477
|
#### `test` (Optional)
|
|
453
478
|
|
|
454
|
-
Regular expression pattern for validating attribute values.
|
|
479
|
+
Regular expression pattern for validating attribute values. The value is
|
|
480
|
+
judged only up to its attribute's length: see
|
|
481
|
+
[`maxLength`](#maxlength-optional) below, which a deployment writing its own
|
|
482
|
+
pattern should read.
|
|
455
483
|
|
|
456
484
|
```json
|
|
457
485
|
{
|
|
@@ -461,7 +489,7 @@ Regular expression pattern for validating attribute values.
|
|
|
461
489
|
},
|
|
462
490
|
"mail": {
|
|
463
491
|
"type": "string",
|
|
464
|
-
"test": "^[^@\\s]+@[^@\\s]
|
|
492
|
+
"test": "^[^@\\s]+@[^@\\s.]+(\\.[^@\\s.]+)+$"
|
|
465
493
|
}
|
|
466
494
|
}
|
|
467
495
|
```
|
|
@@ -474,7 +502,38 @@ Regular expression pattern for validating attribute values.
|
|
|
474
502
|
"type": "array",
|
|
475
503
|
"items": {
|
|
476
504
|
"type": "string",
|
|
477
|
-
"test": "^[^@\\s]+@[^@\\s]
|
|
505
|
+
"test": "^[^@\\s]+@[^@\\s.]+(\\.[^@\\s.]+)+$"
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
```
|
|
510
|
+
|
|
511
|
+
#### `maxLength` (Optional)
|
|
512
|
+
|
|
513
|
+
Longest value, in UTF-16 code units (what `.length` counts, so an emoji or an
|
|
514
|
+
accented letter outside the basic plane counts as two), accepted before `test`
|
|
515
|
+
runs on it. A value past
|
|
516
|
+
it is refused with 400, and the pattern never reads it — whether or not it
|
|
517
|
+
would have matched. On an array, `maxLength` on the attribute governs every
|
|
518
|
+
item; one declared under `items` is read only when the attribute declares
|
|
519
|
+
none. It is a positive whole number of characters: the server refuses to load
|
|
520
|
+
a schema where it is not.
|
|
521
|
+
|
|
522
|
+
A pattern is written for values of its attribute, not for a payload of any
|
|
523
|
+
size: handed several kilobytes, a pattern whose parts overlap walks the value
|
|
524
|
+
in quadratic time, on the event loop that answers every other request
|
|
525
|
+
meanwhile. The limit keeps the pattern within what it was written for. It is
|
|
526
|
+
**4096** unless the schema says otherwise; an attribute holding longer values
|
|
527
|
+
— a description, a public key — declares its own.
|
|
528
|
+
|
|
529
|
+
```json
|
|
530
|
+
{
|
|
531
|
+
"sshPublicKey": {
|
|
532
|
+
"type": "array",
|
|
533
|
+
"items": {
|
|
534
|
+
"type": "string",
|
|
535
|
+
"maxLength": 16384,
|
|
536
|
+
"test": "^[^\\r\\n]*$"
|
|
478
537
|
}
|
|
479
538
|
}
|
|
480
539
|
}
|
|
@@ -594,7 +653,7 @@ Email-related roles help applications handle email addresses consistently across
|
|
|
594
653
|
{
|
|
595
654
|
"mail": {
|
|
596
655
|
"type": "string",
|
|
597
|
-
"test": "^[^@\\s]+@[^@\\s]
|
|
656
|
+
"test": "^[^@\\s]+@[^@\\s.]+(\\.[^@\\s.]+)+$",
|
|
598
657
|
"required": false,
|
|
599
658
|
"role": "primaryEmail"
|
|
600
659
|
}
|
|
@@ -609,7 +668,7 @@ Email-related roles help applications handle email addresses consistently across
|
|
|
609
668
|
"type": "array",
|
|
610
669
|
"items": {
|
|
611
670
|
"type": "string",
|
|
612
|
-
"test": "^[^@\\s]+@[^@\\s]
|
|
671
|
+
"test": "^[^@\\s]+@[^@\\s.]+(\\.[^@\\s.]+)+$"
|
|
613
672
|
},
|
|
614
673
|
"required": false,
|
|
615
674
|
"role": "emailAliases"
|
|
@@ -686,9 +745,14 @@ Common validation patterns:
|
|
|
686
745
|
**Email:**
|
|
687
746
|
|
|
688
747
|
```regex
|
|
689
|
-
^[^@\s]+@[^@\s]
|
|
748
|
+
^[^@\s]+@[^@\s.]+(\.[^@\s.]+)+$
|
|
690
749
|
```
|
|
691
750
|
|
|
751
|
+
The domain part holds no dot of its own: where it did, the pattern tried every
|
|
752
|
+
dot as the last separator and read the value again each time — seconds for a
|
|
753
|
+
value of a few kilobytes. The result is that a trailing dot (`a@b.c.`) is
|
|
754
|
+
refused, where the older form accepted it.
|
|
755
|
+
|
|
692
756
|
**DN (Distinguished Name):**
|
|
693
757
|
|
|
694
758
|
```regex
|
|
@@ -1045,7 +1109,7 @@ Start with the schema that most closely matches your directory type:
|
|
|
1045
1109
|
"attributes": {
|
|
1046
1110
|
"mail": {
|
|
1047
1111
|
"type": "string",
|
|
1048
|
-
"test": "^[^@\\s]+@[^@\\s]
|
|
1112
|
+
"test": "^[^@\\s]+@[^@\\s.]+(\\.[^@\\s.]+)+$",
|
|
1049
1113
|
"required": false,
|
|
1050
1114
|
"role": "primaryEmail"
|
|
1051
1115
|
},
|
|
@@ -1238,7 +1302,7 @@ Use `test` patterns to enforce data quality:
|
|
|
1238
1302
|
},
|
|
1239
1303
|
"mail": {
|
|
1240
1304
|
"type": "string",
|
|
1241
|
-
"test": "^[^@\\s]+@[^@\\s]
|
|
1305
|
+
"test": "^[^@\\s]+@[^@\\s.]+(\\.[^@\\s.]+)+$"
|
|
1242
1306
|
}
|
|
1243
1307
|
}
|
|
1244
1308
|
```
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# Published contracts
|
|
2
|
+
|
|
3
|
+
Other code depends on three things ldap-rest publishes. A change to one that
|
|
4
|
+
is not additive breaks that code, so it needs a major release and the pull
|
|
5
|
+
request says so before it merges.
|
|
6
|
+
|
|
7
|
+
- **Configuration**: the CLI options and `DM_*` variables of
|
|
8
|
+
[Configuration](../usage/configuration.md) and of each plugin's page.
|
|
9
|
+
- **REST API**: the routes, request bodies and answers of the
|
|
10
|
+
[REST API](../client-development/api/rest-api.md), their parameters,
|
|
11
|
+
responses (references resolved), statuses and response headers. The error
|
|
12
|
+
`code` values are reviewed by hand: the document types them as strings.
|
|
13
|
+
- **Plugin API**: what the npm sub-path exports declare — `ldap-rest`,
|
|
14
|
+
`./hooks`, `./plugin`, `./ldapactions`, `./expressformatedresponses`, the
|
|
15
|
+
`./plugin-*`, `./abstract-*` and `./browser-*` entries — and the JSON
|
|
16
|
+
schema format of the `./schema-*` entries.
|
|
17
|
+
|
|
18
|
+
[API stability](../README.md#api-stability) says what a minor or patch
|
|
19
|
+
release promises. This page says how a change is detected, and what to do
|
|
20
|
+
when it is not additive.
|
|
21
|
+
|
|
22
|
+
## Committed snapshots
|
|
23
|
+
|
|
24
|
+
Two snapshots are generated locally and checked in CI, so a change to a
|
|
25
|
+
contract shows up as a diff instead of a surprise after the release:
|
|
26
|
+
|
|
27
|
+
- `docs/usage/options.snapshot.json` lists every option's CLI name, plural
|
|
28
|
+
form, environment variable, type, default, kind, required flag and aliases.
|
|
29
|
+
Regenerate it with `npm run snapshot:options`; `npm run check:options`, part
|
|
30
|
+
of `npm run check`, fails when it is stale.
|
|
31
|
+
- `openapi.json` is the REST API document the published reference is built
|
|
32
|
+
from. Regenerate it with `npm run generate:openapi`; `npm run check:openapi`
|
|
33
|
+
fails when it is stale.
|
|
34
|
+
|
|
35
|
+
The plugin types have no snapshot yet: one api-extractor report per sub-path
|
|
36
|
+
export is a change of its own. Until it lands, a change to an exported type is
|
|
37
|
+
reviewed by hand.
|
|
38
|
+
|
|
39
|
+
The snapshot records what the parser reads. A narrowed `choices` list, a
|
|
40
|
+
raised `min` or a lowered `max` is checked when a plugin reads its options,
|
|
41
|
+
not by the snapshot, and is reviewed by hand, as is a custom error `code`.
|
|
42
|
+
|
|
43
|
+
## The pull request gate
|
|
44
|
+
|
|
45
|
+
The `contracts` job of `.github/workflows/contracts.yml` generates the
|
|
46
|
+
snapshots from the pull request and compares them with the base branch's
|
|
47
|
+
committed ones. It reports:
|
|
48
|
+
|
|
49
|
+
- additive changes — a new option, route or field — and lets them through;
|
|
50
|
+
- non-additive changes, and fails unless the pull request carries the
|
|
51
|
+
`breaking` label.
|
|
52
|
+
|
|
53
|
+
A change is non-additive when it removes or narrows what was published:
|
|
54
|
+
a removed option or environment variable, a changed type, default, bound,
|
|
55
|
+
`const`, enum or required flag, a request value that becomes an enum, a
|
|
56
|
+
request object that stops accepting additional properties, a removed route,
|
|
57
|
+
method, parameter, response status, response header or field, a request field
|
|
58
|
+
that becomes required, a response that may now be null, changed security
|
|
59
|
+
requirements, a removed union variant, a value an alternative of the type
|
|
60
|
+
closes with an enum or a `const` where the type used to accept any, an
|
|
61
|
+
untyped request value that becomes a union, an `allOf` that adds a
|
|
62
|
+
constraint, or — once the plugin snapshot exists — a removed export or a
|
|
63
|
+
narrowed signature. Renaming an option is a deprecation, not a removal, as
|
|
64
|
+
long as the old CLI name and environment variable stay in its `aliases` and
|
|
65
|
+
`envAliases`. Adding a union variant, a field or an optional parameter is
|
|
66
|
+
additive, and so is a request union with an alternative that still accepts
|
|
67
|
+
everything the base did — in a response the client reads every alternative,
|
|
68
|
+
so a field the others drop is still a removal. A `oneOf` is the exception:
|
|
69
|
+
it refuses a value two alternatives match, so an alternative as wide as the
|
|
70
|
+
base narrows the others away, and the alternatives are not told apart from
|
|
71
|
+
one another — a disjoint `oneOf` therefore asks for the label too.
|
|
72
|
+
Documentation-only edits, such as a summary or description, are ignored.
|
|
73
|
+
|
|
74
|
+
The job runs the scripts from the pull request, so a change to them is
|
|
75
|
+
reviewed like any other code, as `.github/CODEOWNERS` requires.
|
|
76
|
+
|
|
77
|
+
The `breaking` label records that the maintainers accepted the break, and the
|
|
78
|
+
`CHANGELOG.md` section must say so: the release gate below reads the section,
|
|
79
|
+
not the label, and refuses to ship the break as a minor or patch release. The
|
|
80
|
+
workflow listens to label events, so adding the label runs the job again; it
|
|
81
|
+
has its own concurrency group, so that event does not cancel the test matrix.
|
|
82
|
+
|
|
83
|
+
To try the comparison locally against your base branch:
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
npx tsx scripts/contracts.ts --base origin/master
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## The release gate
|
|
90
|
+
|
|
91
|
+
`.github/workflows/release.yml` runs `scripts/check-release.ts` on the tag. A
|
|
92
|
+
non-major tag whose `CHANGELOG.md` section lists `### Breaking Changes` is
|
|
93
|
+
refused. For a 0.x version, a minor release counts as major, as semantic
|
|
94
|
+
versioning lets it break. When the tag has no section of its own, the gate
|
|
95
|
+
reads `## Unreleased`, so a tag cut before the section was renamed is still
|
|
96
|
+
checked; with neither section it fails. When the CHANGELOG lists no earlier
|
|
97
|
+
release, only a first `X.0.0` counts as major, so a trimmed file cannot open
|
|
98
|
+
the gate.
|
|
99
|
+
|
|
100
|
+
## Deprecating instead of breaking
|
|
101
|
+
|
|
102
|
+
The window and the rules are in
|
|
103
|
+
[CONTRIBUTING.md](../../CONTRIBUTING.md#deprecating-a-published-contract).
|
|
104
|
+
The mechanics of an option alias are in
|
|
105
|
+
[plugin options](../plugin-development/options.md#deprecating-an-option): the
|
|
106
|
+
old CLI name and environment variable go in `aliases` and `envAliases`, and
|
|
107
|
+
the server warns at startup while it still reads them. An array option's
|
|
108
|
+
plural form has no alias slot: renaming it is a breaking change, so it waits
|
|
109
|
+
for a major release.
|
|
@@ -7,7 +7,9 @@ This guide will help you create powerful, production-ready plugins for LDAP-Rest
|
|
|
7
7
|
- [Why Create a Plugin](#why-create-a-plugin)
|
|
8
8
|
- [Plugin Structure](#plugin-structure)
|
|
9
9
|
- [Creating Your Plugin](#creating-your-plugin)
|
|
10
|
+
- [Plugin services](./services.md)
|
|
10
11
|
- [Custom Configuration Options](#custom-configuration-options)
|
|
12
|
+
- [Plugin options](./options.md)
|
|
11
13
|
- [Loading Your Plugin](#loading-your-plugin)
|
|
12
14
|
- [Plugin Features](#plugin-features)
|
|
13
15
|
- [Configuration Best Practices](#configuration-best-practices)
|
|
@@ -53,14 +55,21 @@ export default class MyPlugin extends DmPlugin {
|
|
|
53
55
|
- **roles** (optional): Array categorizing plugin purpose
|
|
54
56
|
- **dependencies** (optional): Required plugins that must load first
|
|
55
57
|
- **hooks** (optional): Callbacks for LDAP operations
|
|
58
|
+
- **provides** (optional): Typed services this plugin offers, see
|
|
59
|
+
[plugin services](services.md)
|
|
56
60
|
- **api()** (optional): Method to register REST endpoints
|
|
57
61
|
|
|
58
62
|
### Available from Base Class
|
|
59
63
|
|
|
60
64
|
- **this.server**: DM server instance
|
|
61
65
|
- **this.config**: Complete configuration object
|
|
66
|
+
- **this.options(declarations)**: Values of the options the plugin declares,
|
|
67
|
+
typed and checked, see [plugin options](options.md)
|
|
62
68
|
- **this.logger**: Winston logger instance
|
|
63
|
-
- **this.
|
|
69
|
+
- **this.hookBus**: The server's hooks: chain, notify and wait on them, see
|
|
70
|
+
[hooks](hooks.md#the-bus)
|
|
71
|
+
- **this.service(token)**: The instance another plugin provides under a
|
|
72
|
+
service token, or `null`, see [plugin services](services.md)
|
|
64
73
|
- **this.fetch**: `fetch` timed into the
|
|
65
74
|
[outbound metrics](../usage/operations.md#metrics) under the plugin's
|
|
66
75
|
name; the lint refuses a bare `fetch` or `node-fetch` under `src`, and a
|
|
@@ -272,99 +281,15 @@ npx ldap-rest
|
|
|
272
281
|
|
|
273
282
|
## Custom Configuration Options
|
|
274
283
|
|
|
275
|
-
|
|
284
|
+
A core plugin declares its options next to its code, in a
|
|
285
|
+
`<plugin>.options.ts` file, and reads them through `this.options()` with their
|
|
286
|
+
types, defaults and checks. See [plugin options](options.md).
|
|
276
287
|
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
4. **Access in plugin**: `this.config.option_name`
|
|
283
|
-
|
|
284
|
-
### Single Value Options
|
|
285
|
-
|
|
286
|
-
```bash
|
|
287
|
-
# Command line
|
|
288
|
-
npx ldap-rest \
|
|
289
|
-
--webhook-url https://example.com/webhook \
|
|
290
|
-
--webhook-timeout 5000 \
|
|
291
|
-
--webhook-retry true
|
|
292
|
-
|
|
293
|
-
# Environment variables
|
|
294
|
-
export DM_WEBHOOK_URL=https://example.com/webhook
|
|
295
|
-
export DM_WEBHOOK_TIMEOUT=5000
|
|
296
|
-
export DM_WEBHOOK_RETRY=true
|
|
297
|
-
```
|
|
298
|
-
|
|
299
|
-
In your plugin:
|
|
300
|
-
|
|
301
|
-
```typescript
|
|
302
|
-
constructor(server: DM) {
|
|
303
|
-
super(server);
|
|
304
|
-
|
|
305
|
-
// Access custom options (converted to snake_case)
|
|
306
|
-
const url = this.config.webhook_url; // string
|
|
307
|
-
const timeout = this.config.webhook_timeout; // string (convert if needed)
|
|
308
|
-
const retry = this.config.webhook_retry; // string 'true' (convert if needed)
|
|
309
|
-
|
|
310
|
-
// Type conversion
|
|
311
|
-
const timeoutNum = parseInt(timeout as string || '3000');
|
|
312
|
-
const retryBool = (retry as string) === 'true';
|
|
313
|
-
}
|
|
314
|
-
```
|
|
315
|
-
|
|
316
|
-
### Multiple Value Options
|
|
317
|
-
|
|
318
|
-
Repeat the same option multiple times to create an array:
|
|
319
|
-
|
|
320
|
-
```bash
|
|
321
|
-
# Command line
|
|
322
|
-
npx ldap-rest \
|
|
323
|
-
--allowed-domain example.com \
|
|
324
|
-
--allowed-domain test.com \
|
|
325
|
-
--allowed-domain dev.com
|
|
326
|
-
|
|
327
|
-
# Environment variable (comma or semicolon separated)
|
|
328
|
-
export DM_ALLOWED_DOMAINS=example.com,test.com,dev.com
|
|
329
|
-
```
|
|
330
|
-
|
|
331
|
-
In your plugin:
|
|
332
|
-
|
|
333
|
-
```typescript
|
|
334
|
-
constructor(server: DM) {
|
|
335
|
-
super(server);
|
|
336
|
-
|
|
337
|
-
// Access as array (note: singular becomes plural in config key)
|
|
338
|
-
const domains = this.config.allowed_domain as string[];
|
|
339
|
-
// or sometimes stored as: this.config.allowed_domains
|
|
340
|
-
|
|
341
|
-
this.logger.info(`Allowed domains: ${domains.join(', ')}`);
|
|
342
|
-
}
|
|
343
|
-
```
|
|
344
|
-
|
|
345
|
-
### Configuration Priority
|
|
346
|
-
|
|
347
|
-
Values are resolved in this order (later overrides earlier):
|
|
348
|
-
|
|
349
|
-
1. **Default value** in your plugin
|
|
350
|
-
2. **Environment variable** (`DM_OPTION_NAME`)
|
|
351
|
-
3. **Command-line argument** (`--option-name`)
|
|
352
|
-
|
|
353
|
-
```typescript
|
|
354
|
-
constructor(server: DM) {
|
|
355
|
-
super(server);
|
|
356
|
-
|
|
357
|
-
// Provide defaults for optional configuration
|
|
358
|
-
const webhookUrl = this.config.webhook_url || 'http://localhost:8080/webhook';
|
|
359
|
-
const webhookTimeout = parseInt(this.config.webhook_timeout as string || '3000');
|
|
360
|
-
const maxRetries = parseInt(this.config.max_retries as string || '3');
|
|
361
|
-
|
|
362
|
-
// Validate required configuration
|
|
363
|
-
if (!this.config.webhook_secret) {
|
|
364
|
-
throw new Error('--webhook-secret is required for authentication');
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
```
|
|
288
|
+
A plugin outside the repository cannot add to `src/config/args.ts` yet. It keeps
|
|
289
|
+
reading `this.config.<name>`: LDAP-Rest accepts and stores unknown
|
|
290
|
+
`--option-name value` pairs under `option_name`, with `--option-name` and
|
|
291
|
+
`DM_OPTION_NAME` overriding in that order. See
|
|
292
|
+
[configuration](../usage/configuration.md#environment-variables).
|
|
368
293
|
|
|
369
294
|
---
|
|
370
295
|
|
|
@@ -532,7 +457,8 @@ const results = await this.server.ldap.search(
|
|
|
532
457
|
'ou=users,dc=example,dc=com'
|
|
533
458
|
);
|
|
534
459
|
|
|
535
|
-
// Search with pagination (returns AsyncGenerator
|
|
460
|
+
// Search with pagination (returns AsyncGenerator; the connection is taken
|
|
461
|
+
// when the first page is read)
|
|
536
462
|
const pagedResults = await this.server.ldap.search(
|
|
537
463
|
{
|
|
538
464
|
paged: true,
|
|
@@ -684,7 +610,15 @@ hooks: Hooks = {
|
|
|
684
610
|
|
|
685
611
|
### Exposing API Endpoints
|
|
686
612
|
|
|
687
|
-
|
|
613
|
+
Declare routes with [`defineRoute`](routes.md): it types and validates the
|
|
614
|
+
request (`params`, `query`, `body`), answers a failing request with a 400
|
|
615
|
+
naming the paths at fault, and records the route for the OpenAPI document.
|
|
616
|
+
The `asyncHandler` form below remains for routes that have not been migrated
|
|
617
|
+
yet.
|
|
618
|
+
|
|
619
|
+
Create REST API endpoints for your plugin. Always use the `asyncHandler`
|
|
620
|
+
wrapper for async routes, so that errors are properly handled and do not
|
|
621
|
+
crash the server.
|
|
688
622
|
|
|
689
623
|
```typescript
|
|
690
624
|
import DmPlugin, { asyncHandler } from '../../abstract/plugin';
|
|
@@ -791,6 +725,29 @@ app.get(
|
|
|
791
725
|
);
|
|
792
726
|
```
|
|
793
727
|
|
|
728
|
+
**Wrapping an error keeps its answer:**
|
|
729
|
+
|
|
730
|
+
Wrap with `cause` rather than in the message alone. The status and the class
|
|
731
|
+
of what was thrown are read through the chain, so a refusal stays a 403 and
|
|
732
|
+
a timeout a 504 wherever it surfaces:
|
|
733
|
+
|
|
734
|
+
```typescript
|
|
735
|
+
// ✅ GOOD: the refusal keeps its 403 when it reaches the client
|
|
736
|
+
throw new Error(`Failed to add group ${dn}: ${String(err)}`, { cause: err });
|
|
737
|
+
|
|
738
|
+
// ❌ BAD: a 403 becomes a 500, and its message is all that is left
|
|
739
|
+
throw new Error(`Failed to add group ${dn}: ${String(err)}`);
|
|
740
|
+
```
|
|
741
|
+
|
|
742
|
+
**Refusing a caller:**
|
|
743
|
+
|
|
744
|
+
An authorization plugin throws `AuthzRefusedError`, whose message is for the
|
|
745
|
+
operator: it names the model and the branch it judged. The client is told
|
|
746
|
+
`AUTHZ_REFUSED` with `code: "forbidden"` instead, whatever a plugin wrapped
|
|
747
|
+
it in on the way. A refusal that is not an authorization plugin's is any
|
|
748
|
+
`ForbiddenError`, answered with its own message; `isAuthzRefusal(err)` tells
|
|
749
|
+
the two apart.
|
|
750
|
+
|
|
794
751
|
**Custom error handling:**
|
|
795
752
|
|
|
796
753
|
```typescript
|
|
@@ -1369,6 +1326,7 @@ See [Tests and checks](../../CONTRIBUTING.md#tests-and-checks).
|
|
|
1369
1326
|
|
|
1370
1327
|
- [Contributing Guide](../../CONTRIBUTING.md) - Git workflow and PR guidelines
|
|
1371
1328
|
- [Hooks Reference](./hooks.md) - Complete list of available hooks
|
|
1329
|
+
- [Plugin services](./services.md) - Typed interfaces between plugins
|
|
1372
1330
|
- [Core Plugin Examples](../../src/plugins/) - Browse existing plugins
|
|
1373
1331
|
- [Test Examples](../../test/plugins/) - See how core plugins are tested
|
|
1374
1332
|
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
# Plugin Dependency Graph
|
|
2
2
|
|
|
3
|
-
This document describes the dependencies between LDAP-Rest plugins. There are
|
|
3
|
+
This document describes the dependencies between LDAP-Rest plugins. There are three types of dependencies:
|
|
4
4
|
|
|
5
5
|
1. **Explicit Dependencies**: Defined in the `dependencies` property of a plugin class
|
|
6
|
-
2. **
|
|
6
|
+
2. **Service Dependencies**: A plugin reaches a typed interface another one provides, see [plugin services](services.md)
|
|
7
|
+
3. **Hook Dependencies**: Implicit dependencies through hooks (one plugin provides a hook, another consumes it)
|
|
7
8
|
|
|
8
9
|
## Dependency Types
|
|
9
10
|
|
|
@@ -24,10 +25,20 @@ overrides — a dependency also given to `--plugin`, or an entry listed twice
|
|
|
24
25
|
is loaded once: the second request waits for the first. Only an entry with
|
|
25
26
|
overrides builds a second instance, and it needs a name of its own.
|
|
26
27
|
|
|
28
|
+
### Service Dependencies
|
|
29
|
+
|
|
30
|
+
A plugin provides a typed interface under a token, and a consumer reaches it
|
|
31
|
+
with `this.service(token)`. The token replaces the registry name as the way to
|
|
32
|
+
find another plugin's code; `dependencies` still decides what loads first. A
|
|
33
|
+
consumer whose provider is absent gets `null` and a single warning.
|
|
34
|
+
|
|
35
|
+
See [plugin services](services.md) for the token, the provided interface and
|
|
36
|
+
the registration rules.
|
|
37
|
+
|
|
27
38
|
### Hook Dependencies
|
|
28
39
|
|
|
29
40
|
**Hook Providers**: Plugins that implement hooks (via `hooks: Hooks = { ... }`)
|
|
30
|
-
**Hook Consumers**: Plugins that
|
|
41
|
+
**Hook Consumers**: Plugins that raise hooks (via `this.hookBus`)
|
|
31
42
|
|
|
32
43
|
## Complete Dependency Graph
|
|
33
44
|
|
|
@@ -601,10 +612,10 @@ refused before a plugin judges its content, or replaces it.
|
|
|
601
612
|
2. Returns modified data to next plugin
|
|
602
613
|
3. Last plugin's return value is used
|
|
603
614
|
|
|
604
|
-
For
|
|
615
|
+
For notified hooks, see [hooks](hooks.md#the-bus):
|
|
605
616
|
|
|
606
|
-
- All hooks
|
|
607
|
-
-
|
|
617
|
+
- All hooks run one after the other, in load order
|
|
618
|
+
- A failing one is logged and the next still runs
|
|
608
619
|
|
|
609
620
|
**Example**: `ldapdeleterequest` chain
|
|
610
621
|
|
|
@@ -642,11 +653,16 @@ export default class MyPlugin extends DmPlugin {
|
|
|
642
653
|
|
|
643
654
|
### Providing Hooks
|
|
644
655
|
|
|
656
|
+
A hook is declared in `src/hooks.ts` before anything raises it, and raised
|
|
657
|
+
through the bus of the kind it is, see [hooks](hooks.md#the-bus):
|
|
658
|
+
|
|
645
659
|
```typescript
|
|
646
660
|
export default class MyPlugin extends DmPlugin {
|
|
647
661
|
async someMethod() {
|
|
648
|
-
//
|
|
649
|
-
await this.
|
|
662
|
+
// Thread a value through the subscribers of a chained hook
|
|
663
|
+
value = await this.hookBus.chain('ldapsearchopts', value);
|
|
664
|
+
// Tell the subscribers of a notified one, without waiting for them
|
|
665
|
+
this.hookBus.notify('ldapadddone', dn, entry, changeContext(req));
|
|
650
666
|
}
|
|
651
667
|
}
|
|
652
668
|
```
|