diff --git a/nodejs/app.js b/nodejs/app.js index f5b453e..c278ff0 100755 --- a/nodejs/app.js +++ b/nodejs/app.js @@ -7,27 +7,36 @@ const express = require('express'); // Set up the express app. const app = express(); +// Hold list of functions to run when the server is ready +app.onListen = []; + // Allow the express app to be exported into other files. module.exports = app; -// Build the conf object from the conf files. -app.conf = require('./conf/conf'); - -// List of front end node modules to be served -const frontEndModules = ['bootstrap', 'mustache', 'jquery', 'jquery-ui','@fortawesome', - 'moment', -]; - -// Server front end modules -// https://stackoverflow.com/a/55700773/3140931 -frontEndModules.forEach(dep => { - app.use(`/static-modules/${dep}`, express.static(path.join(__dirname, `node_modules/${dep}`))) -}); - - // Hold onto the auth middleware const middleware = require('./middleware/auth'); +// Grab the projects PubSub +app.contoller = require('./controller'); + +// Push pubsub over the socket and back. +app.onListen.push(function(){ + app.io.use(middleware.authIO); + + app.contoller.ps.subscribe(/./g, function(data, topic){ + app.io.emit('P2PSub', { topic, data }); + }); + + app.io.on('connection', (socket) => { + // console.log('socket', socket) + var user = socket.user; + socket.on('P2PSub', (msg) => { + app.contoller.ps.publish(msg.topic, {...msg.data, __from:socket.user}); + // socket.broadcast.emit('P2PSub', msg); + }); + }); +}); + // load the JSON parser middleware. Express will parse JSON into native objects // for any request that has JSON in its content type. app.use(express.json()); @@ -36,29 +45,11 @@ app.use(express.json()); app.set('views', path.join(__dirname, 'views')); app.set('view engine', 'ejs'); -// Have express server static content( images, CSS, browser JS) from the public -// local folder. -app.use('/static', express.static(path.join(__dirname, 'public'))) - // Routes for front end content. app.use('/', require('./routes/render')); -// API routes for authentication. -app.use('/api/auth', require('./routes/auth')); - - -// API routes for working with users. All endpoints need to be have valid user. -app.use('/api/user', middleware.auth, require('./routes/user')); - -// API routes for working with hosts. All endpoints need to be have valid user. -app.use('/api/host', middleware.auth, require('./routes/host')); - -// API routes for working with hosts. All endpoints need to be have valid user. -app.use('/api/cert', middleware.auth, require('./routes/cert')); - -app.controler = { - host: require('./controler/host') -} +// Routes for API +app.use('/api', require('./routes/api')); // Catch 404 and forward to error handler. If none of the above routes are // used, this is what will be called. diff --git a/nodejs/bin/www b/nodejs/bin/www index 93acb9a..69ccee7 100755 --- a/nodejs/bin/www +++ b/nodejs/bin/www @@ -7,12 +7,13 @@ var app = require('../app'); var debug = require('debug')('proxy-api:server'); var http = require('http'); +const conf = require('../conf'); /** * Get port from environment and store in Express. */ -var port = normalizePort(process.env.NODE_PORT || '3000'); +var port = normalizePort(process.env.NODE_PORT || conf.port || '3000'); app.set('port', port); /** @@ -21,6 +22,9 @@ app.set('port', port); var server = http.createServer(app); +var io = require('socket.io')(server); +app.io = io; + /** * Listen on provided port, on all network interfaces. */ @@ -86,5 +90,9 @@ function onListening() { var bind = typeof addr === 'string' ? 'pipe ' + addr : 'port ' + addr.port; - debug('Listening on ' + bind); -} + console.log('Listening on ' + bind); + + for(let listener of app.onListen){ + listener() + } +} \ No newline at end of file diff --git a/nodejs/controller/auth.js b/nodejs/controller/auth.js new file mode 100644 index 0000000..f57b140 --- /dev/null +++ b/nodejs/controller/auth.js @@ -0,0 +1,56 @@ +'use strict'; + +const {User} = require('../models/user'); +const {AuthToken} = require('../models/token'); + + +class Auth{ + static errors = { + login: function(){ + let error = new Error('LoginFailed'); + error.name = 'LoginFailed'; + error.message = `Invalid Credentials, login failed.`; + error.status = 401; + + return error; + } + } + + static async login(data){ + try{ + let user = await User.login(data); + let token = await AuthToken.create({username: user.username}); + + return {user, token} + }catch(error){ + console.log('login error', error); + throw this.errors.login(); + } + } + + static async checkToken(token){ + try{ + token = await AuthToken.get(token); + if(token && token.check()) return token; + + throw this.errors.login(); + }catch(error){ + throw this.errors.login(); + } + } + + static async logout(data){ + let token = await AuthToken.get(data); + await token.destroy(); + } +} + + +Auth.logOut = async function(data){ + try{ + }catch(error){ + throw error; + } +} + +module.exports = {Auth}; diff --git a/nodejs/controler/host.js b/nodejs/controller/host.js similarity index 95% rename from nodejs/controler/host.js rename to nodejs/controller/host.js index b0d64f5..706f73b 100644 --- a/nodejs/controler/host.js +++ b/nodejs/controller/host.js @@ -2,7 +2,7 @@ const {Host} = require('../models/host'); const {SocketServerJson} = require('../models/socket_server_json'); -const conf = require('../app').conf; +const conf = require('../conf'); const socket = new SocketServerJson({ diff --git a/nodejs/controller/index.js b/nodejs/controller/index.js new file mode 100644 index 0000000..32084e9 --- /dev/null +++ b/nodejs/controller/index.js @@ -0,0 +1,8 @@ +'use strict'; + +module.exports = { + auth: require('./auth'), + ps: require('./pubsub'), + host: require('./host'), +} + diff --git a/nodejs/controller/pubsub.js b/nodejs/controller/pubsub.js new file mode 100644 index 0000000..cf0e5ec --- /dev/null +++ b/nodejs/controller/pubsub.js @@ -0,0 +1,5 @@ +const {PubSub} = require('p2psub'); + +ps = new PubSub(); + +module.exports = ps; diff --git a/nodejs/le_key b/nodejs/le_key new file mode 100644 index 0000000..2d633bc --- /dev/null +++ b/nodejs/le_key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDAykMghkRxBOfK +niTICXpW3CahhIHf/uCDF1ENMf1uTfaextHtIn/SVvpQ+CcOWmNNb34aW/VYNGa9 +P/AidMTRVPRWUuyEjsRSS8lhH6xRmnEeX6dnIfY7XfJQ3HEoIY7yoRgu2udltCgq +qSedyQ5l3F6h9r4gxWyNXcZuYeyXR2YAyRwKIsH7I58I0rgq/sw4Lgb+wFiQHXu/ +ocfnTcAqhikiFJcgZUkIO3HmrTeKjT2T1LrZZ84uWEZ5NHnN4TmpaTAsLrhiNU8d +LXkPR61Y8tr7IGouvsoKj6PQHtm6bqjRp1iKQJ9aTUcFn7EEf/hFijHLPC1nIA+S +czY/BiR9AgMBAAECggEAK/fVEF1ezZHLVUv04oQ62QVzcAG65v2HcY5HR2WfwWDZ +foOki9sC4NNCWmYF7kGSBS6IyXUwgrHMvpuO5iTQYFdqNCfMVj0DLCupnVNuZtv8 +sWsqUByQPiDiayujSP5CTjaMP99fx7OrN3OFm/gnJvb3xCN0YB/2blU1NKZzoVpa +nCJDfa632Aci2pMbyOSx++HeH89dCY+ruWFn36Bz9MJ1jgOZ1dBKxfUogPHI/O2u +9tFLsLHxSfyPIjLfLrwZ0NGpmiRROUQeVQJBKhEaQPfIa7axq3fz6yPZZ+H6ExKp +LATKuLDTo8MzcSYTlL8UAvCU+P9chklM8ZYmtQCypwKBgQD7mTaFLkjH9u2A0TPt +HUn5yjpg0TMCXj06AISoPg+NGBB8UIyuZME2tbkT2J4sPMAergHb9sMmae2paSz3 +8w4AZF5HL/A6eaAdzYtGc2YT+mTAV9zBJ0HzoNY/YPBdBXqRQwsmqph5NZOv3NzQ +QoNeDij7HJBR/fIqvoZ7JMxs1wKBgQDEKazRfO8274esgtQzLoPQIg+rhv5Sktda +pA7pbx92WtfPzWi0deT+Ks7rqlpoTdDA7SIAML5UgqyWa9NP/EmyDlZBpoeWOn+9 +CYCkNjkzu2dudgcmYD3X9iIIl1+2ibF8jm5QYxX5nkq8cuySUM/2iw5IUpHUwRLG +1Juz91IaywKBgQDjRzprAK6ahMNztIgV0Hl8/mPSBejwYLUqakFrwfRGXtC1nAYZ +m8a2Z15zQSFRkOd0T3g6fiU31ETu3qXSrmudiw1nfTSjfi9X/M+tqp0xuuW8oyI2 +EgKP1GD2C9nWDhb0lf3CxiTKic2J9hg6wXruQhhfDySIDMDwQAA3ybwpLQKBgC8+ +ekjZ9iMc/Wgm+kR5Z3WxPmTpVkc85nEGIjFGeiVfK6r4pccQvd4ZIUzQ8oU8eJJ+ +ijnRg4WHE1oHDhWthXJE0bFuEim0XR+CMmFaTdyPvhF0i7RKaZqhxQCctIiaEQ0W +oKrrslc0MHvCkgeLPwr54q64dDbxaTxJ6FYnsraRAoGAYkxElEMtmF1jh6Mb/txJ +S0ElZdSTFgHQE2VquSxr1yAHac6894jEsY22OrPmSSWlELZ74w/NsZqs1zO8lPTH +jrUj2DAuQUx38SZcrijs9Rz5fhE0dk9ofNXlz8Cvyj6cXnogEy0bx+owqqIqVCpl +aL9umqfjjonJzMQUefQLIqU= +-----END PRIVATE KEY----- diff --git a/nodejs/middleware/auth.js b/nodejs/middleware/auth.js index 6b98731..09ea20b 100755 --- a/nodejs/middleware/auth.js +++ b/nodejs/middleware/auth.js @@ -1,17 +1,27 @@ 'use strict'; -const {Auth} = require('../models/auth'); +const { Auth } = require('../controller/auth'); async function auth(req, res, next){ try{ - let user = await Auth.checkToken({token: req.header('auth-token')}); - if(user.username){ - req.user = user; - return next(); - } + req.token = await Auth.checkToken(req.header('auth-token')); + req.user = await req.token.getUser(); + return next(); }catch(error){ next(error); } } -module.exports = {auth}; +async function authIO(socket, next){ + try{ + let token = await Auth.checkToken(socket.handshake.auth.token || 0); + socket.user = await token.getUser(); + console.log('socket is good!') + next(); + }catch(error){ + console.log('reject for', socket.handshake.auth.token) + next(error); + } +} + +module.exports = {auth, authIO}; diff --git a/nodejs/models/auth.js b/nodejs/models/_auth.js similarity index 96% rename from nodejs/models/auth.js rename to nodejs/models/_auth.js index 834f98f..c5de599 100644 --- a/nodejs/models/auth.js +++ b/nodejs/models/_auth.js @@ -1,7 +1,9 @@ +'use strict'; + const {User} = require('./user'); const {Token, AuthToken} = require('./token'); -Auth = {} +let Auth = {} Auth.errors = {} Auth.errors.login = function(){ diff --git a/nodejs/models/host.js b/nodejs/models/host.js index 0a29fff..f2e1417 100755 --- a/nodejs/models/host.js +++ b/nodejs/models/host.js @@ -1,11 +1,12 @@ 'use strict'; const Table = require('../utils/redis_model'); +const ModelPs = require('../utils/model_pubsub'); const tldExtract = require('tld-extract').parse_host; const PorkBun = require('../utils/porkbun'); const LetsEncrypt = require('../utils/letsencrypt'); -const conf = require('../conf/conf'); +const conf = require('../conf'); let porkBun = new PorkBun(conf.porkBun.apiKey, conf.porkBun.secretApiKey); let letsEncrypt = new LetsEncrypt({ @@ -13,7 +14,6 @@ let letsEncrypt = new LetsEncrypt({ }); - class Host extends Table{ static _key = 'host'; static _keyMap = { @@ -86,7 +86,6 @@ class Host extends Table{ static async add(data, ...args){ try{ - let out = await super.add(data, ...args) await this.buildLookUpObj() if(out.is_wildcard) await out.createWildcardCert() @@ -246,8 +245,13 @@ class Host extends Table{ return true; } + static test(pass){ + return `yes ${pass}` + } + } + class Cached extends Table{ static _key = 'host'; static _keyMap = { @@ -262,7 +266,7 @@ class Cached extends Table{ await Host.buildLookUpObj(); })() -module.exports = {Host}; +module.exports = {Host: ModelPs(Host)}; (async function(){ try{ @@ -279,8 +283,8 @@ try{ // }) // console.log('IIFE res:\n', res) - - console.log(await Host.listDetail()) + // console.log(Host.test(55)) + // console.log(await Host.listDetail()) // console.log('IIFE lookup:', Host.lookUp('bld3324sdf.test.holycore.quest')) diff --git a/nodejs/models/token.js b/nodejs/models/token.js index bfa6229..a6cb236 100644 --- a/nodejs/models/token.js +++ b/nodejs/models/token.js @@ -1,6 +1,7 @@ 'use strict'; const Table = require('../utils/redis_model'); +const {User} = require('./user'); const UUID = function b(a){return a?(a^Math.random()*16>>a/4).toString(16):([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g,b)}; @@ -32,6 +33,10 @@ class AuthToken extends Token{ super(...args); } + async getUser(){ + return await User.get(this.created_by); + } + static async add(data){ data.created_by = data.username; return super.add(data) diff --git a/nodejs/models/user.js b/nodejs/models/user.js index 67338a0..ecc284f 100644 --- a/nodejs/models/user.js +++ b/nodejs/models/user.js @@ -1,6 +1,6 @@ 'use strict'; -const conf = require('../app').conf; +const conf = require('../conf'); const User = require(`./user_${conf.userModel}`) diff --git a/nodejs/models/user_redis.js b/nodejs/models/user_redis.js index 9410289..e638aee 100644 --- a/nodejs/models/user_redis.js +++ b/nodejs/models/user_redis.js @@ -1,7 +1,7 @@ 'use strict'; const Table = require('../utils/redis_model'); -const {Token, InviteToken} = require('./token'); +// const {Token, InviteToken} = require('./token'); const bcrypt = require('bcrypt'); const saltRounds = 10; @@ -32,7 +32,7 @@ class User extends Table{ } } - static async addByInvite(data){ +/* static async addByInvite(data){ try{ let token = await InviteToken.get(data.token); @@ -55,7 +55,7 @@ class User extends Table{ throw error; } - }; + };*/ async setPassword(data){ try{ @@ -67,7 +67,7 @@ class User extends Table{ } } - async invite(){ +/* async invite(){ try{ let token = await InviteToken.add({created_by: this.username}); @@ -76,7 +76,7 @@ class User extends Table{ }catch(error){ throw error; } - } + }*/ static async login(data){ try{ diff --git a/nodejs/package-lock.json b/nodejs/package-lock.json index adab679..7c8f5d2 100644 --- a/nodejs/package-lock.json +++ b/nodejs/package-lock.json @@ -24,7 +24,9 @@ "linux-sys-user": "^1.1.8", "moment": "^2.29.4", "mustache": "^4.2.0", + "p2psub": "^0.1.9", "redis": "^4.6.7", + "socket.io": "^4.7.5", "tld-extract": "^2.1.0" }, "devDependencies": { @@ -264,6 +266,11 @@ "@redis/client": "^1.0.0" } }, + "node_modules/@socket.io/component-emitter": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz", + "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==" + }, "node_modules/@types/asn1": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/@types/asn1/-/asn1-0.2.1.tgz", @@ -272,6 +279,19 @@ "@types/node": "*" } }, + "node_modules/@types/cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==" + }, + "node_modules/@types/cors": { + "version": "2.8.17", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.17.tgz", + "integrity": "sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/node": { "version": "14.14.45", "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.45.tgz", @@ -470,6 +490,14 @@ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, + "node_modules/base64id": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", + "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", + "engines": { + "node": "^4.5.0 || >= 5.9" + } + }, "node_modules/bcrypt": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-5.1.1.tgz", @@ -709,6 +737,18 @@ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -787,6 +827,63 @@ "node": ">= 0.8" } }, + "node_modules/engine.io": { + "version": "6.5.5", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.5.tgz", + "integrity": "sha512-C5Pn8Wk+1vKBoHghJODM63yk8MvrO9EWZUfkAt5HAqIgPE4/8FF0PEGHXtEd40l223+cE5ABWuPzm38PHFXfMA==", + "dependencies": { + "@types/cookie": "^0.4.1", + "@types/cors": "^2.8.12", + "@types/node": ">=10.0.0", + "accepts": "~1.3.4", + "base64id": "2.0.0", + "cookie": "~0.4.1", + "cors": "~2.8.5", + "debug": "~4.3.1", + "engine.io-parser": "~5.2.1", + "ws": "~8.17.1" + }, + "engines": { + "node": ">=10.2.0" + } + }, + "node_modules/engine.io-parser": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz", + "integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/engine.io/node_modules/cookie": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/engine.io/node_modules/debug": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", + "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/engine.io/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, "node_modules/escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", @@ -1668,6 +1765,11 @@ "wrappy": "1" } }, + "node_modules/p2psub": { + "version": "0.1.9", + "resolved": "https://registry.npmjs.org/p2psub/-/p2psub-0.1.9.tgz", + "integrity": "sha512-5za6YUq6GLH+iZCqOF7YaOd13joJyqJyjp/6o3wcy9hj969EJq7sJGsU5b3MB7tjMoaHAaIKZ01j99Y9QficUQ==" + }, "node_modules/parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -1953,6 +2055,107 @@ "node": ">=10" } }, + "node_modules/socket.io": { + "version": "4.7.5", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.7.5.tgz", + "integrity": "sha512-DmeAkF6cwM9jSfmp6Dr/5/mfMwb5Z5qRrSXLpo3Fq5SqyU8CMF15jIN4ZhfSwu35ksM1qmHZDQ/DK5XTccSTvA==", + "dependencies": { + "accepts": "~1.3.4", + "base64id": "~2.0.0", + "cors": "~2.8.5", + "debug": "~4.3.2", + "engine.io": "~6.5.2", + "socket.io-adapter": "~2.5.2", + "socket.io-parser": "~4.2.4" + }, + "engines": { + "node": ">=10.2.0" + } + }, + "node_modules/socket.io-adapter": { + "version": "2.5.5", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.5.tgz", + "integrity": "sha512-eLDQas5dzPgOWCk9GuuJC2lBqItuhKI4uxGgo9aIV7MYbk2h9Q6uULEh8WBzThoI7l+qU9Ast9fVUmkqPP9wYg==", + "dependencies": { + "debug": "~4.3.4", + "ws": "~8.17.1" + } + }, + "node_modules/socket.io-adapter/node_modules/debug": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", + "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/socket.io-adapter/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/socket.io-parser": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", + "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/socket.io-parser/node_modules/debug": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", + "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/socket.io-parser/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/socket.io/node_modules/debug": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", + "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/socket.io/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, "node_modules/statuses": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", @@ -2167,6 +2370,26 @@ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, + "node_modules/ws": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", + "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", diff --git a/nodejs/package.json b/nodejs/package.json index 6765550..59121e5 100755 --- a/nodejs/package.json +++ b/nodejs/package.json @@ -22,12 +22,13 @@ "extend": "^3.0.2", "get-root-domain": "^0.0.1", "jquery": "^3.7.1", - "jquery-ui": "^1.13.3", "ldapts": "^2.12.0", "linux-sys-user": "^1.1.8", "moment": "^2.29.4", "mustache": "^4.2.0", + "p2psub": "^0.1.9", "redis": "^4.6.7", + "socket.io": "^4.7.5", "tld-extract": "^2.1.0" }, "license": "MIT", diff --git a/nodejs/public/lib/js/app-base.js b/nodejs/public/lib/js/app-base.js index c4ec287..e061205 100644 --- a/nodejs/public/lib/js/app-base.js +++ b/nodejs/public/lib/js/app-base.js @@ -1,66 +1,76 @@ var app = {}; -// app.pubsub = (function(){ -// app.topics = {}; +app.pubsub = (function(){ + app.topics = {}; -// app.subscribe = function(topic, listener){ -// if(topic instanceof RegExp){ -// listener.match = topic; -// topic = "__REGEX__"; -// } + app.subscribe = function(topic, listener){ + if(topic instanceof RegExp){ + listener.match = topic; + topic = "__REGEX__"; + } -// // create the topic if not yet created -// if(!app.topics[topic]) app.topics[topic] = []; + // create the topic if not yet created + if(!app.topics[topic]) app.topics[topic] = []; -// // add the listener -// app.topics[topic].push(listener); -// } + // add the listener + app.topics[topic].push(listener); + } -// app.matchTopics = function(topic){ -// topic = topic || ''; -// var matches = [... app.topics[topic] ? app.topics[topic] : []]; + app.matchTopics = function(topic){ + topic = topic || ''; + var matches = [... app.topics[topic] ? app.topics[topic] : []]; -// if(!app.topics['__REGEX__']) return matches; + if(!app.topics['__REGEX__']) return matches; -// for(var listener of app.topics['__REGEX__']){ -// if(topic.match(listener.match)) matches.push(listener); -// } + for(var listener of app.topics['__REGEX__']){ + if(topic.match(listener.match)) matches.push(listener); + } -// return matches; -// } + return matches; + } -// app.publish = function(topic, data){ + app.publish = function(topic, data){ -// // send the event to all listeners -// app.matchTopics(topic).forEach(function(listener){ -// setTimeout(function(data, topic){ -// listener(data || {}, topic); -// }, 0, data, topic); -// }); -// } + // send the event to all listeners + app.matchTopics(topic).forEach(function(listener){ + setTimeout(function(data, topic){ + listener(data || {}, topic); + }, 0, data, topic); + }); + } -// return this; -// })(app); + return this; +})(app); -// app.socket = (function(app){ -// var socket = io(); -// // socket.emit('chat message', $('#m').val()); -// socket.on('P2PSub', function(msg){ -// msg.data.__noSocket = true; -// app.publish(msg.topic, msg.data); -// }); +app.socket = (function(app){ + // $.getScript('/socket.io/socket.io.js') + // + + var socket; + $(document).ready(function(){ + socket = io({ + auth: { + token: app.auth.getToken() + } + }); + // socket.emit('chat message', $('#m').val()); + socket.on('P2PSub', function(msg){ + msg.data.__noSocket = true; + app.publish(msg.topic, msg.data); + }); -// app.subscribe(/./g, function(data, topic){ -// // console.log('local_pubs', data, topic) -// if(data.__noSocket) return; -// // console.log('local_pubs 2', data, topic) + app.subscribe(/./g, function(data, topic){ + // console.log('local_pubs', data, topic) + if(data.__noSocket) return; + // console.log('local_pubs 2', data, topic) -// socket.emit('P2PSub', { topic, data }) -// }); + socket.emit('P2PSub', { topic, data }); + }); + }) -// return socket; + return socket; -// })(app); +})(app); app.api = (function(app){ var baseURL = '/api/' diff --git a/nodejs/routes/api.js b/nodejs/routes/api.js new file mode 100644 index 0000000..5f51432 --- /dev/null +++ b/nodejs/routes/api.js @@ -0,0 +1,19 @@ +'use strict'; + +const router = require('express').Router(); +const conf = require('../conf'); +const middleware = require('../middleware/auth'); + +// API routes for authentication. +router.use('/auth', require('./auth')); + +// API routes for working with users. All endpoints need to be have valid user. +router.use('/user', middleware.auth, require('./user')); + +// API routes for working with hosts. All endpoints need to be have valid user. +router.use('/host', middleware.auth, require('./host')); + +// API routes for working with hosts. All endpoints need to be have valid user. +router.use('/cert', middleware.auth, require('./cert')); + +module.exports = router; \ No newline at end of file diff --git a/nodejs/routes/auth.js b/nodejs/routes/auth.js index 3c5aa0d..d651cb8 100755 --- a/nodejs/routes/auth.js +++ b/nodejs/routes/auth.js @@ -1,9 +1,7 @@ 'use strict'; const router = require('express').Router(); -const {User} = require('../models/user'); -const {Auth, AuthToken} = require('../models/auth'); - +const { Auth } = require('../controller/auth'); router.post('/login', async function(req, res, next){ try{ @@ -11,6 +9,7 @@ router.post('/login', async function(req, res, next){ return res.json({ login: true, token: auth.token.token, + message:`${req.body.username} logged in!`, }); }catch(error){ next(error); @@ -29,39 +28,4 @@ router.all('/logout', async function(req, res, next){ } }); -router.post('/invite/:token', async function(req, res, next) { - try{ - req.body.token = req.params.token; - let user = await User.addByInvite(req.body); - let token = await AuthToken.add(user); - - return res.json({ - user: user.username, - token: token.token - }); - - }catch(error){ - next(error); - } - -}); - module.exports = router; - -/* - verify public ssh key -*/ -// router.post('/verifykey', async function(req, res){ -// let key = req.body.key; - -// try{ -// return res.json({ -// info: await Users.verifyKey(key) -// }); -// }catch(error){ -// return res.status(400).json({ -// message: 'Key is not a public key file!' -// }); -// } - -// }); \ No newline at end of file diff --git a/nodejs/routes/host.js b/nodejs/routes/host.js index f6051b9..9eac42a 100755 --- a/nodejs/routes/host.js +++ b/nodejs/routes/host.js @@ -3,7 +3,6 @@ const router = require('express').Router(); const {Host} = require('../models/host'); - const Model = Host; router.get('/', async function(req, res, next){ diff --git a/nodejs/routes/render.js b/nodejs/routes/render.js index 114f191..c5d47d4 100644 --- a/nodejs/routes/render.js +++ b/nodejs/routes/render.js @@ -1,13 +1,29 @@ 'use strict'; +const path = require('path'); +const express = require('express'); const router = require('express').Router(); -const conf = require('../conf') -const middleware = require('../middleware/auth'); +const conf = require('../conf'); const values ={ title: conf.environment !== 'production' ? `` : '' } +// List of front end node modules to be served +const frontEndModules = ['bootstrap', 'mustache', 'jquery', '@fortawesome', + 'moment', +]; + +// Server front end modules +// https://stackoverflow.com/a/55700773/3140931 +frontEndModules.forEach(dep => { + router.use(`/static-modules/${dep}`, express.static(path.join(__dirname, `../node_modules/${dep}`))) +}); + +// Have express server static content( images, CSS, browser JS) from the public +// local folder. +router.use('/static', express.static(path.join(__dirname, '../public'))) + router.get('/', async function(req, res, next) { res.render('hosts', {...values}); }); diff --git a/nodejs/utils/model_pubsub.js b/nodejs/utils/model_pubsub.js new file mode 100644 index 0000000..a352d4c --- /dev/null +++ b/nodejs/utils/model_pubsub.js @@ -0,0 +1,49 @@ +'use strict'; +const ps = require('../controller/pubsub'); + + +function ModelPs(model){ + const Model = model.constructor.name === 'Function' ? model : model.constructor + + function getIndex(req, res){ + if(model[Model._key]) return model[Model._key]; + if(req && req[Model._key]) return req[Model._key]; + if(res && res[Model._key]) return res[Model._key]; + } + + function publish(prop, res, req){ + if(!['add', 'create', 'update', 'remove'].includes(prop)) return; + + ps.publish(`model:${Model.name}:${prop}:${getIndex(res, req)}`, res); + } + + return new Proxy(model, { + construct(target, args) { + let instance = ModelPs(new model(...args)); + + return instance; + }, + get(target, propKey, receiver) { + if(propKey == 'constructor') return target.constructor; + if(propKey === 'isproxy') return 'YESSSSSSSSS' + const targetValue = Reflect.get(target, propKey, receiver); + if (typeof targetValue === 'function') { + return function(...args){ + let res = targetValue.apply(this, args); // (A) + if(targetValue.constructor.name === 'AsyncFunction'){ + res.then(function(res){ + publish(propKey, res, ...args); + }); + }else{ + publish(propKey, res, ...args) + } + return res; + } + } else { + return targetValue; + } + } + }); +} + +module.exports = ModelPs; diff --git a/nodejs/utils/redis_model.js b/nodejs/utils/redis_model.js index c809ba9..5e21110 100644 --- a/nodejs/utils/redis_model.js +++ b/nodejs/utils/redis_model.js @@ -22,7 +22,6 @@ class Table{ static async get(index){ try{ - if(typeof index === 'object'){ index = index[this._key]; } @@ -43,7 +42,7 @@ class Table{ // back to native values. result = objValidate.parseFromString(this._keyMap, result); - return new this.prototype.constructor(result); + return new this(result); }catch(error){ throw error; @@ -84,6 +83,10 @@ class Table{ return out; } + static async create(...args){ + return this.add(...args); + } + static async add(data){ // Add a entry to this redis table. try{ diff --git a/nodejs/views/top.ejs b/nodejs/views/top.ejs index 9000439..404b824 100755 --- a/nodejs/views/top.ejs +++ b/nodejs/views/top.ejs @@ -10,9 +10,8 @@ - + -