Преглед на файлове

More tests for certificates, fixed schema problems

Jamie Curnow преди 1 година
родител
ревизия
351ba8dacd

+ 6 - 5
backend/internal/certificate.js

@@ -3,27 +3,28 @@ const fs               = require('fs');
 const https            = require('https');
 const tempWrite        = require('temp-write');
 const moment           = require('moment');
+const archiver         = require('archiver');
+const path             = require('path');
+const { isArray }      = require('lodash');
 const logger           = require('../logger').ssl;
 const config           = require('../lib/config');
 const error            = require('../lib/error');
 const utils            = require('../lib/utils');
+const certbot          = require('../lib/certbot');
 const certificateModel = require('../models/certificate');
 const tokenModel       = require('../models/token');
 const dnsPlugins       = require('../global/certbot-dns-plugins.json');
 const internalAuditLog = require('./audit-log');
 const internalNginx    = require('./nginx');
 const internalHost     = require('./host');
-const certbot          = require('../lib/certbot');
-const archiver         = require('archiver');
-const path             = require('path');
-const { isArray }      = require('lodash');
+
 
 const letsencryptStaging = config.useLetsencryptStaging();
 const letsencryptConfig  = '/etc/letsencrypt.ini';
 const certbotCommand     = 'certbot';
 
 function omissions() {
-	return ['is_deleted'];
+	return ['is_deleted', 'owner.is_deleted'];
 }
 
 const internalCertificate = {

+ 21 - 7
backend/schema/components/certificate-object.json

@@ -24,13 +24,23 @@
 			"description": "Nice Name for the custom certificate"
 		},
 		"domain_names": {
-			"$ref": "../common.json#/properties/domain_names"
+			"description": "Domain Names separated by a comma",
+			"type": "array",
+			"maxItems": 100,
+			"uniqueItems": true,
+			"items": {
+				"type": "string",
+				"pattern": "^[^&| @!#%^();:/\\\\}{=+?<>,~`'\"]+$"
+			}
 		},
 		"expires_on": {
 			"description": "Date and time of expiration",
 			"readOnly": true,
 			"type": "string"
 		},
+		"owner": {
+			"$ref": "./user-object.json"
+		},
 		"meta": {
 			"type": "object",
 			"additionalProperties": false,
@@ -51,12 +61,16 @@
 					"type": "string"
 				},
 				"propagation_seconds": {
-					"anyOf": [
-						{
-							"type": "integer",
-							"minimum": 0
-						}
-					]
+					"type": "integer",
+					"minimum": 0
+				},
+				"certificate": {
+					"type": "string",
+					"minLength": 1
+				},
+				"certificate_key": {
+					"type": "string",
+					"minLength": 1
 				}
 			}
 		}

+ 19 - 0
backend/schema/paths/nginx/certificates/certID/upload/post.json

@@ -55,6 +55,25 @@
 								"certificate_key": "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC1n9j9C5Bes1nd\nqACDckERauxXVNKCnUlUM1buGBx1xc+j2e2Ar23wUJJuWBY18VfT8yqfqVDktO2w\nrbmvZvLuPmXePOKbIKS+XXh+2NG9L5bDG9rwGFCRXnbQj+GWCdMfzx14+CR1IHge\nYz6Cv/Si2/LJPCh/CoBfM4hUQJON3lxAWrWBpdbZnKYMrxuPBRfW9OuzTbCVXToQ\noxRAHiOR9081Xn1WeoKr7kVBIa5UphlvWXa12w1YmUwJu7YndnJGIavLWeNCVc7Z\nEo+nS8Wr/4QWicatIWZXpVaEOPhRoeplQDxNWg5b/Q26rYoVd7PrCmRs7sVcH79X\nzGONeH1PAgMBAAECggEAANb3Wtwl07pCjRrMvc7WbC0xYIn82yu8/g2qtjkYUJcU\nia5lQbYN7RGCS85Oc/tkq48xQEG5JQWNH8b918jDEMTrFab0aUEyYcru1q9L8PL6\nYHaNgZSrMrDcHcS8h0QOXNRJT5jeGkiHJaTR0irvB526tqF3knbK9yW22KTfycUe\na0Z9voKn5xRk1DCbHi/nk2EpT7xnjeQeLFaTIRXbS68omkr4YGhwWm5OizoyEGZu\nW0Zum5BkQyMr6kor3wdxOTG97ske2rcyvvHi+ErnwL0xBv0qY0Dhe8DpuXpDezqw\no72yY8h31Fu84i7sAj24YuE5Df8DozItFXQpkgbQ6QKBgQDPrufhvIFm2S/MzBdW\nH8JxY7CJlJPyxOvc1NIl9RczQGAQR90kx52cgIcuIGEG6/wJ/xnGfMmW40F0DnQ+\nN+oLgB9SFxeLkRb7s9Z/8N3uIN8JJFYcerEOiRQeN2BXEEWJ7bUThNtsVrAcKoUh\nELsDmnHW/3V+GKwhd0vpk842+wKBgQDf4PGLG9PTE5tlAoyHFodJRd2RhTJQkwsU\nMDNjLJ+KecLv+Nl+QiJhoflG1ccqtSFlBSCG067CDQ5LV0xm3mLJ7pfJoMgjcq31\nqjEmX4Ls91GuVOPtbwst3yFKjsHaSoKB5fBvWRcKFpBUezM7Qcw2JP3+dQT+bQIq\ncMTkRWDSvQKBgQDOdCQFDjxg/lR7NQOZ1PaZe61aBz5P3pxNqa7ClvMaOsuEQ7w9\nvMYcdtRq8TsjA2JImbSI0TIg8gb2FQxPcYwTJKl+FICOeIwtaSg5hTtJZpnxX5LO\nutTaC0DZjNkTk5RdOdWA8tihyUdGqKoxJY2TVmwGe2rUEDjFB++J4inkEwKBgB6V\ng0nmtkxanFrzOzFlMXwgEEHF+Xaqb9QFNa/xs6XeNnREAapO7JV75Cr6H2hFMFe1\nmJjyqCgYUoCWX3iaHtLJRnEkBtNY4kzyQB6m46LtsnnnXO/dwKA2oDyoPfFNRoDq\nYatEd3JIXNU9s2T/+x7WdOBjKhh72dTkbPFmTPDdAoGAU6rlPBevqOFdObYxdPq8\nEQWu44xqky3Mf5sBpOwtu6rqCYuziLiN7K4sjN5GD5mb1cEU+oS92ZiNcUQ7MFXk\n8yTYZ7U0VcXyAcpYreWwE8thmb0BohJBr+Mp3wLTx32x0HKdO6vpUa0d35LUTUmM\nRrKmPK/msHKK/sVHiL+NFqo=\n-----END PRIVATE KEY-----\n"
 							}
 						}
