Updated DNS-01 validation
This commit is contained in:
+44
-10
@@ -39,17 +39,12 @@ class Host extends Table{
|
|||||||
|
|
||||||
static async addCache(host, parentOBJ){
|
static async addCache(host, parentOBJ){
|
||||||
try{
|
try{
|
||||||
console.log('addCache host:', host, 'parentOBJ host', parentOBJ.host)
|
|
||||||
parentOBJ = await this.get(parentOBJ.host);
|
parentOBJ = await this.get(parentOBJ.host);
|
||||||
|
|
||||||
if(parentOBJ.is_cache){
|
if(parentOBJ.is_cache){
|
||||||
console.log('addCache parentOBJ is chace, skipping')
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('addCache, corrent parent?', parentOBJ.wildcard_parent || parentOBJ.host)
|
|
||||||
console.log('addCache, got parent', parentOBJ)
|
|
||||||
|
|
||||||
await this.create({
|
await this.create({
|
||||||
...parentOBJ,
|
...parentOBJ,
|
||||||
host: host,
|
host: host,
|
||||||
@@ -63,7 +58,7 @@ class Host extends Table{
|
|||||||
parent: parentOBJ.host
|
parent: parentOBJ.host
|
||||||
});
|
});
|
||||||
}catch(error){
|
}catch(error){
|
||||||
console.error('add cache error', {...parentOBJ, host, is_cache: true}, error)
|
console.error('add cache error', {...parentOBJ, host, is_cache: true}, error);
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -81,18 +76,35 @@ class Host extends Table{
|
|||||||
|
|
||||||
}catch(error){
|
}catch(error){
|
||||||
console.error('bust cache error', error)
|
console.error('bust cache error', error)
|
||||||
|
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static async create(data, ...args){
|
static async create(data, ...args){
|
||||||
try{
|
try{
|
||||||
if(data.is_wildcard) await this.validateWildcardCreate(data, args);
|
// Validate requested host is valid host and domain
|
||||||
|
if(data.challengeType === 'DNS-01-wildcard') await this.validateWildcardCreate(data, args);
|
||||||
|
|
||||||
|
// 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);
|
let out = await super.create(data, ...args);
|
||||||
|
|
||||||
|
// Update the lookup table to reflect new host
|
||||||
await this.buildLookUpObj();
|
await this.buildLookUpObj();
|
||||||
if(out.is_wildcard) out.createWildcardCert();
|
|
||||||
|
// 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();
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
|
|
||||||
@@ -134,7 +146,8 @@ class Host extends Table{
|
|||||||
type:'TXT',
|
type:'TXT',
|
||||||
name: `_acme-challenge${parts.sub ? `.${parts.sub}` : ''}`,
|
name: `_acme-challenge${parts.sub ? `.${parts.sub}` : ''}`,
|
||||||
data: `${keyAuthorization}`
|
data: `${keyAuthorization}`
|
||||||
}
|
},
|
||||||
|
true // Force the record creation, even if the record exists
|
||||||
);
|
);
|
||||||
}catch(error){
|
}catch(error){
|
||||||
console.log('model Host challengeCreateFn error:', error)
|
console.log('model Host challengeCreateFn error:', error)
|
||||||
@@ -215,6 +228,26 @@ class Host extends Table{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async checkWildcardForRenew(){
|
||||||
|
try{
|
||||||
|
if(this.is_wildcard && Date.now() > this.wildcard_expires - (30 * 24 * 60 * 60 * 1000)){
|
||||||
|
this.createWildcardCert();
|
||||||
|
}
|
||||||
|
}catch(error){
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static async checkWildcardForRenew(){
|
||||||
|
try{
|
||||||
|
for(let host of await this.listDetail()){
|
||||||
|
host.createWildcardCert();
|
||||||
|
}
|
||||||
|
}catch(error){
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async update(...args){
|
async update(...args){
|
||||||
try{
|
try{
|
||||||
let out = await super.update(...args)
|
let out = await super.update(...args)
|
||||||
@@ -330,6 +363,7 @@ class Host extends Table{
|
|||||||
|
|
||||||
// Check every 5ms to see if the look up tree is ready
|
// Check every 5ms to see if the look up tree is ready
|
||||||
while(!this.__lookUpIsReady) await new Promise(r => setTimeout(r, 5));
|
while(!this.__lookUpIsReady) await new Promise(r => setTimeout(r, 5));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,6 +41,17 @@ router.get('/lookup/:item', async function(req, res, next){
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
router.get('/lookupobj', async function(req, res, next){
|
||||||
|
try{
|
||||||
|
return res.json({
|
||||||
|
results: Model.lookUpObj,
|
||||||
|
});
|
||||||
|
|
||||||
|
}catch(error){
|
||||||
|
return next(error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
router.get('/:item', async function(req, res, next){
|
router.get('/:item', async function(req, res, next){
|
||||||
try{
|
try{
|
||||||
|
|
||||||
|
|||||||
+121
-25
@@ -13,6 +13,7 @@
|
|||||||
div.form-group{
|
div.form-group{
|
||||||
margin-bottom: 1em;
|
margin-bottom: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* my Div class for my search bar */
|
/* my Div class for my search bar */
|
||||||
.search-wrapper {
|
.search-wrapper {
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -20,6 +21,7 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The input bar */
|
/* The input bar */
|
||||||
input {
|
input {
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
@@ -28,17 +30,26 @@
|
|||||||
border-top-right-radius: 5px !important;
|
border-top-right-radius: 5px !important;
|
||||||
border-bottom-right-radius: 5px !important;
|
border-bottom-right-radius: 5px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.challengeType-container {
|
||||||
|
pointer-events: none; /* Prevents clicking */
|
||||||
|
opacity: 0.5; /* Greys it out */
|
||||||
|
filter: grayscale(1); /* Removes blue/color tint */
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
var $editHostForm;
|
var $editHostForm;
|
||||||
|
|
||||||
|
// Parse the JSON object for a host to something the UI wants
|
||||||
function hostParseRow(host) {
|
function hostParseRow(host) {
|
||||||
host['updated_on_text'] = moment(host['updated_on'], "x").fromNow();
|
host['updated_on_text'] = moment(host['updated_on'], "x").fromNow();
|
||||||
host['wildcard_expires_text'] = moment(host['wildcard_expires'], "x").fromNow();
|
host['wildcard_expires_text'] = moment(host['wildcard_expires'], "x").fromNow();
|
||||||
host['targetssl_text'] = host['targetssl'] ? 'https://' : 'http://';
|
host['targetssl_text'] = host['targetssl'] ? 'https://' : 'http://';
|
||||||
host['forcessl_text'] = host['forcessl'] ? 'https://' : 'http://';
|
host['forcessl_text'] = host['forcessl'] ? 'https://' : 'http://';
|
||||||
host['wildcard_text'] = host['is_wildcard'] ? host['wildcard_status'] : 'Auto';
|
host['wildcard_text'] = host['is_wildcard'] ? host['wildcard_status'] : 'Auto';
|
||||||
|
host['wildcard_text'] = host['wildcard_parent'] ? 'Child' : host['wildcard_text'];
|
||||||
host['wildcard_text_bg'] = 'warning';
|
host['wildcard_text_bg'] = 'warning';
|
||||||
if(!host['is_wildcard']){
|
if(!host['is_wildcard']){
|
||||||
host['wildcard_text_bg'] = 'success';
|
host['wildcard_text_bg'] = 'success';
|
||||||
@@ -80,6 +91,7 @@
|
|||||||
|
|
||||||
function hostEditOpen(btn, host){
|
function hostEditOpen(btn, host){
|
||||||
hostEditCancle();
|
hostEditCancle();
|
||||||
|
console.log('host:', host)
|
||||||
host = $.scope.hosts.getByKey(host);
|
host = $.scope.hosts.getByKey(host);
|
||||||
host.__jq_$el.addClass('table-warning');
|
host.__jq_$el.addClass('table-warning');
|
||||||
$editHostForm.find('[name=is_wildcard').attr('disabled', true);
|
$editHostForm.find('[name=is_wildcard').attr('disabled', true);
|
||||||
@@ -123,15 +135,73 @@
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
async function verifyWildcardRequirements(host){
|
||||||
|
try{
|
||||||
|
|
||||||
|
let res = await app.api.get(`dns/domain/${host}`);
|
||||||
|
|
||||||
|
return res.results.length === 1;
|
||||||
|
}catch(error){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function hostMatchWildcard(host){
|
||||||
|
try{
|
||||||
|
let res = await app.api.get(`host/lookup/${host}`);
|
||||||
|
|
||||||
|
if(res.results && res.results.is_wildcard){
|
||||||
|
return res.results;
|
||||||
|
}
|
||||||
|
}catch(error){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$(document).ready(function(){
|
$(document).ready(function(){
|
||||||
|
// Clone the new host form to be used on edit requests.
|
||||||
$editHostForm = $('#addHost').clone();
|
$editHostForm = $('#addHost').clone();
|
||||||
$editHostForm.find('hr.buttonBreak').nextAll().remove();
|
$editHostForm.find('hr.buttonBreak').nextAll().remove();
|
||||||
// $editHostForm.find('.autoSll').addClass('bg-secondary');
|
// $editHostForm.find('.autoSll').addClass('bg-secondary');
|
||||||
hostPopulate(); //populate the table
|
|
||||||
|
|
||||||
|
// Populate the host UI table
|
||||||
|
hostPopulate();
|
||||||
|
|
||||||
|
// Determine what lets encrypt challenge type the given host name can use
|
||||||
|
$hostField = $('[name=host');
|
||||||
|
$hostField.keyup(async function(){
|
||||||
|
// Reset the allowed types on start
|
||||||
|
$('#challengeType-child-container').addClass('challengeType-container');
|
||||||
|
$('#challengeType-DNS-01-wildcard-container').addClass('challengeType-container');
|
||||||
|
|
||||||
|
let host = $hostField.val();
|
||||||
|
|
||||||
|
// If its a wild card, we must check if the domain has a registered
|
||||||
|
// provider.
|
||||||
|
if(host.startsWith("*.") && await verifyWildcardRequirements(host)){
|
||||||
|
$('#challengeType-DNS-01-wildcard-container').removeClass('challengeType-container');
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if a wildcard cert is available for the given host.
|
||||||
|
let wildcardParent = await hostMatchWildcard($hostField.val());
|
||||||
|
if(wildcardParent){
|
||||||
|
$('#challengeType-child-container').removeClass('challengeType-container');
|
||||||
|
$('#challengeType-child-relatedHost').text(wildcardParent.host);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we hit here, make sure the form is reverted to a valid state
|
||||||
|
$('#challengeType-child-relatedHost').text('');
|
||||||
|
$('#challengeType-HTTP-01').prop('checked', true);
|
||||||
|
});
|
||||||
|
|
||||||
|
//
|
||||||
$.scope.hosts.take = function($el, item, list){
|
$.scope.hosts.take = function($el, item, list){
|
||||||
$el.addClass('table-danger');
|
$el.addClass('table-danger');
|
||||||
$el.fadeOut(1000, function(){
|
$el.fadeOut(500, function(){
|
||||||
$el.remove()
|
$el.remove()
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@@ -149,9 +219,9 @@
|
|||||||
$el.slideUp();
|
$el.slideUp();
|
||||||
};
|
};
|
||||||
|
|
||||||
app.subscribe(/^model:Host/, function(data, topic){
|
// app.subscribe(/^model:Host/, function(data, topic){
|
||||||
console.log(topic, data);
|
// console.log(topic, data);
|
||||||
});
|
// });
|
||||||
|
|
||||||
app.subscribe(/^model:Host:create/, function(data, topic){
|
app.subscribe(/^model:Host:create/, function(data, topic){
|
||||||
let [a,b, action, host] = topic.split(':');
|
let [a,b, action, host] = topic.split(':');
|
||||||
@@ -259,26 +329,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<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">
|
<div class="form-group">
|
||||||
<label for='host' class="form-label">
|
<label for="host" class="form-label">
|
||||||
Incoming Host Name
|
Incoming Host Name
|
||||||
</label>
|
</label>
|
||||||
<div>
|
<div>
|
||||||
@@ -287,6 +339,30 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group autoSll">
|
||||||
|
<label class="form-label">
|
||||||
|
SSL <a href="https://letsencrypt.org/docs/challenge-types/" target="_blank">Validation Type</a>:
|
||||||
|
</label>
|
||||||
|
<div class="radio" id="challengeType-HTTP-01-container">
|
||||||
|
<label>
|
||||||
|
<input type="radio" name="challengeType" id="challengeType-HTTP-01" value="HTTP-01" checked>
|
||||||
|
HTTP-01
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div class="radio challengeType-container" id="challengeType-DNS-01-wildcard-container">
|
||||||
|
<label>
|
||||||
|
<input type="radio" name="challengeType" id="challengeType-DNS-01-wildcard" value="DNS-01-wildcard">
|
||||||
|
DNS-01 Wildcard
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div class="radio challengeType-container" id="challengeType-child-container">
|
||||||
|
<label>
|
||||||
|
<input type="radio" name="challengeType" id="challengeType-wildcardChild" value="wildcardChild">
|
||||||
|
Parent Wildcard from <i id="challengeType-child-relatedHost"></i>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="mb-3 form-group">
|
<div class="mb-3 form-group">
|
||||||
<label for="ip" class="form-label">
|
<label for="ip" class="form-label">
|
||||||
Target IP or Host Name
|
Target IP or Host Name
|
||||||
@@ -362,6 +438,19 @@
|
|||||||
<table class="m-0 card-body table table-striped overflow-x-scroll">
|
<table class="m-0 card-body table table-striped overflow-x-scroll">
|
||||||
|
|
||||||
<thead>
|
<thead>
|
||||||
|
<th>
|
||||||
|
<input type="checkbox"
|
||||||
|
onclick="$('.host_checkbox:visible').each((i, element)=>{
|
||||||
|
$(element).prop('checked', $(this).prop('checked'));
|
||||||
|
})"
|
||||||
|
/>
|
||||||
|
<br />
|
||||||
|
<button type="button" class="btn btn-sm btn-danger" onclick="$('.host_checkbox:checked').each((i, element)=>{
|
||||||
|
app.api.delete(`host/${$(element).parents('[jq-repeat-index]').attr('jq-repeat-index')}`, function(){});
|
||||||
|
})">
|
||||||
|
<i class="fa-solid fa-trash-can"></i>
|
||||||
|
</button>
|
||||||
|
</th>
|
||||||
<th>
|
<th>
|
||||||
SSL Expire
|
SSL Expire
|
||||||
</th>
|
</th>
|
||||||
@@ -380,7 +469,10 @@
|
|||||||
</thead>
|
</thead>
|
||||||
|
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr action="api" jq-repeat="hosts" jq-repeat-index='host' style="display:none">
|
<tr action="api" jq-repeat="hosts" jq-index-key='host' style="display:none">
|
||||||
|
<td>
|
||||||
|
<input type="checkbox" class="host_checkbox">
|
||||||
|
</td>
|
||||||
<td class="table-{{wildcard_text_bg}}">
|
<td class="table-{{wildcard_text_bg}}">
|
||||||
{{{ wildcard_text }}}
|
{{{ wildcard_text }}}
|
||||||
{{#wildcard_expires}}
|
{{#wildcard_expires}}
|
||||||
@@ -395,6 +487,10 @@
|
|||||||
<br />
|
<br />
|
||||||
<img width="24px" src="{{displayIconHtml}}" /> {{displayName}} - {{name}}
|
<img width="24px" src="{{displayIconHtml}}" /> {{displayName}} - {{name}}
|
||||||
{{/domain.provider}}
|
{{/domain.provider}}
|
||||||
|
|
||||||
|
{{#wildcard_parent}}
|
||||||
|
<i>{{wildcard_parent}}</i>
|
||||||
|
{{/wildcard_parent}}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
{{{ targetssl_text }}}{{ ip }}:{{ targetPort }}
|
{{{ targetssl_text }}}{{ ip }}:{{ targetPort }}
|
||||||
|
|||||||
Reference in New Issue
Block a user