allow closing all active imap sessions of an user

This commit is contained in:
Andris Reinman 2017-10-02 16:30:27 +03:00
parent 7edaf8e0d0
commit a7ec6f9158
6 changed files with 125 additions and 3 deletions

View file

@ -283,7 +283,7 @@ After you have created an user you can use these credentials to log in to the IM
### Update user details
####/users/{user}
#### PUT /users/{user}
Updates the properties of an user. Only specify these fields that you want to be updated.
@ -322,6 +322,33 @@ Response for a successful operation:
}
```
### Log out user from all IMAP sessions
#### PUT /users/{user}/logout
Forces closing all active IMAP session of an user
**Parameters**
- **user** (required) is the ID of the user
- **reason** is an optional message to be sent to the user with logout notification
**Example**
```
curl -XPUT "http://localhost:8080/users/59467f27535f8f0f067ba8e6/logout" -H 'content-type: application/json' -d '{
"reaosn": "Account was deleted"
}'
```
Response for a successful operation:
```json
{
"success": true
}
```
### Reset user password
#### POST /users/{user}/password/reset

View file

@ -119,7 +119,8 @@ function authenticate(connection, token, callback) {
username,
'PLAIN'
);
connection.session.user = response.user;
connection.setUser(response.user);
connection.state = 'Authenticated';
callback(null, {

View file

@ -112,7 +112,8 @@ module.exports = {
username,
'LOGIN'
);
this.session.user = response.user;
this.setUser(response.user);
this.state = 'Authenticated';
callback(null, {

View file

@ -10,6 +10,7 @@ const crypto = require('crypto');
const os = require('os');
const EventEmitter = require('events').EventEmitter;
const packageInfo = require('../../package');
const errors = require('../../lib/errors.js');
const SOCKET_TIMEOUT = 30 * 60 * 1000;
@ -86,6 +87,13 @@ class IMAPConnection extends EventEmitter {
// increment connection count
this._closing = false;
this._closed = false;
this._accountListener = message => {
if (message && message.action === 'LOGOUT') {
this.send('* BYE ' + (message.reason || 'Logout requested'));
this.close();
}
};
}
/**
@ -195,6 +203,8 @@ class IMAPConnection extends EventEmitter {
return;
}
this._server.notifier.removeListener(this.session, '*', this._accountListener);
this._parser = false;
this.state = 'Closed';
@ -251,6 +261,8 @@ class IMAPConnection extends EventEmitter {
return;
}
errors.notifyConnection(this.this, err);
this._server.logger.error(
{
err,
@ -731,6 +743,11 @@ class IMAPConnection extends EventEmitter {
return response;
}
setUser(user) {
this.session.user = user;
this._server.notifier.addListener(this.session, '*', this._accountListener);
}
}
// Expose to the world

View file

@ -459,6 +459,52 @@ module.exports = (db, server, userHandler) => {
});
});
server.put('/users/:user/logout', (req, res, next) => {
res.charSet('utf-8');
const schema = Joi.object().keys({
user: Joi.string()
.hex()
.lowercase()
.length(24)
.required(),
reason: Joi.string()
.empty('')
.max(128),
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();
}
userHandler.logout(result.value.user, result.value.reason || 'Logout requested from API', (err, success) => {
if (err) {
res.json({
error: err.message
});
return next();
}
res.json({
success
});
return next();
});
});
server.post('/users/:user/quota/reset', (req, res, next) => {
res.charSet('utf-8');

View file

@ -1242,6 +1242,36 @@ class UserHandler {
this.users.collection('authlog').insertOne(entry, callback);
});
}
logout(user, reason, callback) {
// register this address as the default address for that user
return this.users.collection('users').findOne({
_id: new ObjectID(user)
}, {
fields: {
_id: true
}
}, (err, userData) => {
if (err) {
log.error('DB', 'DBFAIL logout id=%s error=%s', user, err.message);
err.message = 'Database Error, failed to find user';
return callback(err);
}
if (!userData) {
return callback(new Error('User not found'));
}
if (!this.messageHandler || !this.messageHandler.notifier) {
return callback(null, false);
}
this.messageHandler.notifier.fire(userData._id, '/', {
action: 'LOGOUT',
reason
});
return callback(null, true);
});
}
}
module.exports = UserHandler;