diff --git a/.changeset/refactor-ldap-api-chained-pattern.md b/.changeset/refactor-ldap-api-chained-pattern.md new file mode 100644 index 0000000000000..e402e8609cb46 --- /dev/null +++ b/.changeset/refactor-ldap-api-chained-pattern.md @@ -0,0 +1,5 @@ +--- +'@rocket.chat/meteor': minor +--- + +Migrates `ldap.testConnection` and `ldap.testSearch` REST API endpoints from legacy `addRoute` pattern to the new chained `.post()` API pattern with typed response schemas and AJV body validation (replacing Meteor `check()`). diff --git a/apps/meteor/app/api/server/v1/ldap.ts b/apps/meteor/app/api/server/v1/ldap.ts index 3f9a2c29deded..efbf9a898d02c 100644 --- a/apps/meteor/app/api/server/v1/ldap.ts +++ b/apps/meteor/app/api/server/v1/ldap.ts @@ -1,62 +1,86 @@ import { LDAP } from '@rocket.chat/core-services'; -import { Match, check } from 'meteor/check'; +import { ajv, isLdapTestSearch, validateUnauthorizedErrorResponse, validateForbiddenErrorResponse } from '@rocket.chat/rest-typings'; import { SystemLogger } from '../../../../server/lib/logger/system'; import { settings } from '../../../settings/server'; import { API } from '../api'; -API.v1.addRoute( +const messageResponseSchema = { + type: 'object' as const, + properties: { + message: { type: 'string' as const }, + success: { + type: 'boolean' as const, + enum: [true] as const, + }, + }, + required: ['message', 'success'] as const, + additionalProperties: false, +}; + +API.v1.post( 'ldap.testConnection', - { authRequired: true, permissionsRequired: ['test-admin-options'] }, { - async post() { - if (!this.userId) { - throw new Error('error-invalid-user'); - } - - if (settings.get('LDAP_Enable') !== true) { - throw new Error('LDAP_disabled'); - } - - try { - await LDAP.testConnection(); - } catch (err) { - SystemLogger.error({ err }); - throw new Error('Connection_failed'); - } - - return API.v1.success({ - message: 'LDAP_Connection_successful' as const, - }); + authRequired: true, + permissionsRequired: ['test-admin-options'], + response: { + 200: ajv.compile<{ message: string; success: true }>(messageResponseSchema), + 401: validateUnauthorizedErrorResponse, + 403: validateForbiddenErrorResponse, }, }, + async function action() { + if (!this.userId) { + throw new Error('error-invalid-user'); + } + + if (settings.get('LDAP_Enable') !== true) { + throw new Error('LDAP_disabled'); + } + + try { + await LDAP.testConnection(); + } catch (err) { + SystemLogger.error({ err }); + throw new Error('Connection_failed'); + } + + return API.v1.success({ + message: 'LDAP_Connection_successful' as const, + }); + }, ); -API.v1.addRoute( +API.v1.post( 'ldap.testSearch', - { authRequired: true, permissionsRequired: ['test-admin-options'] }, { - async post() { - check( - this.bodyParams, - Match.ObjectIncluding({ - username: String, - }), - ); - - if (!this.userId) { - throw new Error('error-invalid-user'); - } - - if (settings.get('LDAP_Enable') !== true) { - throw new Error('LDAP_disabled'); - } + authRequired: true, + permissionsRequired: ['test-admin-options'], + body: isLdapTestSearch, + response: { + 200: ajv.compile<{ message: string; success: true }>(messageResponseSchema), + 401: validateUnauthorizedErrorResponse, + 403: validateForbiddenErrorResponse, + }, + }, + async function action() { + if (!this.userId) { + throw new Error('error-invalid-user'); + } + if (settings.get('LDAP_Enable') !== true) { + throw new Error('LDAP_disabled'); + } + + try { await LDAP.testSearch(this.bodyParams.username); + } catch (err) { + SystemLogger.error({ err }); + throw new Error('LDAP_search_failed'); + } - return API.v1.success({ - message: 'LDAP_User_Found' as const, - }); - }, + return API.v1.success({ + message: 'LDAP_User_Found' as const, + }); }, ); diff --git a/packages/rest-typings/src/index.ts b/packages/rest-typings/src/index.ts index 76a36bffc4b45..3edd726658537 100644 --- a/packages/rest-typings/src/index.ts +++ b/packages/rest-typings/src/index.ts @@ -230,6 +230,7 @@ export * from './helpers/ReplacePlaceholders'; export * from './helpers/WithItemCount'; export * from './v1/emojiCustom'; export * from './v1/instances'; +export * from './v1/ldap'; export * from './v1/users'; export * from './v1/users/UsersSetAvatarParamsPOST'; export * from './v1/users/UsersSetPreferenceParamsPOST';