wildduck/lib/api/auth.js

227 lines
6.5 KiB
JavaScript
Raw Normal View History

2017-07-26 16:52:55 +08:00
'use strict';
const Joi = require('joi');
const MongoPaging = require('mongo-cursor-pagination');
const ObjectID = require('mongodb').ObjectID;
module.exports = (db, server, userHandler) => {
server.post('/authenticate', (req, res, next) => {
res.charSet('utf-8');
const schema = Joi.object().keys({
2017-09-01 19:50:53 +08:00
username: Joi.alternatives()
.try(
Joi.string()
.lowercase()
.regex(/^[a-z](?:\.?[a-z0-9]+)*$/, 'username')
.min(3)
.max(30),
Joi.string().email()
)
.required(),
password: Joi.string()
.max(256)
.required(),
2017-07-26 16:52:55 +08:00
protocol: Joi.string().default('API'),
scope: Joi.string().default('master'),
ip: Joi.string().ip({
version: ['ipv4', 'ipv6'],
cidr: 'forbidden'
})
});
const result = Joi.validate(req.params, schema, {
abortEarly: false,
convert: true
});
if (result.error) {
res.json({
error: result.error.message
});
return next();
}
let meta = {
protocol: result.value.protocol,
ip: result.value.ip
};
userHandler.authenticate(result.value.username, result.value.password, result.value.scope, meta, (err, authData) => {
if (err) {
res.json({
error: err.message
});
return next();
}
if (!authData) {
res.json({
error: 'Authentication failed'
});
return next();
}
2017-10-10 16:19:10 +08:00
let authResponse = {
2017-07-26 16:52:55 +08:00
success: true,
id: authData.user,
username: authData.username,
scope: authData.scope,
require2fa: authData.require2fa,
requirePasswordChange: authData.requirePasswordChange
2017-10-10 16:19:10 +08:00
};
if (authData.u2fAuthRequest) {
authResponse.u2fAuthRequest = authData.u2fAuthRequest;
}
res.json(authResponse);
2017-07-26 16:52:55 +08:00
return next();
});
});
server.get({ name: 'authlog', path: '/users/:user/authlog' }, (req, res, next) => {
res.charSet('utf-8');
const schema = Joi.object().keys({
2017-09-01 19:50:53 +08:00
user: Joi.string()
.hex()
.lowercase()
.length(24)
.required(),
action: Joi.string()
.trim()
.lowercase()
.empty('')
.max(100),
limit: Joi.number()
.default(20)
.min(1)
.max(250),
next: Joi.string()
.empty('')
.alphanum()
2017-09-04 19:49:04 +08:00
.max(1024),
2017-09-01 19:50:53 +08:00
previous: Joi.string()
.empty('')
.alphanum()
2017-09-04 19:49:04 +08:00
.max(1024),
2017-09-01 19:50:53 +08:00
page: Joi.number()
.empty('')
.default(1)
2017-07-26 16:52:55 +08:00
});
req.query.user = req.params.user;
const result = Joi.validate(req.query, schema, {
abortEarly: false,
convert: true,
2017-07-30 03:08:43 +08:00
allowUnknown: false
2017-07-26 16:52:55 +08:00
});
if (result.error) {
res.json({
error: result.error.message
});
return next();
}
let user = new ObjectID(result.value.user);
let limit = result.value.limit;
let action = result.value.action;
let page = result.value.page;
let pageNext = result.value.next;
2017-07-30 03:08:43 +08:00
let pagePrevious = result.value.previous;
2017-07-26 16:52:55 +08:00
2017-07-27 21:24:42 +08:00
db.users.collection('users').findOne({
2017-07-26 16:52:55 +08:00
_id: user
}, {
fields: {
_id: true
}
}, (err, userData) => {
if (err) {
res.json({
error: 'MongoDB Error: ' + err.message
});
return next();
}
if (!userData) {
res.json({
error: 'This user does not exist'
});
return next();
}
let filter = action
? {
user,
action
}
: {
user
};
db.database.collection('authlog').count(filter, (err, total) => {
if (err) {
res.json({
error: err.message
});
return next();
}
let opts = {
limit,
query: filter,
sortAscending: false
};
if (pageNext) {
opts.next = pageNext;
2017-07-30 03:08:43 +08:00
} else if (pagePrevious) {
opts.previous = pagePrevious;
2017-07-26 16:52:55 +08:00
}
MongoPaging.find(db.users.collection('authlog'), opts, (err, result) => {
if (err) {
res.json({
error: result.error.message
});
return next();
}
if (!result.hasPrevious) {
page = 1;
}
let response = {
success: true,
action,
total,
page,
2017-07-30 03:08:43 +08:00
previousCursor: result.hasPrevious ? result.previous : false,
nextCursor: result.hasNext ? result.next : false,
2017-07-26 16:52:55 +08:00
results: (result.results || []).map(resultData => {
let response = {
id: resultData._id
};
Object.keys(resultData).forEach(key => {
if (!['_id', 'user'].includes(key)) {
response[key] = resultData[key];
}
});
return response;
})
};
res.json(response);
return next();
});
});
});
});
};