moved all files to code directory

This commit is contained in:
2019-09-02 11:26:48 -04:00
parent 03d6973171
commit 236753b383
18 changed files with 0 additions and 0 deletions

9
nodejs/LICENSE Executable file
View File

@ -0,0 +1,9 @@
MIT License
Copyright (c) <year> <copyright holders>
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

230
nodejs/README.md Executable file
View File

@ -0,0 +1,230 @@
# proxy
## API docs
[API docs](api.md)
## Server set up
The server requires:
* NodeJS 8.x
* open ssh server(any modern version will do)
* inbound Internet access
* OpenResty
* redis
* lua rocks
This has been tested on ubuntu 16.04, but should work on any modern Linux distro. It used the Linux users for its user management, so this will **ONLY** work on Linux, no macOS, BSD or Windows.
The steps below are for a new ubuntu server, they should be mostly the same for other distros, but the paths and availability of packages may vary. A dedicated server is highly recommended (since it will make ever user a system user), a VPS like Digital Ocean will do just fine.
* Install other
These packages are needed for the PAM node package
```bash
apt install libpam0g-dev build-essential
```
* Install open ssh server
```bash
apt install ssh
```
* Install openresty
[OpenResty® Linux Packages](https://openresty.org/en/linux-packages.html)
* Install redis
```bash
apt install redis-server
```
* install lua plugin
```bash
apt install luarocks
sudo luarocks install lua-resty-auto-ssl
```
* Configure sshd for tunneling
* openresty config
Set up fail back SSL certs
```bash
mkdir /etc/ssl/
openssl req -new -newkey rsa:2048 -days 3650 -nodes -x509 -subj '/CN=sni-support-required-for-valid-ssl' -keyout /etc/ssl/resty-auto-ssl-fallback.key -out /etc/ssl/resty-auto-ssl-fallback.crt
openssl req -new -newkey rsa:2048 -days 3650 -nodes -x509 -subj '/CN=sni-support-required-for-valid-ssl' -keyout /etc/ssl/resty-auto-ssl-fallback.key -out /etc/ssl/resty-auto-ssl-fallback.crt
```
change the `/etc/openresty/nginx.conf to have this config`
```
#user nobody;
worker_processes 4;
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid;
events {
worker_connections 1024;
}
http {
client_max_body_size 4g;
lua_shared_dict auto_ssl 100m;
lua_shared_dict auto_ssl_settings 64k;
resolver 8.8.4.4 8.8.8.8;
init_by_lua_block {
auto_ssl = (require "resty.auto-ssl").new()
auto_ssl:set("storage_adapter", "resty.auto-ssl.storage_adapters.redis")
auto_ssl:set("allow_domain", function(domain)
return true
end)
auto_ssl:init()
}
init_worker_by_lua_block {
auto_ssl:init_worker()
}
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
server {
listen 127.0.0.1:8999;
# Increase the body buffer size, to ensure the internal POSTs can always
# parse the full POST contents into memory.
client_body_buffer_size 128k;
client_max_body_size 128k;
location / {
content_by_lua_block {
auto_ssl:hook_server()
}
}
}
include mime.types;
default_type application/octet-stream;
#log_format main '$remote_addr - $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
#gzip on;
include sites-enabled/*;
}
```
add the SSL config file `/etc/openresty/autossl.conf`
```
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers EECDH+CHACHA20:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5;
ssl_certificate_by_lua_block {
auto_ssl:ssl_certificate()
}
location /.well-known/acme-challenge/ {
content_by_lua_block {
auto_ssl:challenge_server()
}
}
ssl_certificate /etc/ssl/resty-auto-ssl-fallback.crt;
ssl_certificate_key /etc/ssl/resty-auto-ssl-fallback.key;
```
Add the proxy config `/etc/openresty/sites-enabled/000-proxy`
```
server {
listen 80;
listen 443 ssl;
include autossl.conf;
location / {
resolver 10.0.3.1; #8.8.4.4; # use Google's open DNS server
set $target '';
access_by_lua '
local key = ngx.var.host
if not key then
ngx.log(ngx.ERR, "no user-agent found")
return ngx.exit(400)
end
local redis = require "resty.redis"
local red = redis:new()
red:set_timeout(1000) -- 1 second
local ok, err = red:connect("127.0.0.1", 6379)
if not ok then
ngx.log(ngx.ERR, "failed to connect to redis: ", err)
return ngx.exit(500)
end
local host, err = red:hget("proxy_host_"..key, "ip")
if not host then
ngx.log(ngx.ERR, "failed to get redis key: ", err)
return ngx.exit(500)
end
if host == ngx.null then
ngx.log(ngx.ERR, "no host found for key ", key)
return ngx.exit(400)
end
ngx.log(ngx.WARN, "==Found match!!! ", key, host)
ngx.var.target = host
';
proxy_pass http://$target;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Host $host;
add_header X-Target-Host $target;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
```
## ref
https://blog.trackets.com/2014/05/17/ssh-tunnel-local-and-remote-port-forwarding-explained-with-examples.html
https://github.com/GUI/lua-resty-auto-ssl

106
nodejs/api.md Executable file
View File

@ -0,0 +1,106 @@
## get host info
**get** `/api/<HOST>`
```bash
curl -H "auth-token: 8eff4f16-086d-40fd-acbd-7634b9a36117" https://admin.rubyisforpussys.com/api/mine.com
```
* 200 {"host":"yours.com","results":{"ip":"127.0.0.1:4000","updated":"1518595297563","username":"test10"}}
* 404 {"host":"mine.comf","results":null}
## view all hosts
**get** `/api/`
```bash
curl -H "auth-token: 8eff4f16-086d-40fd-acbd-7634b9a36117" https://admin.rubyisforpussys.com/api/
```
* 200 {"hosts":["mine.com","mine2.com"]}
## add/edit host
**post** `/api/`
```bash
curl -H "Content-Type: application/json" -H "auth-token: 8eff4f16-086d-40fd-acbd-7634b9a36117" -X POST -d "{\"host\": \"yours.com\", \"ip\": \"127.0.0.1:4000\"}" https://admin.rubyisforpussys.com/api/
```
* 200 {"message":"Host yours.com Added"}
* 400 {"message":"Missing fields: ip"}
## delete host
**delete** /`api`
```bash
curl -H "Content-Type: application/json" -H "auth-token: 8eff4f16-086d-40fd-acbd-7634b9a36117" -X DELETE -d "{\"host\": \"yours.com\"}" https://admin.rubyisforpussys.com/api/
```
* 200 {"message":"Host yours.com deleted"}
## create invite token
**post** `/users/invite`
```bash
curl -H "Content-Type: application/json" -H "auth-token: 0b06eb2e-4ca4-4881-9a0f-b8df55431cd1" -X POST https://admin.rubyisforpussys.com/users/invite
```
* 200 {"token":"5caf94d2-2c91-4010-8df7-968d10802b9d"}
## sing up
**post** `/auth/invite/<INVITE TOKEN>`
```bash
curl -H "Content-Type: application/json" -X POST -d "{\"username\": \"test9\", \"password\": \"palm7\"}" https://admin.rubyisforpussys.com/auth/invite/b33d8819-ec64-4cf4-a6ec-77562d738fa4
```
* 200 {"user":"test9","token":"af662d8b-3d44-4110-8ad9-047dc752d97f"}
* 400 {"message":"Missing fields"}
* 401 {"message":"Token not valid"}
* 409 {"message":"username taken"}
## login
**post** `/auth/login`
```bash
curl -H "Content-Type: application/json" -X POST -d "{\"username\": \"test8\", \"password\": \"palm7\"}" https://admin.rubyisforpussys.com/auth/login
```
* 200 {"login":true,"token":"027d3964-7d81-4462-a6f9-2c1f9b40b4be"}
* 401 {"login":false}
## verify SSH key
**post** `/auth/verifykey`
```bash
curl -H "Content-Type: application/json" -X POST -d "{\"key\":\"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDM9vboz5YGgESsrR2e4JOeP2qtmQo2S8BjI+Y/VxPQ6WbNFzAkXxDniHcnPCrhkeX36SKINvMjWnt4XOK2S+X+1tCoXJzqtcKKyK0gx8ijBxcWVPxsMWjMYTGSVSKiKnt6CyQzrbVGJMh3iAQ8Yv1JwH+6SAtMgT8it7iLyntNFJCesh4I/znEG58A5VBbdUle1Ztz9afjj1CZns17jk7KPm9ig5DmuvdvnMEfhFjfKv1Rp6S5nxacMoTP4tJNSEUh55IicoWk94ii5GwUVLYgyMmzdlA32TqVLFpU2yAvdA9WSnBaI/ZyktlfI7YAmK2wFBsagr9Pq1TcUAY6rZ/GTMjDxExgdYn/FxlufcuqeNJsJXs2A+0xDS/9mv/yGQzNZrL8DrVhY2OKKLoH4Q7enDbhSgEFmJUJMqPxuPEgLEvKfzcURSvIwRj1iCEw6S4dhdaLJl2RRBb1ZWBQbE5ogIbvAl7GFJUAhj3pqYJnd30VENv1MkK+IoCS7EEP0caqL9RNAId0Plud7q2XElHqzkYUE+z+Q/LvGgclXK1ZmZejNaMnV53wfhAevfwVyNGK9i5gbwc1P2lplIa5laXCcVWezqELEkTpdjp4AeKmMuCr8rY8EnLKIcKWEOsX5UumztCow6e1E55v3VeHvRZLpw4DZP7EE0Q8B/jPFWqbCw== wmantly@gmail.com\"}" https://admin.rubyisforpussys.com/auth/verifykey
```
* 200 {"info":"4096 SHA256:dfdCYzt0atMBXVZTJzUxsu99IjXXFXpocSox5q+jOs8 wmantly@gmail.com (RSA)\n"}
* 400 {"message":"Key is not a public key file!"}
## add ssh key to current user
**post** `/users/key`
```bash
curl -H "Content-Type: application/json" -H "auth-token: 8eff4f16-086d-40fd-acbd-7634b9a36117" -X POST -d "{\"key\": \"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDM9vboz5YGgESsrR2e4JOeP2qtmQo2S8BjI+Y/VxPQ6WbNFzAkXxDniHcnPCrhkeX36SKINvMjWnt4XOK2S+X+1tCoXJzqtcKKyK0gx8ijBxcWVPxsMWjMYTGSVSKiKnt6CyQzrbVGJMh3iAQ8Yv1JwH+6SAtMgT8it7iLyntNFJCesh4I/znEG58A5VBbdUle1Ztz9afjj1CZns17jk7KPm9ig5DmuvdvnMEfhFjfKv1Rp6S5nxacMoTP4tJNSEUh55IicoWk94ii5GwUVLYgyMmzdlA32TqVLFpU2yAvdA9WSnBaI/ZyktlfI7YAmK2wFBsagr9Pq1TcUAY6rZ/GTMjDxExgdYn/FxlufcuqeNJsJXs2A+0xDS/9mv/yGQzNZrL8DrVhY2OKKLoH4Q7enDbhSgEFmJUJMqPxuPEgLEvKfzcURSvIwRj1iCEw6S4dhdaLJl2RRBb1ZWBQbE5ogIbvAl7GFJUAhj3pqYJnd30VENv1MkK+IoCS7EEP0caqL9RNAId0Plud7q2XElHqzkYUE+z+Q/LvGgclXK1ZmZejNaMnV53wfhAevfwVyNGK9i5gbwc1P2lplIa5laXCcVWezqELEkTpdjp4AeKmMuCr8rY8EnLKIcKWEOsX5UumztCow6e1E55v3VeHvRZLpw4DZP7EE0Q8B/jPFWqbCw== wmantly@gmail.co\"}" https://admin.rubyisforpussys.com/users/key
```
* 200 {"message":true}
* 400 {"message":"Bad SSH key"}

32
nodejs/app.js Executable file
View File

@ -0,0 +1,32 @@
'use strict';
const express = require('express');
const app = express();
const middleware = require('./middleware/auth');
app.use(express.json());
app.use('/auth', require('./routes/auth'));
app.use('/users', middleware.auth, require('./routes/users'));
app.use('/api', middleware.auth, require('./routes/routes'));
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.json({message: 'error!'});
});
module.exports = app;

