mirror of
https://github.com/nodemailer/wildduck.git
synced 2025-03-03 19:33:36 +08:00
fixed authlog previous paging
This commit is contained in:
parent
1b10664e56
commit
ea4b038f73
6 changed files with 52 additions and 12 deletions
|
@ -432,6 +432,7 @@ This call prepares the user to support 2FA tokens. If 2FA is already enabled the
|
|||
|
||||
- **user** (required) is the ID of the user
|
||||
- **issuer** is the name to be shown in the Authenticator App
|
||||
- **fresh** is a boolean. If true then generates a new seed even if an old one already exists
|
||||
- **ip** is the IP address the request was made from
|
||||
|
||||
**Response fields**
|
||||
|
|
|
@ -10,6 +10,7 @@ module.exports = (db, server, userHandler) => {
|
|||
const schema = Joi.object().keys({
|
||||
user: Joi.string().hex().lowercase().length(24).required(),
|
||||
issuer: Joi.string().trim().max(255).required(),
|
||||
fresh: Joi.boolean().truthy(['Y', 'true', 'yes', 1]).default(false),
|
||||
ip: Joi.string().ip({
|
||||
version: ['ipv4', 'ipv6'],
|
||||
cidr: 'forbidden'
|
||||
|
|
|
@ -116,6 +116,10 @@ module.exports = (db, server, userHandler) => {
|
|||
let generateMobileconfig = result.value.generateMobileconfig;
|
||||
let scopes = result.value.scopes || ['*'];
|
||||
|
||||
if (scopes.includes('*')) {
|
||||
scopes = ['*'];
|
||||
}
|
||||
|
||||
if (generateMobileconfig && !scopes.includes('*') && (!scopes.includes('imap') || !scopes.includes('smtp'))) {
|
||||
res.json({
|
||||
error: 'Profile file requires imap and smtp scopes'
|
||||
|
|
|
@ -72,9 +72,9 @@ module.exports = (db, server, userHandler) => {
|
|||
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().alphanum().max(100),
|
||||
prev: Joi.string().alphanum().max(100),
|
||||
page: Joi.number().default(1)
|
||||
next: Joi.string().empty('').alphanum().max(100),
|
||||
previous: Joi.string().empty('').alphanum().max(100),
|
||||
page: Joi.number().empty('').default(1)
|
||||
});
|
||||
|
||||
req.query.user = req.params.user;
|
||||
|
@ -82,7 +82,7 @@ module.exports = (db, server, userHandler) => {
|
|||
const result = Joi.validate(req.query, schema, {
|
||||
abortEarly: false,
|
||||
convert: true,
|
||||
allowUnknown: true
|
||||
allowUnknown: false
|
||||
});
|
||||
|
||||
if (result.error) {
|
||||
|
@ -97,7 +97,7 @@ module.exports = (db, server, userHandler) => {
|
|||
let action = result.value.action;
|
||||
let page = result.value.page;
|
||||
let pageNext = result.value.next;
|
||||
let pagePrev = result.value.prev;
|
||||
let pagePrevious = result.value.previous;
|
||||
|
||||
db.users.collection('users').findOne({
|
||||
_id: user
|
||||
|
@ -144,8 +144,8 @@ module.exports = (db, server, userHandler) => {
|
|||
|
||||
if (pageNext) {
|
||||
opts.next = pageNext;
|
||||
} else if (pagePrev) {
|
||||
opts.prev = pagePrev;
|
||||
} else if (pagePrevious) {
|
||||
opts.previous = pagePrevious;
|
||||
}
|
||||
|
||||
MongoPaging.find(db.users.collection('authlog'), opts, (err, result) => {
|
||||
|
@ -177,7 +177,9 @@ module.exports = (db, server, userHandler) => {
|
|||
total,
|
||||
page,
|
||||
prev: prevUrl,
|
||||
previousCursor: result.hasPrevious ? result.previous : false,
|
||||
next: nextUrl,
|
||||
nextCursor: result.hasNext ? result.next : false,
|
||||
results: (result.results || []).map(resultData => {
|
||||
let response = {
|
||||
id: resultData._id
|
||||
|
|
|
@ -256,6 +256,9 @@ module.exports = (db, server, userHandler) => {
|
|||
|
||||
enabled2fa: userData.enabled2fa,
|
||||
|
||||
forward: userData.forward,
|
||||
targetUrl: userData.targetUrl,
|
||||
|
||||
limits: {
|
||||
quota: {
|
||||
allowed: Number(userData.quota) || config.maxStorage * 1024 * 1024,
|
||||
|
@ -288,14 +291,14 @@ module.exports = (db, server, userHandler) => {
|
|||
const schema = Joi.object().keys({
|
||||
user: Joi.string().hex().lowercase().length(24).required(),
|
||||
|
||||
existingPassword: Joi.string().min(1).max(256),
|
||||
existingPassword: Joi.string().empty('').min(1).max(256),
|
||||
password: Joi.string().min(8).max(256),
|
||||
|
||||
language: Joi.string().min(2).max(20).lowercase(),
|
||||
|
||||
name: Joi.string().max(256),
|
||||
forward: Joi.string().email(),
|
||||
targetUrl: Joi.string().max(256),
|
||||
name: Joi.string().empty('').max(256),
|
||||
forward: Joi.string().empty('').email(),
|
||||
targetUrl: Joi.string().empty('').max(256),
|
||||
|
||||
retention: Joi.number().min(0),
|
||||
quota: Joi.number().min(0),
|
||||
|
@ -330,6 +333,16 @@ module.exports = (db, server, userHandler) => {
|
|||
let user = new ObjectID(result.value.user);
|
||||
if (forward) {
|
||||
result.value.forward = forward;
|
||||
} else if (!result.value.forward && 'forward' in req.params) {
|
||||
result.value.forward = '';
|
||||
}
|
||||
|
||||
if (!result.value.targetUrl && 'targetUrl' in req.params) {
|
||||
result.value.targetUrl = '';
|
||||
}
|
||||
|
||||
if (!result.value.name && 'name' in req.params) {
|
||||
result.value.name = '';
|
||||
}
|
||||
|
||||
userHandler.update(user, result.value, (err, success) => {
|
||||
|
|
|
@ -12,6 +12,7 @@ const generatePassword = require('generate-password');
|
|||
const os = require('os');
|
||||
const crypto = require('crypto');
|
||||
const mailboxTranslations = require('./translations');
|
||||
const base32 = require('base32.js');
|
||||
|
||||
class UserHandler {
|
||||
constructor(options) {
|
||||
|
@ -499,7 +500,8 @@ class UserHandler {
|
|||
}, {
|
||||
fields: {
|
||||
username: true,
|
||||
enabled2fa: true
|
||||
enabled2fa: true,
|
||||
seed: true
|
||||
}
|
||||
}, (err, userData) => {
|
||||
if (err) {
|
||||
|
@ -515,6 +517,23 @@ class UserHandler {
|
|||
return callback(new Error('2FA is already enabled for this user'));
|
||||
}
|
||||
|
||||
if (!data.fresh && userData.seed) {
|
||||
if (userData.seed) {
|
||||
let otpauth_url = speakeasy.otpauthURL({
|
||||
secret: base32.decode(userData.seed),
|
||||
label: userData.username,
|
||||
issuer: data.issuer || 'Wild Duck'
|
||||
});
|
||||
return QRCode.toDataURL(otpauth_url, (err, data_url) => {
|
||||
if (err) {
|
||||
log.error('DB', 'QRFAIL username=%s error=%s', userData.username, err.message);
|
||||
return callback(new Error('Failed to generate QR code'));
|
||||
}
|
||||
return callback(null, data_url);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let secret = speakeasy.generateSecret({
|
||||
length: 20,
|
||||
name: userData.username
|
||||
|
|
Loading…
Reference in a new issue