+					},
+					"schema": {
+						"type": "object",
+						"additionalProperties": false,
+						"required": ["certificate", "certificate_key"],
+						"properties": {
+							"certificate": {
+								"type": "string",
+								"minLength": 1
+							},
+							"certificate_key": {
+								"type": "string",
+								"minLength": 1
+							},
+							"intermediate_certificate": {
+								"type": "string",
+								"minLength": 1
+							}
+						}
 					}
 				}
 			}

+ 47 - 0
test/cypress/e2e/api/Certificates.cy.js

@@ -2,6 +2,7 @@
 
 describe('Certificates endpoints', () => {
 	let token;
+	let certID;
 
 	before(() => {
 		cy.getToken().then((tok) => {
@@ -24,6 +25,52 @@ describe('Certificates endpoints', () => {
 		});
 	});
 
+	it('Custom certificate lifecycle', function() {
+		cy.task('backendApiPost', {
+			token: token,
+			path:  '/api/nginx/certificates',
+			data:  {
+				provider: "other",
+				nice_name: "Test Certificate",
+			},
+		}).then((data) => {
+			cy.validateSwaggerSchema('post', 201, '/nginx/certificates', data);
+			expect(data).to.have.property('id');
+			certID = data.id;
+
+			cy.task('backendApiPostFiles', {
+				token: token,
+				path:  `/api/nginx/certificates/${certID}/upload`,
+				files:  {
+					certificate: 'test.example.com.pem',
+					certificate_key: 'test.example.com-key.pem',
+				},
+			}).then((data) => {
+				cy.validateSwaggerSchema('post', 201, '/nginx/certificates/upload', data);
+				expect(data).to.have.property('certificate');
+				expect(data).to.have.property('certificate_key');
+
+				cy.task('backendApiDelete', {
+					token: token,
+					path:  `/api/nginx/certificates/${certID}`
+				}).then((data) => {
+					cy.validateSwaggerSchema('delete', 200, '/nginx/certificates/{certID}', data);
+					expect(data).to.be.equal(true);
+				});
+			});
+		});
+	});
+
+	it('Should be able to get all certs', function() {
+		cy.task('backendApiGet', {
+			token: token,
+			path:  '/api/nginx/certificates?expand=owner'
+		}).then((data) => {
+			cy.validateSwaggerSchema('get', 200, '/nginx/certificates', data);
+			expect(data.length).to.be.greaterThan(0);
+		});
+	});
+
 	it('Request Certificate - CVE-2024-46256/CVE-2024-46257', function() {
 		cy.task('backendApiPost', {
 			token: token,

+ 1 - 1
test/package.json

@@ -4,7 +4,7 @@
 	"description": "",
 	"main": "index.js",
 	"dependencies": {
-		"@jc21/cypress-swagger-validation": "^0.2.7",
+		"@jc21/cypress-swagger-validation": "^0.2.8",
 		"axios": "^1.7.7",
 		"cypress": "^13.15.0",
 		"cypress-multi-reporters": "^1.6.4",

+ 4 - 4
test/yarn.lock

@@ -167,10 +167,10 @@
   resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.3.1.tgz#c72a5c76a9fbaf3488e231b13dc52c0da7bab42a"
   integrity sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==
 
-"@jc21/cypress-swagger-validation@^0.2.7":
-  version "0.2.7"
-  resolved "https://registry.yarnpkg.com/@jc21/cypress-swagger-validation/-/cypress-swagger-validation-0.2.7.tgz#64642b12d98b884df8c30b72852162941285d2af"
-  integrity sha512-4EQ0gfigRwVVl3DnVYbR48/EKGnn7oH5YYdMzf6zqypO+bqYvDHu9kgk/WqkGlT/aauGQ7e0YGMo8ZvR7mL0Ng==
+"@jc21/cypress-swagger-validation@^0.2.8":
+  version "0.2.8"
+  resolved "https://registry.yarnpkg.com/@jc21/cypress-swagger-validation/-/cypress-swagger-validation-0.2.8.tgz#8ab059bd41e3ee100a1998a1484b9e5a2e9a4224"
+  integrity sha512-9fiZIHj3//bJjC5YUMOc42RnoEUeeokVn6xtMnP52XIZ/ryWQ9PIyFdlOAH8q/LW/uPxozJo2+hdB6ou4iurag==
   dependencies:
     "@apidevtools/swagger-parser" "^10.1.0"
     ajv "^8.17.1"