90
nodejs/bin/www Executable file
View File

@ -0,0 +1,90 @@
#!/usr/bin/env node
/**
* Module dependencies.
*/
var app = require('../app');
var debug = require('debug')('proxy-api:server');
var http = require('http');
/**
* Get port from environment and store in Express.
*/
var port = normalizePort(process.env.PORT || '3000');
app.set('port', port);
/**
* Create HTTP server.
*/
var server = http.createServer(app);
/**
* Listen on provided port, on all network interfaces.
*/
server.listen(port);
server.on('error', onError);
server.on('listening', onListening);
/**
* Normalize a port into a number, string, or false.
*/
function normalizePort(val) {
var port = parseInt(val, 10);
if (isNaN(port)) {
// named pipe
return val;
}
if (port >= 0) {
// port number
return port;
}
return false;
}
/**
* Event listener for HTTP server "error" event.
*/
function onError(error) {
if (error.syscall !== 'listen') {
throw error;
}
var bind = typeof port === 'string'
? 'Pipe ' + port
: 'Port ' + port;
// handle specific listen errors with friendly messages
switch (error.code) {
case 'EACCES':
console.error(bind + ' requires elevated privileges');
process.exit(1);
break;
case 'EADDRINUSE':
console.error(bind + ' is already in use');
process.exit(1);
break;
default:
throw error;
}
}
/**
* Event listener for HTTP server "listening" event.
*/
function onListening() {
var addr = server.address();
var bind = typeof addr === 'string'
? 'pipe ' + addr
: 'port ' + addr.port;
debug('Listening on ' + bind);
}

