bugfixes for download routes

This commit is contained in:
Jeff Caldwell
2025-12-07 09:29:20 -05:00
parent ca97c9cc9a
commit e29c6d4792
5 changed files with 74 additions and 21 deletions
+19
View File
@@ -4,6 +4,25 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
## [3.1.2] - 2025-12-07
### 🐛 Bug Fixes
- **Fixed certificate download endpoints**: Corrected path resolution for certificate, key, and bundle downloads
- Fixed `validateAndSanitizePath` usage to properly extract resolved path from returned object
- Fixed `validateFilename` error handling to catch thrown exceptions instead of checking return value
- Added support for both `.pem`/`-key.pem` and `.crt`/`.key` certificate formats in bundle downloads
- Resolved 404 errors when attempting to download certificates
## [3.1.1] - 2025-12-05
### 🐛 Bug Fixes
- **Fixed file upload endpoint**: Mounted missing file routes module to enable certificate uploads
- Added `createFileRoutes` import and mounting in server.js
- Corrected upload API endpoint from `/api/certificates/upload` to `/api/upload`
- **Fixed download URL paths**: Removed duplicate `/api` prefix in frontend download URLs
- Fixed downloadCert, downloadKey, downloadBundle, and downloadRootCA functions
- API_BASE constant already includes `/api`, preventing `/api/api/...` double prefix
## [3.1.0] - 2025-10-09
### ✨ New Features - Web-Based Settings Management
+1 -1
View File
@@ -7,7 +7,7 @@ set -e
# Configuration
IMAGE_NAME="jeffcaldwellca/mkcertweb"
VERSION="3.1.1"
VERSION="3.1.2"
# Colors for output
GREEN='\033[0;32m'
+1 -1
View File
@@ -1,6 +1,6 @@
services:
mkcert-web-ui:
image: jeffcaldwellca/mkcertweb:3.1.1
image: jeffcaldwellca/mkcertweb:3.1.2
ports:
- "3000:3000" # HTTP port
- "3443:3443" # HTTPS port
+4 -4
View File
@@ -1415,22 +1415,22 @@ async function downloadFile(url, filename) {
}
function downloadCert(folderParam, filename) {
const url = API_BASE + '/api/download/cert/' + folderParam + '/' + filename;
const url = API_BASE + '/download/cert/' + folderParam + '/' + filename;
downloadFile(url, filename);
}
function downloadKey(folderParam, filename) {
const url = API_BASE + '/api/download/key/' + folderParam + '/' + filename;
const url = API_BASE + '/download/key/' + folderParam + '/' + filename;
downloadFile(url, filename);
}
function downloadBundle(folderParam, certname) {
const url = API_BASE + '/api/download/bundle/' + folderParam + '/' + certname;
const url = API_BASE + '/download/bundle/' + folderParam + '/' + certname;
downloadFile(url, certname + '.zip');
}
function downloadRootCA() {
const url = API_BASE + '/api/download/rootca';
const url = API_BASE + '/download/rootca';
downloadFile(url, 'mkcert-rootCA.pem');
}
+49 -15
View File
@@ -605,7 +605,9 @@ const createCertificateRoutes = (config, rateLimiters, requireAuth) => {
const certificatesDir = path.join(process.cwd(), 'certificates');
// Validate the filename through security module
if (!security.validateFilename(filename)) {
try {
security.validateFilename(filename);
} catch (error) {
return apiResponse.badRequest(res, 'Invalid filename');
}
@@ -622,7 +624,8 @@ const createCertificateRoutes = (config, rateLimiters, requireAuth) => {
// Use security-validated path
let filePath;
try {
filePath = security.validateAndSanitizePath(filename, sourceDir);
const pathInfo = security.validateAndSanitizePath(filename, sourceDir);
filePath = pathInfo.resolved;
} catch (error) {
return apiResponse.badRequest(res, 'Invalid file path');
}
@@ -646,7 +649,9 @@ const createCertificateRoutes = (config, rateLimiters, requireAuth) => {
const certificatesDir = path.join(process.cwd(), 'certificates');
// Validate the filename through security module
if (!security.validateFilename(filename)) {
try {
security.validateFilename(filename);
} catch (error) {
return apiResponse.badRequest(res, 'Invalid filename');
}
@@ -663,7 +668,8 @@ const createCertificateRoutes = (config, rateLimiters, requireAuth) => {
// Use security-validated path
let filePath;
try {
filePath = security.validateAndSanitizePath(filename, sourceDir);
const pathInfo = security.validateAndSanitizePath(filename, sourceDir);
filePath = pathInfo.resolved;
} catch (error) {
return apiResponse.badRequest(res, 'Invalid file path');
}
@@ -687,7 +693,9 @@ const createCertificateRoutes = (config, rateLimiters, requireAuth) => {
const certificatesDir = path.join(process.cwd(), 'certificates');
// Validate the certificate name through security module
if (!security.validateFilename(`${certname}.pem`)) {
try {
security.validateFilename(`${certname}.pem`);
} catch (error) {
return apiResponse.badRequest(res, 'Invalid certificate name');
}
@@ -701,20 +709,46 @@ const createCertificateRoutes = (config, rateLimiters, requireAuth) => {
return apiResponse.badRequest(res, 'Invalid folder parameter');
}
// Use security-validated paths
let certFile, keyFile;
// Use security-validated paths - try both .pem and .crt formats
let certFile, keyFile, certExt, keyExt;
const fs = require('fs');
try {
certFile = security.validateAndSanitizePath(`${certname}.pem`, sourceDir);
keyFile = security.validateAndSanitizePath(`${certname}-key.pem`, sourceDir);
// Try .pem format for certificate
let certPathInfo = security.validateAndSanitizePath(`${certname}.pem`, sourceDir);
if (fs.existsSync(certPathInfo.resolved)) {
certFile = certPathInfo.resolved;
certExt = '.pem';
} else {
// Try .crt format
certPathInfo = security.validateAndSanitizePath(`${certname}.crt`, sourceDir);
if (fs.existsSync(certPathInfo.resolved)) {
certFile = certPathInfo.resolved;
certExt = '.crt';
}
}
// Try -key.pem format for key
let keyPathInfo = security.validateAndSanitizePath(`${certname}-key.pem`, sourceDir);
if (fs.existsSync(keyPathInfo.resolved)) {
keyFile = keyPathInfo.resolved;
keyExt = '-key.pem';
} else {
// Try .key format
keyPathInfo = security.validateAndSanitizePath(`${certname}.key`, sourceDir);
if (fs.existsSync(keyPathInfo.resolved)) {
keyFile = keyPathInfo.resolved;
keyExt = '.key';
}
}
} catch (error) {
return apiResponse.badRequest(res, 'Invalid file path');
}
try {
const fs = require('fs');
const archiver = require('archiver');
if (!fs.existsSync(certFile) && !fs.existsSync(keyFile)) {
if (!certFile && !keyFile) {
return apiResponse.notFound(res, 'Certificate files not found');
}
@@ -724,11 +758,11 @@ const createCertificateRoutes = (config, rateLimiters, requireAuth) => {
const archive = archiver('zip', { zlib: { level: 9 }});
archive.pipe(res);
if (fs.existsSync(certFile)) {
archive.file(certFile, { name: `${certname}.pem` });
if (certFile) {
archive.file(certFile, { name: `${certname}${certExt}` });
}
if (fs.existsSync(keyFile)) {
archive.file(keyFile, { name: `${certname}-key.pem` });
if (keyFile) {
archive.file(keyFile, { name: `${certname}${keyExt}` });
}
await archive.finalize();