diff --git a/security/acme-client/Makefile b/security/acme-client/Makefile
index f61c388d5..0ed3b7948 100644
--- a/security/acme-client/Makefile
+++ b/security/acme-client/Makefile
@@ -1,7 +1,7 @@
PLUGIN_NAME= acme-client
-PLUGIN_VERSION= 1.26
+PLUGIN_VERSION= 1.27
PLUGIN_COMMENT= Let's Encrypt client
PLUGIN_MAINTAINER= opnsense@moov.de
-PLUGIN_DEPENDS= acme.sh
+PLUGIN_DEPENDS= acme.sh py${PLUGIN_PYTHON}-dns-lexicon
.include "../../Mk/plugins.mk"
diff --git a/security/acme-client/src/opnsense/mvc/app/controllers/OPNsense/AcmeClient/forms/dialogValidation.xml b/security/acme-client/src/opnsense/mvc/app/controllers/OPNsense/AcmeClient/forms/dialogValidation.xml
index 27a097063..fb66169e4 100644
--- a/security/acme-client/src/opnsense/mvc/app/controllers/OPNsense/AcmeClient/forms/dialogValidation.xml
+++ b/security/acme-client/src/opnsense/mvc/app/controllers/OPNsense/AcmeClient/forms/dialogValidation.xml
@@ -590,6 +590,26 @@
text
+
+
+ header
+
+
+
+ validation.dns_loopia_api
+
+ text
+
+
+ validation.dns_loopia_user
+
+ text
+
+
+ validation.dns_loopia_password
+
+ text
+
header
diff --git a/security/acme-client/src/opnsense/mvc/app/models/OPNsense/AcmeClient/AcmeClient.xml b/security/acme-client/src/opnsense/mvc/app/models/OPNsense/AcmeClient/AcmeClient.xml
index e8ae22dde..67900ed10 100644
--- a/security/acme-client/src/opnsense/mvc/app/models/OPNsense/AcmeClient/AcmeClient.xml
+++ b/security/acme-client/src/opnsense/mvc/app/models/OPNsense/AcmeClient/AcmeClient.xml
@@ -1,6 +1,6 @@
//OPNsense/AcmeClient
- 1.5.0
+ 1.6.0
A secure Let's Encrypt plugin
@@ -392,6 +392,7 @@
Knot (knsupdate) DNS API
lexicon DNS API
Linode API
+ Loopia API
LuaDNS.com API
Name.com API
Namecheap API
@@ -673,6 +674,16 @@
N
+
+ N
+ https://api.loopia.se/RPCSERV
+
+
+ N
+
+
+ N
+
N
diff --git a/security/acme-client/src/opnsense/mvc/app/models/OPNsense/AcmeClient/Migrations/M1_6_0.php b/security/acme-client/src/opnsense/mvc/app/models/OPNsense/AcmeClient/Migrations/M1_6_0.php
new file mode 100644
index 000000000..c712cb51a
--- /dev/null
+++ b/security/acme-client/src/opnsense/mvc/app/models/OPNsense/AcmeClient/Migrations/M1_6_0.php
@@ -0,0 +1,89 @@
+settings->environment;
+ $dir = '/var/etc/acme-client/accounts/';
+
+ // Search accounts
+ foreach ($model->getNodeByReference('accounts.account')->iterateItems() as $account) {
+ $account_id = (string)$account->id;
+ $account_dir = $dir . $account_id;
+ $new_account_dir = "${dir}${account_id}_${env}";
+
+ // Check if account directory exists
+ // Accounts that haven't been used yet don't need to be migrated.
+ if (is_dir($account_dir)) {
+
+ // Check if account configuration can be found.
+ $account_file = "${account_dir}/account.conf";
+ if (is_file($account_file)) {
+
+ // Parse config file and modify path information
+ $account_conf = parse_ini_file($account_file);
+ foreach ($account_conf as $key => $value) {
+ switch ($key) {
+ case 'ACCOUNT_KEY_PATH':
+ $account_conf[$key] = "${new_account_dir}/account.key";
+ break;
+ case 'ACCOUNT_JSON_PATH':
+ $account_conf[$key] = "${new_account_dir}/account.json";
+ break;
+ case 'CA_CONF':
+ $account_conf[$key] = "${new_account_dir}/ca.conf";
+ break;
+ }
+ }
+
+ // Convert array back to ini file format
+ $new_account_conf = array();
+ foreach($account_conf as $key => $value)
+ {
+ $new_account_conf[] = "${key}='${value}'";
+ }
+
+ // Write changes back to file
+ file_put_contents($account_file, implode("\r\n", $new_account_conf) . "\n");
+ chmod($account_file, 0600);
+
+ // Finally, rename account directory
+ rename($account_dir, $new_account_dir);
+ }
+ }
+ }
+ }
+}
diff --git a/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient/certhelper.php b/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient/certhelper.php
index 307aa79da..f14a6c65f 100755
--- a/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient/certhelper.php
+++ b/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient/certhelper.php
@@ -354,7 +354,8 @@ function run_acme_account_registration($acctObj, $certObj, $modelObj)
$acme_args = eval_optional_acme_args();
// Collect account information
- $account_conf_dir = "/var/etc/acme-client/accounts/" . $acctObj->id;
+ $acme_env = (string)$modelObj->settings->environment;
+ $account_conf_dir = "/var/etc/acme-client/accounts/" . $acctObj->id . "_${acme_env}";
$account_conf_file = $account_conf_dir . "/account.conf";
$account_key_file = $account_conf_dir . "/account.key";
$account_json_file = $account_conf_dir . "/account.json";
@@ -472,7 +473,8 @@ function run_acme_validation($certObj, $valObj, $acctObj)
$modelObj = new OPNsense\AcmeClient\AcmeClient();
// Collect account information
- $account_conf_dir = "/var/etc/acme-client/accounts/" . $acctObj->id;
+ $acme_env = (string)$modelObj->settings->environment;
+ $account_conf_dir = "/var/etc/acme-client/accounts/" . $acctObj->id . "_${acme_env}";
$account_conf_file = $account_conf_dir . "/account.conf";
// Generate certificate filenames
@@ -793,6 +795,11 @@ function run_acme_validation($certObj, $valObj, $acctObj)
// Linode can take up to 15 to update DNS records
$acme_hook_options[] = "--dnssleep 960";
break;
+ case 'dns_loopia':
+ $proc_env['LOOPIA_Api'] = (string)$valObj->dns_loopia_api;
+ $proc_env['LOOPIA_User'] = (string)$valObj->dns_loopia_user;
+ $proc_env['LOOPIA_Password'] = (string)$valObj->dns_loopia_password;
+ break;
case 'dns_lua':
$proc_env['LUA_Key'] = (string)$valObj->dns_lua_key;
$proc_env['LUA_Email'] = (string)$valObj->dns_lua_email;
@@ -1027,7 +1034,8 @@ function revoke_cert($certObj, $valObj, $acctObj)
$acme_args = eval_optional_acme_args();
// Collect account information
- $account_conf_dir = "/var/etc/acme-client/accounts/" . $acctObj->id;
+ $acme_env = (string)$modelObj->settings->environment;
+ $account_conf_dir = "/var/etc/acme-client/accounts/" . $acctObj->id . "_${acme_env}";
$account_conf_file = $account_conf_dir . "/account.conf";
// Generate certificate filenames