25
nodejs/hostcontrol.js Executable file
View File

@ -0,0 +1,25 @@
#! /usr/bin/env node
//you must add the absolute path to hosts.js on line 4, or this file will NOT work
const hosts = require("./models/hosts.js")
const command = process.argv[2];
(async function(command){
if (command == "--list"){
console.log(await hosts.listAll())
process.exit(0)
}
})(command)
/*
if process.argv[2] == "--info"
if process.agrv[2] == "--add"
if process.argv[2] == "--remove"
else{
console.log("help text")
}
*/

19
nodejs/middleware/auth.js Executable file
View File

@ -0,0 +1,19 @@
'use strict';
const Users = require('../models/users');
async function auth(req, res, next){
if(req.header('auth-token')){
let user = await Users.checkToken({token: req.header('auth-token')});
if(user.username){
req.user = user;
return next();
}
}
return res.status(401).json({
message: 'Login failed'
});
}
module.exports = {auth};

0
nodejs/models/auth.js Executable file
View File

48
nodejs/models/hosts.js Executable file
View File

@ -0,0 +1,48 @@
'use strict';
const {promisify} = require('util');
const client = require('../redis');
async function getInfo(data){
let info = await client.HGETALL('host_' + data.host);
return info
}
async function listAll(){
try{
let hosts = await client.SMEMBERS('hosts');
return hosts;
}catch(error){
return new Error(error);
}
}
async function add(data){
try{
await client.SADD('hosts', data.host);
await client.HSET('host_' + data.host, 'ip', data.ip);
await client.HSET('host_' + data.host, 'updated', (new Date).getTime());
await client.HSET('host_' + data.host, 'username', data.username);
} catch (error){
return new Error(error);
}
}
async function remove(data){
try{
await client.SREM('hosts', data.host);
let count = await client.DEL('host_' + data.host);
return count;
} catch(error) {
return new Error(error);
}
}
module.exports = {getInfo, listAll, add, remove};

