wild card UI done
This commit is contained in:
+38
-35
@@ -30,6 +30,7 @@ class Host extends Table{
|
||||
'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},
|
||||
'wildcard_expires': {isRequired: false, type: 'number'},
|
||||
}
|
||||
|
||||
static lookUpObj = {};
|
||||
@@ -62,7 +63,7 @@ class Host extends Table{
|
||||
parent: parentOBJ.host
|
||||
});
|
||||
}catch(error){
|
||||
console.error('add cahce error', {...parentOBJ, host, is_cache: true}, error)
|
||||
console.error('add cache error', {...parentOBJ, host, is_cache: true}, error)
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
@@ -103,16 +104,18 @@ class Host extends Table{
|
||||
|
||||
try{
|
||||
let host = this;
|
||||
|
||||
await host.update({
|
||||
wildcard_status: 'Requesting',
|
||||
});
|
||||
let cert = await letsEncrypt.dnsWildcard(this.host, {
|
||||
challengeCreateFn: async (authz, challenge, keyAuthorization) => {
|
||||
host.update({
|
||||
wildcard_status: `Adding record for ${authz.identifier.value}`
|
||||
await host.update({
|
||||
wildcard_status: `Adding record`
|
||||
});
|
||||
try{
|
||||
let parts = tldExtract(authz.identifier.value);
|
||||
|
||||
console.log('adding DNS record for', `_acme-challenge${parts.sub ? `.${parts.sub}` : ''}`)
|
||||
|
||||
let res = await porkBun.createRecordForce(
|
||||
parts.domain,
|
||||
{
|
||||
@@ -121,56 +124,55 @@ class Host extends Table{
|
||||
content: `${keyAuthorization}`
|
||||
}
|
||||
);
|
||||
console.log('porkbun res', res)
|
||||
}catch(error){
|
||||
console.log('model Host challengeCreateFn error:', error)
|
||||
host.update({
|
||||
await host.update({
|
||||
wildcard_status: `Add DNS record failed`
|
||||
});
|
||||
}
|
||||
},
|
||||
onDnsCheck: async(authz, checkCount)=>{
|
||||
host.update({
|
||||
wildcard_status: `${checkCount} Checking DNS for ${authz.identifier.value}`
|
||||
await host.update({
|
||||
wildcard_status: `${checkCount} Checking DNS`
|
||||
});
|
||||
},
|
||||
onDnsCheckFail: async(authz, error)=>{
|
||||
host.update({
|
||||
await 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}`
|
||||
await host.update({
|
||||
wildcard_status: `DNS check found`
|
||||
});
|
||||
},
|
||||
onDnsCheckSuccess: async(authz)=>{
|
||||
host.update({
|
||||
wildcard_status: `DNS check success for ${authz.identifier.value}`
|
||||
await host.update({
|
||||
wildcard_status: `DNS check success`
|
||||
})
|
||||
},
|
||||
onDnsCheckRemove: async(authz)=>{
|
||||
host.update({
|
||||
wildcard_status: `DNS remove record for ${authz.identifier.value}`
|
||||
await host.update({
|
||||
wildcard_status: `DNS remove record`
|
||||
})
|
||||
},
|
||||
challengeRemoveFn: async (authz, challenge, keyAuthorization)=>{
|
||||
host.update({
|
||||
wildcard_status: `DNS remove record for ${authz.identifier.value}`
|
||||
await host.update({
|
||||
wildcard_status: `DNS remove record`
|
||||
})
|
||||
try{
|
||||
// let parts = tldExtract(authz.identifier.value);
|
||||
// await porkBun.deleteRecords(
|
||||
// parts.domain,
|
||||
// {
|
||||
// type:'TXT',
|
||||
// name: `_acme-challenge${parts.sub ? `.${parts.sub}` : ''
|
||||
// }`,
|
||||
// content: `${keyAuthorization}`}
|
||||
// );
|
||||
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({
|
||||
await host.update({
|
||||
wildcard_status: `DNS remove record failed for ${authz.identifier.value}`
|
||||
})
|
||||
}
|
||||
@@ -188,8 +190,9 @@ class Host extends Table{
|
||||
|
||||
|
||||
await this.constructor.redisClient.SET(`${this.host}:latest`, JSON.stringify(toAdd));
|
||||
this.update({
|
||||
wildcard_status: `Done`
|
||||
await this.update({
|
||||
wildcard_status: `Done`,
|
||||
wildcard_expires: toAdd.real_expiry*1000,
|
||||
});
|
||||
|
||||
return this;
|
||||
@@ -204,8 +207,8 @@ class Host extends Table{
|
||||
async update(...args){
|
||||
try{
|
||||
let out = await super.update(...args)
|
||||
await this.bustCache(this.host)
|
||||
await Host.buildLookUpObj()
|
||||
await this.bustCache(this.host);
|
||||
await Host.buildLookUpObj();
|
||||
|
||||
return out;
|
||||
} catch(error){
|
||||
@@ -215,9 +218,9 @@ class Host extends Table{
|
||||
|
||||
async remove(...args){
|
||||
try{
|
||||
let out = await super.remove(...args)
|
||||
await Host.buildLookUpObj()
|
||||
await this.bustCache(this.host)
|
||||
let out = await super.remove(...args);
|
||||
await Host.buildLookUpObj();
|
||||
await this.bustCache(this.host);
|
||||
|
||||
return out;
|
||||
} catch(error){
|
||||
|
||||
@@ -26,10 +26,17 @@ app.host = (function(app){
|
||||
function remove(args, callack){
|
||||
app.api.delete('host/'+ args.host, function(error, data){
|
||||
callack(error, data);
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
function getCert(args, callack){
|
||||
app.api.get('cert/'+args.host, function(error, data){
|
||||
callack(error, data);
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
getCert,
|
||||
list: list,
|
||||
get: get,
|
||||
add: add,
|
||||
|
||||
@@ -311,7 +311,23 @@ app.util = (function(app){
|
||||
return obj;
|
||||
};
|
||||
|
||||
function downloadFile(filename, text){
|
||||
// https://stackoverflow.com/a/18197341
|
||||
|
||||
var element = document.createElement('a');
|
||||
element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
|
||||
element.setAttribute('download', filename);
|
||||
|
||||
element.style.display = 'none';
|
||||
document.body.appendChild(element);
|
||||
|
||||
element.click();
|
||||
|
||||
document.body.removeChild(element);
|
||||
}
|
||||
|
||||
return {
|
||||
downloadFile: downloadFile,
|
||||
getUrlParameter: getUrlParameter,
|
||||
actionMessage: actionMessage
|
||||
}
|
||||
|
||||
+22
-9
@@ -29,7 +29,19 @@ router.post('/', async function(req, res, next){
|
||||
}
|
||||
});
|
||||
|
||||
router.get('/:item(*)', async function(req, res, next){
|
||||
router.get('/lookup/:item', async function(req, res, next){
|
||||
try{
|
||||
return res.json({
|
||||
string: req.params.item,
|
||||
results: await Model.lookUp(req.params.item),
|
||||
});
|
||||
|
||||
}catch(error){
|
||||
return next(error);
|
||||
}
|
||||
});
|
||||
|
||||
router.get('/:item', async function(req, res, next){
|
||||
try{
|
||||
|
||||
return res.json({
|
||||
@@ -41,7 +53,7 @@ router.get('/:item(*)', async function(req, res, next){
|
||||
}
|
||||
});
|
||||
|
||||
router.put('/:item(*)', async function(req, res, next){
|
||||
router.put('/:item', async function(req, res, next){
|
||||
try{
|
||||
req.body.updated_by = req.user.username;
|
||||
let item = await Model.get(req.params.item);
|
||||
@@ -59,7 +71,7 @@ router.put('/:item(*)', async function(req, res, next){
|
||||
}
|
||||
});
|
||||
|
||||
router.delete('/:item(*)', async function(req, res, next){
|
||||
router.delete('/:item', async function(req, res, next){
|
||||
try{
|
||||
let item = await Model.get(req.params.item);
|
||||
let count = await item.remove();
|
||||
@@ -74,15 +86,16 @@ router.delete('/:item(*)', async function(req, res, next){
|
||||
}
|
||||
});
|
||||
|
||||
router.get('/lookup/:item(*)', async function(req, res, next){
|
||||
router.put('/:item/renew', async function(req, res, next){
|
||||
try{
|
||||
return res.json({
|
||||
string: req.params.item,
|
||||
results: await Model.lookUp(req.params.item),
|
||||
});
|
||||
let item = await Model.get(req.params.item);
|
||||
item.createWildcardCert();
|
||||
|
||||
return res.json({
|
||||
message: `Requesting wildcard cert for ${req.params.item}`,
|
||||
})
|
||||
}catch(error){
|
||||
return next(error);
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -7,10 +7,6 @@ const sleep = require('./sleep');
|
||||
|
||||
// https://dns.google/resolve?name=${name}&type=TXT
|
||||
|
||||
AcmeClient.setLogger((message) => {
|
||||
console.log('ACME:', message);
|
||||
});
|
||||
|
||||
|
||||
class LetsEncrypt{
|
||||
static AcmeClient = AcmeClient;
|
||||
@@ -64,15 +60,12 @@ class LetsEncrypt{
|
||||
skipChallengeVerification: true,
|
||||
challengeCreateFn: async (authz, challenge, keyAuthorization) => {
|
||||
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++
|
||||
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++
|
||||
dnsFound++;
|
||||
if(dnsFound === dnsToAdd){
|
||||
options.onDnsCheckFound(authz, dnsFound)
|
||||
options.onDnsCheckFound(authz, dnsFound);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -83,13 +76,11 @@ class LetsEncrypt{
|
||||
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++
|
||||
dnsFound++;
|
||||
if(dnsFound === dnsToAdd){
|
||||
options.onDnsCheckFound(authz, dnsFound)
|
||||
options.onDnsCheckFound(authz, dnsFound);
|
||||
}
|
||||
// console.log(`found record for key=_acme-challenge.${authz.identifier.value} value=${keyAuthorization}`)
|
||||
await sleep(10000);
|
||||
break;
|
||||
}
|
||||
|
||||
+60
-10
@@ -43,9 +43,21 @@
|
||||
|
||||
function parseHostRow(host) {
|
||||
host['updated_on_text'] = moment(host['updated_on'], "x").fromNow();
|
||||
host['wildcard_expires_text'] = moment(host['wildcard_expires'], "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';
|
||||
host['wildcard_text_bg'] = 'warning';
|
||||
if(!host['is_wildcard']){
|
||||
host['wildcard_text_bg'] = 'success';
|
||||
}
|
||||
if(host['wildcard_status'] == 'Done'){
|
||||
host['wildcard_text_bg'] = 'success';
|
||||
host['wildcard_text'] = undefined;
|
||||
}
|
||||
if(host['wildcard_status'].includes('failed')){
|
||||
host['wildcard_text_bg'] = 'danger';
|
||||
}
|
||||
|
||||
return host;
|
||||
}
|
||||
@@ -94,6 +106,13 @@
|
||||
});
|
||||
}
|
||||
|
||||
function downloadCert(host, type){
|
||||
app.host.getCert({host}, function(error, data){
|
||||
if(error) app.util.actionMessage(error.message, $.scope.hosts.$this, 'danger');
|
||||
app.util.downloadFile(`${host}-${type}.crt`, data[type])
|
||||
});
|
||||
}
|
||||
|
||||
$(document).ready(function(){
|
||||
$editHostForm = $('#addHost').clone();
|
||||
$editHostForm.find('hr.buttonBreak').nextAll().remove();
|
||||
@@ -121,9 +140,9 @@
|
||||
$el.slideUp();
|
||||
});
|
||||
|
||||
app.subscribe(/^model:Host/, function(data, topic){
|
||||
console.log(topic, data);
|
||||
});
|
||||
// app.subscribe(/^model:Host/, function(data, topic){
|
||||
// console.log(topic, data);
|
||||
// });
|
||||
|
||||
app.subscribe(/^model:Host:create/, function(data, topic){
|
||||
let [a,b, action, host] = topic.split(':');
|
||||
@@ -350,7 +369,7 @@
|
||||
|
||||
<thead>
|
||||
<th>
|
||||
SSL
|
||||
SSL Expire
|
||||
</th>
|
||||
<th>
|
||||
Host Name
|
||||
@@ -365,10 +384,14 @@
|
||||
Actions
|
||||
</th>
|
||||
</thead>
|
||||
|
||||
<tbody id="hostsTable">
|
||||
<tr action="api" jq-repeat="hosts" jq-repeat-index='host' style="display:none">
|
||||
<td>
|
||||
<td class="table-{{wildcard_text_bg}}">
|
||||
{{{ wildcard_text }}}
|
||||
{{#wildcard_expires}}
|
||||
<span class="momentFromNow" data-date="{{ wildcard_expires }}" >{{wildcard_expires_text}}</span>
|
||||
{{/wildcard_expires}}
|
||||
</td>
|
||||
<td>
|
||||
<a target="_blank" href="{{ forcessl_text }}{{ host }}">
|
||||
@@ -378,15 +401,42 @@
|
||||
<td>
|
||||
{{{ targetssl_text }}}{{ ip }}:{{ targetPort }}
|
||||
</td>
|
||||
<td class="hidden-xs momentFromNow" data-date="{{ updated_on }}">
|
||||
<td class="hidden-xs momentFromNow" data-date="{{ updated_on }}" >
|
||||
{{ updated_on_text }}
|
||||
</td>
|
||||
<td>
|
||||
<div class="btn-group">
|
||||
<!-- <button type="button" class="btn btn-info">
|
||||
<i class="fa-brands fa-expeditedssl"></i>
|
||||
Cert
|
||||
</button> -->
|
||||
|
||||
<div class="btn-group" role="group">
|
||||
<button type="button" class="btn btn-primary dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
|
||||
<i class="fa-brands fa-expeditedssl"></i>
|
||||
Certs
|
||||
</button>
|
||||
<ul class="dropdown-menu">
|
||||
<li>
|
||||
<button type="button" class="dropdown-item" onclick="downloadCert('{{host}}', 'cert_pem')">
|
||||
<i class="fa-solid fa-certificate"></i>
|
||||
Cert
|
||||
<i class="fa-solid fa-file-arrow-down float-end"></i>
|
||||
</button>
|
||||
</li>
|
||||
<li>
|
||||
<button type="button" class="dropdown-item" onclick="downloadCert('{{host}}', 'fullchain_pem')">
|
||||
<i class="fa-solid fa-link"></i>
|
||||
Full Chain
|
||||
<i class="fa-solid fa-file-arrow-down float-end"></i>
|
||||
</button>
|
||||
</li>
|
||||
<li>
|
||||
<button type="button" class="dropdown-item" onclick="downloadCert('{{host}}', 'privkey_pem')">
|
||||
<i class="fa-solid fa-key"></i>
|
||||
Private key
|
||||
<i class="fa-solid fa-file-arrow-down float-end"></i>
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<button type="button" onclick="editHost(this, '{{ host }}');" class="btn btn-sm btn-warning">
|
||||
<i class="fa-solid fa-pencil"></i>
|
||||
Edit
|
||||
|
||||
Reference in New Issue
Block a user