mirror of
https://github.com/opnsense/plugins.git
synced 2026-06-04 22:33:07 -04:00
security/acme-client: merge version 1.3 from master
This commit is contained in:
parent
4d10a0d12a
commit
130ce651ee
24 changed files with 2732 additions and 420 deletions
|
|
@ -1,5 +1,5 @@
|
|||
PLUGIN_NAME= acme-client
|
||||
PLUGIN_VERSION= 1.2
|
||||
PLUGIN_VERSION= 1.3
|
||||
PLUGIN_COMMENT= Let's Encrypt client
|
||||
PLUGIN_MAINTAINER= opnsense@moov.de
|
||||
|
||||
|
|
|
|||
|
|
@ -24,19 +24,27 @@
|
|||
<help>Pre-defined commands for this restart action.</help>
|
||||
</field>
|
||||
<field>
|
||||
<label>Optional Parameters</label>
|
||||
<label>Required Parameters</label>
|
||||
<type>header</type>
|
||||
<style>method_table method_table_configd</style>
|
||||
</field>
|
||||
<field>
|
||||
<id>action.configd</id>
|
||||
<label>System Command</label>
|
||||
<type>dropdown</type>
|
||||
<help>Select a pre-defined system command which should be run for this action.</help>
|
||||
<style>table_optional table_optional_configd</style>
|
||||
</field>
|
||||
<field>
|
||||
<label>Required Parameters</label>
|
||||
<type>header</type>
|
||||
<style>method_table method_table_custom</style>
|
||||
</field>
|
||||
<field>
|
||||
<id>action.custom</id>
|
||||
<label>Custom Command</label>
|
||||
<type>textbox</type>
|
||||
<help>Specify a custom commands which should be run for this action.</help>
|
||||
<style>table_optional table_optional_custom</style>
|
||||
</field>
|
||||
</form>
|
||||
|
|
|
|||
|
|
@ -35,9 +35,9 @@
|
|||
<help></help>
|
||||
</field>
|
||||
<field>
|
||||
<label>HTTP-01/OPNsense</label>
|
||||
<label>OPNsense</label>
|
||||
<type>header</type>
|
||||
<style>method_table method_table_http01</style>
|
||||
<style>table_http table_http_opnsense</style>
|
||||
</field>
|
||||
<field>
|
||||
<id>validation.http_opn_autodiscovery</id>
|
||||
|
|
@ -61,9 +61,9 @@
|
|||
<hint>Enter IP addresses here. Finish each with TAB.</hint>
|
||||
</field>
|
||||
<field>
|
||||
<label>HTTP-01/HAProxy</label>
|
||||
<label>HAProxy</label>
|
||||
<type>header</type>
|
||||
<style>method_table method_table_http01</style>
|
||||
<style>table_http table_http_haproxy</style>
|
||||
</field>
|
||||
<field>
|
||||
<id>validation.http_haproxyInject</id>
|
||||
|
|
@ -79,20 +79,6 @@
|
|||
<allownew>true</allownew>
|
||||
<help>Choose the local HAProxy frontends. They will automatically be configured to redirect acme challenges to the internal acme client. The HAProxy service will automatically be restarted if a certificate was renewed.</help>
|
||||
</field>
|
||||
<!--
|
||||
<field>
|
||||
<id>validation.http_relaydInject</id>
|
||||
<label>Loadbalancer Config Injection</label>
|
||||
<type>checkbox</type>
|
||||
<help>Automatically inject config into the local Loadbalancer (relayd) to let it serve acme challanges without service interruption.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>validation.http_relaydVserver</id>
|
||||
<label>Loadbalancer Virtual Server</label>
|
||||
<type>text</type>
|
||||
<help>Choose the Virtual Server from the relayd Loadbalancer that should be configured to server acme challenges.</help>
|
||||
</field>
|
||||
-->
|
||||
<field>
|
||||
<label>DNS-01</label>
|
||||
<type>header</type>
|
||||
|
|
@ -111,7 +97,7 @@
|
|||
<help><![CDATA[The time in seconds to wait for all the TXT records to take effect after adding them to the DNS API. Defaults to 120 seconds.]]></help>
|
||||
</field>
|
||||
<field>
|
||||
<label>DNS-01/Alwaysdata</label>
|
||||
<label>Alwaysdata</label>
|
||||
<type>header</type>
|
||||
<style>table_dns table_dns_ad</style>
|
||||
</field>
|
||||
|
|
@ -122,7 +108,7 @@
|
|||
<help></help>
|
||||
</field>
|
||||
<field>
|
||||
<label>DNS-01/aliyun</label>
|
||||
<label>aliyun</label>
|
||||
<type>header</type>
|
||||
<style>table_dns table_dns_ali</style>
|
||||
</field>
|
||||
|
|
@ -139,7 +125,7 @@
|
|||
<help></help>
|
||||
</field>
|
||||
<field>
|
||||
<label>DNS-01/AWS Route53</label>
|
||||
<label>AWS Route53</label>
|
||||
<type>header</type>
|
||||
<style>table_dns table_dns_aws</style>
|
||||
</field>
|
||||
|
|
@ -156,7 +142,7 @@
|
|||
<help></help>
|
||||
</field>
|
||||
<field>
|
||||
<label>DNS-01/Cloudflare</label>
|
||||
<label>Cloudflare</label>
|
||||
<type>header</type>
|
||||
<style>table_dns table_dns_cf</style>
|
||||
</field>
|
||||
|
|
@ -173,7 +159,7 @@
|
|||
<help></help>
|
||||
</field>
|
||||
<field>
|
||||
<label>DNS-01/CloudXNS</label>
|
||||
<label>CloudXNS</label>
|
||||
<type>header</type>
|
||||
<style>table_dns table_dns_cx</style>
|
||||
</field>
|
||||
|
|
@ -190,7 +176,43 @@
|
|||
<help></help>
|
||||
</field>
|
||||
<field>
|
||||
<label>DNS-01/DNSPod</label>
|
||||
<label>cyon</label>
|
||||
<type>header</type>
|
||||
<style>table_dns table_dns_cyon</style>
|
||||
<help></help>
|
||||
</field>
|
||||
<field>
|
||||
<id>validation.dns_cyon_user</id>
|
||||
<label>User</label>
|
||||
<type>text</type>
|
||||
<help></help>
|
||||
</field>
|
||||
<field>
|
||||
<id>validation.dns_cyon_password</id>
|
||||
<label>Password</label>
|
||||
<type>text</type>
|
||||
<help></help>
|
||||
</field>
|
||||
<field>
|
||||
<label>Domain-Offensive</label>
|
||||
<type>header</type>
|
||||
<style>table_dns table_dns_do</style>
|
||||
<help></help>
|
||||
</field>
|
||||
<field>
|
||||
<id>validation.dns_do_pid</id>
|
||||
<label>Partner ID</label>
|
||||
<type>text</type>
|
||||
<help></help>
|
||||
</field>
|
||||
<field>
|
||||
<id>validation.dns_do_password</id>
|
||||
<label>Password</label>
|
||||
<type>text</type>
|
||||
<help></help>
|
||||
</field>
|
||||
<field>
|
||||
<label>DNSPod</label>
|
||||
<type>header</type>
|
||||
<style>table_dns table_dns_dp</style>
|
||||
</field>
|
||||
|
|
@ -207,7 +229,37 @@
|
|||
<help></help>
|
||||
</field>
|
||||
<field>
|
||||
<label>DNS-01/GoDaddy</label>
|
||||
<label>FreeDNS</label>
|
||||
<type>header</type>
|
||||
<style>table_dns table_dns_freedns</style>
|
||||
<help></help>
|
||||
</field>
|
||||
<field>
|
||||
<id>validation.dns_freedns_user</id>
|
||||
<label>User</label>
|
||||
<type>text</type>
|
||||
<help></help>
|
||||
</field>
|
||||
<field>
|
||||
<id>validation.dns_freedns_password</id>
|
||||
<label>Password</label>
|
||||
<type>text</type>
|
||||
<help></help>
|
||||
</field>
|
||||
<field>
|
||||
<label>Gandi LiveDNS</label>
|
||||
<type>header</type>
|
||||
<style>table_dns table_dns_gandi_livedns</style>
|
||||
<help></help>
|
||||
</field>
|
||||
<field>
|
||||
<id>validation.dns_gandi_livedns_key</id>
|
||||
<label>Key</label>
|
||||
<type>text</type>
|
||||
<help></help>
|
||||
</field>
|
||||
<field>
|
||||
<label>GoDaddy</label>
|
||||
<type>header</type>
|
||||
<style>table_dns table_dns_gd</style>
|
||||
</field>
|
||||
|
|
@ -224,7 +276,7 @@
|
|||
<help></help>
|
||||
</field>
|
||||
<field>
|
||||
<label>DNS-01/IPSConfig</label>
|
||||
<label>IPSConfig</label>
|
||||
<type>header</type>
|
||||
<style>table_dns table_dns_ispconfig</style>
|
||||
</field>
|
||||
|
|
@ -253,7 +305,7 @@
|
|||
<help></help>
|
||||
</field>
|
||||
<field>
|
||||
<label>DNS-01/lexicon</label>
|
||||
<label>lexicon</label>
|
||||
<type>header</type>
|
||||
<style>table_dns table_dns_lexicon</style>
|
||||
</field>
|
||||
|
|
@ -276,7 +328,19 @@
|
|||
<help></help>
|
||||
</field>
|
||||
<field>
|
||||
<label>DNS-01/LuaDNS</label>
|
||||
<label>Linode</label>
|
||||
<type>header</type>
|
||||
<style>table_dns table_dns_linode</style>
|
||||
<help></help>
|
||||
</field>
|
||||
<field>
|
||||
<id>validation.dns_linode_key</id>
|
||||
<label>Key</label>
|
||||
<type>text</type>
|
||||
<help></help>
|
||||
</field>
|
||||
<field>
|
||||
<label>LuaDNS</label>
|
||||
<type>header</type>
|
||||
<style>table_dns table_dns_lua</style>
|
||||
</field>
|
||||
|
|
@ -293,7 +357,7 @@
|
|||
<help></help>
|
||||
</field>
|
||||
<field>
|
||||
<label>DNS-01/DNSMadeEasy</label>
|
||||
<label>DNSMadeEasy</label>
|
||||
<type>header</type>
|
||||
<style>table_dns table_dns_me</style>
|
||||
</field>
|
||||
|
|
@ -310,7 +374,7 @@
|
|||
<help></help>
|
||||
</field>
|
||||
<field>
|
||||
<label>DNS-01/nsupdate</label>
|
||||
<label>nsupdate</label>
|
||||
<type>header</type>
|
||||
<style>table_dns table_dns_nsupdate</style>
|
||||
</field>
|
||||
|
|
@ -327,7 +391,7 @@
|
|||
<help><![CDATA[Requires the the whole key file in a format that is compatible with nsupdate.]]></help>
|
||||
</field>
|
||||
<field>
|
||||
<label>DNS-01/OVH</label>
|
||||
<label>OVH</label>
|
||||
<type>header</type>
|
||||
<style>table_dns table_dns_ovh</style>
|
||||
</field>
|
||||
|
|
@ -356,7 +420,7 @@
|
|||
<help><![CDATA[Specify the OVH endpoint, i.e. ovh-eu, ovh-ca, kimsufi-eu, etc. Please refer to the <a href="https://github.com/Neilpang/acme.sh/tree/master/dnsapi">acme.sh documentation</a> for further information.]]></help>
|
||||
</field>
|
||||
<field>
|
||||
<label>DNS-01/PowerDNS</label>
|
||||
<label>PowerDNS</label>
|
||||
<type>header</type>
|
||||
<style>table_dns table_dns_pdns</style>
|
||||
</field>
|
||||
|
|
|
|||
|
|
@ -30,4 +30,11 @@
|
|||
<help><![CDATA[When using HTTP-01 as validation method, a local webserver is used to provide acme challenge data to the Let's Encrypt servers. This setting allows you to change the local port of this webserver in case it interferes with another local services. Defaults to port 43580.]]></help>
|
||||
<advanced>true</advanced>
|
||||
</field>
|
||||
<field>
|
||||
<id>acmeclient.settings.restartTimeout</id>
|
||||
<label>Restart Timeout</label>
|
||||
<type>text</type>
|
||||
<help><![CDATA[The maximum time in seconds to wait for a restart action to complete. When the timeout is reached the command is forcefully aborted. Defaults to 600 seconds.]]></help>
|
||||
<advanced>true</advanced>
|
||||
</field>
|
||||
</form>
|
||||
|
|
|
|||
|
|
@ -43,6 +43,12 @@
|
|||
<MaximumValue>65535</MaximumValue>
|
||||
<Required>Y</Required>
|
||||
</challengePort>
|
||||
<restartTimeout type="IntegerField">
|
||||
<default>600</default>
|
||||
<MinimumValue>10</MinimumValue>
|
||||
<MaximumValue>86400</MaximumValue>
|
||||
<Required>Y</Required>
|
||||
</restartTimeout>
|
||||
<haproxyIntegration type="BooleanField">
|
||||
<default>0</default>
|
||||
<Required>N</Required>
|
||||
|
|
@ -318,10 +324,15 @@
|
|||
<dns_aws>AWS Route 53</dns_aws>
|
||||
<dns_cf>CloudFlare.com API</dns_cf>
|
||||
<dns_cx>CloudXNS.com API</dns_cx>
|
||||
<dns_cyon>cyon.ch API</dns_cyon>
|
||||
<dns_do>Domain-Offensive API</dns_do>
|
||||
<dns_dp>DNSPod.cn API</dns_dp>
|
||||
<dns_freedns>FreeDNS API</dns_freedns>
|
||||
<dns_gandi_livedns>Gandi LiveDNS API</dns_gandi_livedns>
|
||||
<dns_gd>GoDaddy.com API</dns_gd>
|
||||
<dns_ispconfig>ISPConfig 3.1+ API</dns_ispconfig>
|
||||
<dns_lexicon>lexicon DNS API</dns_lexicon>
|
||||
<dns_linode>Linode API</dns_linode>
|
||||
<dns_lua>LuaDNS.com API</dns_lua>
|
||||
<dns_me>DNSMadeEasy.com API</dns_me>
|
||||
<dns_nsupdate>nsupdate (RFC 2136)</dns_nsupdate>
|
||||
|
|
@ -363,12 +374,33 @@
|
|||
<dns_cx_secret type="TextField">
|
||||
<Required>N</Required>
|
||||
</dns_cx_secret>
|
||||
<dns_cyon_user type="TextField">
|
||||
<Required>N</Required>
|
||||
</dns_cyon_user>
|
||||
<dns_cyon_password type="TextField">
|
||||
<Required>N</Required>
|
||||
</dns_cyon_password>
|
||||
<dns_do_pid type="TextField">
|
||||
<Required>N</Required>
|
||||
</dns_do_pid>
|
||||
<dns_do_password type="TextField">
|
||||
<Required>N</Required>
|
||||
</dns_do_password>
|
||||
<dns_dp_id type="TextField">
|
||||
<Required>N</Required>
|
||||
</dns_dp_id>
|
||||
<dns_dp_key type="TextField">
|
||||
<Required>N</Required>
|
||||
</dns_dp_key>
|
||||
<dns_freedns_user type="TextField">
|
||||
<Required>N</Required>
|
||||
</dns_freedns_user>
|
||||
<dns_freedns_password type="TextField">
|
||||
<Required>N</Required>
|
||||
</dns_freedns_password>
|
||||
<dns_gandi_livedns_key type="TextField">
|
||||
<Required>N</Required>
|
||||
</dns_gandi_livedns_key>
|
||||
<dns_gd_key type="TextField">
|
||||
<Required>N</Required>
|
||||
</dns_gd_key>
|
||||
|
|
@ -402,6 +434,9 @@
|
|||
<dns_lexicon_token type="TextField">
|
||||
<Required>N</Required>
|
||||
</dns_lexicon_token>
|
||||
<dns_linode_key type="TextField">
|
||||
<Required>N</Required>
|
||||
</dns_linode_key>
|
||||
<dns_lua_email type="TextField">
|
||||
<Required>N</Required>
|
||||
</dns_lua_email>
|
||||
|
|
|
|||
|
|
@ -48,6 +48,19 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
}
|
||||
);
|
||||
|
||||
// hook into on-show event for dialog to extend layout.
|
||||
$('#DialogAction').on('shown.bs.modal', function (e) {
|
||||
$("#action\\.type").change(function(){
|
||||
var service_id = 'table_optional_' + $(this).val();
|
||||
$(".table_optional").hide();
|
||||
$("."+service_id).show();
|
||||
});
|
||||
$("#action\\.type").change(function(){
|
||||
$(".method_table").hide();
|
||||
$(".method_table_"+$(this).val()).show();
|
||||
});
|
||||
$("#action\\.type").change();
|
||||
})
|
||||
});
|
||||
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -51,16 +51,25 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
// hook into on-show event for dialog to extend layout.
|
||||
$('#DialogValidation').on('shown.bs.modal', function (e) {
|
||||
$("#validation\\.dns_service").change(function(){
|
||||
var service_id = 'table_' + $(this).val() ;
|
||||
var service_id = 'table_' + $(this).val();
|
||||
$(".table_dns").hide();
|
||||
if ($("#validation\\.method").val() == 'dns01') {
|
||||
$("."+service_id).show();
|
||||
}
|
||||
});
|
||||
$("#validation\\.http_service").change(function(){
|
||||
var service_id = 'table_http_' + $(this).val();
|
||||
$(".table_http").hide();
|
||||
if ($("#validation\\.method").val() == 'http01') {
|
||||
$("."+service_id).show();
|
||||
} else {
|
||||
}
|
||||
});
|
||||
$("#validation\\.method").change(function(){
|
||||
$(".method_table").hide();
|
||||
$(".method_table_"+$(this).val()).show();
|
||||
$("#validation\\.dns_service").change();
|
||||
$("#validation\\.http_service").change();
|
||||
});
|
||||
$("#validation\\.method").change();
|
||||
})
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -2,7 +2,7 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Based in parts on certs.inc (thus the extended copyright notice).
|
||||
* Based in parts on certs.inc and system_camanager.php (thus the extended copyright notice).
|
||||
*
|
||||
* Copyright (C) 2017 Frank Wall
|
||||
* Copyright (C) 2015 Deciso B.V.
|
||||
|
|
@ -600,10 +600,25 @@ function run_acme_validation($certObj, $valObj, $acctObj)
|
|||
$proc_env['CX_Key'] = (string)$valObj->dns_cx_key;
|
||||
$proc_env['CX_Secret'] = (string)$valObj->dns_cx_secret;
|
||||
break;
|
||||
case 'dns_cyon':
|
||||
$proc_env['CY_Username'] = (string)$valObj->dns_cyon_user;
|
||||
$proc_env['CY_Password'] = (string)$valObj->dns_cyon_user;
|
||||
break;
|
||||
case 'dns_do':
|
||||
$proc_env['DO_PID'] = (string)$valObj->dns_do_pid;
|
||||
$proc_env['DO_PW'] = (string)$valObj->dns_do_password;
|
||||
break;
|
||||
case 'dns_dp':
|
||||
$proc_env['DP_Id'] = (string)$valObj->dns_dp_id;
|
||||
$proc_env['DP_Key'] = (string)$valObj->dns_dp_key;
|
||||
break;
|
||||
case 'dns_freedns':
|
||||
$proc_env['FREEDNS_User'] = (string)$valObj->dns_freedns_user;
|
||||
$proc_env['FREEDNS_Password'] = (string)$valObj->dns_freedns_password;
|
||||
break;
|
||||
case 'dns_gandi_livedns':
|
||||
$proc_env['GANDI_LIVEDNS_KEY'] = (string)$valObj->dns_gandi_livedns_key;
|
||||
break;
|
||||
case 'dns_gd':
|
||||
$proc_env['GD_Key'] = (string)$valObj->dns_gd_key;
|
||||
$proc_env['GD_Secret'] = (string)$valObj->dns_gd_secret;
|
||||
|
|
@ -624,6 +639,11 @@ function run_acme_validation($certObj, $valObj, $acctObj)
|
|||
$acme_hook_options[] = "--dnssleep 960";
|
||||
}
|
||||
break;
|
||||
case 'dns_linode':
|
||||
$proc_env['LINODE_API_KEY'] = (string)$valObj->dns_linode_key;
|
||||
// Linode can take up to 15 to update DNS records
|
||||
$acme_hook_options[] = "--dnssleep 960";
|
||||
break;
|
||||
case 'dns_lua':
|
||||
$proc_env['LUA_Key'] = (string)$valObj->dns_lua_key;
|
||||
$proc_env['LUA_Email'] = (string)$valObj->dns_lua_email;
|
||||
|
|
@ -757,12 +777,13 @@ function import_certificate($certObj, $modelObj)
|
|||
|
||||
$cert_id = (string)$certObj->id;
|
||||
$cert_filename = "/var/etc/acme-client/certs/${cert_id}/cert.pem";
|
||||
$cert_chain_filename = "/var/etc/acme-client/certs/${cert_id}/chain.pem";
|
||||
$cert_fullchain_filename = "/var/etc/acme-client/certs/${cert_id}/fullchain.pem";
|
||||
$key_filename = "/var/etc/acme-client/keys/${cert_id}/private.key";
|
||||
|
||||
// Check if certificate files can be found
|
||||
clearstatcache(); // don't let the cache fool us
|
||||
foreach (array($cert_filename, $key_filename, $cert_fullchain_filename) as $file) {
|
||||
foreach (array($cert_filename, $key_filename, $cert_chain_filename, $cert_fullchain_filename) as $file) {
|
||||
if (is_file($file)) {
|
||||
// certificate file found
|
||||
} else {
|
||||
|
|
@ -771,6 +792,63 @@ function import_certificate($certObj, $modelObj)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Step 1: import CA
|
||||
*/
|
||||
|
||||
// Read contents from CA file
|
||||
$ca_content = @file_get_contents($cert_chain_filename);
|
||||
if ($ca_content != false) {
|
||||
$ca_subject = cert_get_subject($ca_content, false);
|
||||
$ca_serial = cert_get_serial($ca_content, false);
|
||||
$ca_cn = local_cert_get_cn($ca_content, false);
|
||||
$ca_issuer = cert_get_issuer($ca_content, false);
|
||||
$ca_purpose = cert_get_purpose($ca_content, false);
|
||||
} else {
|
||||
log_error("AcmeClient: unable to read CA certificate content from file");
|
||||
return(1);
|
||||
}
|
||||
|
||||
// Prepare CA for import in Cert Manager
|
||||
$ca = array();
|
||||
$ca['crt'] = base64_encode($ca_content);
|
||||
$ca['refid'] = uniqid();
|
||||
$ca_found = false;
|
||||
|
||||
// Check if CA was previously imported
|
||||
$cacnt = 0;
|
||||
foreach ($config['ca'] as $cacrt) {
|
||||
$cacrt_subject = cert_get_subject($cacrt['crt'], true);
|
||||
$cacrt_issuer = cert_get_issuer($cacrt['crt'], true);
|
||||
if (($ca_subject == $cacrt_subject) and ($ca_issuer == $cacrt_issuer)) {
|
||||
// Use old refid instead of generating a new one
|
||||
$ca['refid'] = (string)$cacrt['refid'];
|
||||
$ca_found = true;
|
||||
break;
|
||||
}
|
||||
$cacnt++;
|
||||
}
|
||||
|
||||
// Collect required CA information
|
||||
$ca_cn = local_cert_get_cn($ca_content, false);
|
||||
$ca['descr'] = (string)$ca_cn . ' (Let\'s Encrypt)';
|
||||
|
||||
// Prepare CA for import
|
||||
local_ca_import($ca, $ca_content);
|
||||
|
||||
// Update existing CA?
|
||||
if ($ca_found == true) {
|
||||
$config['ca'][$cacnt] = $ca;
|
||||
} else {
|
||||
// Create new CA item
|
||||
$config['ca'][] = $ca;
|
||||
log_error("AcmeClient: importing Let's Encrypt CA: ${ca_cn}");
|
||||
}
|
||||
|
||||
/*
|
||||
* Step 2: import certificate
|
||||
*/
|
||||
|
||||
// Read contents from certificate file
|
||||
$cert_content = @file_get_contents($cert_filename);
|
||||
if ($cert_content != false) {
|
||||
|
|
@ -789,6 +867,7 @@ function import_certificate($certObj, $modelObj)
|
|||
$cert = array();
|
||||
$cert_refid = uniqid();
|
||||
$cert['refid'] = $cert_refid;
|
||||
$cert['caref'] = (string)$ca['refid'];
|
||||
$import_log_message = 'Imported';
|
||||
$cert_found = false;
|
||||
|
||||
|
|
@ -822,20 +901,13 @@ function import_certificate($certObj, $modelObj)
|
|||
return(1);
|
||||
}
|
||||
|
||||
// Read cert fullchain
|
||||
$cert_fullchain_content = @file_get_contents($cert_fullchain_filename);
|
||||
if ($cert_fullchain_content == false) {
|
||||
log_error("AcmeClient: unable to read full certificate chain from file: ${cert_fullchain_filename}");
|
||||
return(1);
|
||||
}
|
||||
|
||||
// Collect required cert information
|
||||
$cert_cn = local_cert_get_cn($cert_content, false);
|
||||
$cert['descr'] = (string)$cert_cn . ' (Let\'s Encrypt)';
|
||||
$cert['refid'] = $cert_refid;
|
||||
|
||||
// Prepare certificate for import
|
||||
cert_import($cert, $cert_fullchain_content, $key_content);
|
||||
cert_import($cert, $cert_content, $key_content);
|
||||
|
||||
// Update existing certificate?
|
||||
if ($cert_found == true) {
|
||||
|
|
@ -854,6 +926,10 @@ function import_certificate($certObj, $modelObj)
|
|||
$config['cert'][] = $cert;
|
||||
}
|
||||
|
||||
/*
|
||||
* Step 3: update configuration
|
||||
*/
|
||||
|
||||
// Write changes to config
|
||||
// TODO: Legacy code, should be replaced with code from OPNsense framework
|
||||
write_config("${import_log_message} Let's Encrypt SSL certificate: ${cert_cn}");
|
||||
|
|
@ -881,6 +957,7 @@ function run_restart_actions($certlist, $modelObj)
|
|||
{
|
||||
global $config;
|
||||
$return = 0;
|
||||
$configObj = Config::getInstance()->object();
|
||||
|
||||
// NOTE: Do NOT run any restart action twice, collect duplicates first.
|
||||
$restart_actions = array();
|
||||
|
|
@ -895,11 +972,11 @@ function run_restart_actions($certlist, $modelObj)
|
|||
continue;
|
||||
}
|
||||
// Extract restart actions
|
||||
$_actions = explode(',', $certObj->restartActions);
|
||||
if (empty($_actions)) {
|
||||
if (empty((string)$certObj->restartActions)) {
|
||||
// No restart actions configured.
|
||||
continue;
|
||||
}
|
||||
$_actions = explode(',', $certObj->restartActions);
|
||||
// Walk through all linked restart actions.
|
||||
foreach ($_actions as $_action) {
|
||||
// Extract restart action
|
||||
|
|
@ -965,8 +1042,12 @@ function run_restart_actions($certlist, $modelObj)
|
|||
$proc_stderr = '';
|
||||
$result = ''; // exit code (or '99' in case of timeout)
|
||||
|
||||
// TODO: Make the timeout configurable.
|
||||
$timeout = '600';
|
||||
// Timeout for custom restart actions.
|
||||
if (!empty((string)$configObj->OPNsense->AcmeClient->settings->restartTimeout)) {
|
||||
$timeout = (string)$configObj->OPNsense->AcmeClient->settings->restartTimeout;
|
||||
} else {
|
||||
$timeout = '600';
|
||||
}
|
||||
$starttime = time();
|
||||
|
||||
$proc_cmd = (string)$action->custom;
|
||||
|
|
@ -1081,6 +1162,48 @@ function local_cert_get_cn($crt, $decode = true)
|
|||
return "";
|
||||
}
|
||||
|
||||
// taken from system_camanager.php
|
||||
function local_ca_import(& $ca, $str, $key="", $serial=0) {
|
||||
global $config;
|
||||
|
||||
$ca['crt'] = base64_encode($str);
|
||||
if (!empty($key)) {
|
||||
$ca['prv'] = base64_encode($key);
|
||||
}
|
||||
if (!empty($serial)) {
|
||||
$ca['serial'] = $serial;
|
||||
}
|
||||
$subject = cert_get_subject($str, false);
|
||||
$issuer = cert_get_issuer($str, false);
|
||||
|
||||
// Find my issuer unless self-signed
|
||||
if($issuer <> $subject) {
|
||||
$issuer_crt =& lookup_ca_by_subject($issuer);
|
||||
if($issuer_crt) {
|
||||
$ca['caref'] = $issuer_crt['refid'];
|
||||
}
|
||||
}
|
||||
|
||||
/* Correct if child certificate was loaded first */
|
||||
if (is_array($config['ca'])) {
|
||||
foreach ($config['ca'] as & $oca) {
|
||||
$issuer = cert_get_issuer($oca['crt']);
|
||||
if($ca['refid']<>$oca['refid'] && $issuer==$subject) {
|
||||
$oca['caref'] = $ca['refid'];
|
||||
}
|
||||
}
|
||||
}
|
||||
if (is_array($config['cert'])) {
|
||||
foreach ($config['cert'] as & $cert) {
|
||||
$issuer = cert_get_issuer($cert['crt']);
|
||||
if($issuer==$subject) {
|
||||
$cert['caref'] = $ca['refid'];
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function base64url_encode($str)
|
||||
{
|
||||
return rtrim(strtr(base64_encode($str), '+/', '-_'), '=');
|
||||
|
|
|
|||
0
security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient/dnsapi/dns_ad.sh
Normal file → Executable file
0
security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient/dnsapi/dns_ad.sh
Normal file → Executable file
2
security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient/dnsapi/dns_ali.sh
Normal file → Executable file
2
security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient/dnsapi/dns_ali.sh
Normal file → Executable file
|
|
@ -67,7 +67,7 @@ _get_root() {
|
|||
}
|
||||
|
||||
_ali_rest() {
|
||||
signature=$(printf "%s" "GET&%2F&$(_ali_urlencode "$query")" | _hmac "sha1" "$(_hex "$Ali_Secret&")" | _base64)
|
||||
signature=$(printf "%s" "GET&%2F&$(_ali_urlencode "$query")" | _hmac "sha1" "$(printf "%s" "$Ali_Secret&" | _hex_dump | tr -d " ")" | _base64)
|
||||
signature=$(_ali_urlencode "$signature")
|
||||
url="$Ali_API?$query&Signature=$signature"
|
||||
|
||||
|
|
|
|||
8
security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient/dnsapi/dns_aws.sh
Normal file → Executable file
8
security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient/dnsapi/dns_aws.sh
Normal file → Executable file
|
|
@ -93,7 +93,7 @@ _get_root() {
|
|||
fi
|
||||
|
||||
if _contains "$response" "<Name>$h.</Name>"; then
|
||||
hostedzone="$(echo "$response" | sed 's/<HostedZone>/\n&/g' | _egrep_o "<HostedZone>.*?<Name>$h.<.Name>.*?<.HostedZone>")"
|
||||
hostedzone="$(echo "$response" | sed 's/<HostedZone>/#&/g' | tr '#' '\n' | _egrep_o "<HostedZone><Id>[^<]*<.Id><Name>$h.<.Name>.*<.HostedZone>")"
|
||||
_debug hostedzone "$hostedzone"
|
||||
if [ -z "$hostedzone" ]; then
|
||||
_err "Error, can not get hostedzone."
|
||||
|
|
@ -181,10 +181,10 @@ aws_rest() {
|
|||
|
||||
#kSecret="wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY" ############################
|
||||
|
||||
_debug2 kSecret "$kSecret"
|
||||
_secure_debug2 kSecret "$kSecret"
|
||||
|
||||
kSecretH="$(_hex "$kSecret")"
|
||||
_debug2 kSecretH "$kSecretH"
|
||||
kSecretH="$(printf "%s" "$kSecret" | _hex_dump | tr -d " ")"
|
||||
_secure_debug2 kSecretH "$kSecretH"
|
||||
|
||||
kDateH="$(printf "$RequestDateOnly%s" | _hmac "$Hash" "$kSecretH" hex)"
|
||||
_debug2 kDateH "$kDateH"
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ existing_records() {
|
|||
return 1
|
||||
fi
|
||||
|
||||
seg=$(printf "%s\n" "$response" | _egrep_o '[^{]*host":"'"$_sub_domain"'"[^}]*\}')
|
||||
seg=$(printf "%s\n" "$response" | _egrep_o '"record_id":[^{]*host":"'"$_sub_domain"'"[^}]*\}')
|
||||
_debug seg "$seg"
|
||||
if [ -z "$seg" ]; then
|
||||
return 0
|
||||
|
|
@ -155,7 +155,7 @@ _get_root() {
|
|||
fi
|
||||
|
||||
if _contains "$response" "$h."; then
|
||||
seg=$(printf "%s\n" "$response" | _egrep_o '[^{]*"'"$h"'."[^}]*}')
|
||||
seg=$(printf "%s\n" "$response" | _egrep_o '"id":[^{]*"'"$h"'."[^}]*}')
|
||||
_debug seg "$seg"
|
||||
_domain_id=$(printf "%s\n" "$seg" | _egrep_o "\"id\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \")
|
||||
_debug _domain_id "$_domain_id"
|
||||
|
|
|
|||
328
security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient/dnsapi/dns_cyon.sh
Executable file
328
security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient/dnsapi/dns_cyon.sh
Executable file
|
|
@ -0,0 +1,328 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
########
|
||||
# Custom cyon.ch DNS API for use with [acme.sh](https://github.com/Neilpang/acme.sh)
|
||||
#
|
||||
# Usage: acme.sh --issue --dns dns_cyon -d www.domain.com
|
||||
#
|
||||
# Dependencies:
|
||||
# -------------
|
||||
# - oathtool (When using 2 Factor Authentication)
|
||||
#
|
||||
# Issues:
|
||||
# -------
|
||||
# Any issues / questions / suggestions can be posted here:
|
||||
# https://github.com/noplanman/cyon-api/issues
|
||||
#
|
||||
# Author: Armando Lüscher <armando@noplanman.ch>
|
||||
########
|
||||
|
||||
dns_cyon_add() {
|
||||
_cyon_load_credentials \
|
||||
&& _cyon_load_parameters "$@" \
|
||||
&& _cyon_print_header "add" \
|
||||
&& _cyon_login \
|
||||
&& _cyon_change_domain_env \
|
||||
&& _cyon_add_txt \
|
||||
&& _cyon_logout
|
||||
}
|
||||
|
||||
dns_cyon_rm() {
|
||||
_cyon_load_credentials \
|
||||
&& _cyon_load_parameters "$@" \
|
||||
&& _cyon_print_header "delete" \
|
||||
&& _cyon_login \
|
||||
&& _cyon_change_domain_env \
|
||||
&& _cyon_delete_txt \
|
||||
&& _cyon_logout
|
||||
}
|
||||
|
||||
#########################
|
||||
### PRIVATE FUNCTIONS ###
|
||||
#########################
|
||||
|
||||
_cyon_load_credentials() {
|
||||
# Convert loaded password to/from base64 as needed.
|
||||
if [ "${CY_Password_B64}" ]; then
|
||||
CY_Password="$(printf "%s" "${CY_Password_B64}" | _dbase64 "multiline")"
|
||||
elif [ "${CY_Password}" ]; then
|
||||
CY_Password_B64="$(printf "%s" "${CY_Password}" | _base64)"
|
||||
fi
|
||||
|
||||
if [ -z "${CY_Username}" ] || [ -z "${CY_Password}" ]; then
|
||||
# Dummy entries to satify script checker.
|
||||
CY_Username=""
|
||||
CY_Password=""
|
||||
CY_OTP_Secret=""
|
||||
|
||||
_err ""
|
||||
_err "You haven't set your cyon.ch login credentials yet."
|
||||
_err "Please set the required cyon environment variables."
|
||||
_err ""
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Save the login credentials to the account.conf file.
|
||||
_debug "Save credentials to account.conf"
|
||||
_saveaccountconf CY_Username "${CY_Username}"
|
||||
_saveaccountconf CY_Password_B64 "$CY_Password_B64"
|
||||
if [ ! -z "${CY_OTP_Secret}" ]; then
|
||||
_saveaccountconf CY_OTP_Secret "$CY_OTP_Secret"
|
||||
else
|
||||
_clearaccountconf CY_OTP_Secret
|
||||
fi
|
||||
}
|
||||
|
||||
_cyon_is_idn() {
|
||||
_idn_temp="$(printf "%s" "${1}" | tr -d "0-9a-zA-Z.,-_")"
|
||||
_idn_temp2="$(printf "%s" "${1}" | grep -o "xn--")"
|
||||
[ "$_idn_temp" ] || [ "$_idn_temp2" ]
|
||||
}
|
||||
|
||||
_cyon_load_parameters() {
|
||||
# Read the required parameters to add the TXT entry.
|
||||
# shellcheck disable=SC2018,SC2019
|
||||
fulldomain="$(printf "%s" "${1}" | tr "A-Z" "a-z")"
|
||||
fulldomain_idn="${fulldomain}"
|
||||
|
||||
# Special case for IDNs, as cyon needs a domain environment change,
|
||||
# which uses the "pretty" instead of the punycode version.
|
||||
if _cyon_is_idn "${fulldomain}"; then
|
||||
if ! _exists idn; then
|
||||
_err "Please install idn to process IDN names."
|
||||
_err ""
|
||||
return 1
|
||||
fi
|
||||
|
||||
fulldomain="$(idn -u "${fulldomain}")"
|
||||
fulldomain_idn="$(idn -a "${fulldomain}")"
|
||||
fi
|
||||
|
||||
_debug fulldomain "${fulldomain}"
|
||||
_debug fulldomain_idn "${fulldomain_idn}"
|
||||
|
||||
txtvalue="${2}"
|
||||
_debug txtvalue "${txtvalue}"
|
||||
|
||||
# This header is required for curl calls.
|
||||
_H1="X-Requested-With: XMLHttpRequest"
|
||||
export _H1
|
||||
}
|
||||
|
||||
_cyon_print_header() {
|
||||
if [ "${1}" = "add" ]; then
|
||||
_info ""
|
||||
_info "+---------------------------------------------+"
|
||||
_info "| Adding DNS TXT entry to your cyon.ch domain |"
|
||||
_info "+---------------------------------------------+"
|
||||
_info ""
|
||||
_info " * Full Domain: ${fulldomain}"
|
||||
_info " * TXT Value: ${txtvalue}"
|
||||
_info ""
|
||||
elif [ "${1}" = "delete" ]; then
|
||||
_info ""
|
||||
_info "+-------------------------------------------------+"
|
||||
_info "| Deleting DNS TXT entry from your cyon.ch domain |"
|
||||
_info "+-------------------------------------------------+"
|
||||
_info ""
|
||||
_info " * Full Domain: ${fulldomain}"
|
||||
_info ""
|
||||
fi
|
||||
}
|
||||
|
||||
_cyon_get_cookie_header() {
|
||||
printf "Cookie: %s" "$(grep "cyon=" "$HTTP_HEADER" | grep "^Set-Cookie:" | _tail_n 1 | _egrep_o 'cyon=[^;]*;' | tr -d ';')"
|
||||
}
|
||||
|
||||
_cyon_login() {
|
||||
_info " - Logging in..."
|
||||
|
||||
username_encoded="$(printf "%s" "${CY_Username}" | _url_encode)"
|
||||
password_encoded="$(printf "%s" "${CY_Password}" | _url_encode)"
|
||||
|
||||
login_url="https://my.cyon.ch/auth/index/dologin-async"
|
||||
login_data="$(printf "%s" "username=${username_encoded}&password=${password_encoded}&pathname=%2F")"
|
||||
|
||||
login_response="$(_post "$login_data" "$login_url")"
|
||||
_debug login_response "${login_response}"
|
||||
|
||||
# Bail if login fails.
|
||||
if [ "$(printf "%s" "${login_response}" | _cyon_get_response_success)" != "success" ]; then
|
||||
_err " $(printf "%s" "${login_response}" | _cyon_get_response_message)"
|
||||
_err ""
|
||||
return 1
|
||||
fi
|
||||
|
||||
_info " success"
|
||||
|
||||
# NECESSARY!! Load the main page after login, to get the new cookie.
|
||||
_H2="$(_cyon_get_cookie_header)"
|
||||
export _H2
|
||||
|
||||
_get "https://my.cyon.ch/" >/dev/null
|
||||
|
||||
# todo: instead of just checking if the env variable is defined, check if we actually need to do a 2FA auth request.
|
||||
|
||||
# 2FA authentication with OTP?
|
||||
if [ ! -z "${CY_OTP_Secret}" ]; then
|
||||
_info " - Authorising with OTP code..."
|
||||
|
||||
if ! _exists oathtool; then
|
||||
_err "Please install oathtool to use 2 Factor Authentication."
|
||||
_err ""
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Get OTP code with the defined secret.
|
||||
otp_code="$(oathtool --base32 --totp "${CY_OTP_Secret}" 2>/dev/null)"
|
||||
|
||||
login_otp_url="https://my.cyon.ch/auth/multi-factor/domultifactorauth-async"
|
||||
login_otp_data="totpcode=${otp_code}&pathname=%2F&rememberme=0"
|
||||
|
||||
login_otp_response="$(_post "$login_otp_data" "$login_otp_url")"
|
||||
_debug login_otp_response "${login_otp_response}"
|
||||
|
||||
# Bail if OTP authentication fails.
|
||||
if [ "$(printf "%s" "${login_otp_response}" | _cyon_get_response_success)" != "success" ]; then
|
||||
_err " $(printf "%s" "${login_otp_response}" | _cyon_get_response_message)"
|
||||
_err ""
|
||||
return 1
|
||||
fi
|
||||
|
||||
_info " success"
|
||||
fi
|
||||
|
||||
_info ""
|
||||
}
|
||||
|
||||
_cyon_logout() {
|
||||
_info " - Logging out..."
|
||||
|
||||
_get "https://my.cyon.ch/auth/index/dologout" >/dev/null
|
||||
|
||||
_info " success"
|
||||
_info ""
|
||||
}
|
||||
|
||||
_cyon_change_domain_env() {
|
||||
_info " - Changing domain environment..."
|
||||
|
||||
# Get the "example.com" part of the full domain name.
|
||||
domain_env="$(printf "%s" "${fulldomain}" | sed -E -e 's/.*\.(.*\..*)$/\1/')"
|
||||
_debug "Changing domain environment to ${domain_env}"
|
||||
|
||||
gloo_item_key="$(_get "https://my.cyon.ch/domain/" | tr '\n' ' ' | sed -E -e "s/.*data-domain=\"${domain_env}\"[^<]*data-itemkey=\"([^\"]*).*/\1/")"
|
||||
_debug gloo_item_key "${gloo_item_key}"
|
||||
|
||||
domain_env_url="https://my.cyon.ch/user/environment/setdomain/d/${domain_env}/gik/${gloo_item_key}"
|
||||
|
||||
domain_env_response="$(_get "${domain_env_url}")"
|
||||
_debug domain_env_response "${domain_env_response}"
|
||||
|
||||
if ! _cyon_check_if_2fa_missed "${domain_env_response}"; then return 1; fi
|
||||
|
||||
domain_env_success="$(printf "%s" "${domain_env_response}" | _egrep_o '"authenticated":\w*' | cut -d : -f 2)"
|
||||
|
||||
# Bail if domain environment change fails.
|
||||
if [ "${domain_env_success}" != "true" ]; then
|
||||
_err " $(printf "%s" "${domain_env_response}" | _cyon_get_response_message)"
|
||||
_err ""
|
||||
return 1
|
||||
fi
|
||||
|
||||
_info " success"
|
||||
_info ""
|
||||
}
|
||||
|
||||
_cyon_add_txt() {
|
||||
_info " - Adding DNS TXT entry..."
|
||||
|
||||
add_txt_url="https://my.cyon.ch/domain/dnseditor/add-record-async"
|
||||
add_txt_data="zone=${fulldomain_idn}.&ttl=900&type=TXT&value=${txtvalue}"
|
||||
|
||||
add_txt_response="$(_post "$add_txt_data" "$add_txt_url")"
|
||||
_debug add_txt_response "${add_txt_response}"
|
||||
|
||||
if ! _cyon_check_if_2fa_missed "${add_txt_response}"; then return 1; fi
|
||||
|
||||
add_txt_message="$(printf "%s" "${add_txt_response}" | _cyon_get_response_message)"
|
||||
add_txt_status="$(printf "%s" "${add_txt_response}" | _cyon_get_response_status)"
|
||||
|
||||
# Bail if adding TXT entry fails.
|
||||
if [ "${add_txt_status}" != "true" ]; then
|
||||
_err " ${add_txt_message}"
|
||||
_err ""
|
||||
return 1
|
||||
fi
|
||||
|
||||
_info " success (TXT|${fulldomain_idn}.|${txtvalue})"
|
||||
_info ""
|
||||
}
|
||||
|
||||
_cyon_delete_txt() {
|
||||
_info " - Deleting DNS TXT entry..."
|
||||
|
||||
list_txt_url="https://my.cyon.ch/domain/dnseditor/list-async"
|
||||
|
||||
list_txt_response="$(_get "${list_txt_url}" | sed -e 's/data-hash/\\ndata-hash/g')"
|
||||
_debug list_txt_response "${list_txt_response}"
|
||||
|
||||
if ! _cyon_check_if_2fa_missed "${list_txt_response}"; then return 1; fi
|
||||
|
||||
# Find and delete all acme challenge entries for the $fulldomain.
|
||||
_dns_entries="$(printf "%b\n" "${list_txt_response}" | sed -n 's/data-hash=\\"\([^"]*\)\\" data-identifier=\\"\([^"]*\)\\".*/\1 \2/p')"
|
||||
|
||||
printf "%s" "${_dns_entries}" | while read -r _hash _identifier; do
|
||||
dns_type="$(printf "%s" "$_identifier" | cut -d'|' -f1)"
|
||||
dns_domain="$(printf "%s" "$_identifier" | cut -d'|' -f2)"
|
||||
|
||||
if [ "${dns_type}" != "TXT" ] || [ "${dns_domain}" != "${fulldomain_idn}." ]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
hash_encoded="$(printf "%s" "${_hash}" | _url_encode)"
|
||||
identifier_encoded="$(printf "%s" "${_identifier}" | _url_encode)"
|
||||
|
||||
delete_txt_url="https://my.cyon.ch/domain/dnseditor/delete-record-async"
|
||||
delete_txt_data="$(printf "%s" "hash=${hash_encoded}&identifier=${identifier_encoded}")"
|
||||
|
||||
delete_txt_response="$(_post "$delete_txt_data" "$delete_txt_url")"
|
||||
_debug delete_txt_response "${delete_txt_response}"
|
||||
|
||||
if ! _cyon_check_if_2fa_missed "${delete_txt_response}"; then return 1; fi
|
||||
|
||||
delete_txt_message="$(printf "%s" "${delete_txt_response}" | _cyon_get_response_message)"
|
||||
delete_txt_status="$(printf "%s" "${delete_txt_response}" | _cyon_get_response_status)"
|
||||
|
||||
# Skip if deleting TXT entry fails.
|
||||
if [ "${delete_txt_status}" != "true" ]; then
|
||||
_err " ${delete_txt_message} (${_identifier})"
|
||||
else
|
||||
_info " success (${_identifier})"
|
||||
fi
|
||||
done
|
||||
|
||||
_info " done"
|
||||
_info ""
|
||||
}
|
||||
|
||||
_cyon_get_response_message() {
|
||||
_egrep_o '"message":"[^"]*"' | cut -d : -f 2 | tr -d '"'
|
||||
}
|
||||
|
||||
_cyon_get_response_status() {
|
||||
_egrep_o '"status":\w*' | cut -d : -f 2
|
||||
}
|
||||
|
||||
_cyon_get_response_success() {
|
||||
_egrep_o '"onSuccess":"[^"]*"' | cut -d : -f 2 | tr -d '"'
|
||||
}
|
||||
|
||||
_cyon_check_if_2fa_missed() {
|
||||
# Did we miss the 2FA?
|
||||
if test "${1#*multi_factor_form}" != "${1}"; then
|
||||
_err " Missed OTP authentication!"
|
||||
_err ""
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
148
security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient/dnsapi/dns_do.sh
Executable file
148
security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient/dnsapi/dns_do.sh
Executable file
|
|
@ -0,0 +1,148 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
# DNS API for Domain-Offensive / Resellerinterface / Domainrobot
|
||||
|
||||
# Report bugs at https://github.com/seidler2547/acme.sh/issues
|
||||
|
||||
# set these environment variables to match your customer ID and password:
|
||||
# DO_PID="KD-1234567"
|
||||
# DO_PW="cdfkjl3n2"
|
||||
|
||||
DO_URL="https://soap.resellerinterface.de/"
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
#Usage: dns_myapi_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns_do_add() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
if _dns_do_authenticate; then
|
||||
_info "Adding TXT record to ${_domain} as ${fulldomain}"
|
||||
_dns_do_soap createRR origin "${_domain}" name "${fulldomain}" type TXT data "${txtvalue}" ttl 300
|
||||
if _contains "${response}" '>success<'; then
|
||||
return 0
|
||||
fi
|
||||
_err "Could not create resource record, check logs"
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
#fulldomain
|
||||
dns_do_rm() {
|
||||
fulldomain=$1
|
||||
if _dns_do_authenticate; then
|
||||
if _dns_do_list_rrs; then
|
||||
_dns_do_had_error=0
|
||||
for _rrid in ${_rr_list}; do
|
||||
_info "Deleting resource record $_rrid for $_domain"
|
||||
_dns_do_soap deleteRR origin "${_domain}" rrid "${_rrid}"
|
||||
if ! _contains "${response}" '>success<'; then
|
||||
_dns_do_had_error=1
|
||||
_err "Could not delete resource record for ${_domain}, id ${_rrid}"
|
||||
fi
|
||||
done
|
||||
return $_dns_do_had_error
|
||||
fi
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
_dns_do_authenticate() {
|
||||
_info "Authenticating as ${DO_PID}"
|
||||
_dns_do_soap authPartner partner "${DO_PID}" password "${DO_PW}"
|
||||
if _contains "${response}" '>success<'; then
|
||||
_get_root "$fulldomain"
|
||||
_debug "_domain $_domain"
|
||||
return 0
|
||||
else
|
||||
_err "Authentication failed, are DO_PID and DO_PW set correctly?"
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
_dns_do_list_rrs() {
|
||||
_dns_do_soap getRRList origin "${_domain}"
|
||||
if ! _contains "${response}" 'SOAP-ENC:Array'; then
|
||||
_err "getRRList origin ${_domain} failed"
|
||||
return 1
|
||||
fi
|
||||
_rr_list="$(echo "${response}" \
|
||||
| tr -d "\n\r\t" \
|
||||
| sed -e 's/<item xsi:type="ns2:Map">/\n/g' \
|
||||
| grep ">$(_regexcape "$fulldomain")</value>" \
|
||||
| sed -e 's/<\/item>/\n/g' \
|
||||
| grep '>id</key><value' \
|
||||
| _egrep_o '>[0-9]{1,16}<' \
|
||||
| tr -d '><')"
|
||||
[ "${_rr_list}" ]
|
||||
}
|
||||
|
||||
_dns_do_soap() {
|
||||
func="$1"
|
||||
shift
|
||||
# put the parameters to xml
|
||||
body="<tns:${func} xmlns:tns=\"${DO_URL}\">"
|
||||
while [ "$1" ]; do
|
||||
_k="$1"
|
||||
shift
|
||||
_v="$1"
|
||||
shift
|
||||
body="$body<$_k>$_v</$_k>"
|
||||
done
|
||||
body="$body</tns:${func}>"
|
||||
_debug2 "SOAP request ${body}"
|
||||
|
||||
# build SOAP XML
|
||||
_xml='<?xml version="1.0" encoding="UTF-8"?>
|
||||
<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
|
||||
<env:Body>'"$body"'</env:Body>
|
||||
</env:Envelope>'
|
||||
|
||||
# set SOAP headers
|
||||
export _H1="SOAPAction: ${DO_URL}#${func}"
|
||||
|
||||
if ! response="$(_post "${_xml}" "${DO_URL}")"; then
|
||||
_err "Error <$1>"
|
||||
return 1
|
||||
fi
|
||||
_debug2 "SOAP response $response"
|
||||
|
||||
# retrieve cookie header
|
||||
_H2="$(_egrep_o 'Cookie: [^;]+' <"$HTTP_HEADER" | _head_n 1)"
|
||||
export _H2
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
_get_root() {
|
||||
domain=$1
|
||||
i=1
|
||||
|
||||
_dns_do_soap getDomainList
|
||||
_all_domains="$(echo "${response}" \
|
||||
| tr -d "\n\r\t " \
|
||||
| _egrep_o 'domain</key><value[^>]+>[^<]+' \
|
||||
| sed -e 's/^domain<\/key><value[^>]*>//g')"
|
||||
|
||||
while true; do
|
||||
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||
if [ -z "$h" ]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
if _contains "${_all_domains}" "^$(_regexcape "$h")\$"; then
|
||||
_domain="$h"
|
||||
return 0
|
||||
fi
|
||||
|
||||
i=$(_math $i + 1)
|
||||
done
|
||||
_debug "$domain not found"
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
_regexcape() {
|
||||
echo "$1" | sed -e 's/\([]\.$*^[]\)/\\\1/g'
|
||||
}
|
||||
|
|
@ -0,0 +1,375 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
#This file name is "dns_freedns.sh"
|
||||
#So, here must be a method dns_freedns_add()
|
||||
#Which will be called by acme.sh to add the txt record to your api system.
|
||||
#returns 0 means success, otherwise error.
|
||||
#
|
||||
#Author: David Kerr
|
||||
#Report Bugs here: https://github.com/dkerr64/acme.sh
|
||||
#
|
||||
######## Public functions #####################
|
||||
|
||||
# Export FreeDNS userid and password in folowing variables...
|
||||
# FREEDNS_User=username
|
||||
# FREEDNS_Password=password
|
||||
# login cookie is saved in acme account config file so userid / pw
|
||||
# need to be set only when changed.
|
||||
|
||||
#Usage: dns_freedns_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns_freedns_add() {
|
||||
fulldomain="$1"
|
||||
txtvalue="$2"
|
||||
|
||||
_info "Add TXT record using FreeDNS"
|
||||
_debug "fulldomain: $fulldomain"
|
||||
_debug "txtvalue: $txtvalue"
|
||||
|
||||
if [ -z "$FREEDNS_User" ] || [ -z "$FREEDNS_Password" ]; then
|
||||
FREEDNS_User=""
|
||||
FREEDNS_Password=""
|
||||
if [ -z "$FREEDNS_COOKIE" ]; then
|
||||
_err "You did not specify the FreeDNS username and password yet."
|
||||
_err "Please export as FREEDNS_User / FREEDNS_Password and try again."
|
||||
return 1
|
||||
fi
|
||||
using_cached_cookies="true"
|
||||
else
|
||||
FREEDNS_COOKIE="$(_freedns_login "$FREEDNS_User" "$FREEDNS_Password")"
|
||||
if [ -z "$FREEDNS_COOKIE" ]; then
|
||||
return 1
|
||||
fi
|
||||
using_cached_cookies="false"
|
||||
fi
|
||||
|
||||
_debug "FreeDNS login cookies: $FREEDNS_COOKIE (cached = $using_cached_cookies)"
|
||||
|
||||
_saveaccountconf FREEDNS_COOKIE "$FREEDNS_COOKIE"
|
||||
|
||||
# split our full domain name into two parts...
|
||||
i="$(echo "$fulldomain" | tr '.' ' ' | wc -w)"
|
||||
i="$(_math "$i" - 1)"
|
||||
top_domain="$(echo "$fulldomain" | cut -d. -f "$i"-100)"
|
||||
i="$(_math "$i" - 1)"
|
||||
sub_domain="$(echo "$fulldomain" | cut -d. -f -"$i")"
|
||||
|
||||
# Sometimes FreeDNS does not reurn the subdomain page but rather
|
||||
# returns a page regarding becoming a premium member. This usually
|
||||
# happens after a period of inactivity. Immediately trying again
|
||||
# returns the correct subdomain page. So, we will try twice to
|
||||
# load the page and obtain our domain ID
|
||||
attempts=2
|
||||
while [ "$attempts" -gt "0" ]; do
|
||||
attempts="$(_math "$attempts" - 1)"
|
||||
|
||||
htmlpage="$(_freedns_retrieve_subdomain_page "$FREEDNS_COOKIE")"
|
||||
if [ "$?" != "0" ]; then
|
||||
if [ "$using_cached_cookies" = "true" ]; then
|
||||
_err "Has your FreeDNS username and password channged? If so..."
|
||||
_err "Please export as FREEDNS_User / FREEDNS_Password and try again."
|
||||
fi
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Now convert the tables in the HTML to CSV. This litte gem from
|
||||
# http://stackoverflow.com/questions/1403087/how-can-i-convert-an-html-table-to-csv
|
||||
subdomain_csv="$(echo "$htmlpage" \
|
||||
| grep -i -e '</\?TABLE\|</\?TD\|</\?TR\|</\?TH' \
|
||||
| sed 's/^[\ \t]*//g' \
|
||||
| tr -d '\n' \
|
||||
| sed 's/<\/TR[^>]*>/\n/Ig' \
|
||||
| sed 's/<\/\?\(TABLE\|TR\)[^>]*>//Ig' \
|
||||
| sed 's/^<T[DH][^>]*>\|<\/\?T[DH][^>]*>$//Ig' \
|
||||
| sed 's/<\/T[DH][^>]*><T[DH][^>]*>/,/Ig' \
|
||||
| grep 'edit.php?' \
|
||||
| grep "$top_domain")"
|
||||
# The above beauty ends with striping out rows that do not have an
|
||||
# href to edit.php and do not have the top domain we are looking for.
|
||||
# So all we should be left with is CSV of table of subdomains we are
|
||||
# interested in.
|
||||
|
||||
# Now we have to read through this table and extract the data we need
|
||||
lines="$(echo "$subdomain_csv" | wc -l)"
|
||||
nl='
|
||||
'
|
||||
i=0
|
||||
found=0
|
||||
while [ "$i" -lt "$lines" ]; do
|
||||
i="$(_math "$i" + 1)"
|
||||
line="$(echo "$subdomain_csv" | cut -d "$nl" -f "$i")"
|
||||
tmp="$(echo "$line" | cut -d ',' -f 1)"
|
||||
if [ $found = 0 ] && _startswith "$tmp" "<td>$top_domain"; then
|
||||
# this line will contain DNSdomainid for the top_domain
|
||||
DNSdomainid="$(echo "$line" | cut -d ',' -f 2 | sed 's/^.*domain_id=//;s/>.*//')"
|
||||
found=1
|
||||
else
|
||||
# lines contain DNS records for all subdomains
|
||||
DNSname="$(echo "$line" | cut -d ',' -f 2 | sed 's/^[^>]*>//;s/<\/a>.*//')"
|
||||
DNStype="$(echo "$line" | cut -d ',' -f 3)"
|
||||
if [ "$DNSname" = "$fulldomain" ] && [ "$DNStype" = "TXT" ]; then
|
||||
DNSdataid="$(echo "$line" | cut -d ',' -f 2 | sed 's/^.*data_id=//;s/>.*//')"
|
||||
# Now get current value for the TXT record. This method may
|
||||
# not produce accurate results as the value field is truncated
|
||||
# on this webpage. To get full value we would need to load
|
||||
# another page. However we don't really need this so long as
|
||||
# there is only one TXT record for the acme chalenge subdomain.
|
||||
DNSvalue="$(echo "$line" | cut -d ',' -f 4 | sed 's/^[^"]*"//;s/".*//;s/<\/td>.*//')"
|
||||
if [ $found != 0 ]; then
|
||||
break
|
||||
# we are breaking out of the loop at the first match of DNS name
|
||||
# and DNS type (if we are past finding the domainid). This assumes
|
||||
# that there is only ever one TXT record for the LetsEncrypt/acme
|
||||
# challenge subdomain. This seems to be a reasonable assumption
|
||||
# as the acme client deletes the TXT record on successful validation.
|
||||
fi
|
||||
else
|
||||
DNSname=""
|
||||
DNStype=""
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
_debug "DNSname: $DNSname DNStype: $DNStype DNSdomainid: $DNSdomainid DNSdataid: $DNSdataid"
|
||||
_debug "DNSvalue: $DNSvalue"
|
||||
|
||||
if [ -z "$DNSdomainid" ]; then
|
||||
# If domain ID is empty then something went wrong (top level
|
||||
# domain not found at FreeDNS).
|
||||
if [ "$attempts" = "0" ]; then
|
||||
# exhausted maximum retry attempts
|
||||
_debug "$htmlpage"
|
||||
_debug "$subdomain_csv"
|
||||
_err "Domain $top_domain not found at FreeDNS"
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
# break out of the 'retry' loop... we have found our domain ID
|
||||
break
|
||||
fi
|
||||
_info "Domain $top_domain not found at FreeDNS"
|
||||
_info "Retry loading subdomain page ($attempts attempts remaining)"
|
||||
done
|
||||
|
||||
if [ -z "$DNSdataid" ]; then
|
||||
# If data ID is empty then specific subdomain does not exist yet, need
|
||||
# to create it this should always be the case as the acme client
|
||||
# deletes the entry after domain is validated.
|
||||
_freedns_add_txt_record "$FREEDNS_COOKIE" "$DNSdomainid" "$sub_domain" "$txtvalue"
|
||||
return $?
|
||||
else
|
||||
if [ "$txtvalue" = "$DNSvalue" ]; then
|
||||
# if value in TXT record matches value requested then DNS record
|
||||
# does not need to be updated. But...
|
||||
# Testing value match fails. Website is truncating the value field.
|
||||
# So for now we will always go down the else path. Though in theory
|
||||
# should never come here anyway as the acme client deletes
|
||||
# the TXT record on successful validation, so we should not even
|
||||
# have found a TXT record !!
|
||||
_info "No update necessary for $fulldomain at FreeDNS"
|
||||
return 0
|
||||
else
|
||||
# Delete the old TXT record (with the wrong value)
|
||||
_freedns_delete_txt_record "$FREEDNS_COOKIE" "$DNSdataid"
|
||||
if [ "$?" = "0" ]; then
|
||||
# And add in new TXT record with the value provided
|
||||
_freedns_add_txt_record "$FREEDNS_COOKIE" "$DNSdomainid" "$sub_domain" "$txtvalue"
|
||||
fi
|
||||
return $?
|
||||
fi
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
#Usage: fulldomain txtvalue
|
||||
#Remove the txt record after validation.
|
||||
dns_freedns_rm() {
|
||||
fulldomain="$1"
|
||||
txtvalue="$2"
|
||||
|
||||
_info "Delete TXT record using FreeDNS"
|
||||
_debug "fulldomain: $fulldomain"
|
||||
_debug "txtvalue: $txtvalue"
|
||||
|
||||
# Need to read cookie from conf file again in case new value set
|
||||
# during login to FreeDNS when TXT record was created.
|
||||
# acme.sh does not have a _readaccountconf() fuction
|
||||
FREEDNS_COOKIE="$(_read_conf "$ACCOUNT_CONF_PATH" "FREEDNS_COOKIE")"
|
||||
_debug "FreeDNS login cookies: $FREEDNS_COOKIE"
|
||||
|
||||
# Sometimes FreeDNS does not reurn the subdomain page but rather
|
||||
# returns a page regarding becoming a premium member. This usually
|
||||
# happens after a period of inactivity. Immediately trying again
|
||||
# returns the correct subdomain page. So, we will try twice to
|
||||
# load the page and obtain our TXT record.
|
||||
attempts=2
|
||||
while [ "$attempts" -gt "0" ]; do
|
||||
attempts="$(_math "$attempts" - 1)"
|
||||
|
||||
htmlpage="$(_freedns_retrieve_subdomain_page "$FREEDNS_COOKIE")"
|
||||
if [ "$?" != "0" ]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Now convert the tables in the HTML to CSV. This litte gem from
|
||||
# http://stackoverflow.com/questions/1403087/how-can-i-convert-an-html-table-to-csv
|
||||
subdomain_csv="$(echo "$htmlpage" \
|
||||
| grep -i -e '</\?TABLE\|</\?TD\|</\?TR\|</\?TH' \
|
||||
| sed 's/^[\ \t]*//g' \
|
||||
| tr -d '\n' \
|
||||
| sed 's/<\/TR[^>]*>/\n/Ig' \
|
||||
| sed 's/<\/\?\(TABLE\|TR\)[^>]*>//Ig' \
|
||||
| sed 's/^<T[DH][^>]*>\|<\/\?T[DH][^>]*>$//Ig' \
|
||||
| sed 's/<\/T[DH][^>]*><T[DH][^>]*>/,/Ig' \
|
||||
| grep 'edit.php?' \
|
||||
| grep "$fulldomain")"
|
||||
# The above beauty ends with striping out rows that do not have an
|
||||
# href to edit.php and do not have the domain name we are looking for.
|
||||
# So all we should be left with is CSV of table of subdomains we are
|
||||
# interested in.
|
||||
|
||||
# Now we have to read through this table and extract the data we need
|
||||
lines="$(echo "$subdomain_csv" | wc -l)"
|
||||
nl='
|
||||
'
|
||||
i=0
|
||||
found=0
|
||||
while [ "$i" -lt "$lines" ]; do
|
||||
i="$(_math "$i" + 1)"
|
||||
line="$(echo "$subdomain_csv" | cut -d "$nl" -f "$i")"
|
||||
DNSname="$(echo "$line" | cut -d ',' -f 2 | sed 's/^[^>]*>//;s/<\/a>.*//')"
|
||||
DNStype="$(echo "$line" | cut -d ',' -f 3)"
|
||||
if [ "$DNSname" = "$fulldomain" ] && [ "$DNStype" = "TXT" ]; then
|
||||
DNSdataid="$(echo "$line" | cut -d ',' -f 2 | sed 's/^.*data_id=//;s/>.*//')"
|
||||
DNSvalue="$(echo "$line" | cut -d ',' -f 4 | sed 's/^[^"]*"//;s/".*//;s/<\/td>.*//')"
|
||||
_debug "DNSvalue: $DNSvalue"
|
||||
# if [ "$DNSvalue" = "$txtvalue" ]; then
|
||||
# Testing value match fails. Website is truncating the value
|
||||
# field. So for now we will assume that there is only one TXT
|
||||
# field for the sub domain and just delete it. Currently this
|
||||
# is a safe assumption.
|
||||
_freedns_delete_txt_record "$FREEDNS_COOKIE" "$DNSdataid"
|
||||
return $?
|
||||
# fi
|
||||
fi
|
||||
done
|
||||
done
|
||||
|
||||
# If we get this far we did not find a match (after two attempts)
|
||||
# Not necessarily an error, but log anyway.
|
||||
_debug2 "$subdomain_csv"
|
||||
_info "Cannot delete TXT record for $fulldomain/$txtvalue. Does not exist at FreeDNS"
|
||||
return 0
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
|
||||
# usage: _freedns_login username password
|
||||
# print string "cookie=value" etc.
|
||||
# returns 0 success
|
||||
_freedns_login() {
|
||||
export _H1="Accept-Language:en-US"
|
||||
username="$1"
|
||||
password="$2"
|
||||
url="https://freedns.afraid.org/zc.php?step=2"
|
||||
|
||||
_debug "Login to FreeDNS as user $username"
|
||||
|
||||
htmlpage="$(_post "username=$(printf '%s' "$username" | _url_encode)&password=$(printf '%s' "$password" | _url_encode)&submit=Login&action=auth" "$url")"
|
||||
|
||||
if [ "$?" != "0" ]; then
|
||||
_err "FreeDNS login failed for user $username bad RC from _post"
|
||||
return 1
|
||||
fi
|
||||
|
||||
cookies="$(grep -i '^Set-Cookie.*dns_cookie.*$' "$HTTP_HEADER" | _head_n 1 | tr -d "\r\n" | cut -d " " -f 2)"
|
||||
|
||||
# if cookies is not empty then logon successful
|
||||
if [ -z "$cookies" ]; then
|
||||
_debug "$htmlpage"
|
||||
_err "FreeDNS login failed for user $username. Check $HTTP_HEADER file"
|
||||
return 1
|
||||
fi
|
||||
|
||||
printf "%s" "$cookies"
|
||||
return 0
|
||||
}
|
||||
|
||||
# usage _freedns_retrieve_subdomain_page login_cookies
|
||||
# echo page retrieved (html)
|
||||
# returns 0 success
|
||||
_freedns_retrieve_subdomain_page() {
|
||||
export _H1="Cookie:$1"
|
||||
export _H2="Accept-Language:en-US"
|
||||
url="https://freedns.afraid.org/subdomain/"
|
||||
|
||||
_debug "Retrieve subdmoain page from FreeDNS"
|
||||
|
||||
htmlpage="$(_get "$url")"
|
||||
|
||||
if [ "$?" != "0" ]; then
|
||||
_err "FreeDNS retrieve subdomins failed bad RC from _get"
|
||||
return 1
|
||||
elif [ -z "$htmlpage" ]; then
|
||||
_err "FreeDNS returned empty subdomain page"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug2 "$htmlpage"
|
||||
|
||||
printf "%s" "$htmlpage"
|
||||
return 0
|
||||
}
|
||||
|
||||
# usage _freedns_add_txt_record login_cookies domain_id subdomain value
|
||||
# returns 0 success
|
||||
_freedns_add_txt_record() {
|
||||
export _H1="Cookie:$1"
|
||||
export _H2="Accept-Language:en-US"
|
||||
domain_id="$2"
|
||||
subdomain="$3"
|
||||
value="$(printf '%s' "$4" | _url_encode)"
|
||||
url="http://freedns.afraid.org/subdomain/save.php?step=2"
|
||||
|
||||
htmlpage="$(_post "type=TXT&domain_id=$domain_id&subdomain=$subdomain&address=%22$value%22&send=Save%21" "$url")"
|
||||
|
||||
if [ "$?" != "0" ]; then
|
||||
_err "FreeDNS failed to add TXT record for $subdomain bad RC from _post"
|
||||
return 1
|
||||
elif ! grep "200 OK" "$HTTP_HEADER" >/dev/null; then
|
||||
_debug "$htmlpage"
|
||||
_err "FreeDNS failed to add TXT record for $subdomain. Check $HTTP_HEADER file"
|
||||
return 1
|
||||
elif _contains "$htmlpage" "security code was incorrect"; then
|
||||
_debug "$htmlpage"
|
||||
_err "FreeDNS failed to add TXT record for $subdomain as FreeDNS requested seurity code"
|
||||
_err "Note that you cannot use automatic DNS validation for FreeDNS public domains"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug2 "$htmlpage"
|
||||
_info "Added acme challenge TXT record for $fulldomain at FreeDNS"
|
||||
return 0
|
||||
}
|
||||
|
||||
# usage _freedns_delete_txt_record login_cookies data_id
|
||||
# returns 0 success
|
||||
_freedns_delete_txt_record() {
|
||||
export _H1="Cookie:$1"
|
||||
export _H2="Accept-Language:en-US"
|
||||
data_id="$2"
|
||||
url="https://freedns.afraid.org/subdomain/delete2.php"
|
||||
|
||||
htmlheader="$(_get "$url?data_id%5B%5D=$data_id&submit=delete+selected" "onlyheader")"
|
||||
|
||||
if [ "$?" != "0" ]; then
|
||||
_err "FreeDNS failed to delete TXT record for $data_id bad RC from _get"
|
||||
return 1
|
||||
elif ! _contains "$htmlheader" "200 OK"; then
|
||||
_debug "$htmlheader"
|
||||
_err "FreeDNS failed to delete TXT record $data_id"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_info "Deleted acme challenge TXT record for $fulldomain at FreeDNS"
|
||||
return 0
|
||||
}
|
||||
|
|
@ -0,0 +1,123 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
# Gandi LiveDNS v5 API
|
||||
# http://doc.livedns.gandi.net/
|
||||
# currently under beta
|
||||
#
|
||||
# Requires GANDI API KEY set in GANDI_LIVEDNS_KEY set as environment variable
|
||||
#
|
||||
#Author: Frédéric Crozat <fcrozat@suse.com>
|
||||
#Report Bugs here: https://github.com/fcrozat/acme.sh
|
||||
#
|
||||
######## Public functions #####################
|
||||
|
||||
GANDI_LIVEDNS_API="https://dns.beta.gandi.net/api/v5"
|
||||
|
||||
#Usage: dns_gandi_livedns_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns_gandi_livedns_add() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
if [ -z "$GANDI_LIVEDNS_KEY" ]; then
|
||||
_err "No API key specifed for Gandi LiveDNS."
|
||||
_err "Create your key and export it as GANDI_LIVEDNS_KEY"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_saveaccountconf GANDI_LIVEDNS_KEY "$GANDI_LIVEDNS_KEY"
|
||||
|
||||
_debug "First detect the root zone"
|
||||
if ! _get_root "$fulldomain"; then
|
||||
_err "invalid domain"
|
||||
return 1
|
||||
fi
|
||||
_debug fulldomain "$fulldomain"
|
||||
_debug txtvalue "$txtvalue"
|
||||
_debug domain "$_domain"
|
||||
_debug sub_domain "$_sub_domain"
|
||||
|
||||
_gandi_livedns_rest PUT "domains/$_domain/records/$_sub_domain/TXT" "{\"rrset_ttl\": 300, \"rrset_values\":[\"$txtvalue\"]}" \
|
||||
&& _contains "$response" '{"message": "Zone Record Created"}' \
|
||||
&& _info "Add $(__green "success")"
|
||||
}
|
||||
|
||||
#Usage: fulldomain txtvalue
|
||||
#Remove the txt record after validation.
|
||||
dns_gandi_livedns_rm() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
_debug "First detect the root zone"
|
||||
if ! _get_root "$fulldomain"; then
|
||||
_err "invalid domain"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug fulldomain "$fulldomain"
|
||||
_debug domain "$_domain"
|
||||
_debug sub_domain "$_sub_domain"
|
||||
|
||||
_gandi_livedns_rest DELETE "domains/$_domain/records/$_sub_domain/TXT" ""
|
||||
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
#_acme-challenge.www.domain.com
|
||||
#returns
|
||||
# _sub_domain=_acme-challenge.www
|
||||
# _domain=domain.com
|
||||
_get_root() {
|
||||
domain=$1
|
||||
i=2
|
||||
p=1
|
||||
while true; do
|
||||
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||
_debug h "$h"
|
||||
if [ -z "$h" ]; then
|
||||
#not valid
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! _gandi_livedns_rest GET "domains/$h"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
if _contains "$response" '"code": 401'; then
|
||||
_err "$response"
|
||||
return 1
|
||||
elif _contains "$response" '"code": 404'; then
|
||||
_debug "$h not found"
|
||||
else
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
||||
_domain="$h"
|
||||
return 0
|
||||
fi
|
||||
p="$i"
|
||||
i=$(_math "$i" + 1)
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
_gandi_livedns_rest() {
|
||||
m=$1
|
||||
ep="$2"
|
||||
data="$3"
|
||||
_debug "$ep"
|
||||
|
||||
export _H1="Content-Type: application/json"
|
||||
export _H2="X-Api-Key: $GANDI_LIVEDNS_KEY"
|
||||
|
||||
if [ "$m" = "GET" ]; then
|
||||
response="$(_get "$GANDI_LIVEDNS_API/$ep")"
|
||||
else
|
||||
_debug data "$data"
|
||||
response="$(_post "$data" "$GANDI_LIVEDNS_API/$ep" "" "$m")"
|
||||
fi
|
||||
|
||||
if [ "$?" != "0" ]; then
|
||||
_err "error $ep"
|
||||
return 1
|
||||
fi
|
||||
_debug2 response "$response"
|
||||
return 0
|
||||
}
|
||||
|
|
@ -40,7 +40,7 @@ dns_gd_add() {
|
|||
if _gd_rest PUT "domains/$_domain/records/TXT/$_sub_domain" "[{\"data\":\"$txtvalue\"}]"; then
|
||||
if [ "$response" = "{}" ]; then
|
||||
_info "Added, sleeping 10 seconds"
|
||||
sleep 10
|
||||
_sleep 10
|
||||
#todo: check if the record takes effect
|
||||
return 0
|
||||
else
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ dns_lexicon_add() {
|
|||
# shellcheck disable=SC2018,SC2019
|
||||
Lx_name=$(echo LEXICON_"${PROVIDER}"_USERNAME | tr 'a-z' 'A-Z')
|
||||
Lx_name_v=$(eval echo \$"$Lx_name")
|
||||
_debug "$Lx_name" "$Lx_name_v"
|
||||
_secure_debug "$Lx_name" "$Lx_name_v"
|
||||
if [ "$Lx_name_v" ]; then
|
||||
_saveaccountconf "$Lx_name" "$Lx_name_v"
|
||||
eval export "$Lx_name"
|
||||
|
|
@ -43,7 +43,7 @@ dns_lexicon_add() {
|
|||
# shellcheck disable=SC2018,SC2019
|
||||
Lx_token=$(echo LEXICON_"${PROVIDER}"_TOKEN | tr 'a-z' 'A-Z')
|
||||
Lx_token_v=$(eval echo \$"$Lx_token")
|
||||
_debug "$Lx_token" "$Lx_token_v"
|
||||
_secure_debug "$Lx_token" "$Lx_token_v"
|
||||
if [ "$Lx_token_v" ]; then
|
||||
_saveaccountconf "$Lx_token" "$Lx_token_v"
|
||||
eval export "$Lx_token"
|
||||
|
|
@ -52,7 +52,7 @@ dns_lexicon_add() {
|
|||
# shellcheck disable=SC2018,SC2019
|
||||
Lx_password=$(echo LEXICON_"${PROVIDER}"_PASSWORD | tr 'a-z' 'A-Z')
|
||||
Lx_password_v=$(eval echo \$"$Lx_password")
|
||||
_debug "$Lx_password" "$Lx_password_v"
|
||||
_secure_debug "$Lx_password" "$Lx_password_v"
|
||||
if [ "$Lx_password_v" ]; then
|
||||
_saveaccountconf "$Lx_password" "$Lx_password_v"
|
||||
eval export "$Lx_password"
|
||||
|
|
@ -61,7 +61,7 @@ dns_lexicon_add() {
|
|||
# shellcheck disable=SC2018,SC2019
|
||||
Lx_domaintoken=$(echo LEXICON_"${PROVIDER}"_DOMAINTOKEN | tr 'a-z' 'A-Z')
|
||||
Lx_domaintoken_v=$(eval echo \$"$Lx_domaintoken")
|
||||
_debug "$Lx_domaintoken" "$Lx_domaintoken_v"
|
||||
_secure_debug "$Lx_domaintoken" "$Lx_domaintoken_v"
|
||||
if [ "$Lx_domaintoken_v" ]; then
|
||||
eval export "$Lx_domaintoken"
|
||||
_saveaccountconf "$Lx_domaintoken" "$Lx_domaintoken_v"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,183 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
#Author: Philipp Grosswiler <philipp.grosswiler@swiss-design.net>
|
||||
|
||||
LINODE_API_URL="https://api.linode.com/?api_key=$LINODE_API_KEY&api_action="
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
#Usage: dns_linode_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns_linode_add() {
|
||||
fulldomain="${1}"
|
||||
txtvalue="${2}"
|
||||
|
||||
if ! _Linode_API; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
_info "Using Linode"
|
||||
_debug "Calling: dns_linode_add() '${fulldomain}' '${txtvalue}'"
|
||||
|
||||
_debug "First detect the root zone"
|
||||
if ! _get_root "$fulldomain"; then
|
||||
_err "Domain does not exist."
|
||||
return 1
|
||||
fi
|
||||
_debug _domain_id "$_domain_id"
|
||||
_debug _sub_domain "$_sub_domain"
|
||||
_debug _domain "$_domain"
|
||||
|
||||
_parameters="&DomainID=$_domain_id&Type=TXT&Name=$_sub_domain&Target=$txtvalue"
|
||||
|
||||
if _rest GET "domain.resource.create" "$_parameters" && [ -n "$response" ]; then
|
||||
_resource_id=$(printf "%s\n" "$response" | _egrep_o "\"ResourceID\":\s*[0-9]+" | cut -d : -f 2 | tr -d " " | _head_n 1)
|
||||
_debug _resource_id "$_resource_id"
|
||||
|
||||
if [ -z "$_resource_id" ]; then
|
||||
_err "Error adding the domain resource."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_info "Domain resource successfully added."
|
||||
return 0
|
||||
fi
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
#Usage: dns_linode_rm _acme-challenge.www.domain.com
|
||||
dns_linode_rm() {
|
||||
fulldomain="${1}"
|
||||
|
||||
if ! _Linode_API; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
_info "Using Linode"
|
||||
_debug "Calling: dns_linode_rm() '${fulldomain}'"
|
||||
|
||||
_debug "First detect the root zone"
|
||||
if ! _get_root "$fulldomain"; then
|
||||
_err "Domain does not exist."
|
||||
return 1
|
||||
fi
|
||||
_debug _domain_id "$_domain_id"
|
||||
_debug _sub_domain "$_sub_domain"
|
||||
_debug _domain "$_domain"
|
||||
|
||||
_parameters="&DomainID=$_domain_id"
|
||||
|
||||
if _rest GET "domain.resource.list" "$_parameters" && [ -n "$response" ]; then
|
||||
response="$(echo "$response" | tr -d "\n" | sed 's/{/\n&/g')"
|
||||
|
||||
resource="$(echo "$response" | _egrep_o "{.*\"NAME\":\s*\"$_sub_domain\".*}")"
|
||||
if [ "$resource" ]; then
|
||||
_resource_id=$(printf "%s\n" "$resource" | _egrep_o "\"RESOURCEID\":\s*[0-9]+" | _head_n 1 | cut -d : -f 2 | tr -d \ )
|
||||
if [ "$_resource_id" ]; then
|
||||
_debug _resource_id "$_resource_id"
|
||||
|
||||
_parameters="&DomainID=$_domain_id&ResourceID=$_resource_id"
|
||||
|
||||
if _rest GET "domain.resource.delete" "$_parameters" && [ -n "$response" ]; then
|
||||
_resource_id=$(printf "%s\n" "$response" | _egrep_o "\"ResourceID\":\s*[0-9]+" | cut -d : -f 2 | tr -d " " | _head_n 1)
|
||||
_debug _resource_id "$_resource_id"
|
||||
|
||||
if [ -z "$_resource_id" ]; then
|
||||
_err "Error deleting the domain resource."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_info "Domain resource successfully deleted."
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
fi
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
|
||||
_Linode_API() {
|
||||
if [ -z "$LINODE_API_KEY" ]; then
|
||||
LINODE_API_KEY=""
|
||||
|
||||
_err "You didn't specify the Linode API key yet."
|
||||
_err "Please create your key and try again."
|
||||
|
||||
return 1
|
||||
fi
|
||||
|
||||
_saveaccountconf LINODE_API_KEY "$LINODE_API_KEY"
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
#_acme-challenge.www.domain.com
|
||||
#returns
|
||||
# _sub_domain=_acme-challenge.www
|
||||
# _domain=domain.com
|
||||
# _domain_id=12345
|
||||
_get_root() {
|
||||
domain=$1
|
||||
i=2
|
||||
p=1
|
||||
|
||||
if _rest GET "domain.list"; then
|
||||
response="$(echo "$response" | tr -d "\n" | sed 's/{/\n&/g')"
|
||||
while true; do
|
||||
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||
_debug h "$h"
|
||||
if [ -z "$h" ]; then
|
||||
#not valid
|
||||
return 1
|
||||
fi
|
||||
|
||||
hostedzone="$(echo "$response" | _egrep_o "{.*\"DOMAIN\":\s*\"$h\".*}")"
|
||||
if [ "$hostedzone" ]; then
|
||||
_domain_id=$(printf "%s\n" "$hostedzone" | _egrep_o "\"DOMAINID\":\s*[0-9]+" | _head_n 1 | cut -d : -f 2 | tr -d \ )
|
||||
if [ "$_domain_id" ]; then
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
||||
_domain=$h
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
fi
|
||||
p=$i
|
||||
i=$(_math "$i" + 1)
|
||||
done
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
#method method action data
|
||||
_rest() {
|
||||
mtd="$1"
|
||||
ep="$2"
|
||||
data="$3"
|
||||
|
||||
_debug mtd "$mtd"
|
||||
_debug ep "$ep"
|
||||
|
||||
export _H1="Accept: application/json"
|
||||
export _H2="Content-Type: application/json"
|
||||
|
||||
if [ "$mtd" != "GET" ]; then
|
||||
# both POST and DELETE.
|
||||
_debug data "$data"
|
||||
response="$(_post "$data" "$LINODE_API_URL$ep" "" "$mtd")"
|
||||
else
|
||||
response="$(_get "$LINODE_API_URL$ep$data")"
|
||||
fi
|
||||
|
||||
if [ "$?" != "0" ]; then
|
||||
_err "error $ep"
|
||||
return 1
|
||||
fi
|
||||
_debug2 response "$response"
|
||||
return 0
|
||||
}
|
||||
|
|
@ -46,12 +46,12 @@ dns_lua_add() {
|
|||
return 1
|
||||
fi
|
||||
|
||||
count=$(printf "%s\n" "$response" | _egrep_o "\"name\":\"$fulldomain\"" | wc -l)
|
||||
count=$(printf "%s\n" "$response" | _egrep_o "\"name\":\"$fulldomain.\",\"type\":\"TXT\"" | wc -l | tr -d " ")
|
||||
_debug count "$count"
|
||||
if [ "$count" = "0" ]; then
|
||||
_info "Adding record"
|
||||
if _LUA_rest POST "zones/$_domain_id/records" "{\"type\":\"TXT\",\"name\":\"$fulldomain.\",\"content\":\"$txtvalue\",\"ttl\":120}"; then
|
||||
if printf -- "%s" "$response" | grep "$fulldomain" >/dev/null; then
|
||||
if _contains "$response" "$fulldomain"; then
|
||||
_info "Added"
|
||||
#todo: check if the record takes effect
|
||||
return 0
|
||||
|
|
@ -63,11 +63,11 @@ dns_lua_add() {
|
|||
_err "Add txt record error."
|
||||
else
|
||||
_info "Updating record"
|
||||
record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":[^,]*,\"name\":\"$fulldomain.\",\"type\":\"TXT\"" | cut -d: -f2 | cut -d, -f1)
|
||||
record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":[^,]*,\"name\":\"$fulldomain.\",\"type\":\"TXT\"" | _head_n 1 | cut -d: -f2 | cut -d, -f1)
|
||||
_debug "record_id" "$record_id"
|
||||
|
||||
_LUA_rest PUT "zones/$_domain_id/records/$record_id" "{\"id\":\"$record_id\",\"type\":\"TXT\",\"name\":\"$fulldomain.\",\"content\":\"$txtvalue\",\"zone_id\":\"$_domain_id\",\"ttl\":120}"
|
||||
if [ "$?" = "0" ]; then
|
||||
_LUA_rest PUT "zones/$_domain_id/records/$record_id" "{\"id\":$record_id,\"type\":\"TXT\",\"name\":\"$fulldomain.\",\"content\":\"$txtvalue\",\"zone_id\":$_domain_id,\"ttl\":120}"
|
||||
if [ "$?" = "0" ] && _contains "$response" "updated_at"; then
|
||||
_info "Updated!"
|
||||
#todo: check if the record takes effect
|
||||
return 0
|
||||
|
|
@ -81,7 +81,36 @@ dns_lua_add() {
|
|||
#fulldomain
|
||||
dns_lua_rm() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
_debug "First detect the root zone"
|
||||
if ! _get_root "$fulldomain"; then
|
||||
_err "invalid domain"
|
||||
return 1
|
||||
fi
|
||||
_debug _domain_id "$_domain_id"
|
||||
_debug _sub_domain "$_sub_domain"
|
||||
_debug _domain "$_domain"
|
||||
|
||||
_debug "Getting txt records"
|
||||
_LUA_rest GET "zones/${_domain_id}/records"
|
||||
|
||||
count=$(printf "%s\n" "$response" | _egrep_o "\"name\":\"$fulldomain.\",\"type\":\"TXT\"" | wc -l | tr -d " ")
|
||||
_debug count "$count"
|
||||
if [ "$count" = "0" ]; then
|
||||
_info "Don't need to remove."
|
||||
else
|
||||
record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":[^,]*,\"name\":\"$fulldomain.\",\"type\":\"TXT\"" | _head_n 1 | cut -d: -f2 | cut -d, -f1)
|
||||
_debug "record_id" "$record_id"
|
||||
if [ -z "$record_id" ]; then
|
||||
_err "Can not get record id to remove."
|
||||
return 1
|
||||
fi
|
||||
if ! _LUA_rest DELETE "/zones/$_domain_id/records/$record_id"; then
|
||||
_err "Delete record error."
|
||||
return 1
|
||||
fi
|
||||
_contains "$response" "$record_id"
|
||||
fi
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
|
|
@ -99,6 +128,7 @@ _get_root() {
|
|||
fi
|
||||
while true; do
|
||||
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||
_debug h "$h"
|
||||
if [ -z "$h" ]; then
|
||||
#not valid
|
||||
return 1
|
||||
|
|
@ -106,6 +136,7 @@ _get_root() {
|
|||
|
||||
if _contains "$response" "\"name\":\"$h\""; then
|
||||
_domain_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":[^,]*,\"name\":\"$h\"" | cut -d : -f 2 | cut -d , -f 1)
|
||||
_debug _domain_id "$_domain_id"
|
||||
if [ "$_domain_id" ]; then
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
||||
_domain="$h"
|
||||
|
|
@ -127,7 +158,7 @@ _LUA_rest() {
|
|||
|
||||
export _H1="Accept: application/json"
|
||||
export _H2="Authorization: Basic $LUA_auth"
|
||||
if [ "$data" ]; then
|
||||
if [ "$m" != "GET" ]; then
|
||||
_debug data "$data"
|
||||
response="$(_post "$data" "$LUA_Api/$ep" "" "$m")"
|
||||
else
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
# bug reports to dev@1e.ca
|
||||
|
||||
# ME_Key=qmlkdjflmkqdjf
|
||||
# ME_Key=qmlkdjflmkqdjf
|
||||
# ME_Secret=qmsdlkqmlksdvnnpae
|
||||
|
||||
ME_Api=https://api.dnsmadeeasy.com/V2.0/dns/managed
|
||||
|
|
@ -78,7 +78,36 @@ dns_me_add() {
|
|||
#fulldomain
|
||||
dns_me_rm() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
_debug "First detect the root zone"
|
||||
if ! _get_root "$fulldomain"; then
|
||||
_err "invalid domain"
|
||||
return 1
|
||||
fi
|
||||
_debug _domain_id "$_domain_id"
|
||||
_debug _sub_domain "$_sub_domain"
|
||||
_debug _domain "$_domain"
|
||||
|
||||
_debug "Getting txt records"
|
||||
_me_rest GET "${_domain_id}/records?recordName=$_sub_domain&type=TXT"
|
||||
|
||||
count=$(printf "%s\n" "$response" | _egrep_o "\"totalRecords\":[^,]*" | cut -d : -f 2)
|
||||
_debug count "$count"
|
||||
if [ "$count" = "0" ]; then
|
||||
_info "Don't need to remove."
|
||||
else
|
||||
record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":[^,]*" | cut -d : -f 2 | head -n 1)
|
||||
_debug "record_id" "$record_id"
|
||||
if [ -z "$record_id" ]; then
|
||||
_err "Can not get record id to remove."
|
||||
return 1
|
||||
fi
|
||||
if ! _me_rest DELETE "$_domain_id/records/$record_id"; then
|
||||
_err "Delete record error."
|
||||
return 1
|
||||
fi
|
||||
_contains "$response" ''
|
||||
fi
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
|
|
@ -124,13 +153,13 @@ _me_rest() {
|
|||
_debug "$ep"
|
||||
|
||||
cdate=$(date -u +"%a, %d %b %Y %T %Z")
|
||||
hmac=$(printf "%s" "$cdate" | _hmac sha1 "$(_hex "$ME_Secret")" hex)
|
||||
hmac=$(printf "%s" "$cdate" | _hmac sha1 "$(printf "%s" "$ME_Secret" | _hex_dump | tr -d " ")" hex)
|
||||
|
||||
export _H1="x-dnsme-apiKey: $ME_Key"
|
||||
export _H2="x-dnsme-requestDate: $cdate"
|
||||
export _H3="x-dnsme-hmac: $hmac"
|
||||
|
||||
if [ "$data" ]; then
|
||||
if [ "$m" != "GET" ]; then
|
||||
_debug data "$data"
|
||||
response="$(_post "$data" "$ME_Api/$ep" "" "$m")"
|
||||
else
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
#'ovh-eu'
|
||||
OVH_EU='https://eu.api.ovh.com/1.0'
|
||||
|
||||
#'ovh-ca':
|
||||
#'ovh-ca':
|
||||
OVH_CA='https://ca.api.ovh.com/1.0'
|
||||
|
||||
#'kimsufi-eu'
|
||||
|
|
@ -207,7 +207,7 @@ _ovh_authentication() {
|
|||
_err "Unable to get consumerKey"
|
||||
return 1
|
||||
fi
|
||||
_debug consumerKey "$consumerKey"
|
||||
_secure_debug consumerKey "$consumerKey"
|
||||
|
||||
OVH_CK="$consumerKey"
|
||||
_saveaccountconf OVH_CK "$OVH_CK"
|
||||
|
|
@ -269,7 +269,7 @@ _ovh_rest() {
|
|||
_ovh_t="$(_ovh_timestamp)"
|
||||
_debug2 _ovh_t "$_ovh_t"
|
||||
_ovh_p="$OVH_AS+$OVH_CK+$m+$_ovh_url+$data+$_ovh_t"
|
||||
_debug _ovh_p "$_ovh_p"
|
||||
_secure_debug _ovh_p "$_ovh_p"
|
||||
_ovh_hex="$(printf "%s" "$_ovh_p" | _digest sha1 hex)"
|
||||
_debug2 _ovh_hex "$_ovh_hex"
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ ACME_DIRS="/var/etc/acme-client /var/etc/acme-client/certs /var/etc/acme-client/
|
|||
for directory in ${ACME_DIRS}; do
|
||||
mkdir -p ${directory}
|
||||
chown -R root:wheel ${directory}
|
||||
chmod -R 755 ${directory}
|
||||
chmod -R 750 ${directory}
|
||||
done
|
||||
|
||||
exit 0
|
||||
|
|
|
|||
Loading…
Reference in a new issue