Merge pull request #578 from jc21/develop

develop -> openidc
This commit is contained in:
jc21
2020-08-27 09:34:42 +10:00
committed by GitHub
42 changed files with 4860 additions and 4385 deletions

View File

@@ -0,0 +1,26 @@
{
"database": {
"engine": "knex-native",
"knex": {
"client": "sqlite3",
"connection": {
"filename": "/app/backend/config/mydb.sqlite"
},
"pool": {
"min": 0,
"max": 1,
"createTimeoutMillis": 3000,
"acquireTimeoutMillis": 30000,
"idleTimeoutMillis": 30000,
"reapIntervalMillis": 1000,
"createRetryIntervalMillis": 100,
"propagateCreateError": false
},
"migrations": {
"tableName": "migrations",
"stub": "src/backend/lib/migrate_template.js",
"directory": "src/backend/migrations"
}
}
}
}

View File

@@ -4,19 +4,27 @@ if (!config.has('database')) {
throw new Error('Database config does not exist! Please read the instructions: https://github.com/jc21/nginx-proxy-manager/blob/master/doc/INSTALL.md');
}
let data = {
client: config.database.engine,
connection: {
host: config.database.host,
user: config.database.user,
password: config.database.password,
database: config.database.name,
port: config.database.port
},
migrations: {
tableName: 'migrations'
}
};
function generateDbConfig() {
if (config.database.engine === 'knex-native') {
return config.database.knex;
} else
return {
client: config.database.engine,
connection: {
host: config.database.host,
user: config.database.user,
password: config.database.password,
database: config.database.name,
port: config.database.port
},
migrations: {
tableName: 'migrations'
}
};
}
let data = generateDbConfig();
if (typeof config.database.version !== 'undefined') {
data.version = config.database.version;

View File

@@ -77,7 +77,7 @@ const internalCertificate = {
.where('id', certificate.id)
.andWhere('provider', 'letsencrypt')
.patch({
expires_on: certificateModel.raw('FROM_UNIXTIME(' + cert_info.dates.to + ')')
expires_on: moment(cert_info.dates.to, 'X').format('YYYY-MM-DD HH:mm:ss')
});
})
.catch((err) => {
@@ -180,7 +180,7 @@ const internalCertificate = {
return certificateModel
.query()
.patchAndFetchById(certificate.id, {
expires_on: certificateModel.raw('FROM_UNIXTIME(' + cert_info.dates.to + ')')
expires_on: moment(cert_info.dates.to, 'X').format('YYYY-MM-DD HH:mm:ss')
})
.then((saved_row) => {
// Add cert data for audit log
@@ -558,7 +558,7 @@ const internalCertificate = {
// TODO: This uses a mysql only raw function that won't translate to postgres
return internalCertificate.update(access, {
id: data.id,
expires_on: certificateModel.raw('FROM_UNIXTIME(' + validations.certificate.dates.to + ')'),
expires_on: moment(validations.certificate.dates.to, 'X').format('YYYY-MM-DD HH:mm:ss'),
domain_names: [validations.certificate.cn],
meta: _.clone(row.meta) // Prevent the update method from changing this value that we'll use later
})
@@ -733,7 +733,6 @@ const internalCertificate = {
'--agree-tos ' +
'--email "' + certificate.meta.letsencrypt_email + '" ' +
'--preferred-challenges "dns,http" ' +
'--webroot ' +
'--domains "' + certificate.domain_names.join(',') + '" ' +
(le_staging ? '--staging' : '');
@@ -769,7 +768,7 @@ const internalCertificate = {
return certificateModel
.query()
.patchAndFetchById(certificate.id, {
expires_on: certificateModel.raw('FROM_UNIXTIME(' + cert_info.dates.to + ')')
expires_on: moment(cert_info.dates.to, 'X').format('YYYY-MM-DD HH:mm:ss')
});
})
.then((updated_certificate) => {

View File

@@ -22,22 +22,6 @@ exports.up = function (knex/*, Promise*/) {
})
.then(() => {
logger.info('[' + migrate_name + '] setting Table created');
// TODO: add settings
let settingModel = require('../models/setting');
return settingModel
.query()
.insert({
id: 'default-site',
name: 'Default Site',
description: 'What to show when Nginx is hit with an unknown Host',
value: 'congratulations',
meta: {}
});
})
.then(() => {
logger.info('[' + migrate_name + '] Default settings added');
});
};

View File

@@ -6,13 +6,14 @@ const Model = require('objection').Model;
const User = require('./user');
const AccessListAuth = require('./access_list_auth');
const AccessListClient = require('./access_list_client');
const now = require('./now_helper');
Model.knex(db);
class AccessList extends Model {
$beforeInsert () {
this.created_on = Model.raw('NOW()');
this.modified_on = Model.raw('NOW()');
this.created_on = now();
this.modified_on = now();
// Default for meta
if (typeof this.meta === 'undefined') {
@@ -21,7 +22,7 @@ class AccessList extends Model {
}
$beforeUpdate () {
this.modified_on = Model.raw('NOW()');
this.modified_on = now();
}
static get name () {

View File

@@ -3,13 +3,14 @@
const db = require('../db');
const Model = require('objection').Model;
const now = require('./now_helper');
Model.knex(db);
class AccessListAuth extends Model {
$beforeInsert () {
this.created_on = Model.raw('NOW()');
this.modified_on = Model.raw('NOW()');
this.created_on = now();
this.modified_on = now();
// Default for meta
if (typeof this.meta === 'undefined') {
@@ -18,7 +19,7 @@ class AccessListAuth extends Model {
}
$beforeUpdate () {
this.modified_on = Model.raw('NOW()');
this.modified_on = now();
}
static get name () {

View File

@@ -3,13 +3,14 @@
const db = require('../db');
const Model = require('objection').Model;
const now = require('./now_helper');
Model.knex(db);
class AccessListClient extends Model {
$beforeInsert () {
this.created_on = Model.raw('NOW()');
this.modified_on = Model.raw('NOW()');
this.created_on = now();
this.modified_on = now();
// Default for meta
if (typeof this.meta === 'undefined') {
@@ -18,7 +19,7 @@ class AccessListClient extends Model {
}
$beforeUpdate () {
this.modified_on = Model.raw('NOW()');
this.modified_on = now();
}
static get name () {

View File

@@ -4,13 +4,14 @@
const db = require('../db');
const Model = require('objection').Model;
const User = require('./user');
const now = require('./now_helper');
Model.knex(db);
class AuditLog extends Model {
$beforeInsert () {
this.created_on = Model.raw('NOW()');
this.modified_on = Model.raw('NOW()');
this.created_on = now();
this.modified_on = now();
// Default for meta
if (typeof this.meta === 'undefined') {
@@ -19,7 +20,7 @@ class AuditLog extends Model {
}
$beforeUpdate () {
this.modified_on = Model.raw('NOW()');
this.modified_on = now();
}
static get name () {

View File

@@ -5,6 +5,7 @@ const bcrypt = require('bcrypt');
const db = require('../db');
const Model = require('objection').Model;
const User = require('./user');
const now = require('./now_helper');
Model.knex(db);
@@ -24,8 +25,8 @@ function encryptPassword () {
class Auth extends Model {
$beforeInsert (queryContext) {
this.created_on = Model.raw('NOW()');
this.modified_on = Model.raw('NOW()');
this.created_on = now();
this.modified_on = now();
// Default for meta
if (typeof this.meta === 'undefined') {
@@ -36,7 +37,7 @@ class Auth extends Model {
}
$beforeUpdate (queryContext) {
this.modified_on = Model.raw('NOW()');
this.modified_on = now();
return encryptPassword.apply(this, queryContext);
}

View File

@@ -4,17 +4,18 @@
const db = require('../db');
const Model = require('objection').Model;
const User = require('./user');
const now = require('./now_helper');
Model.knex(db);
class Certificate extends Model {
$beforeInsert () {
this.created_on = Model.raw('NOW()');
this.modified_on = Model.raw('NOW()');
this.created_on = now();
this.modified_on = now();
// Default for expires_on
if (typeof this.expires_on === 'undefined') {
this.expires_on = Model.raw('NOW()');
this.expires_on = now();
}
// Default for domain_names
@@ -31,7 +32,7 @@ class Certificate extends Model {
}
$beforeUpdate () {
this.modified_on = Model.raw('NOW()');
this.modified_on = now();
// Sort domain_names
if (typeof this.domain_names !== 'undefined') {

View File

@@ -5,13 +5,14 @@ const db = require('../db');
const Model = require('objection').Model;
const User = require('./user');
const Certificate = require('./certificate');
const now = require('./now_helper');
Model.knex(db);
class DeadHost extends Model {
$beforeInsert () {
this.created_on = Model.raw('NOW()');
this.modified_on = Model.raw('NOW()');
this.created_on = now();
this.modified_on = now();
// Default for domain_names
if (typeof this.domain_names === 'undefined') {
@@ -27,7 +28,7 @@ class DeadHost extends Model {
}
$beforeUpdate () {
this.modified_on = Model.raw('NOW()');
this.modified_on = now();
// Sort domain_names
if (typeof this.domain_names !== 'undefined') {

View File

@@ -0,0 +1,13 @@
const db = require('../db');
const config = require('config');
const Model = require('objection').Model;
Model.knex(db);
module.exports = function () {
if (config.database.knex && config.database.knex.client === 'sqlite3') {
return Model.raw('datetime(\'now\',\'localtime\')');
} else {
return Model.raw('NOW()');
}
};

View File

@@ -6,13 +6,14 @@ const Model = require('objection').Model;
const User = require('./user');
const AccessList = require('./access_list');
const Certificate = require('./certificate');
const now = require('./now_helper');
Model.knex(db);
class ProxyHost extends Model {
$beforeInsert () {
this.created_on = Model.raw('NOW()');
this.modified_on = Model.raw('NOW()');
this.created_on = now();
this.modified_on = now();
// Default for domain_names
if (typeof this.domain_names === 'undefined') {
@@ -34,7 +35,7 @@ class ProxyHost extends Model {
}
$beforeUpdate () {
this.modified_on = Model.raw('NOW()');
this.modified_on = now();
// Sort domain_names
if (typeof this.domain_names !== 'undefined') {

View File

@@ -5,13 +5,14 @@ const db = require('../db');
const Model = require('objection').Model;
const User = require('./user');
const Certificate = require('./certificate');
const now = require('./now_helper');
Model.knex(db);
class RedirectionHost extends Model {
$beforeInsert () {
this.created_on = Model.raw('NOW()');
this.modified_on = Model.raw('NOW()');
this.created_on = now();
this.modified_on = now();
// Default for domain_names
if (typeof this.domain_names === 'undefined') {
@@ -27,7 +28,7 @@ class RedirectionHost extends Model {
}
$beforeUpdate () {
this.modified_on = Model.raw('NOW()');
this.modified_on = now();
// Sort domain_names
if (typeof this.domain_names !== 'undefined') {

View File

@@ -4,13 +4,14 @@
const db = require('../db');
const Model = require('objection').Model;
const User = require('./user');
const now = require('./now_helper');
Model.knex(db);
class Stream extends Model {
$beforeInsert () {
this.created_on = Model.raw('NOW()');
this.modified_on = Model.raw('NOW()');
this.created_on = now();
this.modified_on = now();
// Default for meta
if (typeof this.meta === 'undefined') {
@@ -19,7 +20,7 @@ class Stream extends Model {
}
$beforeUpdate () {
this.modified_on = Model.raw('NOW()');
this.modified_on = now();
}
static get name () {

View File

@@ -4,13 +4,14 @@
const db = require('../db');
const Model = require('objection').Model;
const UserPermission = require('./user_permission');
const now = require('./now_helper');
Model.knex(db);
class User extends Model {
$beforeInsert () {
this.created_on = Model.raw('NOW()');
this.modified_on = Model.raw('NOW()');
this.created_on = now();
this.modified_on = now();
// Default for roles
if (typeof this.roles === 'undefined') {
@@ -19,7 +20,7 @@ class User extends Model {
}
$beforeUpdate () {
this.modified_on = Model.raw('NOW()');
this.modified_on = now();
}
static get name () {

View File

@@ -3,17 +3,18 @@
const db = require('../db');
const Model = require('objection').Model;
const now = require('./now_helper');
Model.knex(db);
class UserPermission extends Model {
$beforeInsert () {
this.created_on = Model.raw('NOW()');
this.modified_on = Model.raw('NOW()');
this.created_on = now();
this.modified_on = now();
}
$beforeUpdate () {
this.modified_on = Model.raw('NOW()');
this.modified_on = now();
}
static get name () {

View File

@@ -6,28 +6,30 @@
"dependencies": {
"ajv": "^6.12.0",
"batchflow": "^0.4.0",
"bcrypt": "^4.0.1",
"bcrypt": "^5.0.0",
"body-parser": "^1.19.0",
"compression": "^1.7.4",
"config": "^3.3.1",
"diskdb": "^0.1.17",
"express": "^4.17.1",
"express-fileupload": "^1.1.6",
"express-fileupload": "^1.1.9",
"gravatar": "^1.8.0",
"html-entities": "^1.2.1",
"json-schema-ref-parser": "^8.0.0",
"jsonwebtoken": "^8.5.1",
"knex": "^0.20.13",
"liquidjs": "^9.11.10",
"lodash": "^4.17.15",
"lodash": "^4.17.19",
"moment": "^2.24.0",
"mysql": "^2.18.1",
"node-rsa": "^1.0.8",
"nodemon": "^2.0.2",
"objection": "^2.1.3",
"path": "^0.12.7",
"pg": "^7.12.1",
"restler": "^3.4.0",
"signale": "^1.4.0",
"sqlite3": "^4.1.1",
"temp-write": "^4.0.0",
"unix-timestamp": "^0.2.0"
},

View File

@@ -5,9 +5,15 @@ const logger = require('./logger').setup;
const userModel = require('./models/user');
const userPermissionModel = require('./models/user_permission');
const authModel = require('./models/auth');
const settingModel = require('./models/setting');
const debug_mode = process.env.NODE_ENV !== 'production' || !!process.env.DEBUG;
module.exports = function () {
/**
* Creates a new JWT RSA Keypair if not alread set on the config
*
* @returns {Promise}
*/
const setupJwt = () => {
return new Promise((resolve, reject) => {
// Now go and check if the jwt gpg keys have been created and if not, create them
if (!config.has('jwt') || !config.has('jwt.key') || !config.has('jwt.pub')) {
@@ -27,12 +33,12 @@ module.exports = function () {
}
// Now create the keys and save them in the config.
let key = new NodeRSA({b: 2048});
let key = new NodeRSA({ b: 2048 });
key.generateKeyPair();
config_data.jwt = {
key: key.exportKey('private').toString(),
pub: key.exportKey('public').toString()
pub: key.exportKey('public').toString(),
};
// Write config
@@ -47,7 +53,6 @@ module.exports = function () {
process.exit(0);
}
});
} else {
// JWT key pair exists
if (debug_mode) {
@@ -56,14 +61,20 @@ module.exports = function () {
resolve();
}
})
.then(() => {
return userModel
.query()
.select(userModel.raw('COUNT(`id`) as `count`'))
.where('is_deleted', 0)
.first();
})
});
};
/**
* Creates a default admin users if one doesn't already exist in the database
*
* @returns {Promise}
*/
const setupDefaultUser = () => {
return userModel
.query()
.select(userModel.raw('COUNT(`id`) as `count`'))
.where('is_deleted', 0)
.first()
.then((row) => {
if (!row.count) {
// Create a new user and set password
@@ -75,7 +86,7 @@ module.exports = function () {
name: 'Administrator',
nickname: 'Admin',
avatar: '',
roles: ['admin']
roles: ['admin'],
};
return userModel
@@ -88,28 +99,64 @@ module.exports = function () {
user_id: user.id,
type: 'password',
secret: 'changeme',
meta: {}
meta: {},
})
.then(() => {
return userPermissionModel
.query()
.insert({
user_id: user.id,
visibility: 'all',
proxy_hosts: 'manage',
redirection_hosts: 'manage',
dead_hosts: 'manage',
streams: 'manage',
access_lists: 'manage',
certificates: 'manage'
});
return userPermissionModel.query().insert({
user_id: user.id,
visibility: 'all',
proxy_hosts: 'manage',
redirection_hosts: 'manage',
dead_hosts: 'manage',
streams: 'manage',
access_lists: 'manage',
certificates: 'manage',
});
});
})
.then(() => {
logger.info('Initial setup completed');
logger.info('Initial admin setup completed');
});
} else if (debug_mode) {
logger.debug('Admin user setup not required');
}
});
};
/**
* Creates default settings if they don't already exist in the database
*
* @returns {Promise}
*/
const setupDefaultSettings = () => {
return settingModel
.query()
.select(settingModel.raw('COUNT(`id`) as `count`'))
.where({id: 'default-site'})
.first()
.then((row) => {
if (!row.count) {
settingModel
.query()
.insert({
id: 'default-site',
name: 'Default Site',
description: 'What to show when Nginx is hit with an unknown Host',
value: 'congratulations',
meta: {},
})
.then(() => {
logger.info('Default settings added');
});
}
if (debug_mode) {
logger.debug('Default setting setup not required');
}
});
};
module.exports = function () {
return setupJwt()
.then(setupDefaultUser)
.then(setupDefaultSettings);
};

File diff suppressed because it is too large Load Diff