fixed issue with redis models
This commit is contained in:
+20
-12
@@ -53,20 +53,28 @@ app.use('/api', require('./routes/api'));
|
||||
|
||||
// Catch 404 and forward to error handler. If none of the above routes are
|
||||
// used, this is what will be called.
|
||||
app.use(function(req, res, next) {
|
||||
var err = new Error('Not Found');
|
||||
err.message = 'Page not found'
|
||||
err.status = 404;
|
||||
next(err);
|
||||
app.use(async function(req, res, next) {
|
||||
try{
|
||||
var err = new Error('Not Found');
|
||||
err.message = 'Page not found'
|
||||
err.status = 404;
|
||||
next(err);
|
||||
}catch(error){
|
||||
console.log('app 404 catch error', error)
|
||||
}
|
||||
});
|
||||
|
||||
// Error handler. This is where `next()` will go on error
|
||||
app.use(function(err, req, res, next) {
|
||||
console.error(err.status || res.status, err.name, req.method, req.url);
|
||||
console.error(err.message);
|
||||
console.error(err.stack);
|
||||
console.error('=========================================');
|
||||
app.use(async function(err, req, res, next) {
|
||||
try{
|
||||
console.error(err.status || res.status, err.name, req.method, req.url);
|
||||
console.error(err.message);
|
||||
console.error(err.stack);
|
||||
console.error('=========================================');
|
||||
|
||||
res.status(err.status || 500);
|
||||
res.json({name: err.name, message: err.message});
|
||||
res.status(err.status || 500);
|
||||
res.json({name: err.name, message: err.message, keys: err.keys});
|
||||
}catch(error){
|
||||
console.log('error in the catch all error fn....', error);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -45,12 +45,4 @@ class Auth{
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Auth.logOut = async function(data){
|
||||
try{
|
||||
}catch(error){
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {Auth};
|
||||
|
||||
+101
-27
@@ -28,6 +28,7 @@ class Host extends Table{
|
||||
'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, default: 'Requesting'},
|
||||
'wildcard_parent': {isRequired: false, type: 'string', min: 3, max: 500},
|
||||
}
|
||||
|
||||
@@ -84,11 +85,11 @@ class Host extends Table{
|
||||
}
|
||||
}
|
||||
|
||||
static async add(data, ...args){
|
||||
static async create(data, ...args){
|
||||
try{
|
||||
let out = await super.create(data, ...args)
|
||||
await this.buildLookUpObj()
|
||||
if(out.is_wildcard) await out.createWildcardCert()
|
||||
let out = await super.create(data, ...args);
|
||||
await this.buildLookUpObj();
|
||||
if(out.is_wildcard) out.createWildcardCert();
|
||||
|
||||
return out;
|
||||
|
||||
@@ -100,31 +101,104 @@ class Host extends Table{
|
||||
async createWildcardCert(){
|
||||
if(!this.host.startsWith('*.')) throw new Error('not wild card');
|
||||
|
||||
let cert = await letsEncrypt.dnsWildcard(this.host, {
|
||||
challengeCreateFn: async (authz, challenge, keyAuthorization) => {
|
||||
let parts = tldExtract(authz.identifier.value);
|
||||
let res = await porkBun.createRecordForce(parts.domain, {type:'TXT', name: `_acme-challenge${parts.sub ? `.${parts.sub}` : ''}`, content: `${keyAuthorization}`});
|
||||
},
|
||||
challengeRemoveFn: async (authz, challenge, keyAuthorization)=>{
|
||||
let parts = tldExtract(authz.identifier.value);
|
||||
await porkBun.deleteRecords(parts.domain, {type:'TXT', name: `_acme-challenge${parts.sub ? `.${parts.sub}` : ''}`, content: `${keyAuthorization}`});
|
||||
},
|
||||
});
|
||||
try{
|
||||
let host = this;
|
||||
let cert = await letsEncrypt.dnsWildcard(this.host, {
|
||||
challengeCreateFn: async (authz, challenge, keyAuthorization) => {
|
||||
host.update({
|
||||
wildcard_status: `Adding record for ${authz.identifier.value}`
|
||||
});
|
||||
try{
|
||||
let parts = tldExtract(authz.identifier.value);
|
||||
|
||||
let toAdd = {
|
||||
cert_pem: cert.cert.split('\n\n')[0],
|
||||
fullchain_pem: cert.cert,
|
||||
privkey_pem: cert.key.toString(),
|
||||
csr_pem: cert.csr.toString(),
|
||||
expiry: 4120307657,
|
||||
real_expiry: +LetsEncrypt.AcmeClient.crypto.readCertificateInfo(cert.cert).notAfter/1000,
|
||||
console.log('adding DNS record for', `_acme-challenge${parts.sub ? `.${parts.sub}` : ''}`)
|
||||
|
||||
let res = await porkBun.createRecordForce(
|
||||
parts.domain,
|
||||
{
|
||||
type:'TXT',
|
||||
name: `_acme-challenge${parts.sub ? `.${parts.sub}` : ''}`,
|
||||
content: `${keyAuthorization}`
|
||||
}
|
||||
);
|
||||
console.log('porkbun res', res)
|
||||
}catch(error){
|
||||
console.log('model Host challengeCreateFn error:', error)
|
||||
host.update({
|
||||
wildcard_status: `Add DNS record failed`
|
||||
});
|
||||
}
|
||||
},
|
||||
onDnsCheck: async(authz, checkCount)=>{
|
||||
host.update({
|
||||
wildcard_status: `${checkCount} Checking DNS for ${authz.identifier.value}`
|
||||
});
|
||||
},
|
||||
onDnsCheckFail: async(authz, error)=>{
|
||||
host.update({
|
||||
wildcard_status: `DNS check failed for ${authz.identifier.value}`
|
||||
});
|
||||
},
|
||||
onDnsCheckFound: async(authz)=>{
|
||||
host.update({
|
||||
wildcard_status: `DNS check found for ${authz.identifier.value}`
|
||||
});
|
||||
},
|
||||
onDnsCheckSuccess: async(authz)=>{
|
||||
host.update({
|
||||
wildcard_status: `DNS check success for ${authz.identifier.value}`
|
||||
})
|
||||
},
|
||||
onDnsCheckRemove: async(authz)=>{
|
||||
host.update({
|
||||
wildcard_status: `DNS remove record for ${authz.identifier.value}`
|
||||
})
|
||||
},
|
||||
challengeRemoveFn: async (authz, challenge, keyAuthorization)=>{
|
||||
host.update({
|
||||
wildcard_status: `DNS remove record for ${authz.identifier.value}`
|
||||
})
|
||||
try{
|
||||
// let parts = tldExtract(authz.identifier.value);
|
||||
// await porkBun.deleteRecords(
|
||||
// parts.domain,
|
||||
// {
|
||||
// type:'TXT',
|
||||
// name: `_acme-challenge${parts.sub ? `.${parts.sub}` : ''
|
||||
// }`,
|
||||
// content: `${keyAuthorization}`}
|
||||
// );
|
||||
|
||||
}catch(error){
|
||||
host.update({
|
||||
wildcard_status: `DNS remove record failed for ${authz.identifier.value}`
|
||||
})
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
let toAdd = {
|
||||
cert_pem: cert.cert.split('\n\n')[0],
|
||||
fullchain_pem: cert.cert,
|
||||
privkey_pem: cert.key.toString(),
|
||||
csr_pem: cert.csr.toString(),
|
||||
expiry: 4120307657,
|
||||
real_expiry: +LetsEncrypt.AcmeClient.crypto.readCertificateInfo(cert.cert).notAfter/1000,
|
||||
}
|
||||
|
||||
|
||||
await this.constructor.redisClient.SET(`${this.host}:latest`, JSON.stringify(toAdd));
|
||||
this.update({
|
||||
wildcard_status: `Done`
|
||||
});
|
||||
|
||||
return this;
|
||||
}catch(error){
|
||||
console.log('le failed', error)
|
||||
this.update({
|
||||
wildcard_status: `LE failed`
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
await this.constructor.redisClient.SET(`${this.host}:latest`, JSON.stringify(toAdd));
|
||||
return toAdd;
|
||||
|
||||
// Get new wildcard cert from
|
||||
}
|
||||
|
||||
async update(...args){
|
||||
|
||||
@@ -37,7 +37,7 @@ class AuthToken extends Token{
|
||||
return await User.get(this.created_by);
|
||||
}
|
||||
|
||||
static async add(data){
|
||||
static async create(data){
|
||||
data.created_by = data.username;
|
||||
return super.create(data)
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
'use strict';
|
||||
|
||||
const Table = require('../utils/redis_model');
|
||||
// const {Token, InviteToken} = require('./token');
|
||||
const bcrypt = require('bcrypt');
|
||||
const saltRounds = 10;
|
||||
|
||||
@@ -19,9 +18,11 @@ class User extends Table{
|
||||
|
||||
static backing = 'redis'
|
||||
|
||||
static async add(data) {
|
||||
static async create(data) {
|
||||
try{
|
||||
console.log('hash?')
|
||||
data['password'] = await bcrypt.hash(data['password'], saltRounds);
|
||||
console.log('hashed password', data.password);
|
||||
data['backing'] = data['backing'] || 'redis';
|
||||
|
||||
|
||||
@@ -32,31 +33,6 @@ class User extends Table{
|
||||
}
|
||||
}
|
||||
|
||||
/* static async addByInvite(data){
|
||||
try{
|
||||
let token = await InviteToken.get(data.token);
|
||||
|
||||
if(!token.is_valid){
|
||||
let error = new Error('Token Invalid');
|
||||
error.name = 'Token Invalid';
|
||||
error.message = `Token is not valid or as allready been used. ${data.token}`;
|
||||
error.status = 401;
|
||||
throw error;
|
||||
}
|
||||
|
||||
let user = await this.create(data);
|
||||
|
||||
if(user){
|
||||
await token.consume({claimed_by: user.username});
|
||||
return user;
|
||||
}
|
||||
|
||||
}catch(error){
|
||||
throw error;
|
||||
}
|
||||
|
||||
};*/
|
||||
|
||||
async setPassword(data){
|
||||
try{
|
||||
data['password'] = await bcrypt.hash(data['password'], saltRounds);
|
||||
@@ -67,17 +43,6 @@ class User extends Table{
|
||||
}
|
||||
}
|
||||
|
||||
/* async invite(){
|
||||
try{
|
||||
let token = await InviteToken.create({created_by: this.username});
|
||||
|
||||
return token;
|
||||
|
||||
}catch(error){
|
||||
throw error;
|
||||
}
|
||||
}*/
|
||||
|
||||
static async login(data){
|
||||
try{
|
||||
|
||||
@@ -109,7 +74,7 @@ module.exports = {User};
|
||||
|
||||
|
||||
(async function(){
|
||||
var defaultUser = 'proxyadmin3'
|
||||
var defaultUser = 'proxyadmin2'
|
||||
try{
|
||||
let user = await User.get(defaultUser);
|
||||
}catch(error){
|
||||
@@ -117,7 +82,7 @@ module.exports = {User};
|
||||
let user = await User.create({
|
||||
username:defaultUser,
|
||||
password: defaultUser,
|
||||
created_by:defaultUser
|
||||
created_by: defaultUser
|
||||
});
|
||||
console.log(defaultUser, 'created', user);
|
||||
}catch(error){
|
||||
|
||||
Generated
+1
-1
@@ -15,7 +15,7 @@
|
||||
"bcrypt": "^5.1.1",
|
||||
"bootstrap": "^5.3.3",
|
||||
"ejs": "^3.1.10",
|
||||
"express": "^4.19.2",
|
||||
"express": "^4.18.2",
|
||||
"extend": "^3.0.2",
|
||||
"jquery": "^3.7.1",
|
||||
"ldapts": "^2.12.0",
|
||||
|
||||
+1
-1
@@ -18,7 +18,7 @@
|
||||
"bcrypt": "^5.1.1",
|
||||
"bootstrap": "^5.3.3",
|
||||
"ejs": "^3.1.10",
|
||||
"express": "^4.19.2",
|
||||
"express": "^4.18.2",
|
||||
"extend": "^3.0.2",
|
||||
"jquery": "^3.7.1",
|
||||
"ldapts": "^2.12.0",
|
||||
|
||||
@@ -252,10 +252,10 @@ app.user = (function(app){
|
||||
app.util = (function(app){
|
||||
|
||||
function getUrlParameter(name){
|
||||
name = name.replace(/[\[]/, '\\[').replace(/[\]]/, '\\]');
|
||||
var regex = new RegExp('[\\?&]' + name + '=([^&#]*)');
|
||||
var results = regex.exec(location.search);
|
||||
return results === null ? '' : decodeURIComponent(results[1].replace(/\+/g, ' '));
|
||||
name = name.replace(/[\[]/, '\\[').replace(/[\]]/, '\\]');
|
||||
var regex = new RegExp('[\\?&]' + name + '=([^&#]*)');
|
||||
var results = regex.exec(location.search);
|
||||
return results === null ? '' : decodeURIComponent(results[1].replace(/\+/g, ' '));
|
||||
};
|
||||
|
||||
function actionMessage(message, $target, type, callback){
|
||||
@@ -277,28 +277,38 @@ app.util = (function(app){
|
||||
})
|
||||
}else{
|
||||
if(type) $target.addClass('bg-' + type);
|
||||
message = '<span class="align-middle">' + message + '</span><button class="action-close btn btn-sm btn-outline-dark float-right"><i class="fa-solid fa-xmark"></i></button>'
|
||||
message = '<span class="align-middle">' + message + '</span><button class="action-close btn btn-sm btn-outline-dark float-end"><i class="fa-solid fa-xmark"></i></button>'
|
||||
$target.html(message).slideDown('fast');
|
||||
}
|
||||
setTimeout(callback,10)
|
||||
}
|
||||
|
||||
$.fn.serializeObject = function(){
|
||||
var
|
||||
arr = $(this).serializeArray(),
|
||||
obj = {};
|
||||
|
||||
for(var i = 0; i < arr.length; i++){
|
||||
if(obj[arr[i].name] === undefined) {
|
||||
obj[arr[i].name] = arr[i].value;
|
||||
} else {
|
||||
if(!(obj[arr[i].name] instanceof Array)) {
|
||||
obj[arr[i].name] = [obj[arr[i].name]];
|
||||
}
|
||||
obj[arr[i].name].push(arr[i].value);
|
||||
}
|
||||
}
|
||||
return obj;
|
||||
var
|
||||
arr = $(this).serializeArray(),
|
||||
obj = {};
|
||||
|
||||
for(var i = 0; i < arr.length; i++){
|
||||
if(obj[arr[i].name] === undefined) {
|
||||
if(!arr[i].value) continue;
|
||||
obj[arr[i].name] = arr[i].value;
|
||||
let type = $(this).parent().find(`[name="${arr[i].name}"]`).attr('type');
|
||||
if(['number', 'range'].includes(type)){
|
||||
obj[arr[i].name] = Number(arr[i].value);
|
||||
}
|
||||
|
||||
if(['radio'].includes(type) && ['true', 'false'].includes(arr[i].value)){
|
||||
obj[arr[i].name] = arr[i].value == 'true' ? true : false;
|
||||
}
|
||||
} else {
|
||||
if(!(obj[arr[i].name] instanceof Array)) {
|
||||
obj[arr[i].name] = [obj[arr[i].name]];
|
||||
}
|
||||
obj[arr[i].name].push(arr[i].value);
|
||||
}
|
||||
|
||||
}
|
||||
return obj;
|
||||
};
|
||||
|
||||
return {
|
||||
@@ -342,12 +352,12 @@ function formAJAX(btn, del){
|
||||
event.preventDefault(); // avoid to execute the actual submit of the form.
|
||||
var $form = $(btn).closest('[action]'); // gets the 'form' parent
|
||||
var formData = $form.find('[name]').serializeObject(); // builds query formDataing
|
||||
var method = $form.attr('method') || 'post';
|
||||
var method = ($form.attr('method') || 'post').toLowerCase();
|
||||
|
||||
// if( !$form.validate()){
|
||||
// app.util.actionMessage('Please fix the form errors.', $form, 'danger')
|
||||
// return false;
|
||||
// }
|
||||
if($form.validate && !$form.validate()){
|
||||
app.util.actionMessage('Please fix the form errors.', $form, 'danger')
|
||||
return false;
|
||||
}
|
||||
|
||||
app.util.actionMessage(
|
||||
'<div class="spinner-border" role="status"><span class="sr-only">Loading...</span></div>',
|
||||
@@ -357,9 +367,21 @@ function formAJAX(btn, del){
|
||||
|
||||
app.api[method]($form.attr('action'), formData, function(error, data){
|
||||
app.util.actionMessage(data.message, $form, error ? 'danger' : 'success'); //re-populate table
|
||||
$form.validateClear();
|
||||
if(!error){
|
||||
$form.trigger("reset");
|
||||
eval($form.attr('evalAJAX')); //gets JS to run after completion
|
||||
}else{
|
||||
console.log('formAJAX res error', error, data)
|
||||
if(data && data.name === 'ObjectValidateError'){
|
||||
app.util.actionMessage('Please fix the form errors', $form, 'danger'); //re-populate table
|
||||
}
|
||||
if(data && data.keys){
|
||||
console.log('form key errors', data.keys)
|
||||
for(let keyError of data.keys){
|
||||
$form.find(`[name=${keyError.key}]`).validateMessage(keyError.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ MIT license
|
||||
$.scope = {};
|
||||
}
|
||||
|
||||
var make = function( element ){
|
||||
var make = function(element){
|
||||
var result = [];
|
||||
|
||||
result.splice = function(inputValue, ...args){
|
||||
@@ -20,9 +20,9 @@ MIT license
|
||||
|
||||
var index;
|
||||
//if a string is submitted as the index, try to match it to index number
|
||||
if( typeof arguments[0] === 'string' ){
|
||||
if(typeof arguments[0] === 'string'){
|
||||
index = this.indexOf( arguments[0] );//set where to start
|
||||
if ( index === -1 ) {
|
||||
if (index === -1) {
|
||||
return [];
|
||||
}
|
||||
}else{
|
||||
@@ -109,6 +109,7 @@ MIT license
|
||||
//set and return new array
|
||||
return Array.prototype.splice.apply(this, toProto);
|
||||
};
|
||||
|
||||
result.push = function(){
|
||||
//add one or more objects to the array
|
||||
|
||||
@@ -123,19 +124,25 @@ MIT license
|
||||
//return new array length
|
||||
return this.length;
|
||||
};
|
||||
|
||||
result.pop = function(){
|
||||
//remove and return array element
|
||||
|
||||
return this.splice( -1, 1 )[0];
|
||||
};
|
||||
result.reverse = function() {
|
||||
var temp = this.splice( 0 );
|
||||
Array.prototype.reverse.apply( temp );
|
||||
|
||||
for( var i = 0; i < temp.length; i++ ){
|
||||
this.push( temp[i] );
|
||||
result.reverse = function() {
|
||||
let hold = [];
|
||||
for(let item of this){
|
||||
hold.push(item.__jq_$el.html())
|
||||
}
|
||||
|
||||
for(let idx in hold.reverse()){
|
||||
this[idx].__jq_$el.html(hold[idx]);
|
||||
}
|
||||
|
||||
Array.prototype.reverse.apply( this );
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
@@ -149,6 +156,10 @@ MIT license
|
||||
return this.splice( 0, 1 )[0];
|
||||
};
|
||||
|
||||
result.unshift = function(data){
|
||||
return this.splice(0,0, data)
|
||||
}
|
||||
|
||||
result.loop = function(){
|
||||
var temp = this[0];
|
||||
this.splice( 0,1 );
|
||||
@@ -156,13 +167,17 @@ MIT license
|
||||
|
||||
return temp;
|
||||
};
|
||||
|
||||
result.loopUp = function(){
|
||||
var temp = this[this.length-1];
|
||||
this.splice( -1, 1 );
|
||||
this.splice( 0, 0, temp );
|
||||
return temp;
|
||||
};
|
||||
|
||||
result.indexOf = function( key, value ){
|
||||
if(typeof key === 'number') return key;
|
||||
|
||||
if( typeof value !== 'string' ){
|
||||
value = arguments[0];
|
||||
key = this.__index;
|
||||
@@ -175,7 +190,8 @@ MIT license
|
||||
}
|
||||
return -1;
|
||||
};
|
||||
result.update = function( key, value, update ){
|
||||
|
||||
result.update = function(key, value, data){
|
||||
//set variables using sting for index
|
||||
|
||||
// If update is called with no index/key, assume its the 0
|
||||
@@ -186,24 +202,31 @@ MIT license
|
||||
return this.splice(0, 1, key);
|
||||
}
|
||||
|
||||
if( typeof value !== 'string' ){
|
||||
update = arguments[1];
|
||||
value = arguments[0];
|
||||
key = this.__index;
|
||||
if(typeof value !== 'string'){
|
||||
data = arguments[1];
|
||||
if(typeof key !== 'number'){
|
||||
value = arguments[0];
|
||||
key = this.__index;
|
||||
}
|
||||
}
|
||||
|
||||
var index = this.indexOf( key, value );
|
||||
|
||||
if(index === -1) {
|
||||
return [];
|
||||
}
|
||||
var object = $.extend( true, {}, this[index], update );
|
||||
|
||||
var $render = $(Mustache.render(this.__jqTemplate, object));
|
||||
$render.attr('jq-repeat-index', index);
|
||||
this[index].__jq_$el.replaceWith($render);
|
||||
this[index] = $.extend( true, this[index], data );
|
||||
|
||||
var $render = $(Mustache.render(this.__jqTemplate, this[index]));
|
||||
$render.attr('jq-repeat-index', index);
|
||||
|
||||
this.__update(this[index].__jq_$el, $render, this[index], this);
|
||||
this[index].__jq_$el = $render;
|
||||
this.__update(this[index].__jq_$el, this[index], this);
|
||||
};
|
||||
|
||||
result.getByKey = function(key, value){
|
||||
return this[this.indexOf(key, value)];
|
||||
}
|
||||
|
||||
result.__put = function($el, item, list){
|
||||
$el.show();
|
||||
@@ -213,8 +236,8 @@ MIT license
|
||||
$el.remove();
|
||||
};
|
||||
|
||||
result.__update = function($el, item, list){
|
||||
console.log('here', $el)
|
||||
result.__update = function($el, $render, item, list){
|
||||
$el.replaceWith($render);
|
||||
$el.show();
|
||||
};
|
||||
|
||||
|
||||
+53
-70
@@ -1,96 +1,79 @@
|
||||
( function( $ ) {
|
||||
var settings = {
|
||||
rule: {
|
||||
eq: function( value, options ) {
|
||||
var compare = $( '[name=' + options + ']' ).val();
|
||||
eq: function(value, options){
|
||||
var compare = $('[name=' + options + ']').val();
|
||||
|
||||
if ( value != compare ) {
|
||||
return "Miss-match";
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
form: {
|
||||
alertCount: false, //pop-up with error count
|
||||
alertCountMessage: " errors!"
|
||||
},
|
||||
|
||||
processValidation: function ( error_message, $input ) {
|
||||
if ( typeof error_message == 'undefined' || error_message == true ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$( '<b>' ).html( ' - ' + error_message ).appendTo( $input.siblings( 'label' ) );
|
||||
$input.parent().addClass("has-error");
|
||||
failedCount++;
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
var failedCount = 0;
|
||||
$.fn.validate = function(event) {
|
||||
// let thisSettings = $.extend(true, settings, settingsObj);
|
||||
let hasErrors = false;
|
||||
|
||||
function processRule( thisSettings, $input ) {
|
||||
var attr = $input.attr( 'validate' ).split( ':' ), //array of params
|
||||
requirement = attr[1],
|
||||
value = $input.val(), //link to input value
|
||||
rule = attr[0];
|
||||
if(this.is('[validate]')) return this.validateField(event);
|
||||
|
||||
$input.siblings( 'label' ).children( 'b' ).remove(); //removes old error
|
||||
$input.parent().removeClass( "has-error" ); //removes has-error class
|
||||
if(!this.attr('isValid')){
|
||||
console.log('adding reset event')
|
||||
this.on('reset', function(){
|
||||
$(this).attr('isValid', false);
|
||||
$(this).validateClear();
|
||||
})
|
||||
}
|
||||
|
||||
this.find('[validate]').each(function(){
|
||||
if(!$(this).validateField()) hasErrors = true;
|
||||
});
|
||||
|
||||
this.attr('isValid', !hasErrors);
|
||||
|
||||
if(hasErrors && event) event.preventDefault();
|
||||
|
||||
return !hasErrors;
|
||||
};
|
||||
|
||||
$.fn.validateClear = function(){
|
||||
$(this).find('input').each(function(){
|
||||
$(this).removeClass('is-invalid');
|
||||
$(this).removeClass('is-valid');
|
||||
})
|
||||
}
|
||||
|
||||
$.fn.validateField = function(){
|
||||
var attr = this.attr('validate').split(':'); //array of params
|
||||
var rule = attr[0];
|
||||
var options = attr[1];
|
||||
var value = this.val(); //link to input value
|
||||
var message;
|
||||
|
||||
//checks if field is required, and length
|
||||
if (isNaN(requirement) === false && requirement && value.length < requirement) {
|
||||
return thisSettings.processValidation( 'Must be ' + requirement + ' characters', $input );
|
||||
if(!isNaN(options) && value.length < options){
|
||||
message = `Must be ${options} characters`;
|
||||
}
|
||||
|
||||
//checks if empty to stop processing
|
||||
if ( isNaN( requirement ) === false && value.length === 0 ) {
|
||||
return;
|
||||
if(!isNaN(options) && value.length === 0) {
|
||||
}else if(rule in settings.rule){
|
||||
let message = settings.rule[rule].apply(this, [value, options]);
|
||||
}
|
||||
|
||||
if ( rule in thisSettings.rule ) {
|
||||
return thisSettings.processValidation( thisSettings.rule[rule].apply( this, [value, requirement] ), $input );
|
||||
}
|
||||
this.validateMessage(message)
|
||||
return !message;
|
||||
}
|
||||
|
||||
$.fn.validate = function( settingsObj, event ) {
|
||||
event = event || window.event;
|
||||
|
||||
failedCount = 0;
|
||||
var thisForm = false,
|
||||
thisSettings = $.extend( true, settings, settingsObj );
|
||||
|
||||
if ( this.is( '[validate]' ) ) {
|
||||
processRule( thisSettings, this );
|
||||
} else {
|
||||
thisForm = true;
|
||||
this.find( '[validate]' ).each( function () {
|
||||
if(!processRule( thisSettings, $( this ) )){
|
||||
// failedCount++;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
this.attr('isValid', !failedCount);
|
||||
if ( failedCount === 0 ) { //no errors
|
||||
return true;
|
||||
} else { //errors
|
||||
if ( thisForm ){
|
||||
if(thisSettings.form.alertCount){
|
||||
alert( failedCount + thisSettings.form.alertCountMessage );
|
||||
}
|
||||
/* if(event) event.returnValue = false;
|
||||
if(event) event.preventDefault();
|
||||
return false;
|
||||
|
||||
if(event.preventDefault) if(event)*/
|
||||
//event.returnValue = false;
|
||||
event.preventDefault();
|
||||
event.defaultPrevented;
|
||||
|
||||
}
|
||||
return false;
|
||||
$.fn.validateMessage = function(message){
|
||||
if(message && message !== true){
|
||||
this.closest('.form-group').find('b.invalid-feedback').html(message);
|
||||
this.addClass('is-invalid');
|
||||
}else{
|
||||
this.removeClass('is-invalid');
|
||||
this.addClass('is-valid');
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
jQuery.extend({
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
const router = require('express').Router();
|
||||
const { Auth } = require('../controller/auth');
|
||||
|
||||
|
||||
router.post('/login', async function(req, res, next){
|
||||
try{
|
||||
let auth = await Auth.login(req.body);
|
||||
|
||||
@@ -25,7 +25,7 @@ router.post('/', async function(req, res, next){
|
||||
...item,
|
||||
});
|
||||
} catch (error){
|
||||
return next(error);
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -40,4 +40,7 @@ router.get('/login', async function(req, res, next) {
|
||||
res.render('login', {...values, redirect: req.query.redirect});
|
||||
});
|
||||
|
||||
router.get('/test', async function(req, res, next) {
|
||||
res.render('test', {...values, redirect: req.query.redirect});
|
||||
});
|
||||
module.exports = router;
|
||||
|
||||
+45
-15
@@ -7,6 +7,11 @@ const sleep = require('./sleep');
|
||||
|
||||
// https://dns.google/resolve?name=${name}&type=TXT
|
||||
|
||||
AcmeClient.setLogger((message) => {
|
||||
console.log('ACME:', message);
|
||||
});
|
||||
|
||||
|
||||
class LetsEncrypt{
|
||||
static AcmeClient = AcmeClient;
|
||||
|
||||
@@ -43,32 +48,57 @@ class LetsEncrypt{
|
||||
|
||||
try{
|
||||
domain = domain.replace(/^\*\./, '');
|
||||
|
||||
const [key, csr] = await AcmeClient.crypto.createCsr({
|
||||
altNames: [domain, `*.${domain}`],
|
||||
});
|
||||
|
||||
let dnsToAdd = 0;
|
||||
let dnsFound = 0;
|
||||
|
||||
const cert = await this.client.auto({
|
||||
csr,
|
||||
email: 'wmantly@gmail.com',
|
||||
termsOfServiceAgreed: true,
|
||||
challengePriority: ['dns-01'],
|
||||
skipChallengeVerification: true,
|
||||
challengeCreateFn: async (authz, challenge, keyAuthorization) => {
|
||||
// console.log(`start TXT record key=_acme-challenge.${authz.identifier.value} value=${keyAuthorization}`)
|
||||
|
||||
let resCheck = await axios.get(`https://dns.google/resolve?name=_acme-challenge.${authz.identifier.value}&type=TXT`);
|
||||
if(resCheck.data.Answer.some(record => record.data === keyAuthorization)) return;
|
||||
|
||||
await options.challengeCreateFn(authz, challenge, keyAuthorization);
|
||||
|
||||
let checkCount = 0;
|
||||
while(true){
|
||||
await sleep(1500);
|
||||
let res = await axios.get(`https://dns.google/resolve?name=_acme-challenge.${authz.identifier.value}&type=TXT`);
|
||||
if(res.data.Answer.some(record => record.data === keyAuthorization)){
|
||||
// console.log(`found record for key=_acme-challenge.${authz.identifier.value} value=${keyAuthorization}`)
|
||||
break;
|
||||
try{
|
||||
console.log('challenge', challenge)
|
||||
console.log(`start TXT record key=_acme-challenge.${authz.identifier.value} value=${keyAuthorization} challenge=${challenge} googleDNS=https://dns.google/resolve?name=_acme-challenge.${authz.identifier.value}&type=TXT`)
|
||||
dnsToAdd++
|
||||
let resCheck = await axios.get(`https://dns.google/resolve?name=_acme-challenge.${authz.identifier.value}&type=TXT`);
|
||||
if(resCheck.data.Answer && resCheck.data.Answer.some(record => record.data === keyAuthorization)){
|
||||
await sleep(1000);
|
||||
dnsFound++
|
||||
if(dnsFound === dnsToAdd){
|
||||
options.onDnsCheckFound(authz, dnsFound)
|
||||
}
|
||||
return;
|
||||
}
|
||||
if(checkCount++ > 60) throw new Error('challengeCreateFn validation timed out');
|
||||
|
||||
await options.challengeCreateFn(authz, challenge, keyAuthorization);
|
||||
|
||||
let checkCount = 0;
|
||||
while(true){
|
||||
options.onDnsCheck(authz, checkCount);
|
||||
let res = await axios.get(`https://dns.google/resolve?name=_acme-challenge.${authz.identifier.value}&type=TXT`);
|
||||
// console.log(keyAuthorization, res.data);
|
||||
if(res.data.Answer && res.data.Answer.some(record => record.data === keyAuthorization)){
|
||||
dnsFound++
|
||||
if(dnsFound === dnsToAdd){
|
||||
options.onDnsCheckFound(authz, dnsFound)
|
||||
}
|
||||
// console.log(`found record for key=_acme-challenge.${authz.identifier.value} value=${keyAuthorization}`)
|
||||
await sleep(10000);
|
||||
break;
|
||||
}
|
||||
if(checkCount++ > 60) throw new Error('challengeCreateFn validation timed out');
|
||||
await sleep(1500);
|
||||
}
|
||||
}catch(error){
|
||||
console.log('dns check failed error:', error)
|
||||
options.onDnsCheckFail(authz, error)
|
||||
}
|
||||
},
|
||||
challengeRemoveFn: options.challengeRemoveFn,
|
||||
|
||||
@@ -12,9 +12,13 @@ function ModelPs(model){
|
||||
}
|
||||
|
||||
function publish(prop, res, req){
|
||||
if(!['add', 'create', 'update', 'remove'].includes(prop)) return;
|
||||
try{
|
||||
if(!['add', 'create', 'update', 'remove'].includes(prop)) return;
|
||||
|
||||
ps.publish(`model:${Model.name}:${prop}:${getIndex(res, req)}`, res);
|
||||
ps.publish(`model:${Model.name}:${prop}:${getIndex(res, req)}`, res);
|
||||
}catch(error){
|
||||
console.log('ModelPs.publish ERROR', error)
|
||||
}
|
||||
}
|
||||
|
||||
return new Proxy(model, {
|
||||
@@ -28,16 +32,22 @@ function ModelPs(model){
|
||||
const targetValue = Reflect.get(target, propKey, receiver);
|
||||
if (typeof targetValue === 'function') {
|
||||
return function(...args){
|
||||
try{
|
||||
// let res = targetValue.apply(this, args); // (A)
|
||||
let res = Reflect.apply(targetValue, this, args);
|
||||
if(targetValue.constructor.name === 'AsyncFunction'){
|
||||
res.then(function(res){
|
||||
publish(propKey, res, ...args);
|
||||
});
|
||||
}else{
|
||||
publish(propKey, res, ...args)
|
||||
var res = Reflect.apply(targetValue, this, args);
|
||||
if(targetValue.constructor.name === 'AsyncFunction'){
|
||||
res.then(function(res){
|
||||
publish(propKey, res, ...args);
|
||||
}).catch(function(error){
|
||||
console.log('toDo, publish errors...')
|
||||
});
|
||||
}else{
|
||||
publish(propKey, res, ...args)
|
||||
}
|
||||
return res;
|
||||
}catch(error){
|
||||
console.log("grrrr")
|
||||
}
|
||||
return res;
|
||||
}
|
||||
} else {
|
||||
return targetValue;
|
||||
|
||||
@@ -33,6 +33,8 @@ function processKeys(map, data, partial){
|
||||
continue;
|
||||
}
|
||||
|
||||
// console.log(key, data[key], map[key].default, data.hasOwnProperty(key) && data[key] !== undefined ? data[key] : returnOrCall(map[key].default))
|
||||
|
||||
out[key] = data.hasOwnProperty(key) && data[key] !== undefined ? data[key] : returnOrCall(map[key].default);
|
||||
|
||||
if(data.hasOwnProperty(key) && process_type[map[key].type]){
|
||||
@@ -46,7 +48,6 @@ function processKeys(map, data, partial){
|
||||
}
|
||||
|
||||
if(errors.length !== 0){
|
||||
console.log('errors', errors)
|
||||
throw new ObjectValidateError(errors);
|
||||
return {__errors__: errors};
|
||||
}
|
||||
@@ -79,9 +80,10 @@ function parseToString(data){
|
||||
return (types[typeof(data)] || String)(data);
|
||||
}
|
||||
|
||||
function ObjectValidateError(message) {
|
||||
function ObjectValidateError(message){
|
||||
this.name = 'ObjectValidateError';
|
||||
this.message = (message || {});
|
||||
this.keys = (message || {})
|
||||
this.status = 422;
|
||||
}
|
||||
|
||||
|
||||
+35
-11
@@ -47,17 +47,17 @@ class Table{
|
||||
}catch(error){
|
||||
throw error;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static async exists(index){
|
||||
try{
|
||||
await this.get(data);
|
||||
|
||||
return true;
|
||||
}catch(error){
|
||||
return false;
|
||||
if(typeof index === 'object'){
|
||||
index = index[this._key];
|
||||
}
|
||||
|
||||
return await client.SISMEMBER(
|
||||
redisPrefix(this.prototype.constructor.name),
|
||||
index
|
||||
);
|
||||
}
|
||||
|
||||
static async list(){
|
||||
@@ -86,6 +86,7 @@ class Table{
|
||||
static async create(data){
|
||||
// Add a entry to this redis table.
|
||||
try{
|
||||
|
||||
// Validate the passed data by the keyMap schema.
|
||||
data = objValidate.processKeys(this._keyMap, data);
|
||||
|
||||
@@ -94,6 +95,10 @@ class Table{
|
||||
let error = new Error('EntryNameUsed');
|
||||
error.name = 'EntryNameUsed';
|
||||
error.message = `${this.prototype.constructor.name}:${data[this._key]} already exists`;
|
||||
error.keys = [{
|
||||
key: this._key,
|
||||
message: `${this.prototype.constructor.name}:${data[this._key]} already exists`
|
||||
}]
|
||||
error.status = 409;
|
||||
|
||||
throw error;
|
||||
@@ -107,7 +112,7 @@ class Table{
|
||||
|
||||
// Add the values for this entry.
|
||||
for(let key of Object.keys(data)){
|
||||
if(!data[key]) continue;
|
||||
if(data[key] === undefined) continue;
|
||||
await client.HSET(
|
||||
redisPrefix(`${this.prototype.constructor.name}_${data[this._key]}`),
|
||||
key,
|
||||
@@ -125,9 +130,26 @@ class Table{
|
||||
async update(data, key){
|
||||
// Update an existing entry.
|
||||
try{
|
||||
// Validate the passed data, ignoring required fields.
|
||||
data = objValidate.processKeys(this.constructor._keyMap, data, true);
|
||||
|
||||
// Check to see if entry name changed.
|
||||
if(data[this.constructor._key] && data[this.constructor._key] !== this[this.constructor._key]){
|
||||
// Remove the index key from the tables members list.
|
||||
|
||||
if(data[this.constructor._key] && await this.constructor.exists(data)){
|
||||
let error = new Error('EntryNameUsed');
|
||||
error.name = 'EntryNameUsed';
|
||||
error.message = `${this.constructor.name}:${data[this.constructor._key]} already exists`;
|
||||
error.keys = [{
|
||||
key: this.constructor._key,
|
||||
message: `${this.constructor.name}:${data[this.constructor._key]} already exists`
|
||||
}]
|
||||
error.status = 409;
|
||||
|
||||
throw error;
|
||||
}
|
||||
|
||||
await client.SREM(
|
||||
redisPrefix(this.constructor.name),
|
||||
this[this.constructor._key]
|
||||
@@ -139,12 +161,14 @@ class Table{
|
||||
data[this.constructor._key]
|
||||
);
|
||||
|
||||
await client.RENAME(
|
||||
redisPrefix(`${this.constructor.name}_${this[this.constructor._key]}`),
|
||||
redisPrefix(`${this.constructor.name}_${data[this.constructor._key]}`),
|
||||
);
|
||||
|
||||
}
|
||||
// Update what ever fields that where passed.
|
||||
|
||||
// Validate the passed data, ignoring required fields.
|
||||
data = objValidate.processKeys(this.constructor._keyMap, data, true);
|
||||
|
||||
// Loop over the data fields and apply them to redis
|
||||
for(let key of Object.keys(data)){
|
||||
this[key] = data[key];
|
||||
|
||||
+100
-76
@@ -5,7 +5,7 @@
|
||||
</script>
|
||||
|
||||
<style type="text/css">
|
||||
label.control-label{
|
||||
label.form-label{
|
||||
font-weight: bold;
|
||||
margin-bottom: 1px;
|
||||
}
|
||||
@@ -14,7 +14,10 @@
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
div.editWindow{
|
||||
div.hostEditPanel{
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
div.form-group{
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
/* my Div class for my search bar */
|
||||
@@ -36,11 +39,13 @@
|
||||
</style>
|
||||
|
||||
<script type="text/javascript">
|
||||
var $editHostForm;
|
||||
|
||||
function parseHostRow(host) {
|
||||
host['updated_on_text'] = moment(host['updated_on'], "x").fromNow();
|
||||
host['targetssl_text'] = host['targetssl'] ? 'https://' : 'http://';
|
||||
host['forcessl_text'] = host['forcessl'] ? 'https://' : 'http://';
|
||||
host['wildcard_text'] = host['is_wildcard'] ? host['wildcard_status'] : 'Auto';
|
||||
|
||||
return host;
|
||||
}
|
||||
@@ -66,40 +71,34 @@
|
||||
$('#hostsTable').find('tr').each(function(idx, el){
|
||||
$(el).removeClass('table-warning');
|
||||
});
|
||||
$('.editWindow').slideUp('fast');
|
||||
$.scope.editHost.remove();
|
||||
}
|
||||
|
||||
function editHost(btn, host){
|
||||
cancleHostEdit();
|
||||
$(btn).closest('tr').addClass('table-warning');
|
||||
$('.editWindow .card-title').html("Edit "+ host);
|
||||
host = $.scope.hosts.getByKey(host);
|
||||
$.scope.editHost.update({...host, form: $editHostForm.html()});
|
||||
|
||||
$('div.editWindow .card-body span').html($('#addHost').html());
|
||||
$('div.editWindow .card-body span button').remove();
|
||||
|
||||
$(".editWindow input[name='edit_host']").val(host);
|
||||
|
||||
$('.editWindow').slideDown('fast');
|
||||
|
||||
app.host.get(host, function(error, data){
|
||||
$.each( data.results, function( key, value ) {
|
||||
if(typeof value == "boolean"){
|
||||
$(".editWindow #"+ key +"-"+ value).prop('checked', true)
|
||||
}else{
|
||||
$(".editWindow input[name='" + key + "']").val(value);
|
||||
}
|
||||
});
|
||||
$.each(host, function( key, value ) { if(typeof value == "boolean"){
|
||||
$(".hostEditPanel #"+ key +"-"+ value).prop('checked', true)
|
||||
}else{
|
||||
$(".hostEditPanel input[name='" + key + "']").val(value);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
function deleteHost(host){
|
||||
app.host.remove({host: host}, function(err, data){
|
||||
// app.util.actionMessage(`Host ${host} deleted!`, $.scope.hosts.$this, 'danger');
|
||||
$.scope.hosts.remove(host);
|
||||
app.host.remove({host: host}, function(error, data){
|
||||
if(error) app.util.actionMessage(error.message, $.scope.hosts.$this, 'danger');
|
||||
});
|
||||
}
|
||||
|
||||
$(document).ready(function(){
|
||||
$editHostForm = $('#addHost').clone();
|
||||
$editHostForm.find('hr.buttonBreak').nextAll().remove();
|
||||
// $editHostForm.find('.autoSll').addClass('bg-secondary');
|
||||
$editHostForm.find('[name=is_wildcard').attr('disabled', true);
|
||||
populateHosts(); //populate the table
|
||||
|
||||
$.scope.hosts.__setTake(function($el, item, list){
|
||||
@@ -109,6 +108,19 @@
|
||||
});
|
||||
});
|
||||
|
||||
$.scope.hosts.__setUpdate(function($el, $render, item, list){
|
||||
$render.show()
|
||||
$el.replaceWith($render);
|
||||
});
|
||||
|
||||
$.scope.editHost.__setPut(function($el, item, list){
|
||||
$el.slideDown();
|
||||
});
|
||||
|
||||
$.scope.editHost.__setTake(function($el, item, list){
|
||||
$el.slideUp();
|
||||
});
|
||||
|
||||
app.subscribe(/^model:Host/, function(data, topic){
|
||||
console.log(topic, data);
|
||||
});
|
||||
@@ -119,7 +131,7 @@
|
||||
if($.scope.hosts.indexOf(host) >= 0){
|
||||
$.scope.hosts.update(host, parseHostRow(data));
|
||||
}else{
|
||||
$.scope.hosts.splice(0,0, parseHostRow(data))
|
||||
$.scope.hosts.unshift(parseHostRow(data));
|
||||
}
|
||||
});
|
||||
|
||||
@@ -129,11 +141,10 @@
|
||||
if($.scope.hosts.indexOf(host) >= 0){
|
||||
$.scope.hosts.update(host, parseHostRow(data));
|
||||
}else{
|
||||
$.scope.hosts.splice(0,0, parseHostRow(data))
|
||||
$.scope.hosts.unshift(parseHostRow(data));
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
app.subscribe(/^model:Host:remove/, function(data, topic){
|
||||
let [a,b, action, host] = topic.split(':');
|
||||
|
||||
@@ -156,38 +167,6 @@
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$('form.addHost').on('submit', function(){
|
||||
event.preventDefault();
|
||||
|
||||
$form = $(this);
|
||||
var action = $($form.find('button[type="submit"]')[0]).data('type');
|
||||
app.util.actionMessage('', $form);
|
||||
|
||||
if($form.attr('isValid') === 'true'){
|
||||
var formdata = $form.serializeObject();
|
||||
if(formdata.targetPort) formdata.targetPort = Number(formdata.targetPort);
|
||||
if(formdata.targetssl) formdata.targetssl = formdata.targetssl == 'true' ? true : false;
|
||||
if(formdata.forcessl) formdata.forcessl = formdata.forcessl == 'true' ? true : false;
|
||||
|
||||
app.host[action](formdata, function(error, data){
|
||||
if(error){
|
||||
app.util.actionMessage(error + data.message, $form, 'danger');
|
||||
return;
|
||||
}
|
||||
|
||||
// if($.scope.hosts.indexOf(data.__requestedHost) >= 0){
|
||||
// $.scope.hosts.update(data.__requestedHost, parseHostRow(data));
|
||||
// }else{
|
||||
// // $.scope.hosts.splice(0,0, parseHostRow(data))
|
||||
// }
|
||||
|
||||
if(action == 'edit') $('.editWindow').slideUp('fast');
|
||||
|
||||
$form.trigger('reset');
|
||||
})
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<div class="row" style="display:none">
|
||||
@@ -195,7 +174,7 @@
|
||||
<!--
|
||||
left column
|
||||
-->
|
||||
<div class="card shadow-lg editWindow" style="display:none">
|
||||
<div jq-repeat="editHost" class="card shadow-lg border-warning hostEditPanel" style="display:none">
|
||||
<!--
|
||||
Edit host card
|
||||
-->
|
||||
@@ -204,6 +183,7 @@
|
||||
<i class="fa-solid fa-pencil"></i>
|
||||
</span>
|
||||
<span class="card-title">
|
||||
Edit {{ host }}
|
||||
</span>
|
||||
<span class="float-end">
|
||||
<i class="fa-solid fa-circle-minus"></i>
|
||||
@@ -212,8 +192,8 @@
|
||||
</div>
|
||||
|
||||
<div class="card-body">
|
||||
<form class="addHost" onsubmit="$(this).validate()">
|
||||
<span></span>
|
||||
<form class="addHost" method="PUT" action="/host/{{ host }}" onsubmit="formAJAX(this)" evalAJAX="cancleHostEdit()">
|
||||
{{{ form }}}
|
||||
<input type="hidden" name="edit_host" />
|
||||
<button type="submit" data-type="edit" class="btn btn-warning">
|
||||
<i class="fa-solid fa-pencil"></i>
|
||||
@@ -227,7 +207,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card shadow-lg">
|
||||
<div class="card shadow-lg hostAddPanel">
|
||||
<!--
|
||||
Add new host card
|
||||
-->
|
||||
@@ -246,10 +226,13 @@
|
||||
<div class="card-header actionMessage" style="display:none"></div>
|
||||
|
||||
<div class="card-body">
|
||||
<form class="addHost" id="addHost" onsubmit="$(this).validate()">
|
||||
|
||||
<form class="addHost" id="addHost" method="POST" action="host" onsubmit="formAJAX(this)">
|
||||
|
||||
<div class="form-group">
|
||||
<label class="control-label">Incoming SSL</label>
|
||||
<label class="form-label">
|
||||
Incoming SSL
|
||||
</label>
|
||||
<br />
|
||||
<div class="radio">
|
||||
<label>
|
||||
<input type="radio" name="forcessl" id="forcessl-true" value="true" checked>
|
||||
@@ -264,23 +247,54 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="control-label">Incoming Host Name</label>
|
||||
<input type="text" name="host" class="form-control" placeholder="ex: proxy.cloud-ops.net" validate=":3" >
|
||||
<div class="form-group autoSll">
|
||||
<label class="form-label">
|
||||
Auto SSL
|
||||
</label>
|
||||
<div class="radio">
|
||||
<label>
|
||||
<input type="radio" name="is_wildcard" id="is_wildcard-false" value="false" checked>
|
||||
On demand certs
|
||||
</label>
|
||||
</div>
|
||||
<div class="radio">
|
||||
<label>
|
||||
<input type="radio" name="is_wildcard" id="is_wildcard-true" value="true">
|
||||
Request Wildcard cert
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="control-label">Target IP or Host Name</label>
|
||||
<label for='host' class="form-label">
|
||||
Incoming Host Name
|
||||
</label>
|
||||
<div>
|
||||
<input type="text" name="host" class="form-control" placeholder="ex: proxy.cloud-ops.net" validate=":3" >
|
||||
<b class="invalid-feedback"></b>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3 form-group">
|
||||
<label for="ip" class="form-label">
|
||||
Target IP or Host Name
|
||||
</label>
|
||||
<input type="text" name="ip" class="form-control" placeholder="ex: 10.10.10.10" validate=":3" />
|
||||
<b class="invalid-feedback"></b>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="control-label">Target TCP Port</label>
|
||||
<label for="targetPort" class="form-label">
|
||||
Target TCP Port
|
||||
</label>
|
||||
<input type="number" name="targetPort" class="form-control" value="80" min="0" max="65535" />
|
||||
<b class="invalid-feedback"></b>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="control-label">Target SSL</label>
|
||||
<label class="form-label">
|
||||
Target SSL
|
||||
</label>
|
||||
<div class="radio">
|
||||
<label>
|
||||
<input type="radio" name="targetssl" id="targetssl-true" value="true">
|
||||
@@ -293,9 +307,10 @@
|
||||
Proxy to HTTP <b>Recommended</b>
|
||||
</label>
|
||||
</div>
|
||||
<b class="invalid-feedback"></b>
|
||||
</div>
|
||||
<hr />
|
||||
<button type="submit" data-type="add" class="btn btn-success">
|
||||
<hr class="buttonBreak" />
|
||||
<button type="submit" class="btn btn-success">
|
||||
<i class="fa-solid fa-plus"></i>
|
||||
Add
|
||||
</button>
|
||||
@@ -308,7 +323,7 @@
|
||||
<!--
|
||||
Right column
|
||||
-->
|
||||
<div class="card shadow-lg">
|
||||
<div class="card shadow-lg hostListPanel">
|
||||
<!--
|
||||
List current hosts
|
||||
-->
|
||||
@@ -326,12 +341,17 @@
|
||||
|
||||
<div class="card-header actionMessage" style="display:none"></div>
|
||||
<div class="card-body search-wrapper">
|
||||
<label class="control-label" for="search" style="margin-left: -5px;">Search Hosts: </label>
|
||||
<label class="form-label" for="search" style="margin-left: -5px;">
|
||||
Search Hosts:
|
||||
</label>
|
||||
<input type="search" id="search" host-search>
|
||||
</div>
|
||||
<table class="card-body table table-striped" style="margin-bottom:0">
|
||||
|
||||
<thead>
|
||||
<th>
|
||||
SSL
|
||||
</th>
|
||||
<th>
|
||||
Host Name
|
||||
</th>
|
||||
@@ -347,6 +367,9 @@
|
||||
</thead>
|
||||
<tbody id="hostsTable">
|
||||
<tr action="api" jq-repeat="hosts" jq-repeat-index='host' style="display:none">
|
||||
<td>
|
||||
{{{ wildcard_text }}}
|
||||
</td>
|
||||
<td>
|
||||
<a target="_blank" href="{{ forcessl_text }}{{ host }}">
|
||||
{{{ forcessl_text }}}{{ host }}
|
||||
@@ -360,12 +383,13 @@
|
||||
</td>
|
||||
<td>
|
||||
<div class="btn-group">
|
||||
<!-- <button type="button" class="btn btn-info">
|
||||
<!-- <button type="button" class="btn btn-info">
|
||||
<i class="fa-brands fa-expeditedssl"></i>
|
||||
Cert
|
||||
</button> -->
|
||||
<button type="button" onclick="editHost(this, '{{ host }}');" class="btn btn-sm btn-warning">
|
||||
<i class="fa-solid fa-pencil"></i> Edit
|
||||
<i class="fa-solid fa-pencil"></i>
|
||||
Edit
|
||||
</button>
|
||||
<button type="button" onclick="deleteHost('{{ host }}')" class="btn btn-sm btn-danger">
|
||||
<i class="fa-solid fa-trash-can"></i>
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<!-- need to load jq-query cdn or file. -->
|
||||
<script src="https://code.jquery.com/jquery-3.7.1.min.js"
|
||||
integrity="sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo=" crossorigin="anonymous"></script>
|
||||
|
||||
<!-- need to load mustache cdn or file. -->
|
||||
<script src="
|
||||
https://cdn.jsdelivr.net/npm/mustache@4.2.0/mustache.min.js
|
||||
"></script>
|
||||
|
||||
<!-- need to load jq-repeat cdn or file -->
|
||||
<script type="text/javascript" src='/static/lib/js/jq-repeat_new.js'></script>
|
||||
<script>
|
||||
//on document ready. the logic would execute.
|
||||
$(document).ready(function () {
|
||||
$.scope.toDo.__setPut(function($el, item, list){
|
||||
$el.slideDown('slow');
|
||||
})
|
||||
|
||||
// $.scope.toDo.__setUpdate(function($el, $render, item, list){
|
||||
// $el.fadeOut(2000, function() {
|
||||
// $(this).html($render.html()).fadeIn(2000);
|
||||
// });
|
||||
// });
|
||||
|
||||
// $.scope.toDo.__setUpdate(function($el, $render, item, list){
|
||||
// $el.animate({'opacity': 0}, 400, function(){
|
||||
// $(this).html($render.html()).animate({'opacity': 1}, 400);
|
||||
// });
|
||||
// });
|
||||
|
||||
$.scope.toDo.__setUpdate(function($el, $render, item, list){
|
||||
$el.slideUp(function(){
|
||||
$(this).replaceWith($render)
|
||||
$render.slideDown()
|
||||
})
|
||||
});
|
||||
|
||||
|
||||
$.scope.toDo.push({ item: "Get milk", done: "Yes" }); // 0
|
||||
$.scope.toDo.push({ item: "Do laundry", done: "No" }); // 1
|
||||
//should take array id or array key
|
||||
|
||||
// - **howMany** _Type: Number_
|
||||
// Number of repeat objects that will be removed. If there are non to be removed, it is not required to use this argument.
|
||||
// - **update** _Type: Array_
|
||||
// This is the array of repeat objects to add. If there are none to this is not required.
|
||||
|
||||
//remove works
|
||||
// $.scope.toDo.splice("Get milk" , "1")
|
||||
|
||||
//update
|
||||
$.scope.toDo.splice(-1,0, { item: "Get Bread", done: "Yes" })
|
||||
|
||||
|
||||
});
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Document</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<ul>
|
||||
<li jq-repeat="toDo" jq-repeat-index="item" style="display:none;"><span class="item">{{ item }}</span>: {{ done }}</li>
|
||||
</ul>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -67,7 +67,7 @@
|
||||
|
||||
<div class="card-header actionMessage" style="display:none"></div>
|
||||
<div class="card-body">
|
||||
<form action="user/" evalAJAX="
|
||||
<form action="user/" onsubmit="formAJAX(this)" evalAJAX="
|
||||
$.scope.users.splice(0, 0, data);
|
||||
">
|
||||
<input type="hidden" class="form-control" name="delete" value="false" />
|
||||
@@ -84,7 +84,7 @@
|
||||
<input type="password" class="form-control" name="passwordMatch" placeholder="Retype password" validate="eq:password"/>
|
||||
</div>
|
||||
<hr />
|
||||
<button type="button" onclick="formAJAX(this)" class="btn btn-info">
|
||||
<button type="button" class="btn btn-info">
|
||||
Add
|
||||
</button>
|
||||
</form>
|
||||
|
||||
Reference in New Issue
Block a user