Skip to content

Commit 7220dbb

Browse files
committed
[FIX] Ensure SSL credentials are only readable by owner
SSL certificate and key used for the local development server (restricted to 'localhost' domain) are currently created with standard file permissions. This fix ensures '400' permission (only readable and only readable by owner) when the files are created and also updates any existing files with incorrect permissions.
1 parent 8256308 commit 7220dbb

File tree

1 file changed

+26
-8
lines changed

1 file changed

+26
-8
lines changed

lib/sslUtil.js

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import os from "node:os";
2-
import {stat, readFile, writeFile, mkdir} from "node:fs/promises";
2+
import {stat, readFile, writeFile, mkdir, chmod, constants} from "node:fs/promises";
33
import path from "node:path";
44
import {getLogger} from "@ui5/logger";
55

@@ -27,18 +27,36 @@ export function getSslCertificate(
2727
) {
2828
// checks the certificates if they are present
2929
return Promise.all([
30-
fileExists(keyPath).then((bExists) => {
31-
if (!bExists) {
30+
fileExists(keyPath).then(async (statsOrFalse) => {
31+
if (!statsOrFalse) {
3232
log.verbose(`No SSL private key found at ${keyPath}`);
3333
return false;
3434
}
35+
if (statsOrFalse.mode & constants.S_IWUSR || statsOrFalse.mode & constants.S_IROTH) {
36+
// Note: According to the Node.js docs, "On Windows, only S_IRUSR and S_IWUSR are available"
37+
// Therefore we first check for "writable by owner" (S_IWUSR), even though we are more interested in
38+
// "readable by others", which we still check on platforms where it's supported
39+
log.verbose(`Detected outdated file permissions for private key file at ${keyPath}. ` +
40+
`Fixing permissions...`);
41+
await chmod(keyPath, 0o400).catch((err) => {
42+
log.error(`Failed to update permissions of private key file at ${keyPath}: ${err}`);
43+
});
44+
}
3545
return readFile(keyPath);
3646
}),
37-
fileExists(certPath).then((bExists) => {
38-
if (!bExists) {
47+
fileExists(certPath).then(async (statsOrFalse) => {
48+
if (!statsOrFalse) {
3949
log.verbose(`No SSL certificate found at ${certPath}`);
4050
return false;
4151
}
52+
53+
if (statsOrFalse.mode & constants.S_IWUSR || statsOrFalse.mode & constants.S_IROTH) {
54+
log.verbose(`Detected outdated file permissions for certificate file at ${keyPath}. ` +
55+
`Fixing permissions...`);
56+
await chmod(certPath, 0o400).catch((err) => {
57+
log.error(`Failed to update permissions of certificate file at ${certPath}: ${err}`);
58+
});
59+
}
4260
return readFile(certPath);
4361
})
4462
]).then(function([key, cert]) {
@@ -84,14 +102,14 @@ async function createAndInstallCertificate(keyPath, certPath) {
84102
await Promise.all([
85103
// Write certificates to the ui5 certificate folder
86104
// such that they are used by default upon next startup
87-
mkdir(path.dirname(keyPath), {recursive: true}).then(() => writeFile(keyPath, key)),
88-
mkdir(path.dirname(certPath), {recursive: true}).then(() => writeFile(certPath, cert))
105+
mkdir(path.dirname(keyPath), {recursive: true}).then(() => writeFile(keyPath, key, {mode: 0o400})),
106+
mkdir(path.dirname(certPath), {recursive: true}).then(() => writeFile(certPath, cert, {mode: 0o400}))
89107
]);
90108
return {key, cert};
91109
}
92110

93111
function fileExists(filePath) {
94-
return stat(filePath).then(() => true, (err) => {
112+
return stat(filePath).then((s) => s, (err) => {
95113
if (err.code === "ENOENT") { // "File or directory does not exist"
96114
return false;
97115
} else {

0 commit comments

Comments
 (0)