From a7d3af33230914de57822efaf9c4ba2f313f74c2 Mon Sep 17 00:00:00 2001 From: Liz Cray Date: Tue, 21 Apr 2026 00:08:25 +0000 Subject: [PATCH] Dirty GeoJSON API --- aserve.js | 100 +++++++++++++++++++++++++++++++++++++++++++++++++ dehaze.service | 10 +++++ run.sh | 4 ++ serve.js | 18 +++++---- 4 files changed, 125 insertions(+), 7 deletions(-) create mode 100644 aserve.js create mode 100644 dehaze.service create mode 100755 run.sh diff --git a/aserve.js b/aserve.js new file mode 100644 index 0000000..dba992d --- /dev/null +++ b/aserve.js @@ -0,0 +1,100 @@ +const express = require('express'); +const { createHash } = require('crypto'); + + +const app = express(); +const port = 8356; +const geonJsonTemplate = { + type: "FeatureCollection", + features: [], + "marker-symbol-images": { + "star": "data:image/svg+xml;utf8,", + "star-stroked": "data:image/svg+xml;utf8," + } +}; + +app.all('/locations.geojson', (req, res) => { + // Verify Inputs + if (!req.query.auth) { + res.status(401).send('Unauthorized'); + return; + } + // Query Haze API Websocket + let hazePwHash = null; + let hazeUser = null; + if (req.query.auth){ + let paramAuth = Buffer.from(req.query.auth, 'base64').toString('utf-8').replaceAll('\n', ''); + hazeUser = paramAuth.split(":")[0]; + hazePwHash = paramAuth.split(":")[1]; + } + const haze = new WebSocket('wss://do.ecven.com:8120/explr'); + haze.addEventListener('message', (event) => { + const data = JSON.parse(event.data); + let haze_authToken = '', haze_username = ''; + switch (data['event']) { + case "connected": + let pld = { + "event": "authenticateAccount_request", + "body": [ + { + "password": hazePwHash, + "email": hazeUser + } + ], + "socketMessageId": 0 + }; + haze.send(JSON.stringify(pld)); + break; + case "authenticateAccount_response": + if (data['body']['response'] === 1) { + haze_authToken = data['body']['authToken']; + haze_username = data['body']['username']; + haze.send('{"event": "getMyLocationsRequest_request","body": [{"higlightImages": true}],"socketMessageId": 0}'); + } else { + console.dir(req.query); + res.status(401).json({ ...data, password: req.query.auth }); + haze.close(); + res.end(); + } + break; + case "getMyLocationsRequest_response": + if (data['body']['response'] === 1) { + const hazeLocations = data['body']['locations'].map(location => { + return { + type: "Feature", + geometry: { + type: "Point", + coordinates: [location['coordinates']['longitude'], location['coordinates']['latitude']] + }, + properties: { + id: location['id'], + title: location['name'], + "marker-symbol": location['isUnconfirmedLocation'] === 1 ? "star-stroked" : "star", + } + } + }); + res.setHeader('Content-Type', 'application/json'); + haze.close(); + res.end(JSON.stringify({ + ...geonJsonTemplate, + features: hazeLocations + })); + } else { + console.dir(data); + res.status(500).send('Failed to retrieve locations'); + haze.close(); + res.end(); + } + break; + default: + console.dir(data); + res.status(500).send('Unexpected response from Haze API'); + haze.close(); + res.end(); + } + }); +}); + +app.listen(port, () => { + console.log(`Server is running on http://localhost:${port}`); +}); diff --git a/dehaze.service b/dehaze.service new file mode 100644 index 0000000..a7849fc --- /dev/null +++ b/dehaze.service @@ -0,0 +1,10 @@ +[Unit] +Descripton=HazeExplr API porting tool + +[Service] +ExecStart=/home/liz/dehaze/run.sh +User=liz + +[Install] +WantedBy=multi-user.target + diff --git a/run.sh b/run.sh new file mode 100755 index 0000000..ca6ac36 --- /dev/null +++ b/run.sh @@ -0,0 +1,4 @@ +#!/bin/bash +cd /home/liz/dehaze +/home/liz/.nvm/versions/node/v24.14.1/bin/node aserve.js & +/home/liz/.nvm/versions/node/v24.14.1/bin/node serve.js diff --git a/serve.js b/serve.js index ed34899..94c5ee2 100644 --- a/serve.js +++ b/serve.js @@ -1,12 +1,10 @@ -const { loadEnvFile } = require('node:process'); const express = require('express'); const auth = require('express-basic-auth'); const { createHash } = require('crypto'); -loadEnvFile(); const app = express(); -const port = process.env.PORT || 3000; +const port = 8355; const geonJsonTemplate = { type: "FeatureCollection", features: [], @@ -15,7 +13,6 @@ const geonJsonTemplate = { "star-stroked": "data:image/svg+xml;utf8," } }; - app.use(auth({ authorizer: (username, password) => { return true; @@ -24,17 +21,25 @@ app.use(auth({ app.all('/locations.geojson', (req, res) => { // Verify Inputs - if (!req.auth.user || !req.auth.password) { + if ((!req.auth.user || !req.auth.password) && (!req.query.auth)) { res.status(401).send('Unauthorized'); return; } // Query Haze API Websocket let hazePwHash = null; + let hazeUser = null; + if (req.query.auth){ + let paramAuth = Buffer.from(req.query.auth, 'base64').toString('utf-8'); + hawUser = paramAuth.split(":")[0]; + hazePwHash = paramAuth.split(":")[1]; + } else { + hazeUser = req.auth.user; if (/\b[A-Fa-f0-9]{64}\b/.test(req.auth.password)) { hazePwHash = req.auth.password; } else { hazePwHash = createHash('sha256').update(req.auth.password).digest('hex'); } + } const haze = new WebSocket('wss://do.ecven.com:8120/explr'); haze.addEventListener('message', (event) => { const data = JSON.parse(event.data); @@ -46,7 +51,7 @@ app.all('/locations.geojson', (req, res) => { "body": [ { "password": hazePwHash, - "email": req.auth.user + "email": hazeUser } ], "socketMessageId": 0 @@ -56,7 +61,6 @@ app.all('/locations.geojson', (req, res) => { if (data['body']['response'] === 1) { haze_authToken = data['body']['authToken']; haze_username = data['body']['username']; - console.dir(data); haze.send('{"event": "getMyLocationsRequest_request","body": [{"higlightImages": true}],"socketMessageId": 0}'); } else { res.status(401).json({ ...data, password: req.auth.password });