diff --git a/README.md b/README.md index d4cdfc0..eb20df1 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,27 @@ # DeHaze Port the Haze Explr API to GEOJSON for use in GIS applications. + +This was a quick and dirty project, and will probably get some updates slowly in the future. I put what I learned from this in the [HacDC Wiki](https://wiki.hacdc.org/en/Projects/API/HazeExplr). + +## Usage + +```bash +npm i +node serve.js +``` + +To use the endpoint, replace 'EMAIL' and 'PASSWORD' with your Haze Explr account details: + +```bash +echo "EMAIL:`echo 'PASSWORD' | sha256sum | sed -e 's/ -//'`" | base64 +``` + +Then, make a request to the endpoint with the resulting string as the value of the `auth` query parameter: + +```bash +curl "http://localhost:3000/locations?auth=BASE64_ENCODED_STRING" +``` + + +`basicauth_serve.js` does the same thing bus expects account details to be passed via basic HTTP auth, but does not work with QGIS. diff --git a/aserve.js b/basicauth_serve.js similarity index 87% rename from aserve.js rename to basicauth_serve.js index dba992d..b1b63bc 100644 --- a/aserve.js +++ b/basicauth_serve.js @@ -1,9 +1,10 @@ const express = require('express'); +const auth = require('express-basic-auth'); const { createHash } = require('crypto'); const app = express(); -const port = 8356; +const port = 8355; const geonJsonTemplate = { type: "FeatureCollection", features: [], @@ -12,20 +13,32 @@ const geonJsonTemplate = { "star-stroked": "data:image/svg+xml;utf8," } }; +app.use(auth({ + authorizer: (username, password) => { + return true; + } +})); app.all('/locations.geojson', (req, res) => { // Verify Inputs - if (!req.query.auth) { + 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').replaceAll('\n', ''); - hazeUser = paramAuth.split(":")[0]; + 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) => { @@ -33,7 +46,7 @@ app.all('/locations.geojson', (req, res) => { let haze_authToken = '', haze_username = ''; switch (data['event']) { case "connected": - let pld = { + haze.send(JSON.stringify({ "event": "authenticateAccount_request", "body": [ { @@ -42,8 +55,7 @@ app.all('/locations.geojson', (req, res) => { } ], "socketMessageId": 0 - }; - haze.send(JSON.stringify(pld)); + })); break; case "authenticateAccount_response": if (data['body']['response'] === 1) { @@ -51,8 +63,8 @@ app.all('/locations.geojson', (req, res) => { 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 }); + console.dir(req.query); + res.status(401).json({ ...data, password: req.auth.password }); haze.close(); res.end(); } diff --git a/dehaze.service b/dehaze.service deleted file mode 100644 index a7849fc..0000000 --- a/dehaze.service +++ /dev/null @@ -1,10 +0,0 @@ -[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 deleted file mode 100755 index ca6ac36..0000000 --- a/run.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/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 94c5ee2..279b8f8 100644 --- a/serve.js +++ b/serve.js @@ -1,10 +1,8 @@ const express = require('express'); -const auth = require('express-basic-auth'); const { createHash } = require('crypto'); - const app = express(); -const port = 8355; +const port = 8356; const geonJsonTemplate = { type: "FeatureCollection", features: [], @@ -13,32 +11,20 @@ const geonJsonTemplate = { "star-stroked": "data:image/svg+xml;utf8," } }; -app.use(auth({ - authorizer: (username, password) => { - return true; - } -})); app.all('/locations.geojson', (req, res) => { // Verify Inputs - if ((!req.auth.user || !req.auth.password) && (!req.query.auth)) { + 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'); - hawUser = paramAuth.split(":")[0]; + 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]; - } 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) => { @@ -46,7 +32,7 @@ app.all('/locations.geojson', (req, res) => { let haze_authToken = '', haze_username = ''; switch (data['event']) { case "connected": - haze.send(JSON.stringify({ + let pld = { "event": "authenticateAccount_request", "body": [ { @@ -55,7 +41,8 @@ app.all('/locations.geojson', (req, res) => { } ], "socketMessageId": 0 - })); + }; + haze.send(JSON.stringify(pld)); break; case "authenticateAccount_response": if (data['body']['response'] === 1) { @@ -63,7 +50,8 @@ app.all('/locations.geojson', (req, res) => { haze_username = data['body']['username']; haze.send('{"event": "getMyLocationsRequest_request","body": [{"higlightImages": true}],"socketMessageId": 0}'); } else { - res.status(401).json({ ...data, password: req.auth.password }); + console.dir(req.query); + res.status(401).json({ ...data, password: req.query.auth }); haze.close(); res.end(); }