From 7a56c889079a67d6f7324fcef028ad3f0e60329e Mon Sep 17 00:00:00 2001 From: Chandu Date: Sun, 5 Jul 2026 13:23:54 -0400 Subject: [PATCH] Add HTTPS server (self-signed fallback), update frontend messages, and README --- README.md | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ package.json | 3 ++- script.js | 7 +++++-- server.js | 34 ++++++++++++++++++++++++++++++++++ 4 files changed, 92 insertions(+), 3 deletions(-) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..a24cc0b --- /dev/null +++ b/README.md @@ -0,0 +1,51 @@ +# Voice Translator App + +This app provides text translation, speech-to-text, and text-to-speech functionality. It runs an Express server and serves a single-page frontend. + +HTTPS for microphone access +--------------------------------- +Modern browsers require a secure context (HTTPS or localhost over HTTPS) for getUserMedia microphone access. This project can start an HTTPS server on `https://localhost:3443` using either your own certificate files or a generated self-signed certificate. + +How to run +----------- +1. Install dependencies: + +```bash +cd /Users/chadee/Ria +npm install +``` + +2. Start the server (HTTP + HTTPS): + +```bash +npm start +``` + +This starts the HTTP server on `http://localhost:3000` and an HTTPS server on `https://localhost:3443`. + +Using your own certificate +-------------------------- +If you have SSL certificate and key files, set the following environment variables before starting the server: + +```bash +export SSL_CERT_PATH=/path/to/cert.pem +export SSL_KEY_PATH=/path/to/key.pem +npm start +``` + +When no certificate is provided, the server generates a temporary self-signed certificate at runtime and serves HTTPS on `https://localhost:3443`. + +Accepting the self-signed cert warning +------------------------------------ +When using the generated self-signed certificate, your browser will show a security warning. To proceed: + +- In Chrome/Edge/Brave: Click "Advanced" → "Proceed to localhost (unsafe)". +- In Firefox: Accept the risk and continue. +- In Safari: Go to System Settings → Privacy & Security → Certificates to trust the localhost certificate if needed. + +After accepting the warning, open `https://localhost:3443` and allow microphone access when prompted. The site will run in a secure context and `getUserMedia` will work. + +Notes +----- +- The server will log a warning when generating a temporary self-signed certificate. +- For production deployments use valid CA-signed certificates. diff --git a/package.json b/package.json index 6377b0c..a76cac1 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "google-tts-api": "^2.0.1" }, "devDependencies": { - "puppeteer": "^25.3.0" + "puppeteer": "^25.3.0", + "selfsigned": "^2.1.0" } } diff --git a/script.js b/script.js index 1e1ae1c..91ab760 100644 --- a/script.js +++ b/script.js @@ -165,7 +165,9 @@ async function checkMicrophonePermission() { if (status.state === 'denied') { if (microphoneHint) { - microphoneHint.innerHTML = 'šŸ”’ Microphone blocked for this site. To allow:\n• Click the lock icon in the address bar → Site settings → Microphone → Allow\n• Or open this app via http://localhost:3000 and re-grant permissions.' + // If the page was loaded over HTTP (not secure), recommend using HTTPS localhost:3443 + const suggestedUrl = (location.protocol === 'http:') ? 'https://localhost:3443' : 'http://localhost:3000'; + microphoneHint.innerHTML = `šŸ”’ Microphone blocked for this site. To allow:\n• Click the lock icon in the address bar → Site settings → Microphone → Allow\n• Or open this app via ${suggestedUrl} and re-grant permissions.` .replace(/\n/g, '
'); microphoneHint.style.display = 'block'; } @@ -224,7 +226,8 @@ async function verifyServerReachability() { throw new Error(`HTTP ${response.status}`); } catch (error) { console.error('Server reachability check failed:', error); - showStatus('Cannot reach the app server. Open the app via http://localhost:3000', 'error'); + const openUrl = (location.protocol === 'http:') ? 'https://localhost:3443' : 'http://localhost:3000'; + showStatus(`Cannot reach the app server. Open the app via ${openUrl}`, 'error'); logDev(`Server reachability failed: ${error?.message || error}`); } } diff --git a/server.js b/server.js index 92ab9c8..17d9c8a 100644 --- a/server.js +++ b/server.js @@ -57,6 +57,30 @@ const m2m100LangMap = { const app = express(); const PORT = process.env.PORT || 3000; +// HTTPS setup (optional). Serve HTTPS on 3443 using provided certs or generate a self-signed cert. +const https = require('https'); +const fs = require('fs'); +const selfsigned = require('selfsigned'); +const SSL_PORT = process.env.SSL_PORT || 3443; + +function loadSslOptions() { + const keyPath = process.env.SSL_KEY_PATH; + const certPath = process.env.SSL_CERT_PATH; + + if (keyPath && certPath && fs.existsSync(keyPath) && fs.existsSync(certPath)) { + return { + key: fs.readFileSync(keyPath), + cert: fs.readFileSync(certPath) + }; + } + + // Generate a temporary self-signed certificate for localhost + console.warn('No SSL cert/key provided. Generating a temporary self-signed certificate for https://localhost:' + SSL_PORT); + const attrs = [{ name: 'commonName', value: 'localhost' }]; + const pems = selfsigned.generate(attrs, { days: 365 }); + return { key: pems.private, cert: pems.cert }; +} + // Middleware app.use(cors()); app.use(bodyParser.json({ limit: '10mb' })); @@ -478,3 +502,13 @@ app.listen(PORT, () => { ======================================== `); }); + +// Start HTTPS server on SSL_PORT +try { + const sslOptions = loadSslOptions(); + https.createServer(sslOptions, app).listen(SSL_PORT, () => { + console.log(`HTTPS server running on: https://localhost:${SSL_PORT}`); + }); +} catch (err) { + console.error('Failed to start HTTPS server:', err); +}