Skip to content

Commit

Permalink
feat(upload): ZMS-111 (#584)
Browse files Browse the repository at this point in the history
  • Loading branch information
NickOvt authored Jan 4, 2024
1 parent eecb31a commit 6bdeeaa
Showing 1 changed file with 217 additions and 46 deletions.
263 changes: 217 additions & 46 deletions lib/api/auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,53 @@ const ObjectId = require('mongodb').ObjectId;
const tools = require('../tools');
const roles = require('../roles');
const { nextPageCursorSchema, previousPageCursorSchema, pageNrSchema, sessSchema, sessIPSchema, booleanSchema, usernameSchema } = require('../schemas');
const { successRes } = require('../schemas/response/general-schemas');
const { userId } = require('../schemas/request/general-schemas');

module.exports = (db, server, userHandler) => {
server.post(
'/preauth',
{
path: '/preauth',
summary: 'Pre-auth check',
description: 'Check if an username exists and can be used for authentication',
tags: ['Authentication'],
validationObjs: {
requestBody: {
username: Joi.alternatives()
.try(usernameSchema, Joi.string().email({ tlds: false }))
.required()
.description('Username or E-mail address'),

scope: Joi.string().default('master').description('Required scope. One of master, imap, smtp, pop3'),

sess: sessSchema,
ip: sessIPSchema
},
queryParams: {},
pathParams: {},
response: {
200: {
description: 'Success',
model: Joi.object({
success: successRes,
id: userId,
username: Joi.string().required().description('Username of authenticated User'),
scope: Joi.string().required().description('The scope this authentication is valid for'),
require2fa: Joi.array().items(Joi.string()).required().description('List of enabled 2FA mechanisms')
})
}
}
}
},
tools.responseWrapper(async (req, res) => {
res.charSet('utf-8');

const schema = Joi.object().keys({
username: Joi.alternatives()
.try(usernameSchema, Joi.string().email({ tlds: false }))
.required(),
const { requestBody, pathParams, queryParams } = req.route.spec.validationObjs;

scope: Joi.string().default('master'),

sess: sessSchema,
ip: sessIPSchema
const schema = Joi.object({
...requestBody,
...pathParams,
...queryParams
});

const result = schema.validate(req.params, {
Expand Down Expand Up @@ -88,28 +119,65 @@ module.exports = (db, server, userHandler) => {
);

server.post(
'/authenticate',
{
path: '/authenticate',
summary: 'Authenticate a User',
tags: ['Authentication'],
validationObjs: {
requestBody: {
username: Joi.alternatives()
.try(usernameSchema, Joi.string().email({ tlds: false }))
.required()
.description('Username or E-mail address'),
password: Joi.string().max(256).required().description('Password'),

protocol: Joi.string().default('API').description('Application identifier for security logs'),
scope: Joi.string()
.default('master')
// token can be true only if scope is master
.when('token', { is: true, then: Joi.valid('master') })
.description('Required scope. One of master, imap, smtp, pop3'),

appId: Joi.string().empty('').uri().description('Optional appId which is the URL of the app'),

token: booleanSchema
.default(false)
.description(
'If true then generates a temporary access token that is valid for this user. Only available if scope is "master". When using user tokens then you can replace user ID in URLs with "me".'
),

sess: sessSchema,
ip: sessIPSchema
},
queryParams: {},
pathParams: {},
response: {
200: {
description: 'Success',
model: Joi.object({
success: successRes,
id: userId,
username: Joi.string().required().description('Username of authenticated User'),
scope: Joi.string().required().description('The scope this authentication is valid for'),
require2fa: Joi.array().items(Joi.string()).required().description('List of enabled 2FA mechanisms'),
requirePasswordChange: booleanSchema.required().description('Indicates if account hassword has been reset and should be replaced'),
token: Joi.string().description(
'If access token was requested then this is the value to use as access token when making API requests on behalf of logged in user.'
)
})
}
}
}
},
tools.responseWrapper(async (req, res) => {
res.charSet('utf-8');

const schema = Joi.object().keys({
username: Joi.alternatives()
.try(usernameSchema, Joi.string().email({ tlds: false }))
.required(),
password: Joi.string().max(256).required(),

protocol: Joi.string().default('API'),
scope: Joi.string()
.default('master')
// token can be true only if scope is master
.when('token', { is: true, then: Joi.valid('master') }),

appId: Joi.string().empty('').uri(),
const { requestBody, pathParams, queryParams } = req.route.spec.validationObjs;

token: booleanSchema.default(false),

sess: sessSchema,
ip: sessIPSchema
const schema = Joi.object({
...requestBody,
...pathParams,
...queryParams
});

const result = schema.validate(req.params, {
Expand Down Expand Up @@ -203,7 +271,23 @@ module.exports = (db, server, userHandler) => {
);

server.del(
'/authenticate',
{
path: '/authenticate',
summary: 'Invalidate authentication token',
description: 'This method invalidates currently used authentication token. If token is not provided then nothing happens',
tags: ['Authentication'],
validationObjs: {
requestBody: {},
pathParams: {},
queryParams: {},
response: {
200: {
description: 'Success',
model: Joi.object({ success: successRes })
}
}
}
},
tools.responseWrapper(async (req, res) => {
res.charSet('utf-8');

Expand All @@ -223,21 +307,71 @@ module.exports = (db, server, userHandler) => {
);

server.get(
{ name: 'authlog', path: '/users/:user/authlog' },
{
name: 'authlog',
path: '/users/:user/authlog',
summary: 'List authentication Events',
tags: ['Authentication'],
validationObjs: {
requestBody: {},
pathParams: { user: userId },
queryParams: {
action: Joi.string().trim().lowercase().empty('').max(100).description('Limit listing only to values with specific action value'),
limit: Joi.number().default(20).min(1).max(250).description('How many records to return'),
next: nextPageCursorSchema,
previous: previousPageCursorSchema,
page: pageNrSchema,
filterip: sessIPSchema.description('Limit listing only to values with specific IP address'),

sess: sessSchema,
ip: sessIPSchema
},
response: {
200: {
description: 'Success',
model: Joi.object({
success: successRes,
action: Joi.string().required().description('Limit listing only to values with specific action value'),
total: Joi.number().required().description('How many results were found'),
page: Joi.number().required().description('Current page number. Derived from page query argument'),
previousCursor: previousPageCursorSchema,
nextCursor: nextPageCursorSchema,
results: Joi.array()
.items(
Joi.object({
id: Joi.string().required().description('ID of the event'),
action: Joi.string().required().description('Action identifier'),
result: Joi.string().required().description('Did the action succeed'),
sess: sessSchema,
ip: sessIPSchema,
created: Joi.date().required().description('Datestring of the Event time'),
protocol: Joi.string().description('Protocol that the authentication was made from'),
requiredScope: Joi.string().description('Scope of the auth'),
last: Joi.date().required().description('Date of the last update of data'),
events: Joi.number().required().description('Number of times same auth log has accured'),
source: Joi.string().description('Source of auth. Example: `master` if password auth was used'),
expires: Joi.date()
.required()
.description(
'After this date the given auth log document will not be updated and instead a new one will be created'
)
}).$_setFlag('objectName', 'GetAuthlogResult')
)
.required()
})
}
}
}
},
tools.responseWrapper(async (req, res) => {
res.charSet('utf-8');

const schema = Joi.object().keys({
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: nextPageCursorSchema,
previous: previousPageCursorSchema,
page: pageNrSchema,
filterip: sessIPSchema,

sess: sessSchema,
ip: sessIPSchema
const { requestBody, pathParams, queryParams } = req.route.spec.validationObjs;

const schema = Joi.object({
...requestBody,
...pathParams,
...queryParams
});

const result = schema.validate(req.params, {
Expand Down Expand Up @@ -359,15 +493,52 @@ module.exports = (db, server, userHandler) => {
);

server.get(
'/users/:user/authlog/:event',
{
path: '/users/:user/authlog/:event',
summary: 'Request Event information',
tags: ['Authentication'],
validationObjs: {
requestBody: {},
queryParams: {
sess: sessSchema,
ip: sessIPSchema
},
pathParams: {
user: userId,
event: Joi.string().hex().lowercase().length(24).required().description('ID of the Event')
},
response: {
200: {
description: 'Success',
model: Joi.object({
id: Joi.string().required().description('ID of the event'),
action: Joi.string().required().description('Action identifier'),
result: Joi.string().required().description('Did the action succeed'),
sess: sessSchema,
ip: sessIPSchema,
created: Joi.date().required().description('Datestring of the Event time'),
protocol: Joi.string().description('Protocol that the authentication was made from'),
requiredScope: Joi.string().description('Scope of the auth'),
last: Joi.date().required().description('Date of the last update of Event'),
events: Joi.number().required().description('Number of times same auth Event has accured'),
source: Joi.string().description('Source of auth. Example: `master` if password auth was used'),
expires: Joi.date()
.required()
.description('After this date the given auth Event will not be updated and instead a new one will be created')
})
}
}
}
},
tools.responseWrapper(async (req, res) => {
res.charSet('utf-8');

const schema = Joi.object().keys({
user: Joi.string().hex().lowercase().length(24).required(),
event: Joi.string().hex().lowercase().length(24).required(),
sess: sessSchema,
ip: sessIPSchema
const { requestBody, pathParams, queryParams } = req.route.spec.validationObjs;

const schema = Joi.object({
...requestBody,
...pathParams,
...queryParams
});

const result = schema.validate(req.params, {
Expand Down

0 comments on commit 6bdeeaa

Please sign in to comment.