diff --git a/backend/schema/common.json b/backend/schema/common.json
index ebeb344..83de014 100644
--- a/backend/schema/common.json
+++ b/backend/schema/common.json
@@ -76,7 +76,7 @@
"uniqueItems": true,
"items": {
"type": "string",
- "pattern": "^(?:\\*\\.)?(?:[^.*]+\\.?)+[^.]$"
+ "pattern": "^[^&| @!#%^();:/\\\\}{=+?<>,~`'\"]+$"
}
},
"enabled": {
diff --git a/backend/schema/components/error.json b/backend/schema/components/error.json
new file mode 100644
index 0000000..ceb3e14
--- /dev/null
+++ b/backend/schema/components/error.json
@@ -0,0 +1,9 @@
+{
+ "type": "object",
+ "description": "Error",
+ "properties": {
+ "error": {
+ "$ref": "./error-object.json"
+ }
+ }
+}
diff --git a/backend/schema/paths/nginx/certificates/post.json b/backend/schema/paths/nginx/certificates/post.json
index 1b2e046..5a3306c 100644
--- a/backend/schema/paths/nginx/certificates/post.json
+++ b/backend/schema/paths/nginx/certificates/post.json
@@ -72,6 +72,26 @@
}
}
}
+ },
+ "400": {
+ "description": "400 response",
+ "content": {
+ "application/json": {
+ "examples": {
+ "default": {
+ "value": {
+ "error": {
+ "code": 400,
+ "message": "Domains are invalid"
+ }
+ }
+ }
+ },
+ "schema": {
+ "$ref": "../../../components/error.json"
+ }
+ }
+ }
}
}
}
diff --git a/backend/schema/paths/nginx/certificates/validate/post.json b/backend/schema/paths/nginx/certificates/validate/post.json
index 94f02f5..21eb325 100644
--- a/backend/schema/paths/nginx/certificates/validate/post.json
+++ b/backend/schema/paths/nginx/certificates/validate/post.json
@@ -50,6 +50,42 @@
"certificate_key": true
}
}
+ },
+ "schema": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": ["certificate", "certificate_key"],
+ "properties": {
+ "certificate": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": ["cn", "issuer", "dates"],
+ "properties": {
+ "cn": {
+ "type": "string"
+ },
+ "issuer": {
+ "type": "string"
+ },
+ "dates": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": ["from", "to"],
+ "properties": {
+ "from": {
+ "type": "integer"
+ },
+ "to": {
+ "type": "integer"
+ }
+ }
+ }
+ }
+ },
+ "certificate_key": {
+ "type": "boolean"
+ }
+ }
}
}
}
@@ -67,6 +103,9 @@
}
}
}
+ },
+ "schema": {
+ "$ref": "../../../../components/error.json"
}
}
}
diff --git a/backend/schema/paths/nginx/dead-hosts/hostID/disable/post.json b/backend/schema/paths/nginx/dead-hosts/hostID/disable/post.json
index 528d05d..2cdcecf 100644
--- a/backend/schema/paths/nginx/dead-hosts/hostID/disable/post.json
+++ b/backend/schema/paths/nginx/dead-hosts/hostID/disable/post.json
@@ -50,7 +50,7 @@
}
},
"schema": {
- "$ref": "../../../../../components/error-object.json"
+ "$ref": "../../../../../components/error.json"
}
}
}
diff --git a/backend/schema/paths/nginx/dead-hosts/hostID/enable/post.json b/backend/schema/paths/nginx/dead-hosts/hostID/enable/post.json
index dd95943..ca3ce9f 100644
--- a/backend/schema/paths/nginx/dead-hosts/hostID/enable/post.json
+++ b/backend/schema/paths/nginx/dead-hosts/hostID/enable/post.json
@@ -50,7 +50,7 @@
}
},
"schema": {
- "$ref": "../../../../../components/error-object.json"
+ "$ref": "../../../../../components/error.json"
}
}
}
diff --git a/backend/schema/paths/nginx/proxy-hosts/hostID/disable/post.json b/backend/schema/paths/nginx/proxy-hosts/hostID/disable/post.json
index 1ff95e8..54ff8a6 100644
--- a/backend/schema/paths/nginx/proxy-hosts/hostID/disable/post.json
+++ b/backend/schema/paths/nginx/proxy-hosts/hostID/disable/post.json
@@ -50,7 +50,7 @@
}
},
"schema": {
- "$ref": "../../../../../components/error-object.json"
+ "$ref": "../../../../../components/error.json"
}
}
}
diff --git a/backend/schema/paths/nginx/proxy-hosts/hostID/enable/post.json b/backend/schema/paths/nginx/proxy-hosts/hostID/enable/post.json
index 3a5694b..9f052de 100644
--- a/backend/schema/paths/nginx/proxy-hosts/hostID/enable/post.json
+++ b/backend/schema/paths/nginx/proxy-hosts/hostID/enable/post.json
@@ -50,7 +50,7 @@
}
},
"schema": {
- "$ref": "../../../../../components/error-object.json"
+ "$ref": "../../../../../components/error.json"
}
}
}
diff --git a/backend/schema/paths/nginx/redirection-hosts/hostID/disable/post.json b/backend/schema/paths/nginx/redirection-hosts/hostID/disable/post.json
index 7531ac3..8433220 100644
--- a/backend/schema/paths/nginx/redirection-hosts/hostID/disable/post.json
+++ b/backend/schema/paths/nginx/redirection-hosts/hostID/disable/post.json
@@ -50,7 +50,7 @@
}
},
"schema": {
- "$ref": "../../../../../components/error-object.json"
+ "$ref": "../../../../../components/error.json"
}
}
}
diff --git a/backend/schema/paths/nginx/redirection-hosts/hostID/enable/post.json b/backend/schema/paths/nginx/redirection-hosts/hostID/enable/post.json
index 60f4faf..bef5343 100644
--- a/backend/schema/paths/nginx/redirection-hosts/hostID/enable/post.json
+++ b/backend/schema/paths/nginx/redirection-hosts/hostID/enable/post.json
@@ -50,7 +50,7 @@
}
},
"schema": {
- "$ref": "../../../../../components/error-object.json"
+ "$ref": "../../../../../components/error.json"
}
}
}
diff --git a/backend/schema/paths/nginx/streams/streamID/disable/post.json b/backend/schema/paths/nginx/streams/streamID/disable/post.json
index 91c58bb..d1c1b1c 100644
--- a/backend/schema/paths/nginx/streams/streamID/disable/post.json
+++ b/backend/schema/paths/nginx/streams/streamID/disable/post.json
@@ -50,7 +50,7 @@
}
},
"schema": {
- "$ref": "../../../../../components/error-object.json"
+ "$ref": "../../../../../components/error.json"
}
}
}
diff --git a/backend/schema/paths/nginx/streams/streamID/enable/post.json b/backend/schema/paths/nginx/streams/streamID/enable/post.json
index b14a86f..dc914f5 100644
--- a/backend/schema/paths/nginx/streams/streamID/enable/post.json
+++ b/backend/schema/paths/nginx/streams/streamID/enable/post.json
@@ -50,7 +50,7 @@
}
},
"schema": {
- "$ref": "../../../../../components/error-object.json"
+ "$ref": "../../../../../components/error.json"
}
}
}
diff --git a/test/cypress/e2e/api/Certificates.cy.js b/test/cypress/e2e/api/Certificates.cy.js
new file mode 100644
index 0000000..043680f
--- /dev/null
+++ b/test/cypress/e2e/api/Certificates.cy.js
@@ -0,0 +1,50 @@
+///
+
+describe('Certificates endpoints', () => {
+ let token;
+
+ before(() => {
+ cy.getToken().then((tok) => {
+ token = tok;
+ });
+ });
+
+ it('Validate custom certificate', function() {
+ cy.task('backendApiPostFiles', {
+ token: token,
+ path: '/api/nginx/certificates/validate',
+ files: {
+ certificate: 'test.example.com.pem',
+ certificate_key: 'test.example.com-key.pem',
+ },
+ }).then((data) => {
+ cy.validateSwaggerSchema('post', 200, '/nginx/certificates/validate', data);
+ expect(data).to.have.property('certificate');
+ expect(data).to.have.property('certificate_key');
+ });
+ });
+
+ it('Request Certificate - CVE-2024-46256/CVE-2024-46257', function() {
+ cy.task('backendApiPost', {
+ token: token,
+ path: '/api/nginx/certificates',
+ data: {
+ domain_names: ['test.com"||echo hello-world||\\\\n test.com"'],
+ meta: {
+ dns_challenge: false,
+ letsencrypt_agree: true,
+ letsencrypt_email: 'admin@example.com',
+ },
+ provider: 'letsencrypt',
+ },
+ returnOnError: true,
+ }).then((data) => {
+ cy.validateSwaggerSchema('post', 400, '/nginx/certificates', data);
+ expect(data).to.have.property('error');
+ expect(data.error).to.have.property('message');
+ expect(data.error).to.have.property('code');
+ expect(data.error.code).to.equal(400);
+ expect(data.error.message).to.contain('data/domain_names/0 must match pattern');
+ });
+ });
+});
diff --git a/test/cypress/fixtures/test.example.com-key.pem b/test/cypress/fixtures/test.example.com-key.pem
new file mode 100644
index 0000000..307cdc3
--- /dev/null
+++ b/test/cypress/fixtures/test.example.com-key.pem
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC1n9j9C5Bes1nd
+qACDckERauxXVNKCnUlUM1buGBx1xc+j2e2Ar23wUJJuWBY18VfT8yqfqVDktO2w
+rbmvZvLuPmXePOKbIKS+XXh+2NG9L5bDG9rwGFCRXnbQj+GWCdMfzx14+CR1IHge
+Yz6Cv/Si2/LJPCh/CoBfM4hUQJON3lxAWrWBpdbZnKYMrxuPBRfW9OuzTbCVXToQ
+oxRAHiOR9081Xn1WeoKr7kVBIa5UphlvWXa12w1YmUwJu7YndnJGIavLWeNCVc7Z
+Eo+nS8Wr/4QWicatIWZXpVaEOPhRoeplQDxNWg5b/Q26rYoVd7PrCmRs7sVcH79X
+zGONeH1PAgMBAAECggEAANb3Wtwl07pCjRrMvc7WbC0xYIn82yu8/g2qtjkYUJcU
+ia5lQbYN7RGCS85Oc/tkq48xQEG5JQWNH8b918jDEMTrFab0aUEyYcru1q9L8PL6
+YHaNgZSrMrDcHcS8h0QOXNRJT5jeGkiHJaTR0irvB526tqF3knbK9yW22KTfycUe
+a0Z9voKn5xRk1DCbHi/nk2EpT7xnjeQeLFaTIRXbS68omkr4YGhwWm5OizoyEGZu
+W0Zum5BkQyMr6kor3wdxOTG97ske2rcyvvHi+ErnwL0xBv0qY0Dhe8DpuXpDezqw
+o72yY8h31Fu84i7sAj24YuE5Df8DozItFXQpkgbQ6QKBgQDPrufhvIFm2S/MzBdW
+H8JxY7CJlJPyxOvc1NIl9RczQGAQR90kx52cgIcuIGEG6/wJ/xnGfMmW40F0DnQ+
+N+oLgB9SFxeLkRb7s9Z/8N3uIN8JJFYcerEOiRQeN2BXEEWJ7bUThNtsVrAcKoUh
+ELsDmnHW/3V+GKwhd0vpk842+wKBgQDf4PGLG9PTE5tlAoyHFodJRd2RhTJQkwsU
+MDNjLJ+KecLv+Nl+QiJhoflG1ccqtSFlBSCG067CDQ5LV0xm3mLJ7pfJoMgjcq31
+qjEmX4Ls91GuVOPtbwst3yFKjsHaSoKB5fBvWRcKFpBUezM7Qcw2JP3+dQT+bQIq
+cMTkRWDSvQKBgQDOdCQFDjxg/lR7NQOZ1PaZe61aBz5P3pxNqa7ClvMaOsuEQ7w9
+vMYcdtRq8TsjA2JImbSI0TIg8gb2FQxPcYwTJKl+FICOeIwtaSg5hTtJZpnxX5LO
+utTaC0DZjNkTk5RdOdWA8tihyUdGqKoxJY2TVmwGe2rUEDjFB++J4inkEwKBgB6V
+g0nmtkxanFrzOzFlMXwgEEHF+Xaqb9QFNa/xs6XeNnREAapO7JV75Cr6H2hFMFe1
+mJjyqCgYUoCWX3iaHtLJRnEkBtNY4kzyQB6m46LtsnnnXO/dwKA2oDyoPfFNRoDq
+YatEd3JIXNU9s2T/+x7WdOBjKhh72dTkbPFmTPDdAoGAU6rlPBevqOFdObYxdPq8
+EQWu44xqky3Mf5sBpOwtu6rqCYuziLiN7K4sjN5GD5mb1cEU+oS92ZiNcUQ7MFXk
+8yTYZ7U0VcXyAcpYreWwE8thmb0BohJBr+Mp3wLTx32x0HKdO6vpUa0d35LUTUmM
+RrKmPK/msHKK/sVHiL+NFqo=
+-----END PRIVATE KEY-----
diff --git a/test/cypress/fixtures/test.example.com.pem b/test/cypress/fixtures/test.example.com.pem
new file mode 100644
index 0000000..16340cd
--- /dev/null
+++ b/test/cypress/fixtures/test.example.com.pem
@@ -0,0 +1,26 @@
+-----BEGIN CERTIFICATE-----
+MIIEYDCCAsigAwIBAgIRAPoSC0hvitb26ODMlsH6YbowDQYJKoZIhvcNAQELBQAw
+gZExHjAcBgNVBAoTFW1rY2VydCBkZXZlbG9wbWVudCBDQTEzMDEGA1UECwwqamN1
+cm5vd0BKYW1pZXMtTGFwdG9wLmxvY2FsIChKYW1pZSBDdXJub3cpMTowOAYDVQQD
+DDFta2NlcnQgamN1cm5vd0BKYW1pZXMtTGFwdG9wLmxvY2FsIChKYW1pZSBDdXJu
+b3cpMB4XDTI0MTAwOTA3MjIxN1oXDTI3MDEwOTA3MjIxN1owXjEnMCUGA1UEChMe
+bWtjZXJ0IGRldmVsb3BtZW50IGNlcnRpZmljYXRlMTMwMQYDVQQLDCpqY3Vybm93
+QEphbWllcy1MYXB0b3AubG9jYWwgKEphbWllIEN1cm5vdykwggEiMA0GCSqGSIb3
+DQEBAQUAA4IBDwAwggEKAoIBAQC1n9j9C5Bes1ndqACDckERauxXVNKCnUlUM1bu
+GBx1xc+j2e2Ar23wUJJuWBY18VfT8yqfqVDktO2wrbmvZvLuPmXePOKbIKS+XXh+
+2NG9L5bDG9rwGFCRXnbQj+GWCdMfzx14+CR1IHgeYz6Cv/Si2/LJPCh/CoBfM4hU
+QJON3lxAWrWBpdbZnKYMrxuPBRfW9OuzTbCVXToQoxRAHiOR9081Xn1WeoKr7kVB
+Ia5UphlvWXa12w1YmUwJu7YndnJGIavLWeNCVc7ZEo+nS8Wr/4QWicatIWZXpVaE
+OPhRoeplQDxNWg5b/Q26rYoVd7PrCmRs7sVcH79XzGONeH1PAgMBAAGjZTBjMA4G
+A1UdDwEB/wQEAwIFoDATBgNVHSUEDDAKBggrBgEFBQcDATAfBgNVHSMEGDAWgBSB
+/vfmBUd4W7CvyEMl7YpMVQs8vTAbBgNVHREEFDASghB0ZXN0LmV4YW1wbGUuY29t
+MA0GCSqGSIb3DQEBCwUAA4IBgQASwON/jPAHzcARSenY0ZGY1m5OVTYoQ/JWH0oy
+l8SyFCQFEXt7UHDD/eTtLT0vMyc190nP57P8lTnZGf7hSinZz1B1d6V4cmzxpk0s
+VXZT+irL6bJVJoMBHRpllKAhGULIo33baTrWFKA0oBuWx4AevSWKcLW5j87kEawn
+ATCuMQ1I3ifR1mSlB7X8fb+vF+571q0NGuB3a42j6rdtXJ6SmH4+9B4qO0sfHDNt
+IImpLCH/tycDpcYrGSCn1QrekFG1bSEh+Bb9i8rqMDSDsYrTFPZTuOQ3EtjGni9u
+m+rEP3OyJg+md8c+0LVP7/UU4QWWnw3/Wolo5kSCxE8vNTFqi4GhVbdLnUtcIdTV
+XxuR6cKyW87Snj1a0nG76ZLclt/akxDhtzqeV60BO0p8pmiev8frp+E94wFNYCmp
+1cr3CnMEGRaficLSDFC6EBENzlZW2BQT6OMIV+g0NBgSyQe39s2zcdEl5+SzDVuw
+hp8bJUp/QN7pnOVCDbjTQ+HVMXw=
+-----END CERTIFICATE-----
diff --git a/test/cypress/plugins/backendApi/client.js b/test/cypress/plugins/backendApi/client.js
index 29684cf..e7c0c43 100644
--- a/test/cypress/plugins/backendApi/client.js
+++ b/test/cypress/plugins/backendApi/client.js
@@ -1,9 +1,14 @@
const logger = require('./logger');
-const restler = require('@jc21/restler');
+const axios = require('axios').default;
const BackendApi = function(config, token) {
this.config = config;
this.token = token;
+
+ this.axios = axios.create({
+ baseURL: config.baseUrl,
+ timeout: 5000,
+ });
};
/**
@@ -14,129 +19,114 @@ BackendApi.prototype.setToken = function(token) {
};
/**
+ * @param {bool} returnOnError
+ */
+BackendApi.prototype._prepareOptions = function(returnOnError) {
+ let options = {
+ headers: {
+ Accept: 'application/json'
+ }
+ }
+ if (this.token) {
+ options.headers.Authorization = 'Bearer ' + this.token;
+ }
+ if (returnOnError) {
+ options.validateStatus = function () {
+ return true;
+ }
+ }
+ return options;
+};
+
+/**
+ * @param {*} response
+ * @param {function} resolve
+ * @param {function} reject
+ * @param {bool} returnOnError
+ */
+BackendApi.prototype._handleResponse = function(response, resolve, reject, returnOnError) {
+ logger('Response data:', response.data);
+ if (!returnOnError && typeof response.data === 'object' && typeof response.data.error === 'object') {
+ if (typeof response.data === 'object' && typeof response.data.error === 'object' && typeof response.data.error.message !== 'undefined') {
+ reject(new Error(response.data.error.code + ': ' + response.data.error.message));
+ } else {
+ reject(new Error('Error ' + response.status));
+ }
+ } else {
+ resolve(response.data);
+ }
+};
+
+/**
+ * @param {*} err
+ * @param {function} resolve
+ * @param {function} reject
+ * @param {bool} returnOnError
+ */
+BackendApi.prototype._handleError = function(err, resolve, reject, returnOnError) {
+ logger('Axios Error:', err);
+ if (returnOnError) {
+ resolve(typeof err.response.data !== 'undefined' ? err.response.data : err);
+ } else {
+ reject(err);
+ }
+};
+
+/**
+ * @param {string} method
* @param {string} path
* @param {bool} [returnOnError]
+ * @param {*} [data]
* @returns {Promise