Merge remote-tracking branch 'origin/develop' into FEAT/open-id-connect-authentication

This commit is contained in:
Samuel Oechsler
2024-10-30 20:30:36 +01:00
182 changed files with 7882 additions and 5228 deletions

View File

@ -10,7 +10,7 @@
const _ = require('lodash');
const logger = require('../logger').access;
const validator = require('ajv');
const Ajv = require('ajv/dist/2020');
const error = require('./error');
const userModel = require('../models/user');
const proxyHostModel = require('../models/proxy_host');
@ -174,7 +174,6 @@ module.exports = function (token_string) {
let schema = {
$id: 'objects',
$schema: 'http://json-schema.org/draft-07/schema#',
description: 'Actor Properties',
type: 'object',
additionalProperties: false,
@ -251,7 +250,7 @@ module.exports = function (token_string) {
// Initialised, token decoded ok
return this.getObjectSchema(permission)
.then((objectSchema) => {
let data_schema = {
const data_schema = {
[permission]: {
data: data,
scope: Token.get('scope'),
@ -267,24 +266,18 @@ module.exports = function (token_string) {
};
let permissionSchema = {
$schema: 'http://json-schema.org/draft-07/schema#',
$async: true,
$id: 'permissions',
type: 'object',
additionalProperties: false,
properties: {}
};
permissionSchema.properties[permission] = require('./access/' + permission.replace(/:/gim, '-') + '.json');
// logger.info('objectSchema', JSON.stringify(objectSchema, null, 2));
// logger.info('permissionSchema', JSON.stringify(permissionSchema, null, 2));
// logger.info('data_schema', JSON.stringify(data_schema, null, 2));
let ajv = validator({
const ajv = new Ajv({
verbose: true,
allErrors: true,
format: 'full',
missingRefs: 'fail',
breakOnError: true,
coerceTypes: true,
schemas: [

View File

@ -1,5 +1,4 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "perms",
"definitions": {
"view": {

View File

@ -1,5 +1,4 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "roles",
"definitions": {
"admin": {

View File

@ -34,7 +34,7 @@ const configure = () => {
logger.info('Using MySQL configuration');
instance = {
database: {
engine: 'mysql',
engine: 'mysql2',
host: envMysqlHost,
port: process.env.DB_MYSQL_PORT || 3306,
user: envMysqlUser,
@ -180,5 +180,15 @@ module.exports = {
*/
useLetsencryptStaging: function () {
return !!process.env.LE_STAGING;
},
/**
* @returns {string|null}
*/
useLetsencryptServer: function () {
if (process.env.LE_SERVER) {
return process.env.LE_SERVER;
}
return null;
}
};

View File

@ -1,40 +1,16 @@
const validator = require('../validator');
module.exports = function (req, res, next) {
if (req.headers.origin) {
const originSchema = {
oneOf: [
{
type: 'string',
pattern: '^[a-z\\-]+:\\/\\/(?:[\\w\\-\\.]+(:[0-9]+)?/?)?$'
},
{
type: 'string',
pattern: '^[a-z\\-]+:\\/\\/(?:\\[([a-z0-9]{0,4}\\:?)+\\])?/?(:[0-9]+)?$'
}
]
};
// very relaxed validation....
validator(originSchema, req.headers.origin)
.then(function () {
res.set({
'Access-Control-Allow-Origin': req.headers.origin,
'Access-Control-Allow-Credentials': true,
'Access-Control-Allow-Methods': 'OPTIONS, GET, POST',
'Access-Control-Allow-Headers': 'Content-Type, Cache-Control, Pragma, Expires, Authorization, X-Dataset-Total, X-Dataset-Offset, X-Dataset-Limit',
'Access-Control-Max-Age': 5 * 60,
'Access-Control-Expose-Headers': 'X-Dataset-Total, X-Dataset-Offset, X-Dataset-Limit'
});
next();
})
.catch(next);
res.set({
'Access-Control-Allow-Origin': req.headers.origin,
'Access-Control-Allow-Credentials': true,
'Access-Control-Allow-Methods': 'OPTIONS, GET, POST',
'Access-Control-Allow-Headers': 'Content-Type, Cache-Control, Pragma, Expires, Authorization, X-Dataset-Total, X-Dataset-Offset, X-Dataset-Limit',
'Access-Control-Max-Age': 5 * 60,
'Access-Control-Expose-Headers': 'X-Dataset-Total, X-Dataset-Offset, X-Dataset-Limit'
});
next();
} else {
// No origin
next();
}
};

View File

@ -27,6 +27,24 @@ module.exports = {
}
return null;
},
convertIntFieldsToBool: function (obj, fields) {
fields.forEach(function (field) {
if (typeof obj[field] !== 'undefined') {
obj[field] = obj[field] === 1;
}
});
return obj;
},
convertBoolFieldsToInt: function (obj, fields) {
fields.forEach(function (field) {
if (typeof obj[field] !== 'undefined') {
obj[field] = obj[field] ? 1 : 0;
}
});
return obj;
}
};

View File

@ -1,13 +1,12 @@
const error = require('../error');
const path = require('path');
const parser = require('json-schema-ref-parser');
const Ajv = require('ajv/dist/2020');
const error = require('../error');
const ajv = require('ajv')({
verbose: true,
validateSchema: true,
allErrors: false,
format: 'full',
coerceTypes: true
const ajv = new Ajv({
verbose: true,
allErrors: true,
allowUnionTypes: true,
strict: false,
coerceTypes: true,
});
/**
@ -17,12 +16,18 @@ const ajv = require('ajv')({
*/
function apiValidator (schema, payload/*, description*/) {
return new Promise(function Promise_apiValidator (resolve, reject) {
if (typeof payload === 'undefined') {
reject(new error.ValidationError('Payload is undefined'));
if (schema === null) {
reject(new error.ValidationError('Schema is undefined'));
return;
}
let validate = ajv.compile(schema);
let valid = validate(payload);
if (typeof payload === 'undefined') {
reject(new error.ValidationError('Payload is undefined'));
return;
}
const validate = ajv.compile(schema);
const valid = validate(payload);
if (valid && !validate.errors) {
resolve(payload);
@ -35,11 +40,4 @@ function apiValidator (schema, payload/*, description*/) {
});
}
apiValidator.loadSchemas = parser
.dereference(path.resolve('schema/index.json'))
.then((schema) => {
ajv.addSchema(schema);
return schema;
});
module.exports = apiValidator;

View File

@ -1,17 +1,17 @@
const _ = require('lodash');
const error = require('../error');
const definitions = require('../../schema/definitions.json');
const _ = require('lodash');
const Ajv = require('ajv/dist/2020');
const error = require('../error');
const commonDefinitions = require('../../schema/common.json');
RegExp.prototype.toJSON = RegExp.prototype.toString;
const ajv = require('ajv')({
verbose: true,
allErrors: true,
format: 'full', // strict regexes for format checks
coerceTypes: true,
schemas: [
definitions
]
const ajv = new Ajv({
verbose: true,
allErrors: true,
allowUnionTypes: true,
coerceTypes: true,
strict: false,
schemas: [commonDefinitions]
});
/**
@ -27,23 +27,19 @@ function validator (schema, payload) {
} else {
try {
let validate = ajv.compile(schema);
let valid = validate(payload);
let valid = validate(payload);
if (valid && !validate.errors) {
resolve(_.cloneDeep(payload));
} else {
let message = ajv.errorsText(validate.errors);
reject(new error.InternalValidationError(message));
}
} catch (err) {
reject(err);
}
}
});
}
module.exports = validator;