frist pass
This commit is contained in:
parent
45b0efaaec
commit
b067b65a45
32
app.js
Normal file
32
app.js
Normal 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.render('error');
|
||||
});
|
||||
|
||||
module.exports = app;
|
90
bin/www
Executable file
90
bin/www
Executable 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);
|
||||
}
|
17
middleware/auth.js
Normal file
17
middleware/auth.js
Normal file
@ -0,0 +1,17 @@
|
||||
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){
|
||||
req.user = user;
|
||||
return next();
|
||||
}
|
||||
}
|
||||
|
||||
return res.status(401).json({
|
||||
message: 'Login failed'
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {auth};
|
0
models/auth.js
Normal file
0
models/auth.js
Normal file
86
models/users.js
Normal file
86
models/users.js
Normal file
@ -0,0 +1,86 @@
|
||||
const {promisify} = require('util');
|
||||
const linuxUser = require('linux-user');
|
||||
const pam = require('authenticate-pam');
|
||||
const client = require('../redis');
|
||||
|
||||
const UUID = function b(a){return a?(a^Math.random()*16>>a/4).toString(16):([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g,b)};
|
||||
|
||||
/*
|
||||
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 checkInviteToken(data){
|
||||
let token = await client.HGET('users_tokens', data.token);
|
||||
|
||||
return JSON.parse(token);
|
||||
}
|
||||
|
||||
async function useInviteToken(data){
|
||||
let invite = await checkInviteToken(data);
|
||||
|
||||
invite.invited = data.username;
|
||||
|
||||
await client.HSET('users_tokens', data.token, JSON.stringify(invite));
|
||||
}
|
||||
|
||||
/*
|
||||
Auth/ Auth token
|
||||
*/
|
||||
|
||||
async function login(data){
|
||||
const authenticate = promisify(pam.authenticate);
|
||||
const getUserGroups = promisify(linuxUser.getUserGroups);
|
||||
|
||||
try{
|
||||
await authenticate(data.username, data.password);
|
||||
let groups = await getUserGroups(data.username);
|
||||
console.log('groups', groups)
|
||||
return true;
|
||||
}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 user;
|
||||
}
|
||||
|
||||
/*
|
||||
Users
|
||||
*/
|
||||
|
||||
async function add(data) {
|
||||
const addUser = promisify(linuxUser.addUser);
|
||||
const setPassword = promisify(linuxUser.setPassword);
|
||||
|
||||
let systemUser = await addUser(data.username);
|
||||
let systemUserPassword = await setPassword(data.username, data.password);
|
||||
|
||||
}
|
||||
|
||||
async function ifUserExists(data){
|
||||
const getUserInfo = promisify(linuxUser.getUserInfo);
|
||||
return await getUserInfo(data.username);
|
||||
}
|
||||
|
||||
module.exports = {login, add, addToken, checkToken, ifUserExists,
|
||||
makeInviteToken, checkInviteToken, useInviteToken};
|
1181
package-lock.json
generated
Normal file
1181
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
16
package.json
Normal file
16
package.json
Normal file
@ -0,0 +1,16 @@
|
||||
{
|
||||
"name": "proxy-api",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"start": "node ./bin/www"
|
||||
},
|
||||
"dependencies": {
|
||||
"authenticate-pam": "^1.0.2",
|
||||
"bcrypt": "^1.0.3",
|
||||
"express": "~4.16.1",
|
||||
"linux-user": "github:wmantly/linux-user",
|
||||
"pubsub-js": "^1.6.0",
|
||||
"redis": "^2.8.0"
|
||||
}
|
||||
}
|
19
redis.js
Normal file
19
redis.js
Normal file
@ -0,0 +1,19 @@
|
||||
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),
|
||||
HSET: promisify(_client.HSET).bind(_client),
|
||||
};
|
83
routes/auth.js
Normal file
83
routes/auth.js
Normal file
@ -0,0 +1,83 @@
|
||||
'use strict';
|
||||
|
||||
const router = require('express').Router();
|
||||
const linuxUser = require('linux-user');
|
||||
const {promisify} = require('util');
|
||||
|
||||
const Users = require('../models/users');
|
||||
|
||||
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
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
router.post('/verifykey', async function(req, res){
|
||||
let key = req.body.key;
|
||||
const verifySSHKey = promisify(linuxUser.verifySSHKey);
|
||||
|
||||
let isValid;
|
||||
|
||||
try{
|
||||
isValid = await verifySSHKey(key);
|
||||
return res.json({
|
||||
info: isValid
|
||||
});
|
||||
}catch(error){
|
||||
return res.status(400).json({
|
||||
message: 'Key is not a public key file!'
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
router.post('/:token', async function(req, res, next) {
|
||||
let username = req.body.username;
|
||||
let password = req.body.password;
|
||||
let token = req.params.token;
|
||||
|
||||
let invite = await Users.checkInviteToken({token});
|
||||
|
||||
console.log('invite', invite)
|
||||
|
||||
if(!invite || invite.invited){
|
||||
return res.status(401).json({
|
||||
message: 'Token not valid'
|
||||
});
|
||||
}
|
||||
|
||||
if(!username || !password){
|
||||
return res.status(400).json({
|
||||
message: 'Missing fields'
|
||||
});
|
||||
}
|
||||
|
||||
if(await Users.ifUserExists({username})){
|
||||
return res.json({
|
||||
message: 'username taken'
|
||||
});
|
||||
}
|
||||
|
||||
await Users.add({username, password, isAdmin: invite.isAdmin});
|
||||
|
||||
await Users.useInviteToken({token, username});
|
||||
|
||||
return res.json({user:username});
|
||||
|
||||
});
|
||||
|
||||
module.exports = router;
|
9
routes/index.js
Normal file
9
routes/index.js
Normal 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;
|
74
routes/routes.js
Normal file
74
routes/routes.js
Normal file
@ -0,0 +1,74 @@
|
||||
const client = require('../redis');
|
||||
const router = require('express').Router();
|
||||
const app = require('../app');
|
||||
|
||||
router.get('/:host', async function(req, res){
|
||||
client.HGETALL('host_' + req.params.host, function (error, results) {
|
||||
res.json({
|
||||
host: req.params.host,
|
||||
results: results
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
router.get('/', async function(req, res){
|
||||
client.SMEMBERS('hosts', function(error, results){
|
||||
if(error){
|
||||
return res.status(500).json({message: `ERROR ${error}`});
|
||||
}
|
||||
return res.json({hosts: results});
|
||||
});
|
||||
});
|
||||
|
||||
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' : ''}`
|
||||
});
|
||||
}else{
|
||||
|
||||
try{
|
||||
await client.SADD('hosts', host);
|
||||
await client.HSET('host_' + host, 'ip', ip);
|
||||
await client.HSET('host_' + host, 'updated', (new Date).getTime());
|
||||
|
||||
} catch (error){
|
||||
return res.status(500).json({
|
||||
message: `ERROR: ${error}`
|
||||
});
|
||||
}
|
||||
|
||||
return res.json({
|
||||
message: `Host ${host} Added`
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
router.delete('/', async function(req, res){
|
||||
let host = req.body.host;
|
||||
|
||||
if(!host){
|
||||
return res.status(400).json({
|
||||
message: `Missing fields: ${!host ? 'host' : ''}`
|
||||
});
|
||||
}else{
|
||||
|
||||
try{
|
||||
await client.SREM('hosts', host);
|
||||
await client.DEL('host_' + host);
|
||||
}catch(error){
|
||||
return res.status(500).json({
|
||||
message: `ERROR: ${error}`
|
||||
});
|
||||
}
|
||||
|
||||
return res.json({
|
||||
message: `Host ${host} deleted`
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = router;
|
13
routes/users.js
Normal file
13
routes/users.js
Normal file
@ -0,0 +1,13 @@
|
||||
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})
|
||||
});
|
||||
|
||||
module.exports = router;
|
0
ssh-keygen
Normal file
0
ssh-keygen
Normal file
Loading…
x
Reference in New Issue
Block a user