+10
-1
@@ -14,5 +14,14 @@ module.exports = {
|
||||
socketFile: '/var/run/proxy_lookup.socket',
|
||||
redis: {
|
||||
prefix: 'proxy_'
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
service:{
|
||||
hostScheduler:{
|
||||
enabled: true,
|
||||
initial: 30000,
|
||||
interval: 86400000,
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
'use strict';
|
||||
// Using https://github.com/simpleworkjs/conf to handle configuration
|
||||
|
||||
module.exports = {
|
||||
userModel: 'redis', // pam, redis, ldap
|
||||
ldap: {
|
||||
url: 'ldap://192.168.1.55:389',
|
||||
bindDN: 'cn=ldapclient service,ou=people,dc=theta42,dc=com',
|
||||
bindPassword: '__IN SRECREST FILE__',
|
||||
searchBase: 'ou=people,dc=theta42,dc=com',
|
||||
userFilter: '(objectClass=inetOrgPerson)',
|
||||
userNameAttribute: 'uid'
|
||||
},
|
||||
socketFile: '/var/run/proxy_lookup.socket',
|
||||
redis: {
|
||||
prefix: 'proxy_'
|
||||
},
|
||||
service:{
|
||||
hostScheduler:{
|
||||
enabled: true,
|
||||
initial: 5000,
|
||||
interval: 86400000,
|
||||
}
|
||||
},
|
||||
};
|
||||
+10
-1
@@ -14,4 +14,13 @@ async function getCert(host){
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {getCert};
|
||||
async function deleteCert(host){
|
||||
try{
|
||||
console.log('looking for', host);
|
||||
return JSON.parse(await client.DEL(`${host}:latest`));
|
||||
}catch(error){
|
||||
return {}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {getCert, deleteCert};
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
const crypto = require("crypto");
|
||||
|
||||
const conf = require('@simpleworkjs/conf');
|
||||
const Table = require('../utils/redis_model');
|
||||
const Table = require('.');
|
||||
const ModelPs = require('../utils/model_pubsub');
|
||||
|
||||
const tldExtract = require('tld-extract').parse_host;
|
||||
@@ -182,17 +182,21 @@ if(require.main === module){(async function(){try{
|
||||
|
||||
// console.log(await DnsProvider.findall());
|
||||
|
||||
let provider = await DnsProvider.get('e8443e03ac503c7b');
|
||||
let provider = await DnsProvider.get('84c6613b9464fbe1');
|
||||
|
||||
console.log(await provider.listDomains())
|
||||
// console.log(await provider.listDomains())
|
||||
|
||||
let domain = await Domain.get('holycore.quest') // pork
|
||||
// let domain = await Domain.get('rm-rf.stream') // DO
|
||||
// let domain = await Domain.get('test.wtf') // CF
|
||||
|
||||
// console.log(await domain.createRecord({type: 'TXT', name: 'apitewefweefwsewft222', data:'hiiiiiii'}))
|
||||
console.log(await domain.createRecord({
|
||||
type: 'TXT',
|
||||
name: 'apitewefweefwsewft222',
|
||||
data: 'sdddddddad'
|
||||
}));
|
||||
|
||||
let txtRecords = await domain.getRecords({type: 'TXT'});
|
||||
let txtRecords = await domain.getRecords();
|
||||
console.log(txtRecords.map(i=>`${i.name}: ${i.data}`))
|
||||
// console.log(await domain.deleteRecords({type: 'TXT'}))
|
||||
|
||||
|
||||
@@ -93,13 +93,19 @@ class PorkBun extends DnsApi{
|
||||
});
|
||||
}
|
||||
|
||||
async createRecord(domain, options, force){
|
||||
if(force){
|
||||
await this.deleteRecords(domain, options)
|
||||
}
|
||||
|
||||
async createRecord(domain, options, force = true){
|
||||
try{
|
||||
// Throw errors for missing keys, do this first.
|
||||
options = this.__parseOptions(options, ['type', 'name', 'data']);
|
||||
|
||||
// Delete the current records
|
||||
if(force){
|
||||
let forceOptions = new Map(Object.entries(options));
|
||||
forceOptions.delete('data');
|
||||
forceOptions.delete('content');
|
||||
await this.deleteRecords(domain, Object.fromEntries(forceOptions));
|
||||
}
|
||||
|
||||
let res = await this.post(`/dns/create/${domain}`, options);
|
||||
|
||||
return res.data.result;
|
||||
|
||||
+18
-6
@@ -2,6 +2,7 @@
|
||||
|
||||
const Table = require('.');
|
||||
const {Domain} = require('.').models;
|
||||
const {deleteCert} = require('./cert');
|
||||
const ModelPs = require('../utils/model_pubsub');
|
||||
|
||||
const tldExtract = require('tld-extract').parse_host;
|
||||
@@ -21,14 +22,18 @@ class Host extends Table{
|
||||
'created_on': {default: function(){return (new Date).getTime()}},
|
||||
'updated_by': {default:"__NONE__", isRequired: false, type: 'string',},
|
||||
'updated_on': {default: function(){return (new Date).getTime()}, always: true},
|
||||
|
||||
'host': {isRequired: true, type: 'string', min: 3, max: 500},
|
||||
'ip': {isRequired: true, type: 'string', min: 3, max: 500},
|
||||
'targetPort': {isRequired: true, type: 'number', min:0, max:65535},
|
||||
'forcessl': {isRequired: false, default: true, type: 'boolean'},
|
||||
'targetssl': {isRequired: false, default: false, type: 'boolean'},
|
||||
|
||||
'is_cache': {default: false, isRequired: false, type: 'boolean',},
|
||||
|
||||
'is_wildcard': {default: false, isRequired: false, type: 'boolean',},
|
||||
'wildcard_status': {isRequired: false, type: 'string', min: 3, max: 500},
|
||||
'wildcard_matchAny': {default: false, isRequired: false, type: 'boolean',},
|
||||
'wildcard_parent': {isRequired: false, type: 'string', min: 3, max: 500},
|
||||
'wildcard_expires': {isRequired: false, type: 'number'},
|
||||
'domain': {model: 'Domain', rel: 'one'},
|
||||
@@ -76,26 +81,28 @@ class Host extends Table{
|
||||
|
||||
}catch(error){
|
||||
console.error('bust cache error', error)
|
||||
throw error;
|
||||
// throw error;
|
||||
}
|
||||
}
|
||||
|
||||
static async create(data, ...args){
|
||||
try{
|
||||
// Validate requested host is valid host and domain
|
||||
if(data.challengeType === 'DNS-01-wildcard') await this.validateWildcardCreate(data, args);
|
||||
if(data.challengeType === 'DNS-01-wildcard'){
|
||||
await this.validateWildcardCreate(data, args);
|
||||
data.is_wildcard = true;
|
||||
data.wildcard_status = "Starting"
|
||||
}
|
||||
|
||||
// Validate requested host has a valid wildcard parent
|
||||
if(data.challengeType === 'wildcardChild'){
|
||||
let parentHost = await this.lookUp(data.host);
|
||||
console.log('parentHost:', parentHost)
|
||||
if(parentHost.is_wildcard){
|
||||
data.wildcard_parent = parentHost.host;
|
||||
}else{
|
||||
throw new Error(`No parent wild card for ${data.host}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Create the new host entry
|
||||
let out = await super.create(data, ...args);
|
||||
|
||||
@@ -104,7 +111,7 @@ class Host extends Table{
|
||||
|
||||
// Fire the request for the wild card cert
|
||||
// This is "back ground" job, await is intentionally missing
|
||||
if(out.challengeType === 'DNS-01-wildcard') out.createWildcardCert();
|
||||
if(data.challengeType === 'DNS-01-wildcard') out.createWildcardCert();
|
||||
|
||||
return out;
|
||||
|
||||
@@ -114,6 +121,7 @@ class Host extends Table{
|
||||
}
|
||||
|
||||
static async validateWildcardCreate(data, ...args){
|
||||
console.log('validateWildcardCreate here')
|
||||
try{
|
||||
if(!data.host.startsWith('*.')) throw new Error('not wild card');
|
||||
await Domain.get(data.host);
|
||||
@@ -125,6 +133,7 @@ class Host extends Table{
|
||||
}
|
||||
|
||||
async createWildcardCert(){
|
||||
console.log('createWildcardCert', this.domain)
|
||||
if(!this.host.startsWith('*.')) throw new Error('not wild card');
|
||||
|
||||
try{
|
||||
@@ -234,6 +243,7 @@ class Host extends Table{
|
||||
this.createWildcardCert();
|
||||
}
|
||||
}catch(error){
|
||||
console.error('checkWildcardForRenew instance', this.host, error)
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
@@ -241,9 +251,10 @@ class Host extends Table{
|
||||
static async checkWildcardForRenew(){
|
||||
try{
|
||||
for(let host of await this.listDetail()){
|
||||
host.createWildcardCert();
|
||||
host.checkWildcardForRenew();
|
||||
}
|
||||
}catch(error){
|
||||
console.error('checkWildcardForRenew', error)
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
@@ -265,6 +276,7 @@ class Host extends Table{
|
||||
let out = await super.remove(...args);
|
||||
await Host.buildLookUpObj();
|
||||
await this.bustCache(this.host);
|
||||
await deleteCert(this.host);
|
||||
|
||||
return out;
|
||||
} catch(error){
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
'use strict';
|
||||
const conf = require('@simpleworkjs/conf');
|
||||
const {setUpTable} = require('model-redis');
|
||||
|
||||
const Table = setUpTable(conf.redis);
|
||||
|
||||
const Table = require('../utils/redis_model');
|
||||
module.exports = Table;
|
||||
|
||||
require('./dns_provider');
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
'use strict';
|
||||
|
||||
const Table = require('../utils/redis_model');
|
||||
const Table = require('.');
|
||||
const bcrypt = require('bcrypt');
|
||||
const saltRounds = 10;
|
||||
|
||||
|
||||
Generated
+306
-421
File diff suppressed because it is too large
Load Diff
+3
-3
@@ -24,7 +24,7 @@
|
||||
"@popperjs/core": "^2.11.8",
|
||||
"@simpleworkjs/conf": "^1.0.0",
|
||||
"acme-client": "^5.4.0",
|
||||
"axios": "^1.13.2",
|
||||
"axios": "^1.13.5",
|
||||
"bcrypt": "^6.0.0",
|
||||
"bootstrap": "^5.3.8",
|
||||
"ejs": "^3.1.10",
|
||||
@@ -34,11 +34,11 @@
|
||||
"jquery": "^3.7.1",
|
||||
"ldapts": "^8.1.2",
|
||||
"linux-sys-user": "^1.2.0",
|
||||
"model-redis": "^0.4.0",
|
||||
"model-redis": "^1.4.0",
|
||||
"moment": "^2.30.1",
|
||||
"mustache": "^4.2.0",
|
||||
"p2psub": "^0.2.0",
|
||||
"redis": "^5.10.0",
|
||||
"redis": "^6.1.0",
|
||||
"socket.io": "^4.8.3",
|
||||
"tld-extract": "^2.1.0"
|
||||
},
|
||||
|
||||
@@ -25,8 +25,8 @@ frontEndModules.forEach(dep => {
|
||||
// local folder.
|
||||
router.use('/static', express.static(path.join(__dirname, '../public')))
|
||||
|
||||
router.get('/', async function(req, res, next) {
|
||||
res.render('hosts', {...values});
|
||||
router.get('/', (req, res) => {
|
||||
res.redirect(301, '/hosts');
|
||||
});
|
||||
|
||||
router.get('/hosts', async function(req, res, next) {
|
||||
|
||||
@@ -35,6 +35,16 @@ const socket = new SocketServerJson({
|
||||
// If we don't have a match, return empty object
|
||||
if(!parentHost) return clientSocket.write(JSON.stringify({}));
|
||||
|
||||
// A wildcard host with matchAny disabled only serves subdomains that
|
||||
// are explicitly defined in redis. Reaching this service means redis
|
||||
// had no direct entry for the requested domain, so an inexact match
|
||||
// here (the request isn't the wildcard host itself) is an undefined
|
||||
// subdomain and must not be routed to the wildcard parent.
|
||||
if(parentHost.is_wildcard && !parentHost.wildcard_matchAny
|
||||
&& parentHost.host !== data['domain']){
|
||||
return clientSocket.write(JSON.stringify({}));
|
||||
}
|
||||
|
||||
// If the matched host belongs to a wildcard domain, set wildcard_parent
|
||||
// This allows child domains to use the parent's wildcard SSL certificate
|
||||
if(!parentHost.wildcard_parent){
|
||||
|
||||
@@ -1,32 +1,39 @@
|
||||
'use strict';
|
||||
|
||||
const conf = require('@simpleworkjs/conf');
|
||||
const {Host} = require('../models/host');
|
||||
|
||||
/**
|
||||
* Host Scheduler Service
|
||||
*
|
||||
* Manages scheduled tasks for host-related operations:
|
||||
* - Wildcard SSL certificate renewal checks
|
||||
*
|
||||
* Schedule:
|
||||
* - Initial check: 30 seconds after application starts
|
||||
* - Recurring checks: Every 24 hours (86400000ms)
|
||||
*
|
||||
* The checkWildcardForRenew method:
|
||||
* - Iterates through all hosts in the system
|
||||
* - Checks if wildcard certificates are expiring within 30 days
|
||||
* - Automatically renews certificates that are approaching expiration
|
||||
*/
|
||||
|
||||
// Initial wildcard cert check 30 seconds after app starts
|
||||
// Delay allows the system to fully initialize before checking certs
|
||||
setTimeout(Host.checkWildcardForRenew, 30000);
|
||||
function hostSchedulerService(){
|
||||
/**
|
||||
* Host Scheduler Service
|
||||
*
|
||||
* Manages scheduled tasks for host-related operations:
|
||||
* - Wildcard SSL certificate renewal checks
|
||||
*
|
||||
* Schedule:
|
||||
* - Initial check: 30 seconds after application starts
|
||||
* - Recurring checks: Every 24 hours (86400000ms)
|
||||
*
|
||||
* The checkWildcardForRenew method:
|
||||
* - Iterates through all hosts in the system
|
||||
* - Checks if wildcard certificates are expiring within 30 days
|
||||
* - Automatically renews certificates that are approaching expiration
|
||||
*/
|
||||
|
||||
// Check wildcard certs once every 24 hours
|
||||
// Ensures certificates are renewed well before expiration
|
||||
setInterval(Host.checkWildcardForRenew, 86400000);
|
||||
// Initial wildcard cert check 30 seconds after app starts
|
||||
// Delay allows the system to fully initialize before checking certs
|
||||
setTimeout(Host.checkWildcardForRenew.bind(Host), conf.service.hostScheduler.initial);
|
||||
|
||||
// Check wildcard certs once every 24 hours
|
||||
// Ensures certificates are renewed well before expiration
|
||||
setInterval(Host.checkWildcardForRenew.bind(Host), conf.service.hostScheduler.interval);
|
||||
|
||||
console.log('Host scheduler service initialized');
|
||||
console.log('- Wildcard cert check: 30s after start, then every 24h');
|
||||
}
|
||||
|
||||
if(conf.service.hostScheduler.enabled !== false) hostSchedulerService();
|
||||
|
||||
console.log('Host scheduler service initialized');
|
||||
console.log('- Wildcard cert check: 30s after start, then every 24h');
|
||||
|
||||
module.exports = {};
|
||||
|
||||
@@ -1,55 +1,91 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* PubSub controller dependency to handle message broadcasting
|
||||
*/
|
||||
const ps = require('../controller/pubsub');
|
||||
|
||||
|
||||
function ModelPs(model){
|
||||
const Model = model.constructor.name === 'Function' ? model : model.constructor
|
||||
/**
|
||||
* Wraps a model in a Proxy to automatically publish events on specific method calls.
|
||||
* @param {Object|Function} model - The data model or instance to be proxied.
|
||||
* @returns {Proxy} - The proxied model.
|
||||
*/
|
||||
function ModelPs(model) {
|
||||
// Ensure we have a reference to the class constructor regardless of whether an instance or class was passed
|
||||
const Model = model.constructor.name === 'Function' ? model : model.constructor;
|
||||
|
||||
function getIndex(req, res){
|
||||
if(model[Model._key]) return model[Model._key];
|
||||
if(req && req[Model._key]) return req[Model._key];
|
||||
if(res && res[Model._key]) return res[Model._key];
|
||||
/**
|
||||
* Extracts the unique identifier (primary key) from the model or request/response objects.
|
||||
*/
|
||||
function getIndex(req, res) {
|
||||
if (model[Model._key]) return model[Model._key];
|
||||
if (req && req[Model._key]) return req[Model._key];
|
||||
if (res && res[Model._key]) return res[Model._key];
|
||||
}
|
||||
|
||||
function publish(prop, res, req){
|
||||
try{
|
||||
if(!['add', 'create', 'update', 'remove'].includes(prop)) return;
|
||||
/**
|
||||
* Formats and broadcasts the message via PubSub.
|
||||
* Topic format: model:ClassName:Action:ID
|
||||
*/
|
||||
function publish(prop, res, req) {
|
||||
try {
|
||||
// Only trigger for specific mutation keywords
|
||||
if (!['add', 'create', 'update', 'remove'].includes(prop)) return;
|
||||
|
||||
ps.publish(`model:${Model.name}:${prop}:${getIndex(res, req)}`, res);
|
||||
}catch(error){
|
||||
console.log('ModelPs.publish ERROR', error)
|
||||
} catch (error) {
|
||||
console.log('ModelPs.publish ERROR', error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Standardized error logger that ignores common/non-critical HTTP errors
|
||||
*/
|
||||
function handleError(error, model, propKey) {
|
||||
if (![401, 404, 429].includes(error.status)) {
|
||||
console.error("Error PS", model.name, propKey, error);
|
||||
}
|
||||
}
|
||||
|
||||
return new Proxy(model, {
|
||||
/**
|
||||
* Intercepts 'new' keyword calls to ensure instances are also proxied.
|
||||
*/
|
||||
construct(target, args, newTarget) {
|
||||
return ModelPs(Reflect.construct(target, args, newTarget))
|
||||
return ModelPs(Reflect.construct(target, args, newTarget));
|
||||
},
|
||||
get(target, propKey, receiver) {
|
||||
if(propKey == 'constructor') return target.constructor;
|
||||
const targetValue = Reflect.get(target, propKey, receiver);
|
||||
if (typeof targetValue === 'function') {
|
||||
return function(...args){
|
||||
try{
|
||||
// let res = targetValue.apply(this, args); // (A)
|
||||
var res = Reflect.apply(targetValue, this, args);
|
||||
if(targetValue.constructor.name === 'AsyncFunction'){
|
||||
res.then(function(res){
|
||||
publish(propKey, res, ...args);
|
||||
}).catch(function(error){
|
||||
|
||||
// console.error("Error PS", model.name, propKey, error)
|
||||
console.log('toDo, publish errors...');
|
||||
});
|
||||
}else{
|
||||
/**
|
||||
* Intercepts property/method access.
|
||||
*/
|
||||
get(target, propKey, receiver) {
|
||||
// Ensure constructor access remains direct
|
||||
if (propKey == 'constructor') return target.constructor;
|
||||
|
||||
const targetValue = Reflect.get(target, propKey, receiver);
|
||||
|
||||
// If the property accessed is a function, wrap it to inject the PubSub logic
|
||||
if (typeof targetValue === 'function') {
|
||||
return function(...args) {
|
||||
try {
|
||||
// Execute the original method
|
||||
var res = Reflect.apply(targetValue, this, args);
|
||||
|
||||
// Handle Asynchronous results (Promises)
|
||||
if (targetValue.constructor.name === 'AsyncFunction') {
|
||||
res.then(function(res) {
|
||||
publish(propKey, res, ...args);
|
||||
}).catch((error) => handleError(error, model, propKey));
|
||||
|
||||
} else {
|
||||
// Handle Synchronous results
|
||||
publish(propKey, res, ...args);
|
||||
}
|
||||
return res;
|
||||
}catch(error){
|
||||
// console.error("Error PS", model.name, propKey, error)
|
||||
console.log("toDo, publish errors...");
|
||||
} catch (error) {
|
||||
handleError(error, model, propKey);
|
||||
}
|
||||
}
|
||||
};
|
||||
} else {
|
||||
return targetValue;
|
||||
}
|
||||
@@ -57,4 +93,4 @@ function ModelPs(model){
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = ModelPs;
|
||||
module.exports = ModelPs;
|
||||
@@ -1,112 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
const process_type = {
|
||||
number: function(key, value){
|
||||
if(key.min && value < key.min) return `is to small, min ${key.min}.`
|
||||
if(key.max && value > key.max) return `is to large, max ${key.max}.`
|
||||
},
|
||||
string: function(key, value){
|
||||
if(key.min && value.length < key.min) return `is too short, min ${key.min}.`
|
||||
if(key.max && value.length > key.max) return `is too short, max ${key.max}.`
|
||||
},
|
||||
}
|
||||
|
||||
function returnOrCall(value){
|
||||
return typeof(value) === 'function' ? value() : value;
|
||||
}
|
||||
|
||||
function processKeys(map, data, partial){
|
||||
let errors = [];
|
||||
let out = {};
|
||||
|
||||
for(let key of Object.keys(map)){
|
||||
|
||||
// Do not require "isRequired" fields for partial validation, useful for
|
||||
// updates.
|
||||
if(!map[key].always && partial && !data.hasOwnProperty(key)) continue;
|
||||
|
||||
// Make sure required keys are present
|
||||
if(!partial && map[key].isRequired && !data.hasOwnProperty(key)){
|
||||
errors.push({key, message:`${key} is required.`});
|
||||
continue;
|
||||
}
|
||||
|
||||
// Remove undefined keys unless they have a default option or are a
|
||||
// relation
|
||||
if(data[key] === undefined){
|
||||
if(!map[key].default){
|
||||
if(map[key].model && !map[key].type) continue;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Check the type of the key
|
||||
if(data.hasOwnProperty(key) && map[key].type && typeof(data[key]) !== map[key].type){
|
||||
errors.push({key, message:`${key} is not ${map[key].type} type.`});
|
||||
continue;
|
||||
}
|
||||
|
||||
// Add the key to the process object to be returned and set any default
|
||||
// if the key is blank
|
||||
out[key] = data.hasOwnProperty(key) && data[key] !== undefined ? data[key] : returnOrCall(map[key].default);
|
||||
|
||||
// Check for type specific validations, ie: string length
|
||||
if(data.hasOwnProperty(key) && process_type[map[key].type]){
|
||||
let typeError = process_type[map[key].type](map[key], data[key]);
|
||||
if(typeError){
|
||||
errors.push({key, message:`${key} ${typeError}`});
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check for errors, throw validation error if any
|
||||
if(errors.length !== 0){
|
||||
throw ObjectValidateError(errors);
|
||||
return {__errors__: errors};
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
function parseFromString(map, data){
|
||||
// Use the key maps data type to return string values to native
|
||||
let types = {
|
||||
boolean: function(value){ return value === 'false' ? false : true },
|
||||
number: Number,
|
||||
string: String,
|
||||
object: JSON.parse
|
||||
};
|
||||
|
||||
for(let key of Object.keys(data)){
|
||||
if(map[key] && map[key].type && data[key]){
|
||||
data[key] = types[map[key].type](data[key]);
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
function parseToString(data){
|
||||
let types = {
|
||||
object: JSON.stringify
|
||||
}
|
||||
|
||||
return (types[typeof(data)] || String)(data);
|
||||
}
|
||||
|
||||
function ObjectValidateError(keys, message){
|
||||
let error = new Error('ObjectValidateError')
|
||||
error.name = "ObjectValidateError"
|
||||
error.message = message || `Invalid Keys: ${message}`
|
||||
error.keys = (keys || {});
|
||||
error.status = 422;
|
||||
|
||||
return error
|
||||
}
|
||||
|
||||
ObjectValidateError.prototype = Error.prototype;
|
||||
|
||||
|
||||
module.exports = {processKeys, parseFromString, ObjectValidateError, parseToString};
|
||||
@@ -1,10 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
const {setUpTable} = require('model-redis');
|
||||
const conf = require('@simpleworkjs/conf');
|
||||
|
||||
const Table = setUpTable({
|
||||
prefix: conf.redis.prefix
|
||||
});
|
||||
|
||||
module.exports = Table;
|
||||
@@ -66,7 +66,7 @@
|
||||
$(document).ready(async function(){
|
||||
// Set the jq Templates
|
||||
$.scope.providerField.put = function(){};
|
||||
$.scope.DnsProvider.push(...(await app.api.get('/dns?detail=true')).results);
|
||||
$.scope.DnsProvider.push(...(await app.api.get('dns?detail=true')).results);
|
||||
|
||||
// Populate
|
||||
providerGet();
|
||||
|
||||
+25
-2
@@ -86,7 +86,7 @@
|
||||
$('tr.jq-repeat-hosts').each(function(idx, el){
|
||||
$(el).removeClass('table-warning');
|
||||
});
|
||||
$.scope.editHost.remove();
|
||||
$.scope.editHost.remove(0);
|
||||
}
|
||||
|
||||
function hostEditOpen(btn, host){
|
||||
@@ -99,6 +99,8 @@
|
||||
|
||||
if(host.is_wildcard){
|
||||
$('.hostEditPanel [name="host"]').attr('disabled', true);
|
||||
// Allow toggling the wildcard matching mode when editing a wildcard host.
|
||||
$('.hostEditPanel #wildcard_matchAny-container').removeClass('challengeType-container');
|
||||
}
|
||||
|
||||
$.each(host, function( key, value ) { if(typeof value == "boolean"){
|
||||
@@ -173,6 +175,7 @@
|
||||
// Reset the allowed types on start
|
||||
$('#challengeType-child-container').addClass('challengeType-container');
|
||||
$('#challengeType-DNS-01-wildcard-container').addClass('challengeType-container');
|
||||
$('#wildcard_matchAny-container').addClass('challengeType-container');
|
||||
|
||||
let host = $hostField.val();
|
||||
|
||||
@@ -180,6 +183,8 @@
|
||||
// provider.
|
||||
if(host.startsWith("*.") && await verifyWildcardRequirements(host)){
|
||||
$('#challengeType-DNS-01-wildcard-container').removeClass('challengeType-container');
|
||||
// Wildcard matching mode only applies to wildcard hosts.
|
||||
$('#wildcard_matchAny-container').removeClass('challengeType-container');
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -274,7 +279,7 @@
|
||||
</div>
|
||||
|
||||
<div class="card-body">
|
||||
<form class="addHost" method="PUT" action="/host/{{ host }}" onsubmit="formAJAX(this)" evalAJAX="hostEditCancle()">
|
||||
<form class="addHost" method="PUT" action="host/{{ host }}" onsubmit="formAJAX(this)" evalAJAX="hostEditCancle()">
|
||||
{{{ form }}}
|
||||
<input type="hidden" name="edit_host" />
|
||||
<button type="submit" data-type="edit" class="btn btn-warning">
|
||||
@@ -363,6 +368,24 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group challengeType-container" id="wildcard_matchAny-container">
|
||||
<label class="form-label">
|
||||
Wildcard Matching
|
||||
</label>
|
||||
<div class="radio">
|
||||
<label>
|
||||
<input type="radio" name="wildcard_matchAny" id="wildcard_matchAny-false" value="false" checked>
|
||||
Match only subdomains defined here <b>Recommended</b>
|
||||
</label>
|
||||
</div>
|
||||
<div class="radio">
|
||||
<label>
|
||||
<input type="radio" name="wildcard_matchAny" id="wildcard_matchAny-true" value="true">
|
||||
Match any subdomain and proxy to this host
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3 form-group">
|
||||
<label for="ip" class="form-label">
|
||||
Target IP or Host Name
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
listen 443 ssl http2;
|
||||
listen 4443 ssl;
|
||||
|
||||
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_prefer_server_ciphers on;
|
||||
ssl_ciphers EECDH+CHACHA20:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5;
|
||||
ssl_ciphers EECDH+CHACHA20:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:!3DES:!MD5;
|
||||
|
||||
ssl_certificate_by_lua_block {
|
||||
auto_ssl:ssl_certificate()
|
||||
|
||||
@@ -37,6 +37,14 @@ function M.get(ngx, domain, targetInfo)
|
||||
local res, err = red:hgetall("proxy_Host_"..domain)
|
||||
res = red:array_to_hash(res)
|
||||
|
||||
-- Return the connection to the pool instead of closing it, so it can be
|
||||
-- reused by later requests. Without this a new connection is opened per
|
||||
-- request and never released, exhausting sockets under load.
|
||||
local ok, err = red:set_keepalive(10000, 100)
|
||||
if not ok then
|
||||
ngx.log(ngx.ERR, "failed to set redis keepalive: ", err)
|
||||
end
|
||||
|
||||
if not res["ip"] then
|
||||
if connect("/var/run/proxy_lookup.socket") then
|
||||
local socket = require("socket.unix")()
|
||||
|
||||
Reference in New Issue
Block a user