From 950f554d46e8ee3324e3ef80b09c8baa0024ae42 Mon Sep 17 00:00:00 2001 From: ado24 Date: Thu, 23 Jan 2025 12:26:08 -0500 Subject: [PATCH 01/13] Adding module type to `package.json` --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index a2f2b62..88373d3 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,7 @@ "version": "1.0.0", "description": "NAD C338 REST API, with Express.js proxy", "main": "api-server/server.js", + "type": "module", "scripts": { "start-servers": "concurrently \"npm run api-server\" \"npm run tcp-server\"", "api-server": "node api-server/server.js", From fb351afa305833577f8a716b4efc9c99f9fe8feb Mon Sep 17 00:00:00 2001 From: ado24 Date: Mon, 27 Jan 2025 12:12:59 -0500 Subject: [PATCH 02/13] Latest changes to server, OpenAPI spec and updated readme # server.js - Fixed excessive listener attachment issues observed on testing - Added exports to `connectToServer` `attemptReconnect` # package.json - Added workspaces: - `tcp-server` - `api-server` - Added `run-tests` script - Added dev dependencies # nad-c338-api.yaml - Moved file to new `api` directory - Updated `server` entry with updated `ip` and `port` variables --- README.md | 2 +- nad-c338-api.yaml => api/nad-c338-api.yaml | 8 +++++++- package.json | 18 ++++++++++++++++-- tcp-server/server.js | 14 +++++++++----- 4 files changed, 33 insertions(+), 9 deletions(-) rename nad-c338-api.yaml => api/nad-c338-api.yaml (97%) diff --git a/README.md b/README.md index 9377b4d..8361921 100644 --- a/README.md +++ b/README.md @@ -17,4 +17,4 @@ Run `npm run tcp-server` to start the TCP server. Use Ctrl+C to stop the server. Ensure the binding on port 30001 is available. ## Client usage -See nad-c338-api for OpenAPI specification \ No newline at end of file +See [nad-c338-api.yaml](api/nad-c338-api.yaml) for OpenAPI specification for the RESTful API in use \ No newline at end of file diff --git a/nad-c338-api.yaml b/api/nad-c338-api.yaml similarity index 97% rename from nad-c338-api.yaml rename to api/nad-c338-api.yaml index 4f12505..ce060c7 100644 --- a/nad-c338-api.yaml +++ b/api/nad-c338-api.yaml @@ -4,7 +4,13 @@ info: version: 1.0.0 description: API for controlling NAD C338 amplifier servers: - - url: http://localhost:3000 + - url: http://{ip}:{port} + description: NAD C338 Amplifier + variables: + ip: + default: localhost + port: + default: 3000 paths: /power: get: diff --git a/package.json b/package.json index 88373d3..e069f79 100644 --- a/package.json +++ b/package.json @@ -7,11 +7,25 @@ "scripts": { "start-servers": "concurrently \"npm run api-server\" \"npm run tcp-server\"", "api-server": "node api-server/server.js", - "tcp-server": "node tcp-server/server.js" + "tcp-server": "node tcp-server/server.js", + "run-test": "jest --verbose --coverage" }, + "workspaces": [ + "api-server", + "tcp-server" + ], "dependencies": { "concurrently": "^9.1.2", "dotenv": "^16.4.7", "express": "^4.21.2" + }, + "devDependencies": { + "@jest/globals": "^29.7.0", + "@babel/preset-env": "^7.26.0", + "babel-jest": "^29.7.0", + "jest": "^29.7.0", + "nock": "^13.5.6", + "node": "^18.20.6", + "supertest": "^7.0.0" } -} \ No newline at end of file +} diff --git a/tcp-server/server.js b/tcp-server/server.js index 7dd3fc2..cb4f388 100644 --- a/tcp-server/server.js +++ b/tcp-server/server.js @@ -6,14 +6,14 @@ dotenv.config({'path': './tcp-server/properties.env'}); let client; let reconnectAttempts = 0; -const nadTcpPort = process.env.NAD_TCP_PORT; +const nadTcpPort = parseInt(process.env.NAD_TCP_PORT); const maxReconnectAttempts = process.env.MAX_RECONNECT_ATTEMPTS; const reconnectInterval = process.env.RECONNECT_INTERVAL; // 5 seconds const maxListeners = parseInt(process.env.MAX_LISTENERS); const errorCodes = ["ECONNRESET", "ECONNREFUSED", "ENETUNREACH", "ETIMEDOUT"]; -const connectToServer = async (ip, port) => { +export const connectToServer = async (ip, port) => { return new Promise((resolve, reject) => { client = net.createConnection({ port: port, host: ip }, () => { client.setMaxListeners(maxListeners); @@ -39,7 +39,7 @@ const connectToServer = async (ip, port) => { }); }; -const attemptReconnect = (ip, port) => { +export const attemptReconnect = (ip, port) => { if (reconnectAttempts < maxReconnectAttempts) { console.log(`Reconnection attempt ${++reconnectAttempts}...`); setTimeout(() => connectToServer(ip, port), reconnectInterval); @@ -80,11 +80,15 @@ const requestHandler = async (req, res) => { client.write(cmd + '\n'); - client.on('data', data => { + // Remove existing listeners to avoid adding multiple listeners + client.removeAllListeners('data'); + client.removeAllListeners('error'); + + client.once('data', data => { res.end(data.toString()); }); - client.on('error', err => { + client.once('error', err => { res.statusCode = 500; console.error(`Error: ${err}`); res.end('Error: ' + err.message); From 0460dc524dd48bacb51380917a2567b37665c7b8 Mon Sep 17 00:00:00 2001 From: ado24 Date: Mon, 3 Feb 2025 23:37:10 -0500 Subject: [PATCH 03/13] Adding gulp to GitHub workflow --- .github/workflows/npm-gulp.yml | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 .github/workflows/npm-gulp.yml diff --git a/.github/workflows/npm-gulp.yml b/.github/workflows/npm-gulp.yml new file mode 100644 index 0000000..6d04c0d --- /dev/null +++ b/.github/workflows/npm-gulp.yml @@ -0,0 +1,28 @@ +name: NodeJS with Gulp + +on: + push: + branches: [ "master" ] + pull_request: + branches: [ "master" ] + +jobs: + build: + runs-on: ubuntu-latest + + strategy: + matrix: + node-version: [18.x, 20.x, 22.x] + + steps: + - uses: actions/checkout@v4 + + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node-version }} + + - name: Build + run: | + npm install + gulp From 57f6189d8e08de4b033b0c540505521ea1ad9575 Mon Sep 17 00:00:00 2001 From: ado24 Date: Mon, 3 Feb 2025 23:42:24 -0500 Subject: [PATCH 04/13] Update package.json Adding gulp to package.json --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 336622e..3708706 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,8 @@ "dependencies": { "concurrently": "^9.1.2", "dotenv": "^16.4.7", - "express": "^4.21.2" + "express": "^4.21.2", + "gulp": "^5.0.0" }, "devDependencies": { "@jest/globals": "^29.7.0", From 027e91558a846dbdc7806997858ad2d2209856d1 Mon Sep 17 00:00:00 2001 From: ado24 Date: Mon, 3 Feb 2025 23:57:11 -0500 Subject: [PATCH 05/13] Adding gulpfile and dev dependencies --- gulpfile.js | 26 ++++++++++++++++++++++++++ package.json | 9 ++++++--- 2 files changed, 32 insertions(+), 3 deletions(-) create mode 100644 gulpfile.js diff --git a/gulpfile.js b/gulpfile.js new file mode 100644 index 0000000..8fd9594 --- /dev/null +++ b/gulpfile.js @@ -0,0 +1,26 @@ +import gulp from 'gulp'; +import babel from 'gulp-babel'; +import { deleteAsync } from 'del'; + +// Clean the dist directory +gulp.task('clean', () => { + return deleteAsync(['dist']); +}); + +// Transpile JavaScript files +gulp.task('transpile', () => { + return gulp.src(['api-server/**/*.js', 'tcp-server/**/*.js']) + .pipe(babel({ + presets: ['@babel/preset-env'] + })) + .pipe(gulp.dest('dist')); +}); + +// Copy non-JS files +gulp.task('copy', () => { + return gulp.src(['api-server/**/*.json', 'tcp-server/**/*.json', 'tcp-server/properties.env']) + .pipe(gulp.dest('dist')); +}); + +// Default task +gulp.task('default', gulp.series('clean', 'transpile', 'copy')); \ No newline at end of file diff --git a/package.json b/package.json index 3708706..a965dd4 100644 --- a/package.json +++ b/package.json @@ -17,13 +17,16 @@ "dependencies": { "concurrently": "^9.1.2", "dotenv": "^16.4.7", - "express": "^4.21.2", - "gulp": "^5.0.0" + "express": "^4.21.2" }, "devDependencies": { + "@babel/core": "^7.26.7", + "@babel/preset-env": "^7.26.7", "@jest/globals": "^29.7.0", - "@babel/preset-env": "^7.26.0", "babel-jest": "^29.7.0", + "del": "^8.0.0", + "gulp": "^5.0.0", + "gulp-babel": "^8.0.0", "jest": "^29.7.0", "nock": "^14.0.0", "node": "^23.7.0", From 29b67895df559e6c617f01495323341837071773 Mon Sep 17 00:00:00 2001 From: ado24 Date: Tue, 11 Feb 2025 16:36:50 -0500 Subject: [PATCH 06/13] Adding gulpfile and dev dependencies --- .eslintrc.cjs | 1 + gulpfile.js | 96 +++++++++++++++++++++++++++++++++++++++++++-------- package.json | 4 ++- 3 files changed, 86 insertions(+), 15 deletions(-) diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 3eab0c6..a7d79fa 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -12,5 +12,6 @@ module.exports = { }, rules: { // Add your custom rules here + }, }; \ No newline at end of file diff --git a/gulpfile.js b/gulpfile.js index 8fd9594..0e0b7cd 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -1,26 +1,94 @@ import gulp from 'gulp'; import babel from 'gulp-babel'; +import ts from 'gulp-typescript'; import { deleteAsync } from 'del'; // Clean the dist directory -gulp.task('clean', () => { - return deleteAsync(['dist']); -}); +const clean = () => deleteAsync(['dist']); -// Transpile JavaScript files -gulp.task('transpile', () => { - return gulp.src(['api-server/**/*.js', 'tcp-server/**/*.js']) +// Transpile JavaScript files for api-server +const transpileApiServer = () => { + return gulp.src('api-server/**/*.js') .pipe(babel({ - presets: ['@babel/preset-env'] + presets: [['@babel/preset-env', { modules: false }]] })) - .pipe(gulp.dest('dist')); -}); + .pipe(gulp.dest('dist/api-server')); +}; + +// Transpile JavaScript files for tcp-server +const transpileTcpServer = () => { + return gulp.src('tcp-server/**/*.js') + .pipe(babel({ + presets: [['@babel/preset-env', { modules: false }]] + })) + .pipe(gulp.dest('dist/tcp-server')); +}; + +// Transpile model files +const transpileModel = () => { + return gulp.src('model/**/*.js') + .pipe(babel({ + presets: [['@babel/preset-env', { modules: false }]] + })) + .pipe(gulp.dest('dist/model')); +} + +// Copy non-JS files for api-server +const copyApiServer = () => { + return gulp.src(['api-server/**/*.json', 'api-server/properties.env']) + .pipe(gulp.dest('dist/api-server')); +}; + +// Copy non-JS files for tcp-server +const copyTcpServer = () => { + return gulp.src(['tcp-server/**/*.json', 'tcp-server/properties.env']) + .pipe(gulp.dest('dist/tcp-server')); +}; + +// Copy non-JS files for model +const copyModel = () => { + return gulp.src('model/**/*.json') + .pipe(gulp.dest('dist/model')); +}; -// Copy non-JS files -gulp.task('copy', () => { - return gulp.src(['api-server/**/*.json', 'tcp-server/**/*.json', 'tcp-server/properties.env']) +// Generate package.json +const generatePackageJson = () => { + return gulp.src('package.json') .pipe(gulp.dest('dist')); -}); +}; + + +// Create a TypeScript project +const tsProject = ts.createProject('tsconfig.json'); + +// Transpile TypeScript files for api-server +const transpileApiServerTS = () => { + return gulp.src('api-server/**/*.ts') + .pipe(tsProject()) + .pipe(gulp.dest('dist/api-server-ts')); +}; + +// Transpile TypeScript files for tcp-server +const transpileTcpServerTS = () => { + return gulp.src('tcp-server/**/*.ts') + .pipe(tsProject()) + .pipe(gulp.dest('dist/tcp-server-ts')); +}; + +// Wrapper for the clean task +gulp.task('clean', clean); + +// Wrapper for transpiling JavaScript +gulp.task('transpile', gulp.parallel(transpileApiServer, transpileTcpServer,transpileModel)); + +// Wrapper for copying non-JS files +gulp.task('copy', gulp.parallel(copyApiServer, copyTcpServer, copyModel)); + +// Task to transpile JavaScript files +gulp.task('package-js', gulp.series(transpileApiServer, transpileTcpServer, transpileModel, "copy")); // gulp.parallel(copyApiServer, copyTcpServer, copyModel))); + +// Task to transpile TypeScript files +gulp.task('package-ts', gulp.parallel(transpileApiServerTS, transpileTcpServerTS)); // Default task -gulp.task('default', gulp.series('clean', 'transpile', 'copy')); \ No newline at end of file +gulp.task('default', gulp.series(clean, gulp.series(transpileApiServer, transpileTcpServer, transpileModel, "copy", generatePackageJson))); \ No newline at end of file diff --git a/package.json b/package.json index a965dd4..404f4ae 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,8 @@ "start-servers": "concurrently \"npm run api-server\" \"npm run tcp-server\"", "api-server": "node api-server/server.js", "tcp-server": "node tcp-server/server.js", - "run-test": "jest --verbose --coverage" + "run-test": "jest --coverage", + "test": "node --experimental-vm-modules node_modules/jest/bin/jest.js" }, "workspaces": [ "api-server", @@ -26,6 +27,7 @@ "babel-jest": "^29.7.0", "del": "^8.0.0", "gulp": "^5.0.0", + "gulp-typescript": "^6.0.0-alpha.1", "gulp-babel": "^8.0.0", "jest": "^29.7.0", "nock": "^14.0.0", From cfe0d51e9fdfe33319113a669d54a7ea92f8b2c4 Mon Sep 17 00:00:00 2001 From: ado24 Date: Tue, 11 Feb 2025 16:39:46 -0500 Subject: [PATCH 07/13] TCP server changes --- model/NAD-C338.js | 2 +- tcp-server/properties.env | 3 +++ tcp-server/server.js | 21 ++++++++++++++------- 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/model/NAD-C338.js b/model/NAD-C338.js index 2ade2a8..00b84a6 100644 --- a/model/NAD-C338.js +++ b/model/NAD-C338.js @@ -3,7 +3,7 @@ export class NADC338 { this.ip = ip; this.port = port; this.powerState = null; - this.volume = null; + this.volume = 0; this.source = null; this.mute = null; this.brightness = null; diff --git a/tcp-server/properties.env b/tcp-server/properties.env index 703ac67..71ce032 100644 --- a/tcp-server/properties.env +++ b/tcp-server/properties.env @@ -2,3 +2,6 @@ MAX_RECONNECT_ATTEMPTS=5 RECONNECT_INTERVAL=5000 MAX_LISTENERS=30 NAD_TCP_PORT=30001 +NAD_HOSTNAME=localhost +SERVER_LISTENER_IP=0.0.0.0 +LOG_LEVEL=none \ No newline at end of file diff --git a/tcp-server/server.js b/tcp-server/server.js index cb4f388..efa4c0e 100644 --- a/tcp-server/server.js +++ b/tcp-server/server.js @@ -10,6 +10,8 @@ const nadTcpPort = parseInt(process.env.NAD_TCP_PORT); const maxReconnectAttempts = process.env.MAX_RECONNECT_ATTEMPTS; const reconnectInterval = process.env.RECONNECT_INTERVAL; // 5 seconds const maxListeners = parseInt(process.env.MAX_LISTENERS); +const serverListenerIp = process.env.SERVER_LISTENER_IP; +const logLevel = process.env.LOG_LEVEL; const errorCodes = ["ECONNRESET", "ECONNREFUSED", "ENETUNREACH", "ETIMEDOUT"]; @@ -17,12 +19,13 @@ export const connectToServer = async (ip, port) => { return new Promise((resolve, reject) => { client = net.createConnection({ port: port, host: ip }, () => { client.setMaxListeners(maxListeners); - console.log(`Connected to ${ip}:${port}`); + if (logLevel !== "none") + console.log(`Connected to ${ip}:${port}`); reconnectAttempts = 0; // Reset attempts on successful connection resolve(client); }); - client.on('error', err => { + client.on('error', /** @param {Error & { code?: string }} err */ err => { if (errorCodes.includes(err.code)) { console.error(`Connection error: ${err.message}`); client.destroy(); @@ -34,14 +37,16 @@ export const connectToServer = async (ip, port) => { }); client.on('close', () => { - console.log('Connection closed'); + if (logLevel !== "none") + console.log('Connection closed'); }); }); }; export const attemptReconnect = (ip, port) => { if (reconnectAttempts < maxReconnectAttempts) { - console.log(`Reconnection attempt ${++reconnectAttempts}...`); + if (logLevel !== "none") + console.log(`Reconnection attempt ${++reconnectAttempts}...`); setTimeout(() => connectToServer(ip, port), reconnectInterval); } else { console.error('Max reconnection attempts reached. Giving up.'); @@ -102,14 +107,16 @@ const requestHandler = async (req, res) => { const server = http.createServer(requestHandler); -server.listen(nadTcpPort, '0.0.0.0', () => { - console.log('Server is listening on port 30001'); +server.listen(nadTcpPort, serverListenerIp, () => { + if (logLevel !== "none") + console.log(`TCP server running at ${serverListenerIp}:${nadTcpPort}`); }); process.on('SIGINT', () => { if (client) { client.end(); - console.log('TCP connection closed'); + if (logLevel !== "none") + console.log('TCP connection closed'); } process.exit(); }); From ae7d2f3cc6246013c862bf270769e69e57d9d9a4 Mon Sep 17 00:00:00 2001 From: ado24 Date: Thu, 13 Mar 2025 16:12:33 -0400 Subject: [PATCH 08/13] Initial release for HTTPS server support for REST API, along with example self-signed cert and keys --- api-server/package.json | 5 +- api-server/properties.env | 4 +- api-server/server.js | 133 ++++++++++++++++++++++++++-- api/nad-c338-api.yaml | 180 +++++++++++++++++++++++++++++++++++++- certs/server.crt | 32 +++++++ gulpfile.js | 14 ++- keys/server.key | 52 +++++++++++ tcp-server/server.js | 2 +- 8 files changed, 409 insertions(+), 13 deletions(-) create mode 100644 certs/server.crt create mode 100644 keys/server.key diff --git a/api-server/package.json b/api-server/package.json index d4fbc1f..a4b415b 100644 --- a/api-server/package.json +++ b/api-server/package.json @@ -12,5 +12,8 @@ "type": "git", "url": "https://github.com/ado24/NAD-C338-REST-API.git" }, - "private": true + "private": true, + "dependencies": { + "cors": "^2.8.5" + } } diff --git a/api-server/properties.env b/api-server/properties.env index 0a0c5a1..1b4b2d5 100644 --- a/api-server/properties.env +++ b/api-server/properties.env @@ -1,3 +1,5 @@ API_SERVER_LISTENER_PORT=3000 BLUOS_TCP_PORT=30001 -BLUOS_IP=10.0.0.251 \ No newline at end of file +BLUOS_IP=10.0.0.251 +KEEPALIVE_TIMEOUT=61000 +HEADERS_TIMEOUT=62000 \ No newline at end of file diff --git a/api-server/server.js b/api-server/server.js index 3a860aa..25b50ef 100644 --- a/api-server/server.js +++ b/api-server/server.js @@ -1,6 +1,9 @@ import express from 'express'; import { NADC338 } from '../model/NAD-C338.js'; import dotenv from 'dotenv'; +import https from 'https'; +import fs from 'fs'; +import cors from 'cors'; dotenv.config({'path': './api-server/properties.env'}); const app = express(); @@ -8,14 +11,52 @@ const app = express(); const port = process.env.API_SERVER_LISTENER_PORT; const ip = process.env.BLUOS_IP; const bluOsPort = parseInt(process.env.BLUOS_TCP_PORT); +const keepAliveTimeout = parseInt(process.env.KEEPALIVE_TIMEOUT); +const headersTimeout = parseInt(process.env.HEADERS_TIMEOUT); -app.use(express.json()); +// Load SSL certificate and private key +//const ca = fs.readFileSync('path/to/your/ca_bundle.crt', 'utf8'); + +const endpointKeyPath = "./keys/server.key"; +const endpointCertPath = "./certs/server.crt"; +const caPath = "./certs/server.crt"; + +const credentials = { + key: fs.readFileSync(endpointKeyPath), + cert: fs.readFileSync(endpointCertPath), + ca: fs.readFileSync(caPath) +}; let nad = new NADC338(ip, bluOsPort); +app.use(cors()); +app.use(express.json()); +app.use((req, res, next) => { + // Set default security headers + res.set('Strict-Transport-Security', 'max-age=31536000; includeSubDomains'); + next(); +}); +app.use((req, res, next) => { + // Add default cache control for modification endpoints + if (req.method !== 'GET') { + res.set({ + 'Cache-Control': 'no-cache, no-store, must-revalidate', + 'Pragma': 'no-cache', + 'Expires': '0' + }); + } + next(); +}); + // GET endpoints +// Frequently changing state - minimal cache app.get('/power', async (req, res) => { try { const power = await nad.getPower(); + res.set({ + 'Cache-Control': 'no-cache, no-store, must-revalidate', + 'Pragma': 'no-cache', + 'Expires': '0' + }); res.json({ power }); } catch (error) { res.status(500).send(error.message); @@ -25,6 +66,11 @@ app.get('/power', async (req, res) => { app.get('/volume', async (req, res) => { try { const volume = await nad.getVolume(); + res.set({ + 'Cache-Control': 'no-cache, no-store, must-revalidate', + 'Pragma': 'no-cache', + 'Expires': '0' + }); res.json({ volume }); } catch (error) { res.status(500).send(error.message); @@ -34,6 +80,11 @@ app.get('/volume', async (req, res) => { app.get('/source', async (req, res) => { try { const source = await nad.getSource(); + res.set({ + 'Cache-Control': 'no-cache, no-store, must-revalidate', + 'Pragma': 'no-cache', + 'Expires': '0' + }); res.json({ source }); } catch (error) { res.status(500).send(error.message); @@ -43,15 +94,25 @@ app.get('/source', async (req, res) => { app.get('/mute', async (req, res) => { try { const mute = await nad.getMute(); + res.set({ + 'Cache-Control': 'no-cache, no-store, must-revalidate', + 'Pragma': 'no-cache', + 'Expires': '0' + }); res.json({ mute }); } catch (error) { res.status(500).send(error.message); } }); +// Less frequently changing settings - short cache app.get('/brightness', async (req, res) => { try { const brightness = await nad.getBrightness(); + res.set({ + 'Cache-Control': 'public, max-age=5', + 'Vary': 'Accept-Encoding' + }); res.json({ brightness }); } catch (error) { res.status(500).send(error.message); @@ -61,15 +122,24 @@ app.get('/brightness', async (req, res) => { app.get('/bass', async (req, res) => { try { const bass = await nad.getBass(); + res.set({ + 'Cache-Control': 'public, max-age=5', + 'Vary': 'Accept-Encoding' + }); res.json({ bass }); } catch (error) { res.status(500).send(error.message); } }); +// Configuration settings - longer cache app.get('/auto-sense', async (req, res) => { try { const autoSense = await nad.getAutoSense(); + res.set({ + 'Cache-Control': 'public, max-age=60', + 'Vary': 'Accept-Encoding' + }); res.json({ autoSense }); } catch (error) { res.status(500).send(error.message); @@ -79,13 +149,17 @@ app.get('/auto-sense', async (req, res) => { app.get('/auto-standby', async (req, res) => { try { const autoStandby = await nad.getAutoStandby(); + res.set({ + 'Cache-Control': 'public, max-age=60', + 'Vary': 'Accept-Encoding' + }); res.json({ autoStandby }); } catch (error) { res.status(500).send(error.message); } }); -// POST/PUT endpoints +// POST/PUT/PATCH/DELETE endpoints app.post('/power', async (req, res) => { try { const { state } = req.body; @@ -94,7 +168,23 @@ app.post('/power', async (req, res) => { } else if (state === 'Off') { await nad.powerOff(); } - res.sendStatus(200); + const power = await nad.getPower(); + res.json({ power }); + } catch (error) { + res.status(500).send(error.message); + } +}); + +app.patch('/power', async (req, res) => { + try { + const { state } = req.body; + if (state === 'On') { + await nad.powerOn(); + } else if (state === 'Off') { + await nad.powerOff(); + } + //const power = await nad.getPower(); + res.json({ state }); } catch (error) { res.status(500).send(error.message); } @@ -104,7 +194,19 @@ app.put('/volume', async (req, res) => { try { const { level } = req.body; await nad.setVolume(level); - res.sendStatus(200); + const volume = await nad.getVolume(); + res.json({ volume }); + } catch (error) { + res.status(500).send(error.message); + } +}); + +app.patch('/volume', async (req, res) => { + try { + const { level } = req.body; + await nad.setVolume(level); + //const volume = await nad.getVolume(); + res.json({ level }); } catch (error) { res.status(500).send(error.message); } @@ -157,6 +259,15 @@ app.post('/bass', async (req, res) => { } }); +app.patch('/bass', async (req, res) => { + try { + await nad.setBass(); + res.json({ bass: 'On' }); + } catch (error) { + res.status(500).send(error.message); + } +}); + app.delete('/bass', async (req, res) => { try { await nad.unsetBass(); @@ -202,6 +313,14 @@ app.delete('/auto-standby', async (req, res) => { } }); -app.listen(port, () => { - console.log(`Node.js server running at http://localhost:${port}`); -}); \ No newline at end of file +// Create HTTPS server +const httpsServer = https.createServer(credentials, app); + +httpsServer.listen(port, () => { + console.log(`HTTPS server running at https://localhost:${port}`); +}); + +httpsServer.keepAliveTimeout = keepAliveTimeout; +httpsServer.headersTimeout = headersTimeout; + +app.set('timeout', keepAliveTimeout); \ No newline at end of file diff --git a/api/nad-c338-api.yaml b/api/nad-c338-api.yaml index ce060c7..33aa508 100644 --- a/api/nad-c338-api.yaml +++ b/api/nad-c338-api.yaml @@ -10,7 +10,7 @@ servers: ip: default: localhost port: - default: 3000 + default: 3000 paths: /power: get: @@ -27,6 +27,13 @@ paths: type: string '500': description: Server error + content: + application/json: + schema: + type: object + properties: + error: + type: string post: summary: Set power status requestBody: @@ -42,8 +49,23 @@ paths: responses: '200': description: Power status set + content: + application/json: + schema: + type: object + properties: + power: + type: string '500': description: Server error + content: + application/json: + schema: + type: object + properties: + error: + type: string + /volume: get: summary: Get volume level @@ -59,6 +81,13 @@ paths: type: number '500': description: Server error + content: + application/json: + schema: + type: object + properties: + error: + type: string put: summary: Set volume level requestBody: @@ -73,8 +102,23 @@ paths: responses: '200': description: Volume level set + content: + application/json: + schema: + type: object + properties: + volume: + type: number '500': description: Server error + content: + application/json: + schema: + type: object + properties: + error: + type: string + /source: get: summary: Get source @@ -90,6 +134,13 @@ paths: type: string '500': description: Server error + content: + application/json: + schema: + type: object + properties: + error: + type: string put: summary: Set source requestBody: @@ -104,8 +155,23 @@ paths: responses: '200': description: Source set + content: + application/json: + schema: + type: object + properties: + source: + type: string '500': description: Server error + content: + application/json: + schema: + type: object + properties: + error: + type: string + /mute: get: summary: Get mute status @@ -121,6 +187,13 @@ paths: type: string '500': description: Server error + content: + application/json: + schema: + type: object + properties: + error: + type: string post: summary: Mute responses: @@ -128,6 +201,14 @@ paths: description: Muted '500': description: Server error + content: + application/json: + schema: + type: object + properties: + error: + type: string + /unmute: post: summary: Unmute @@ -136,6 +217,14 @@ paths: description: Unmuted '500': description: Server error + content: + application/json: + schema: + type: object + properties: + error: + type: string + /brightness: get: summary: Get brightness level @@ -151,6 +240,13 @@ paths: type: number '500': description: Server error + content: + application/json: + schema: + type: object + properties: + error: + type: string put: summary: Set brightness level requestBody: @@ -165,8 +261,23 @@ paths: responses: '200': description: Brightness level set + content: + application/json: + schema: + type: object + properties: + brightness: + type: number '500': description: Server error + content: + application/json: + schema: + type: object + properties: + error: + type: string + /bass: get: summary: Get bass status @@ -182,6 +293,13 @@ paths: type: string '500': description: Server error + content: + application/json: + schema: + type: object + properties: + error: + type: string post: summary: Set bass responses: @@ -189,6 +307,13 @@ paths: description: Bass set '500': description: Server error + content: + application/json: + schema: + type: object + properties: + error: + type: string delete: summary: Unset bass responses: @@ -196,6 +321,14 @@ paths: description: Bass unset '500': description: Server error + content: + application/json: + schema: + type: object + properties: + error: + type: string + /auto-sense: get: summary: Get auto sense status @@ -211,6 +344,13 @@ paths: type: string '500': description: Server error + content: + application/json: + schema: + type: object + properties: + error: + type: string post: summary: Set auto sense responses: @@ -218,6 +358,13 @@ paths: description: Auto sense set '500': description: Server error + content: + application/json: + schema: + type: object + properties: + error: + type: string delete: summary: Unset auto sense responses: @@ -225,6 +372,14 @@ paths: description: Auto sense unset '500': description: Server error + content: + application/json: + schema: + type: object + properties: + error: + type: string + /auto-standby: get: summary: Get auto standby status @@ -240,6 +395,13 @@ paths: type: string '500': description: Server error + content: + application/json: + schema: + type: object + properties: + error: + type: string post: summary: Set auto standby responses: @@ -247,10 +409,24 @@ paths: description: Auto standby set '500': description: Server error + content: + application/json: + schema: + type: object + properties: + error: + type: string delete: summary: Unset auto standby responses: '200': description: Auto standby unset '500': - description: Server error \ No newline at end of file + description: Server error + content: + application/json: + schema: + type: object + properties: + error: + type: string \ No newline at end of file diff --git a/certs/server.crt b/certs/server.crt new file mode 100644 index 0000000..133dd94 --- /dev/null +++ b/certs/server.crt @@ -0,0 +1,32 @@ +-----BEGIN CERTIFICATE----- +MIIFhDCCA2ygAwIBAgIUVz4d61IgxW97PqQwDcC14xnPzfwwDQYJKoZIhvcNAQEN +BQAwPDELMAkGA1UEBhMCQ0ExCzAJBgNVBAgMAk9OMQ4wDAYDVQQKDAVhZG8yNDEQ +MA4GA1UEAwwHbGVnaW9uNzAgFw0yNTAyMTExODQ1MTVaGA8yMTI1MDExODE4NDUx +NVowPDELMAkGA1UEBhMCQ0ExCzAJBgNVBAgMAk9OMQ4wDAYDVQQKDAVhZG8yNDEQ +MA4GA1UEAwwHbGVnaW9uNzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB +AMWL0pu5OJJZembWBm+qkJmuE4JXSjKYXklS5tR+nxKeO9TUOjx/MmRvfoapYh3t +YRUjur4+Kng4dLOpwL0NCkeVo5BnmCZtFwHASMElhmZmDszpEu6Lxsa1Dck6VG50 +yFXXBj+mmhbSpr6qf0/GcjzxbKJncDweDNticQIK1b+Yg5vfp89U85JH8BNdW7VY +5GKiD/Y/b9Aij0TzzhIDAAe4FJphT7gdEG8eUIKbroJkIvpmc85UEiilbnGzMwky +AlqQ8CpRDoefYHGS8jTktifjeBorq/whpL1M/hvvP1Km+PEDwaBondP7fHxkgHGp +3eQW3Jgz45pZ+sIX0iGGfRl2+079eJscce0On4h9jtwT0cpxw+/gIe+2h+K6qxyO +Od1zlvwPDFDeJBOT+cr2RMFDJllYEF44qHjICRCq3FPP4H1m9575I1jB1KviK+Nm +vSoEI5ZhUlKU3BbjM8xBzM9Ufi4YetK2jX8l/VOanTL/v9ugn1/q3dddjod2bhE9 +VfKD/5XlvoWwbT3hr8LdGOSHHdgzIAiLFLoprcRzvfanpGZCIGxR9w4ejc2QuB/G +Nr/4rGTIXH2ITwFW6gJ16pIvtzeHmPe5uiqSCmNTZHsMg+Mq4fZPFSbR00NxbGFI +mvu076Dx7obA/C7bFqbexq9KwAbDfVH42XMuIvTojD3NAgMBAAGjfDB6MB0GA1Ud +DgQWBBR7IJrxqe7Qp/MBDQhYOc2Br5WnWTAfBgNVHSMEGDAWgBR7IJrxqe7Qp/MB +DQhYOc2Br5WnWTAPBgNVHRMBAf8EBTADAQH/MCcGA1UdEQQgMB6CB2xlZ2lvbjeC +CWxvY2FsaG9zdIIIMTAuMC4wLjQwDQYJKoZIhvcNAQENBQADggIBAJUKDOtmqq40 +U4xhi4ysJ/1Vrma/D1dZ0AzKeAX4gJfXNUZlU/mBf90RrwX+Zr5/m8rDo8TrB3tO +bKdZLLMKwHTKwWDZbldAkqCiYhW1BPCZZNXhXJWOUWtwbb9cX+D0oQCYQ+EEmwcx +OrG9MSHua3adlHBMF8FlnwGHuRsaMK0nZx6Ny9gsfG4rNlX0tdrg+gK8GNAen+3F +TRiyXmfVK2yM5pH+Xg39GC7QdUQEQQbnateF2rqCfPZyguC4YUne6B5OCPI8i+Rs +uO3MCBiKu2iNwaxT62sU6/l+TMgIzNbzBCAUFqhiooSwH6/9JbVEKs1pMOjUNJ6y +ipZoYwqO/XePi5qocNYxhg4NDH7W6KIxcqXLSviwq+JSAdmAg/NBVVe9M/jSiH03 +oLYz91Fkc0syRkgg+LzjtBk9I1o7gIpQapqepjGXq1FEzkA03lN/7IugjuTbA4RD +w6/hKDNrf2zfRy+tTmc+6WnSbC3/Q4V+kh63JLXzBYYB1hWmyMWOO9916vPWmHCb +rBTa7BvwrneiokytTZHYMdKJ1ac9C4LekSGEPjiR3Bz7i7A5vjQrdNuM1XUPyetZ +l+Ch47j38YQzBkYmDy1/y/9I8gB1w2/De5318Jx4oWpg0elFoe9n3Ps6br8iP3e9 +lTGdAnvW3AEutII657DJK/AI8VKZTsqF +-----END CERTIFICATE----- diff --git a/gulpfile.js b/gulpfile.js index 0e0b7cd..5d47a5a 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -51,6 +51,17 @@ const copyModel = () => { .pipe(gulp.dest('dist/model')); }; +// Copy keys and certs +const copyKeys = () => { + return gulp.src('keys/**/*') + .pipe(gulp.dest('dist/keys')); +} + +const copyCerts = () => { + return gulp.src('certs/**/*') + .pipe(gulp.dest('dist/certs')); +} + // Generate package.json const generatePackageJson = () => { return gulp.src('package.json') @@ -82,7 +93,8 @@ gulp.task('clean', clean); gulp.task('transpile', gulp.parallel(transpileApiServer, transpileTcpServer,transpileModel)); // Wrapper for copying non-JS files -gulp.task('copy', gulp.parallel(copyApiServer, copyTcpServer, copyModel)); +gulp.task('copy', gulp.parallel(copyApiServer, copyTcpServer, copyModel, copyKeys, copyCerts)); + // Task to transpile JavaScript files gulp.task('package-js', gulp.series(transpileApiServer, transpileTcpServer, transpileModel, "copy")); // gulp.parallel(copyApiServer, copyTcpServer, copyModel))); diff --git a/keys/server.key b/keys/server.key new file mode 100644 index 0000000..053f74d --- /dev/null +++ b/keys/server.key @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +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 +Zo0caJBSUPBGA69acVnBOSMAG8q9yQ== +-----END PRIVATE KEY----- diff --git a/tcp-server/server.js b/tcp-server/server.js index efa4c0e..c554bb9 100644 --- a/tcp-server/server.js +++ b/tcp-server/server.js @@ -65,7 +65,7 @@ const requestHandler = async (req, res) => { return; } - if (req.method === 'POST') { + if (req.method === 'POST' || req.method === 'PUT' || req.method === 'DELETE') { let body = ''; req.on('data', chunk => { body += chunk.toString(); From 8820d87ddcb44f243d8d15991090d58b29cb68f8 Mon Sep 17 00:00:00 2001 From: ado24 Date: Thu, 13 Mar 2025 16:12:33 -0400 Subject: [PATCH 09/13] Initial release for HTTPS server support for REST API, along with example self-signed cert and keys --- api-server/package.json | 5 +- api-server/properties.env | 4 +- api-server/server.js | 133 ++++++++++++++++++++++++++-- api/nad-c338-api.yaml | 180 +++++++++++++++++++++++++++++++++++++- certs/server.crt | 32 +++++++ gulpfile.js | 14 ++- keys/server.key | 52 +++++++++++ tcp-server/server.js | 2 +- 8 files changed, 409 insertions(+), 13 deletions(-) create mode 100644 certs/server.crt create mode 100644 keys/server.key diff --git a/api-server/package.json b/api-server/package.json index d4fbc1f..a4b415b 100644 --- a/api-server/package.json +++ b/api-server/package.json @@ -12,5 +12,8 @@ "type": "git", "url": "https://github.com/ado24/NAD-C338-REST-API.git" }, - "private": true + "private": true, + "dependencies": { + "cors": "^2.8.5" + } } diff --git a/api-server/properties.env b/api-server/properties.env index 0a0c5a1..1b4b2d5 100644 --- a/api-server/properties.env +++ b/api-server/properties.env @@ -1,3 +1,5 @@ API_SERVER_LISTENER_PORT=3000 BLUOS_TCP_PORT=30001 -BLUOS_IP=10.0.0.251 \ No newline at end of file +BLUOS_IP=10.0.0.251 +KEEPALIVE_TIMEOUT=61000 +HEADERS_TIMEOUT=62000 \ No newline at end of file diff --git a/api-server/server.js b/api-server/server.js index 3a860aa..25b50ef 100644 --- a/api-server/server.js +++ b/api-server/server.js @@ -1,6 +1,9 @@ import express from 'express'; import { NADC338 } from '../model/NAD-C338.js'; import dotenv from 'dotenv'; +import https from 'https'; +import fs from 'fs'; +import cors from 'cors'; dotenv.config({'path': './api-server/properties.env'}); const app = express(); @@ -8,14 +11,52 @@ const app = express(); const port = process.env.API_SERVER_LISTENER_PORT; const ip = process.env.BLUOS_IP; const bluOsPort = parseInt(process.env.BLUOS_TCP_PORT); +const keepAliveTimeout = parseInt(process.env.KEEPALIVE_TIMEOUT); +const headersTimeout = parseInt(process.env.HEADERS_TIMEOUT); -app.use(express.json()); +// Load SSL certificate and private key +//const ca = fs.readFileSync('path/to/your/ca_bundle.crt', 'utf8'); + +const endpointKeyPath = "./keys/server.key"; +const endpointCertPath = "./certs/server.crt"; +const caPath = "./certs/server.crt"; + +const credentials = { + key: fs.readFileSync(endpointKeyPath), + cert: fs.readFileSync(endpointCertPath), + ca: fs.readFileSync(caPath) +}; let nad = new NADC338(ip, bluOsPort); +app.use(cors()); +app.use(express.json()); +app.use((req, res, next) => { + // Set default security headers + res.set('Strict-Transport-Security', 'max-age=31536000; includeSubDomains'); + next(); +}); +app.use((req, res, next) => { + // Add default cache control for modification endpoints + if (req.method !== 'GET') { + res.set({ + 'Cache-Control': 'no-cache, no-store, must-revalidate', + 'Pragma': 'no-cache', + 'Expires': '0' + }); + } + next(); +}); + // GET endpoints +// Frequently changing state - minimal cache app.get('/power', async (req, res) => { try { const power = await nad.getPower(); + res.set({ + 'Cache-Control': 'no-cache, no-store, must-revalidate', + 'Pragma': 'no-cache', + 'Expires': '0' + }); res.json({ power }); } catch (error) { res.status(500).send(error.message); @@ -25,6 +66,11 @@ app.get('/power', async (req, res) => { app.get('/volume', async (req, res) => { try { const volume = await nad.getVolume(); + res.set({ + 'Cache-Control': 'no-cache, no-store, must-revalidate', + 'Pragma': 'no-cache', + 'Expires': '0' + }); res.json({ volume }); } catch (error) { res.status(500).send(error.message); @@ -34,6 +80,11 @@ app.get('/volume', async (req, res) => { app.get('/source', async (req, res) => { try { const source = await nad.getSource(); + res.set({ + 'Cache-Control': 'no-cache, no-store, must-revalidate', + 'Pragma': 'no-cache', + 'Expires': '0' + }); res.json({ source }); } catch (error) { res.status(500).send(error.message); @@ -43,15 +94,25 @@ app.get('/source', async (req, res) => { app.get('/mute', async (req, res) => { try { const mute = await nad.getMute(); + res.set({ + 'Cache-Control': 'no-cache, no-store, must-revalidate', + 'Pragma': 'no-cache', + 'Expires': '0' + }); res.json({ mute }); } catch (error) { res.status(500).send(error.message); } }); +// Less frequently changing settings - short cache app.get('/brightness', async (req, res) => { try { const brightness = await nad.getBrightness(); + res.set({ + 'Cache-Control': 'public, max-age=5', + 'Vary': 'Accept-Encoding' + }); res.json({ brightness }); } catch (error) { res.status(500).send(error.message); @@ -61,15 +122,24 @@ app.get('/brightness', async (req, res) => { app.get('/bass', async (req, res) => { try { const bass = await nad.getBass(); + res.set({ + 'Cache-Control': 'public, max-age=5', + 'Vary': 'Accept-Encoding' + }); res.json({ bass }); } catch (error) { res.status(500).send(error.message); } }); +// Configuration settings - longer cache app.get('/auto-sense', async (req, res) => { try { const autoSense = await nad.getAutoSense(); + res.set({ + 'Cache-Control': 'public, max-age=60', + 'Vary': 'Accept-Encoding' + }); res.json({ autoSense }); } catch (error) { res.status(500).send(error.message); @@ -79,13 +149,17 @@ app.get('/auto-sense', async (req, res) => { app.get('/auto-standby', async (req, res) => { try { const autoStandby = await nad.getAutoStandby(); + res.set({ + 'Cache-Control': 'public, max-age=60', + 'Vary': 'Accept-Encoding' + }); res.json({ autoStandby }); } catch (error) { res.status(500).send(error.message); } }); -// POST/PUT endpoints +// POST/PUT/PATCH/DELETE endpoints app.post('/power', async (req, res) => { try { const { state } = req.body; @@ -94,7 +168,23 @@ app.post('/power', async (req, res) => { } else if (state === 'Off') { await nad.powerOff(); } - res.sendStatus(200); + const power = await nad.getPower(); + res.json({ power }); + } catch (error) { + res.status(500).send(error.message); + } +}); + +app.patch('/power', async (req, res) => { + try { + const { state } = req.body; + if (state === 'On') { + await nad.powerOn(); + } else if (state === 'Off') { + await nad.powerOff(); + } + //const power = await nad.getPower(); + res.json({ state }); } catch (error) { res.status(500).send(error.message); } @@ -104,7 +194,19 @@ app.put('/volume', async (req, res) => { try { const { level } = req.body; await nad.setVolume(level); - res.sendStatus(200); + const volume = await nad.getVolume(); + res.json({ volume }); + } catch (error) { + res.status(500).send(error.message); + } +}); + +app.patch('/volume', async (req, res) => { + try { + const { level } = req.body; + await nad.setVolume(level); + //const volume = await nad.getVolume(); + res.json({ level }); } catch (error) { res.status(500).send(error.message); } @@ -157,6 +259,15 @@ app.post('/bass', async (req, res) => { } }); +app.patch('/bass', async (req, res) => { + try { + await nad.setBass(); + res.json({ bass: 'On' }); + } catch (error) { + res.status(500).send(error.message); + } +}); + app.delete('/bass', async (req, res) => { try { await nad.unsetBass(); @@ -202,6 +313,14 @@ app.delete('/auto-standby', async (req, res) => { } }); -app.listen(port, () => { - console.log(`Node.js server running at http://localhost:${port}`); -}); \ No newline at end of file +// Create HTTPS server +const httpsServer = https.createServer(credentials, app); + +httpsServer.listen(port, () => { + console.log(`HTTPS server running at https://localhost:${port}`); +}); + +httpsServer.keepAliveTimeout = keepAliveTimeout; +httpsServer.headersTimeout = headersTimeout; + +app.set('timeout', keepAliveTimeout); \ No newline at end of file diff --git a/api/nad-c338-api.yaml b/api/nad-c338-api.yaml index ce060c7..33aa508 100644 --- a/api/nad-c338-api.yaml +++ b/api/nad-c338-api.yaml @@ -10,7 +10,7 @@ servers: ip: default: localhost port: - default: 3000 + default: 3000 paths: /power: get: @@ -27,6 +27,13 @@ paths: type: string '500': description: Server error + content: + application/json: + schema: + type: object + properties: + error: + type: string post: summary: Set power status requestBody: @@ -42,8 +49,23 @@ paths: responses: '200': description: Power status set + content: + application/json: + schema: + type: object + properties: + power: + type: string '500': description: Server error + content: + application/json: + schema: + type: object + properties: + error: + type: string + /volume: get: summary: Get volume level @@ -59,6 +81,13 @@ paths: type: number '500': description: Server error + content: + application/json: + schema: + type: object + properties: + error: + type: string put: summary: Set volume level requestBody: @@ -73,8 +102,23 @@ paths: responses: '200': description: Volume level set + content: + application/json: + schema: + type: object + properties: + volume: + type: number '500': description: Server error + content: + application/json: + schema: + type: object + properties: + error: + type: string + /source: get: summary: Get source @@ -90,6 +134,13 @@ paths: type: string '500': description: Server error + content: + application/json: + schema: + type: object + properties: + error: + type: string put: summary: Set source requestBody: @@ -104,8 +155,23 @@ paths: responses: '200': description: Source set + content: + application/json: + schema: + type: object + properties: + source: + type: string '500': description: Server error + content: + application/json: + schema: + type: object + properties: + error: + type: string + /mute: get: summary: Get mute status @@ -121,6 +187,13 @@ paths: type: string '500': description: Server error + content: + application/json: + schema: + type: object + properties: + error: + type: string post: summary: Mute responses: @@ -128,6 +201,14 @@ paths: description: Muted '500': description: Server error + content: + application/json: + schema: + type: object + properties: + error: + type: string + /unmute: post: summary: Unmute @@ -136,6 +217,14 @@ paths: description: Unmuted '500': description: Server error + content: + application/json: + schema: + type: object + properties: + error: + type: string + /brightness: get: summary: Get brightness level @@ -151,6 +240,13 @@ paths: type: number '500': description: Server error + content: + application/json: + schema: + type: object + properties: + error: + type: string put: summary: Set brightness level requestBody: @@ -165,8 +261,23 @@ paths: responses: '200': description: Brightness level set + content: + application/json: + schema: + type: object + properties: + brightness: + type: number '500': description: Server error + content: + application/json: + schema: + type: object + properties: + error: + type: string + /bass: get: summary: Get bass status @@ -182,6 +293,13 @@ paths: type: string '500': description: Server error + content: + application/json: + schema: + type: object + properties: + error: + type: string post: summary: Set bass responses: @@ -189,6 +307,13 @@ paths: description: Bass set '500': description: Server error + content: + application/json: + schema: + type: object + properties: + error: + type: string delete: summary: Unset bass responses: @@ -196,6 +321,14 @@ paths: description: Bass unset '500': description: Server error + content: + application/json: + schema: + type: object + properties: + error: + type: string + /auto-sense: get: summary: Get auto sense status @@ -211,6 +344,13 @@ paths: type: string '500': description: Server error + content: + application/json: + schema: + type: object + properties: + error: + type: string post: summary: Set auto sense responses: @@ -218,6 +358,13 @@ paths: description: Auto sense set '500': description: Server error + content: + application/json: + schema: + type: object + properties: + error: + type: string delete: summary: Unset auto sense responses: @@ -225,6 +372,14 @@ paths: description: Auto sense unset '500': description: Server error + content: + application/json: + schema: + type: object + properties: + error: + type: string + /auto-standby: get: summary: Get auto standby status @@ -240,6 +395,13 @@ paths: type: string '500': description: Server error + content: + application/json: + schema: + type: object + properties: + error: + type: string post: summary: Set auto standby responses: @@ -247,10 +409,24 @@ paths: description: Auto standby set '500': description: Server error + content: + application/json: + schema: + type: object + properties: + error: + type: string delete: summary: Unset auto standby responses: '200': description: Auto standby unset '500': - description: Server error \ No newline at end of file + description: Server error + content: + application/json: + schema: + type: object + properties: + error: + type: string \ No newline at end of file diff --git a/certs/server.crt b/certs/server.crt new file mode 100644 index 0000000..133dd94 --- /dev/null +++ b/certs/server.crt @@ -0,0 +1,32 @@ +-----BEGIN CERTIFICATE----- +MIIFhDCCA2ygAwIBAgIUVz4d61IgxW97PqQwDcC14xnPzfwwDQYJKoZIhvcNAQEN +BQAwPDELMAkGA1UEBhMCQ0ExCzAJBgNVBAgMAk9OMQ4wDAYDVQQKDAVhZG8yNDEQ +MA4GA1UEAwwHbGVnaW9uNzAgFw0yNTAyMTExODQ1MTVaGA8yMTI1MDExODE4NDUx +NVowPDELMAkGA1UEBhMCQ0ExCzAJBgNVBAgMAk9OMQ4wDAYDVQQKDAVhZG8yNDEQ +MA4GA1UEAwwHbGVnaW9uNzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB +AMWL0pu5OJJZembWBm+qkJmuE4JXSjKYXklS5tR+nxKeO9TUOjx/MmRvfoapYh3t +YRUjur4+Kng4dLOpwL0NCkeVo5BnmCZtFwHASMElhmZmDszpEu6Lxsa1Dck6VG50 +yFXXBj+mmhbSpr6qf0/GcjzxbKJncDweDNticQIK1b+Yg5vfp89U85JH8BNdW7VY +5GKiD/Y/b9Aij0TzzhIDAAe4FJphT7gdEG8eUIKbroJkIvpmc85UEiilbnGzMwky +AlqQ8CpRDoefYHGS8jTktifjeBorq/whpL1M/hvvP1Km+PEDwaBondP7fHxkgHGp +3eQW3Jgz45pZ+sIX0iGGfRl2+079eJscce0On4h9jtwT0cpxw+/gIe+2h+K6qxyO +Od1zlvwPDFDeJBOT+cr2RMFDJllYEF44qHjICRCq3FPP4H1m9575I1jB1KviK+Nm +vSoEI5ZhUlKU3BbjM8xBzM9Ufi4YetK2jX8l/VOanTL/v9ugn1/q3dddjod2bhE9 +VfKD/5XlvoWwbT3hr8LdGOSHHdgzIAiLFLoprcRzvfanpGZCIGxR9w4ejc2QuB/G +Nr/4rGTIXH2ITwFW6gJ16pIvtzeHmPe5uiqSCmNTZHsMg+Mq4fZPFSbR00NxbGFI +mvu076Dx7obA/C7bFqbexq9KwAbDfVH42XMuIvTojD3NAgMBAAGjfDB6MB0GA1Ud +DgQWBBR7IJrxqe7Qp/MBDQhYOc2Br5WnWTAfBgNVHSMEGDAWgBR7IJrxqe7Qp/MB +DQhYOc2Br5WnWTAPBgNVHRMBAf8EBTADAQH/MCcGA1UdEQQgMB6CB2xlZ2lvbjeC +CWxvY2FsaG9zdIIIMTAuMC4wLjQwDQYJKoZIhvcNAQENBQADggIBAJUKDOtmqq40 +U4xhi4ysJ/1Vrma/D1dZ0AzKeAX4gJfXNUZlU/mBf90RrwX+Zr5/m8rDo8TrB3tO +bKdZLLMKwHTKwWDZbldAkqCiYhW1BPCZZNXhXJWOUWtwbb9cX+D0oQCYQ+EEmwcx +OrG9MSHua3adlHBMF8FlnwGHuRsaMK0nZx6Ny9gsfG4rNlX0tdrg+gK8GNAen+3F +TRiyXmfVK2yM5pH+Xg39GC7QdUQEQQbnateF2rqCfPZyguC4YUne6B5OCPI8i+Rs +uO3MCBiKu2iNwaxT62sU6/l+TMgIzNbzBCAUFqhiooSwH6/9JbVEKs1pMOjUNJ6y +ipZoYwqO/XePi5qocNYxhg4NDH7W6KIxcqXLSviwq+JSAdmAg/NBVVe9M/jSiH03 +oLYz91Fkc0syRkgg+LzjtBk9I1o7gIpQapqepjGXq1FEzkA03lN/7IugjuTbA4RD +w6/hKDNrf2zfRy+tTmc+6WnSbC3/Q4V+kh63JLXzBYYB1hWmyMWOO9916vPWmHCb +rBTa7BvwrneiokytTZHYMdKJ1ac9C4LekSGEPjiR3Bz7i7A5vjQrdNuM1XUPyetZ +l+Ch47j38YQzBkYmDy1/y/9I8gB1w2/De5318Jx4oWpg0elFoe9n3Ps6br8iP3e9 +lTGdAnvW3AEutII657DJK/AI8VKZTsqF +-----END CERTIFICATE----- diff --git a/gulpfile.js b/gulpfile.js index 0e0b7cd..5d47a5a 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -51,6 +51,17 @@ const copyModel = () => { .pipe(gulp.dest('dist/model')); }; +// Copy keys and certs +const copyKeys = () => { + return gulp.src('keys/**/*') + .pipe(gulp.dest('dist/keys')); +} + +const copyCerts = () => { + return gulp.src('certs/**/*') + .pipe(gulp.dest('dist/certs')); +} + // Generate package.json const generatePackageJson = () => { return gulp.src('package.json') @@ -82,7 +93,8 @@ gulp.task('clean', clean); gulp.task('transpile', gulp.parallel(transpileApiServer, transpileTcpServer,transpileModel)); // Wrapper for copying non-JS files -gulp.task('copy', gulp.parallel(copyApiServer, copyTcpServer, copyModel)); +gulp.task('copy', gulp.parallel(copyApiServer, copyTcpServer, copyModel, copyKeys, copyCerts)); + // Task to transpile JavaScript files gulp.task('package-js', gulp.series(transpileApiServer, transpileTcpServer, transpileModel, "copy")); // gulp.parallel(copyApiServer, copyTcpServer, copyModel))); diff --git a/keys/server.key b/keys/server.key new file mode 100644 index 0000000..053f74d --- /dev/null +++ b/keys/server.key @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +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 +Zo0caJBSUPBGA69acVnBOSMAG8q9yQ== +-----END PRIVATE KEY----- diff --git a/tcp-server/server.js b/tcp-server/server.js index efa4c0e..c554bb9 100644 --- a/tcp-server/server.js +++ b/tcp-server/server.js @@ -65,7 +65,7 @@ const requestHandler = async (req, res) => { return; } - if (req.method === 'POST') { + if (req.method === 'POST' || req.method === 'PUT' || req.method === 'DELETE') { let body = ''; req.on('data', chunk => { body += chunk.toString(); From aea1954c5edce490f8aceac88db30f6720fbde48 Mon Sep 17 00:00:00 2001 From: ado24 Date: Mon, 31 Mar 2025 13:32:03 -0400 Subject: [PATCH 10/13] Updated certs and keys --- certs/server.crt | 56 +++++++++++++------------- keys/server.key | 100 +++++++++++++++++++++++------------------------ 2 files changed, 78 insertions(+), 78 deletions(-) diff --git a/certs/server.crt b/certs/server.crt index 133dd94..587919b 100644 --- a/certs/server.crt +++ b/certs/server.crt @@ -1,32 +1,32 @@ -----BEGIN CERTIFICATE----- -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 -lTGdAnvW3AEutII657DJK/AI8VKZTsqF +AOATNCkWRD6M4T4G8ThZmI7QNtBZ+4xQ9Fc1OqLgI5813N+/GM+g40HmjUq++5X3 +p91KbR802oSGl6/s+Hy5YWzffA8NhcjbJRY4A0Gehtqw4Wr8NUIbF+utADAMAREU +1DFRmx2NhRj9A+5yXo4QgQ53ZO75SO8zWk1piiXnBKthufOtBMwNR23//ronb9U9 +TCvzEnuRMl2bObcVVjyMWxbe27kyb/0DFFfabownt3a8yUtoIVuBec/k3g+giOnQ +jhcyyDYoUf+7sHu6jKXl9/ZZBk6LEEu6gLmin+0y6gVxRm6jSQCkZZAlHNpOB6R+ +PHEjGjMcJmiXu3/oZCWdQjamtAW9dWhD0eB34kc6A2dOMcNcVEKqfGwnlQGKRRfw +io/I/+/DoZfMMF31G0qB5A2rKfw0r+1f5GUaivY4GpoOsUdvL13re0Y0j5UVlmtF +WvNkIW4GTA0Sao+FPQ+TTfj8JrgxrvBx21Wqb3/ogbFiNWtVzdb5v4s2gpFSsTAR +zPsRmLZBNsBf2DN7RAFC3zIf0ngmrOf/J5nYlBM1yTUf7y9OsHcVPtbk65b/Wj4v +K1MpPFKsBcQSuNc1JH2qBT1ddrgLG6KW4Cn91WUORjS5x4RkvO/AHUtldThdgUF3 +cHLwkt43TZPECxBoZjZuOVnnlVS+Araz41Zj2MWr5Q8jAgMBAAGjeDB2MB0GA1Ud +DgQWBBRrZFXoDcG6qNHDlNhjj+/36SHK2DAfBgNVHSMEGDAWgBRrZFXoDcG6qNHD +lNhjj+/36SHK2DAPBgNVHRMBAf8EBTADAQH/MCMGA1UdEQQcMBqCB2xlZ2lvbjeC +CWxvY2FsaG9zdIcECgAABDANBgkqhkiG9w0BAQ0FAAOCAgEAdbP9JqGjWTr53zME +cYEpcAuexXOUJngoJ3RI756L++IDARQdI6K+VchrITQEe/btbks7C8YAp6LkfREZ +x7+IX47nUCAyTp+CKWe2CbxZS+7WWVS/vb+DnmTw69nKUaWrA4bEyq4MNbt5qWFf +DdCw6uZiNvKvkM/4yJrSriQ+cYa0BZ2moL4iJbxa37700rlJaBKWzBC86GXntDa7 +RxB+lbKN+J28wADS/5JrnZFjbAKsvjx7pGiO5HY2j0CzHX9Cv0zmFCqYTO+29l0v +2PwO0MHMKNBI9kS/QFfUD5fQ5Z6K/rdNpE+C7Imy/ftHRtP4ROeJgScP55x2Y2F/ +eDPkkbRhfS7P3RTClKFsOSnvdQEsIEZIJSx27sN5tf8EO4d2+vF2SohnJyGJ/SEd +haNoQYvD6vZVH8/WBQoU268CE5Qs3FDBLF/toWFKU7efI+NvHfe5YR9t//akFetJ +A3Hk146v5ocFoqTvdQosw+cjAs4hoXZIxAI3o2mCfnXxCpjtCaPHHI5GTUQArpIR +Ztt+zCv7jMkqqUx+vMC+n/euLRnYpeJf5UWnB6OOTkpuxzNXZiFC22PTWD6lNCPU +7JnSz+DEntbLtBazFxI/3cPkZ6VZSvWzUGF7Gs4huZ5d+vb1XfxN7P+nYWrjQkmK +lr1F98szsX/HYZXOpPcM2E9pnjY= -----END CERTIFICATE----- diff --git a/keys/server.key b/keys/server.key index 053f74d..2538789 100644 --- a/keys/server.key +++ b/keys/server.key @@ -1,52 +1,52 @@ -----BEGIN PRIVATE KEY----- -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 -Zo0caJBSUPBGA69acVnBOSMAG8q9yQ== +MIIJRQIBADANBgkqhkiG9w0BAQEFAASCCS8wggkrAgEAAoICAQDgEzQpFkQ+jOE+ +BvE4WZiO0DbQWfuMUPRXNTqi4COfNdzfvxjPoONB5o1KvvuV96fdSm0fNNqEhpev +7Ph8uWFs33wPDYXI2yUWOANBnobasOFq/DVCGxfrrQAwDAERFNQxUZsdjYUY/QPu +cl6OEIEOd2Tu+UjvM1pNaYol5wSrYbnzrQTMDUdt//66J2/VPUwr8xJ7kTJdmzm3 +FVY8jFsW3tu5Mm/9AxRX2m6MJ7d2vMlLaCFbgXnP5N4PoIjp0I4XMsg2KFH/u7B7 +uoyl5ff2WQZOixBLuoC5op/tMuoFcUZuo0kApGWQJRzaTgekfjxxIxozHCZol7t/ +6GQlnUI2prQFvXVoQ9Hgd+JHOgNnTjHDXFRCqnxsJ5UBikUX8IqPyP/vw6GXzDBd +9RtKgeQNqyn8NK/tX+RlGor2OBqaDrFHby9d63tGNI+VFZZrRVrzZCFuBkwNEmqP +hT0Pk034/Ca4Ma7wcdtVqm9/6IGxYjVrVc3W+b+LNoKRUrEwEcz7EZi2QTbAX9gz +e0QBQt8yH9J4Jqzn/yeZ2JQTNck1H+8vTrB3FT7W5OuW/1o+LytTKTxSrAXEErjX +NSR9qgU9XXa4CxuiluAp/dVlDkY0uceEZLzvwB1LZXU4XYFBd3By8JLeN02TxAsQ +aGY2bjlZ55VUvgK2s+NWY9jFq+UPIwIDAQABAoICAQCRzy1EBz9FTLtNd4sEVhkV +5ZulnMg5mHxHO1X6osvLUGt4FYv5oAIB4hrTJs/j2JIdR88WXXhMgKC4VAWmc6NY +C11ZFj2WZDQP70b/Lj8mk687xP6LE8JPE/ZpTYZsLRefODEt2+deSVaDlVy+KTMx +zLObZg/1x37dnO3OmDPLqf4s+MuEVKfEhq6lSABXzFmCx9uhGOyjSN0XrAS/xb2I +dmCYdJ+3DofwWy1Qeo/B7js2nH4IY4p2o8F0fcxaCeJMajkqNLaXKPVArjXTxn/C +iE+4UHm8LZKSOabD3Tu3auygFhTtHA0S7XOHAvuqKJMANA1acNj1ercCFqEEcP6i +Bcd/K7jyu7EOBC6P2mmDHfHGiR5R5RuYDpn3dNlKThzuhWecKMBTh9/UO90A98vP +Mr9zb96xc9n21THNCpKcnmEYPA5DJ5JJ5FQLcrvsNKu2ehcDWohOQgAr8KQCm+rd +hpNBpXPMGZf1h5j/nuvZ1cg18ZhY+fNUE1DIfN+aLYJ7nw6ptvWy/331ebkpz+xg +Q9znsoSS4BvUuttsGnckCmPcBw+oniUafXVb9lPm8GNa8KvVMarCrVptPPMTkoLB +HRJl+tDhfRT/FCn8mW0vUKXu56VBkJWk8gYdAdkQffYwK55fDlep0pqpG84EyZ03 ++5/zMQPQeU9RLDwnWHcbMQKCAQEA8AFqBcEsm2JI1M6fmmzb9vlrwCXAMg2BytR2 +cayzQ//kpulnelP7wAQBJKH1yIyMOqZOEZG+PJEl8dmbB72665/bQ7saEarelbj5 +2IyhatpY9dlgPLBYjUB9KYDEwlv1H/CJncS1KHmZMSDEffkAU+ED/IfAVOCW04I9 +i/P8XXco3JOT9jOMyxAVlc5sJ1PTtRJD5pb0cY4r5sgKv1sAghsBedoXjNkBHqcF +adfrMYL1f+PW4kvnebq3gXmeFqGz5hj6oAWU0Tv7VBl9XPWxdvuvG0ZQveQVqymy +q5dXq7gCGdoBwIYVc8Mf6iVLOPySBw8yUsLKoys9Lt86U3aXnQKCAQEA7wICT91y +Ppsde4CMHLp+FuxwRtPDfEER/gnBJDA8YtSe2WRbT3WQL0IUltau5RYankz39ws0 +/lnMO3pkZSeI3odQ4rhOhmapKBCuC/+Ny//0PEfBzjJNJfSlbLla9uYe436WcqZz +DqxJHNXpBtdAzcYvOQMtNpJYalHV/lNQ/fBdfUTzxdLRfIxYlSkbssGrhFQCpVEx +FC4nCLcW0n7g6i+4ioLi/FPe3AkJCzPxT0614UzTozYuC12N9HkVBB8YFZsSQZCb +ehX48SmGi4umIHbPhtYMT4J44NPLR+n4pAyWt+A8eF8pcWDOITa45+JIic5ttrAt ++HHTVfVz7i1lvwKCAQEAzhroyXhSrj2A/f9S4HKLk1QuTBwfKNygkWZTMNt2NvcR +jKTz0AE/OG437RWI1GieI9+dO0lFbQ3Y4BBXKhas5puo2Elc4b8y1rC7HlPmarSH +oNjD5FosMWEoGvQSBDakEoGmLG44hEGoZKAXHXcv6NhbbAnICRu1an12DTHBjyI9 +XO7/KXaredaeMr/J8RvzupOs6+DGmp3U5aL0V8/2Z8R5SAMaJkJUy9XyuCpMN4CX +AvTOHBfC+K532CBwuk6zBu58i98/JU+1TUt2dNYpSFxqy6levTOZyBtO7DxTdYvX +ggvNZV/AHGF8jr7oElATtyw9swTEr8r6B757gCFfoQKCAQEA5HbxKtKtgDbaKdIp +HNUP7m24rZuDQ+UXg9RjMWqCbp578aZCumPQnbv23nD84bMNYsCETzwBPhksZraJ +/T+bT8vdf7taJJNBozC+jm2MZ7KVDoIxOh9PK7b94j4UO+qhIClDOvjtBtudT9kS +VR2xroGBZmgo8f9WUNtFSUTvKK55T2N3+mOZKAsoKf0PowIKKAX+OXSxC29KlMQf +Jrtt164iIxUWUMkDQSXJ5VGTm5HLvj+oFl2WCfs11LlhY30tkomXG+FVHZCfVDez +ivTEqken/GXjgqVfUtpheK6opHf8ImxQoWelv+EfaRRcEBx35nLS4UzrxI9ZytNE +LCptFQKCAQEA4jBNABYgeTJb9beJEBDO5ADMykSeHOhjcAGFrB9S3NHA3ZbQcmGC +vePCdFPgXRd0XvQ23OhV+GUbqCQ6DX+tu5FWGiJCsreqNFkMCZ8nYUUuUJLjEI0u +WqDljVXQrgL4cYRahhr3przcz1G2xH96TDcfOJbM3RYzRjxklkpVzSUobPLNcCDU +zyjy5H6OqKn5bFpEupGZY3ZKczimOyQwZQqjR6sHzQzzo9xRdZ1s3mA4eX832m/P +vqq/a8NoCO2qj1Fyj1S49+I3EfIHY1Md7FUmJviH0Km6FaSnXSNsDZIohmojf/af +TwScgdOyIqBWRmFz8S+MxK1kZhYJIXyrbA== -----END PRIVATE KEY----- From e08537fae82067b8f972d95b34ff4906766a3ad1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 19 May 2025 17:05:58 +0000 Subject: [PATCH 11/13] Bump node from 23.11.1 to 24.0.2 Bumps [node](https://github.com/aredridel/node-bin-gen) from 23.11.1 to 24.0.2. - [Commits](https://github.com/aredridel/node-bin-gen/commits) --- updated-dependencies: - dependency-name: node dependency-version: 24.0.2 dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 977932f..4a250c0 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,7 @@ "gulp-babel": "^8.0.0", "jest": "^29.7.0", "nock": "^14.0.0", - "node": "^23.7.0", + "node": "^24.0.2", "supertest": "^7.0.0" } } From b297176183cc787f9c537afae988261b98850a52 Mon Sep 17 00:00:00 2001 From: ado24 Date: Tue, 20 May 2025 13:04:18 -0400 Subject: [PATCH 12/13] Potential fix for code scanning alert no. 18: Workflow does not contain permissions Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> --- .github/workflows/npm-gulp.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/npm-gulp.yml b/.github/workflows/npm-gulp.yml index 6d04c0d..190148c 100644 --- a/.github/workflows/npm-gulp.yml +++ b/.github/workflows/npm-gulp.yml @@ -6,6 +6,9 @@ on: pull_request: branches: [ "master" ] +permissions: + contents: read + jobs: build: runs-on: ubuntu-latest From d607e5b348857ee86f79f36a1aafaf8dd92bed7c Mon Sep 17 00:00:00 2001 From: ado24 Date: Wed, 5 Nov 2025 19:33:18 -0500 Subject: [PATCH 13/13] Updated headers to allow for autoplay --- api-server/package.json | 1 + tcp-server/package.json | 5 ++++- tcp-server/server.js | 2 ++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/api-server/package.json b/api-server/package.json index a4b415b..ef513fd 100644 --- a/api-server/package.json +++ b/api-server/package.json @@ -14,6 +14,7 @@ }, "private": true, "dependencies": { + "api-server": "file:", "cors": "^2.8.5" } } diff --git a/tcp-server/package.json b/tcp-server/package.json index a606524..68e8a99 100644 --- a/tcp-server/package.json +++ b/tcp-server/package.json @@ -10,5 +10,8 @@ }, "keywords": [], "author": "", - "license": "ISC" + "license": "ISC", + "dependencies": { + "tcp-server": "file:" + } } diff --git a/tcp-server/server.js b/tcp-server/server.js index c554bb9..18b348e 100644 --- a/tcp-server/server.js +++ b/tcp-server/server.js @@ -58,6 +58,8 @@ const requestHandler = async (req, res) => { res.setHeader('Access-Control-Allow-Origin', '*'); res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS'); res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization'); + res.setHeader('Feature-Policy', "autoplay *; camera 'none'; microphone 'none'"); + res.setHeader('Permissions-Policy', "autoplay=(self), camera=(), microphone=()"); if (req.method === 'OPTIONS') { res.writeHead(204);