From 78a9e1b2a8fbc413663716bfe92fe3b2855c54d1 Mon Sep 17 00:00:00 2001 From: NickOvt Date: Mon, 26 Feb 2024 09:34:36 +0200 Subject: [PATCH] fix(api-dkim): Add all DKIM API endpoints to API docs generation ZMS-129 (#630) * added List registered DKIM keys to API docs generation * Added Resolve ID for a DKIM domain api endpoint to API docs generation * Added Delete a DKIM key api endpoint to API docs generation * Added Request DKIM information api endpoint to api docs generation. Fix typo * added create or update dkim key for domain api endpoint to api docs generation --- lib/api/dkim.js | 277 +++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 224 insertions(+), 53 deletions(-) diff --git a/lib/api/dkim.js b/lib/api/dkim.js index e8b25ffb..4dbf9fa2 100644 --- a/lib/api/dkim.js +++ b/lib/api/dkim.js @@ -8,6 +8,7 @@ const DkimHandler = require('../dkim-handler'); const tools = require('../tools'); const roles = require('../roles'); const { nextPageCursorSchema, previousPageCursorSchema, pageNrSchema, sessSchema, sessIPSchema } = require('../schemas'); +const { successRes, totalRes, pageRes, previousCursorRes, nextCursorRes } = require('../schemas/response/general-schemas'); module.exports = (db, server) => { const dkimHandler = new DkimHandler({ @@ -18,18 +19,62 @@ module.exports = (db, server) => { }); server.get( - { name: 'dkim', path: '/dkim' }, + { + name: 'dkim', + path: '/dkim', + tags: ['DKIM'], + summary: 'List registered DKIM keys', + validationObjs: { + requestBody: {}, + queryParams: { + query: Joi.string().empty('').trim().max(255).description('Partial match of a Domain name'), + limit: Joi.number().default(20).min(1).max(250).description('How many records to return'), + next: nextPageCursorSchema, + previous: previousPageCursorSchema, + page: pageNrSchema, + sess: sessSchema, + ip: sessIPSchema + }, + pathParams: {}, + response: { + 200: { + description: 'Success', + model: Joi.object({ + success: successRes, + total: totalRes, + page: pageRes, + previousCursor: previousCursorRes, + nextCursor: nextCursorRes, + query: Joi.string().required().description('Query string. Partial match of a Domain name'), + results: Joi.array() + .required() + .items( + Joi.object({ + id: Joi.string().required().description('ID of the DKIM'), + domain: Joi.string().required().description('The domain this DKIM key applies to'), + selector: Joi.string().required().description('DKIM selector'), + description: Joi.string().required().description('Key description'), + fingerprint: Joi.string().required().description('Key fingerprint (SHA1)'), + created: Joi.date().required().description('DKIM created datestring') + }) + .$_setFlag('objectName', 'GetDkimKeysResult') + .required() + ) + .description('DKIM listing') + }) + } + } + } + }, tools.responseWrapper(async (req, res) => { res.charSet('utf-8'); - const schema = Joi.object().keys({ - query: Joi.string().empty('').trim().max(255), - limit: Joi.number().default(20).min(1).max(250), - next: nextPageCursorSchema, - previous: previousPageCursorSchema, - page: pageNrSchema, - sess: sessSchema, - ip: sessIPSchema + const { pathParams, requestBody, queryParams } = req.route.spec.validationObjs; + + const schema = Joi.object({ + ...pathParams, + ...queryParams, + ...requestBody }); const result = schema.validate(req.params, { @@ -117,17 +162,43 @@ module.exports = (db, server) => { ); server.get( - '/dkim/resolve/:domain', + { + path: '/dkim/resolve/:domain', + tags: ['DKIM'], + summary: 'Resolve ID for a DKIM domain', + validationObjs: { + requestBody: {}, + queryParams: { + sess: sessSchema, + ip: sessIPSchema + }, + pathParams: { + domain: Joi.string() + .max(255) + //.hostname() + .required() + .description('DKIM domain') + }, + response: { + 200: { + description: 'Success', + model: Joi.object({ + success: successRes, + id: Joi.string().required().description('DKIM unique ID (24 byte hex)').example('609d201236d1d936948f23b1') + }) + } + } + } + }, tools.responseWrapper(async (req, res) => { res.charSet('utf-8'); - const schema = Joi.object().keys({ - domain: Joi.string() - .max(255) - //.hostname() - .required(), - sess: sessSchema, - ip: sessIPSchema + const { pathParams, requestBody, queryParams } = req.route.spec.validationObjs; + + const schema = Joi.object({ + ...pathParams, + ...queryParams, + ...requestBody }); const result = schema.validate(req.params, { @@ -184,34 +255,80 @@ module.exports = (db, server) => { ); server.post( - '/dkim', + { + path: '/dkim', + tags: ['DKIM'], + summary: 'Create or update DKIM key for domain', + description: 'Add a new DKIM key for a Domain or update existing one. There can be single DKIM key registered for each domain name.', + validationObjs: { + requestBody: { + domain: Joi.string() + .max(255) + //.hostname() + .required() + .description( + 'Domain name this DKIM key applies to. Use "*" as a special value that will be used for domains that do not have their own DKIM key set' + ), + selector: Joi.string() + .max(255) + //.hostname() + .trim() + .required() + .description('Selector for the key'), + privateKey: Joi.alternatives() + .try( + Joi.string() + .empty('') + .trim() + .regex(/^-----BEGIN (RSA )?PRIVATE KEY-----/, 'DKIM key format') + .description('PEM format RSA or ED25519 string'), + Joi.string().empty('').trim().base64().length(44).description('Raw ED25519 key 44 bytes long if using base64') + ) + .description( + 'Pem formatted DKIM private key, raw ED25519 is also allowed. If not set then a new 2048 bit RSA key is generated, beware though that it can take several seconds to complete.' + ), + description: Joi.string() + .max(255) + //.hostname() + .trim() + .description('Key description'), + sess: sessSchema, + ip: sessIPSchema + }, + queryParams: {}, + pathParams: {}, + response: { + 200: { + description: 'Success', + model: Joi.object({ + success: successRes, + id: Joi.string().required().description('ID of the DKIM'), + domain: Joi.string().required().description('The domain this DKIM key applies to'), + selector: Joi.string().required().description('DKIM selector'), + description: Joi.string().required().description('Key description'), + fingerprint: Joi.string().required().description('Key fingerprint (SHA1)'), + publicKey: Joi.string().required().description('Public key in DNS format (no prefix/suffix, single line)'), + dnsTxt: Joi.object({ + name: Joi.string().required().description('Is the domain name of TXT'), + value: Joi.string().required().description('Is the value of TXT') + }) + .required() + .description('Value for DNS TXT entry') + .$_setFlag('objectName', 'DnsTxt') + }) + } + } + } + }, tools.responseWrapper(async (req, res) => { res.charSet('utf-8'); - const schema = Joi.object().keys({ - domain: Joi.string() - .max(255) - //.hostname() - .required(), - selector: Joi.string() - .max(255) - //.hostname() - .trim() - .required(), - privateKey: Joi.alternatives().try( - Joi.string() - .empty('') - .trim() - .regex(/^-----BEGIN (RSA )?PRIVATE KEY-----/, 'DKIM key format') - .description('PEM format RSA or ED25519 string'), - Joi.string().empty('').trim().base64().length(44).description('Raw ED25519 key 44 bytes long if using base64') - ), - description: Joi.string() - .max(255) - //.hostname() - .trim(), - sess: sessSchema, - ip: sessIPSchema + const { pathParams, requestBody, queryParams } = req.route.spec.validationObjs; + + const schema = Joi.object({ + ...pathParams, + ...queryParams, + ...requestBody }); const result = schema.validate(req.params, { @@ -252,14 +369,52 @@ module.exports = (db, server) => { ); server.get( - '/dkim/:dkim', + { + path: '/dkim/:dkim', + tags: ['DKIM'], + summary: 'Request DKIM information', + validationObjs: { + requestBody: {}, + queryParams: { + sess: sessSchema, + ip: sessIPSchema + }, + pathParams: { + dkim: Joi.string().hex().lowercase().length(24).required().description('ID of the DKIM') + }, + response: { + 200: { + description: 'Success', + model: Joi.object({ + success: successRes, + id: Joi.string().required().description('ID of the DKIM'), + domain: Joi.string().required().description('The domain this DKIM key applies to'), + selector: Joi.string().required().description('DKIM selector'), + description: Joi.string().required().description('Key description'), + fingerprint: Joi.string().required().description('Key fingerprint (SHA1)'), + publicKey: Joi.string().required().description('Public key in DNS format (no prefix/suffix, single line)'), + dnsTxt: Joi.object({ + name: Joi.string().required().description('Is the domain name of TXT'), + value: Joi.string().required().description('Is the value of TXT') + }) + .required() + .description('Value for DNS TXT entry') + .$_setFlag('objectName', 'DnsTxt'), + created: Joi.date().required().description('DKIM created datestring') + }) + } + } + } + }, tools.responseWrapper(async (req, res) => { res.charSet('utf-8'); - const schema = Joi.object().keys({ - dkim: Joi.string().hex().lowercase().length(24).required(), - sess: sessSchema, - ip: sessIPSchema + const { pathParams, requestBody, queryParams } = req.route.spec.validationObjs; + + const schema = Joi.object({ + ...pathParams, + ...queryParams, + ...requestBody }); const result = schema.validate(req.params, { @@ -301,16 +456,32 @@ module.exports = (db, server) => { ); server.del( - '/dkim/:dkim', + { + path: '/dkim/:dkim', + tags: ['DKIM'], + summary: 'Delete a DKIM key', + validationObjs: { + requestBody: {}, + queryParams: { + sess: sessSchema, + ip: sessIPSchema + }, + pathParams: { + dkim: Joi.string().hex().lowercase().length(24).required().description('ID of the DKIM') + }, + response: { 200: { description: 'Success', model: Joi.object({ success: successRes }) } } + } + }, tools.responseWrapper(async (req, res) => { res.charSet('utf-8'); - const schema = Joi.object().keys({ - dkim: Joi.string().hex().lowercase().length(24).required(), - sess: sessSchema, - ip: sessIPSchema - }); + const { pathParams, requestBody, queryParams } = req.route.spec.validationObjs; + const schema = Joi.object({ + ...pathParams, + ...queryParams, + ...requestBody + }); const result = schema.validate(req.params, { abortEarly: false, convert: true