107
nodejs/models/users.js Executable file
View File

@ -0,0 +1,107 @@
'use strict';
const {promisify} = require('util');
const client = require('../redis');
const linuxUser = require('linux-user');
const pam = require('authenticate-pam');
const UUID = function b(a){return a?(a^Math.random()*16>>a/4).toString(16):([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g,b)};
const authenticate = promisify(pam.authenticate);
const addSSHtoUser = promisify(linuxUser.addSSHtoUser)
const getUserGroups = promisify(linuxUser.getUserGroups);
const verifySSHKey = promisify(linuxUser.verifySSHKey);
const addUser = promisify(linuxUser.addUser);
const setPassword = promisify(linuxUser.setPassword);
/*
Invite
*/
async function makeInviteToken(data){
let token = UUID();
await client.HSET('users_tokens', token, JSON.stringify({
created_by: data.username,
isAdmin: data.isAdmin,
invited: false
}));
return token;
}
async function checkInvite(data){
let token = await client.HGET('users_tokens', data.token);
return JSON.parse(token);
}
async function consumeInvite(data){
let invite = await checkInvite(data);
invite.invited = data.username;
await client.HSET('users_tokens', data.token, JSON.stringify(invite));
}
/*
Auth/ Auth token
*/
async function login(data){
try{
await authenticate(data.username, data.password);
return await getUserGroups(data.username);
}catch(error){
return false;
}
}
async function addToken(data){
let token = UUID();
await client.HSET('users_tokens', token, data.username);
return token;
}
async function checkToken(data){
let user = await client.HGET('users_tokens', data.token);
return {
username: user,
groups: (user && await getUserGroups(user))
}
}
async function addSSHkey(data){
try{
let user = await addSSHtoUser(data.username, data.key);
return true;
} catch (error) {
return error;
}
}
/*
Users
*/
async function add(data) {
let systemUser = await addUser(data.username);
let systemUserPassword = await setPassword(data.username, data.password);
}
async function verifyKey(data){
return await verifySSHKey(key)
}
async function ifUserExists(data){
const getUserInfo = promisify(linuxUser.getUserInfo);
return await getUserInfo(data.username);
}
module.exports = {login, add, addToken, checkToken, ifUserExists,
makeInviteToken, checkInvite, consumeInvite, addSSHkey, verifyKey};

2906
nodejs/package-lock.json generated Executable file

File diff suppressed because it is too large Load Diff

27
nodejs/package.json Executable file
View File

@ -0,0 +1,27 @@
{
"name": "proxy-api",
"version": "1.0.0",
"private": true,
"author": [
{
"name": "William Mantly",
"email": "wmantly@gmail.com"
}
],
"scripts": {
"start": "node ./bin/www"
},
"dependencies": {
"authenticate-pam": "github:WeiAnAn/node-authenticate-pam",
"express": "~4.16.1",
"forever": "^1.0.0",
"linux-sys-user": "github:wmantly/linux-user",
"linux-user": "github:wmantly/linux-user",
"redis": "^2.8.0"
},
"license": "MIT",
"repository": {
"type": "git",
"url": "https://git.theta42.com/wmantly/proxy.git"
}
}

23
nodejs/redis.js Executable file
View File

@ -0,0 +1,23 @@
const {createClient} = require('redis');
const {promisify} = require('util');
const config = {
prefix: 'proxy_'
}
function client() {
return createClient(config);
}
const _client = client();
module.exports = {
client: client,
HGET: promisify(_client.HGET).bind(_client),
SADD: promisify(_client.SADD).bind(_client),
SREM: promisify(_client.SREM).bind(_client),
DEL: promisify(_client.DEL).bind(_client),
HSET: promisify(_client.HSET).bind(_client),
HGETALL: promisify(_client.HGETALL).bind(_client),
SMEMBERS: promisify(_client.SMEMBERS).bind(_client),
};

90
nodejs/routes/auth.js Executable file
View File

@ -0,0 +1,90 @@
'use strict';
const router = require('express').Router();
const Users = require('../models/users');
/*
Password login
*/
router.post('/login', async function(req, res){
let username = req.body.username;
let password = req.body.password;
let groups = await Users.login({username, password});
if(groups){
return res.json({
login: true,
token: await Users.addToken({username}),
groups: groups,
});
}else{
return res.status(401).json({
login: false
});
}
});
/*
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!'
});
}
});
router.post('/invite/:token', async function(req, res, next) {
let username = req.body.username;
let password = req.body.password;
let token = req.params.token;
// make sure invite token is valid
let invite = await Users.checkInvite({token});
if(!invite || invite.invited){
return res.status(401).json({
message: 'Token not valid'
});
}
// make sure requires fields are in
if(!username || !password){
return res.status(400).json({
message: 'Missing fields'
});
}
// make sure the requested user name can be used
if(await Users.ifUserExists({username})){
return res.status(409).json({
message: 'Username taken'
});
}
// create the new user
await Users.add({username, password, isAdmin: invite.isAdmin});
// consume the invite token
await Users.consumeInvite({token, username});
// send back API token for the new user
return res.json({
user: username,
token: await Users.addToken({username})
});
});
module.exports = router;

9
nodejs/routes/index.js Executable file
View File

@ -0,0 +1,9 @@
var express = require('express');
var router = express.Router();
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index', { title: 'Express' });
});
module.exports = router;

76
nodejs/routes/routes.js Executable file
View File

@ -0,0 +1,76 @@
'use strict';
const router = require('express').Router();
const Host = require('../models/hosts');
router.get('/:host', async function(req, res){
let host = req.params.host;
let info = await Host.getInfo({host});
return res.status(info ? 200 : 404).json({
host: req.params.host,
results: info
});
});
router.get('/', async function(req, res){
try{
let hosts = await Host.listAll();
return res.json({hosts: hosts});
}catch(error){
return res.status(500).json({message: `ERROR ${error}`});
}
});
router.post('/', async function(req, res){
let ip = req.body.ip;
let host = req.body.host;
if(!host || !ip){
return res.status(400).json({
message: `Missing fields: ${!host ? 'host' : ''} ${!ip ? 'ip' : ''}`
});
}
try{
Host.add({host, ip, username: req.user.username});
return res.json({
message: `Host ${host} Added`
});
} catch (error){
return res.status(500).json({
message: `ERROR: ${error}`
});
}
});
router.delete('/', async function(req, res){
let host = req.body.host;
let count;
if(!host){
return res.status(400).json({
message: `Missing fields: ${!host ? 'host' : ''}`
});
}
try{
count = await Host.remove({host});
}catch(error){
return res.status(500).json({
message: `ERROR: ${error}`
});
}
return res.json({
message: `Host ${host} deleted`,
});
});
module.exports = router;

26
nodejs/routes/users.js Executable file
View File

@ -0,0 +1,26 @@
'use strict';
const router = require('express').Router();
const Users = require('../models/users');
router.post('/invite', async function(req, res){
let token = await Users.makeInviteToken({
username: res.user
});
return res.json({token:token});
});
router.post('/key', async function(req, res){
let added = await Users.addSSHkey({
username: req.user.username,
key: req.body.key
});
return res.status(added === true ? 200 : 400).json({
message: added
});
});
module.exports = router;

0
nodejs/ssh-keygen Executable file
View File