Merge pull request #14126 from jgrumboe/fix-13074

fix(backend): fix certificate validation
This commit is contained in:
Johan Haals
2022-10-25 15:09:31 +02:00
committed by GitHub
4 changed files with 38 additions and 14 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/backend-common': patch
---
Generated development HTTPS backend certificate is now checked for expiration date instead of file age.
+2
View File
@@ -75,6 +75,7 @@
"morgan": "^1.10.0",
"node-abort-controller": "^3.0.1",
"node-fetch": "^2.6.7",
"node-forge": "^1.3.1",
"raw-body": "^2.4.1",
"request": "^2.88.2",
"selfsigned": "^2.0.0",
@@ -105,6 +106,7 @@
"@types/minimist": "^1.2.0",
"@types/mock-fs": "^4.13.0",
"@types/morgan": "^1.9.0",
"@types/node-forge": "^1.3.0",
"@types/recursive-readdir": "^2.2.0",
"@types/stoppable": "^1.1.0",
"@types/supertest": "^2.0.8",
@@ -21,8 +21,9 @@ import * as http from 'http';
import * as https from 'https';
import { Logger } from 'winston';
import { HttpsSettings } from './config';
import forge from 'node-forge';
const ALMOST_MONTH_IN_MS = 25 * 24 * 60 * 60 * 1000;
const FIVE_DAYS_IN_MS = 5 * 24 * 60 * 60 * 1000;
const IP_HOSTNAME_REGEX = /:|^\d+\.\d+\.\d+\.\d+$/;
@@ -82,6 +83,16 @@ export async function createHttpsServer(
return https.createServer(credentials, app) as http.Server;
}
function getCertificateExpiration(cert: string, logger?: Logger) {
try {
const crt = forge.pki.certificateFromPem(cert);
return crt.validity.notAfter.getTime() - Date.now();
} catch (error) {
logger?.warn(`Unable to parse self-signed certificate. ${error}`);
return 0;
}
}
async function getGeneratedCertificate(hostname: string, logger?: Logger) {
const hasModules = await fs.pathExists('node_modules');
let certPath;
@@ -94,23 +105,18 @@ async function getGeneratedCertificate(hostname: string, logger?: Logger) {
certPath = resolvePath('.dev-cert.pem');
}
let cert = undefined;
if (await fs.pathExists(certPath)) {
const stat = await fs.stat(certPath);
const ageMs = Date.now() - stat.ctimeMs;
if (stat.isFile() && ageMs < ALMOST_MONTH_IN_MS) {
cert = await fs.readFile(certPath);
const cert = await fs.readFile(certPath);
const remainingMs = getCertificateExpiration(cert.toString(), logger);
if (remainingMs > FIVE_DAYS_IN_MS) {
logger?.info('Using existing self-signed certificate');
return {
key: cert,
cert,
};
}
}
if (cert) {
logger?.info('Using existing self-signed certificate');
return {
key: cert,
cert: cert,
};
}
logger?.info('Generating new self-signed certificate');
const newCert = await createCertificate(hostname);
await fs.writeFile(certPath, newCert.cert + newCert.key, 'utf8');
+11
View File
@@ -3164,6 +3164,7 @@ __metadata:
"@types/minimist": ^1.2.0
"@types/mock-fs": ^4.13.0
"@types/morgan": ^1.9.0
"@types/node-forge": ^1.3.0
"@types/recursive-readdir": ^2.2.0
"@types/stoppable": ^1.1.0
"@types/supertest": ^2.0.8
@@ -3201,6 +3202,7 @@ __metadata:
mysql2: ^2.2.5
node-abort-controller: ^3.0.1
node-fetch: ^2.6.7
node-forge: ^1.3.1
raw-body: ^2.4.1
recursive-readdir: ^2.2.2
request: ^2.88.2
@@ -14012,6 +14014,15 @@ __metadata:
languageName: node
linkType: hard
"@types/node-forge@npm:^1.3.0":
version: 1.3.0
resolution: "@types/node-forge@npm:1.3.0"
dependencies:
"@types/node": "*"
checksum: f811885f997fbeebb0df2db8249b9b288ad5f5573beaecf6d323b019bb9a4c12f1476a8974c934f62329862f29986c116263a50aef0008364cc3f9867672a5a0
languageName: node
linkType: hard
"@types/node@npm:*, @types/node@npm:>=12.12.47, @types/node@npm:>=13.7.0":
version: 17.0.25
resolution: "@types/node@npm:17.0.25"