From 8fa83dc24e0e4e7ad3ec24ab1ffb7ee7fb050138 Mon Sep 17 00:00:00 2001 From: Jared Hendrickson Date: Sat, 14 Mar 2026 10:09:23 -0600 Subject: [PATCH 1/6] fix(CertificateAuthority): use ca_in_use instead of cert_in_use #856 --- .../files/usr/local/pkg/RESTAPI/Models/CertificateAuthority.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Models/CertificateAuthority.inc b/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Models/CertificateAuthority.inc index bfe4645ac..23ada631a 100644 --- a/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Models/CertificateAuthority.inc +++ b/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Models/CertificateAuthority.inc @@ -115,7 +115,7 @@ class CertificateAuthority extends Model { */ public function _delete(): void { # Do not allow this CertificateAuthority to be deleted if it is in use - if (cert_in_use($this->refid->value)) { + if (ca_in_use($this->refid->value)) { throw new ForbiddenError( message: 'Certificate authority cannot be deleted because it is in use.', response_id: 'CERTIFICATE_AUTHORITY_CANNOT_BE_DELETED_WHILE_IN_USE', From 07bdfa10e0c392c35697bdfc10e1399258b16f40 Mon Sep 17 00:00:00 2001 From: Jared Hendrickson Date: Sat, 14 Mar 2026 10:14:31 -0600 Subject: [PATCH 2/6] fix(CertificateAuthority): set a 409 instead of 403 for bad ca deletions A conflict error is a more accurate choice when someone tries to delete a CA that is currently in use. --- .../usr/local/pkg/RESTAPI/Models/CertificateAuthority.inc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Models/CertificateAuthority.inc b/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Models/CertificateAuthority.inc index 23ada631a..0f1219697 100644 --- a/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Models/CertificateAuthority.inc +++ b/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Models/CertificateAuthority.inc @@ -8,6 +8,7 @@ use RESTAPI\Fields\BooleanField; use RESTAPI\Fields\IntegerField; use RESTAPI\Fields\StringField; use RESTAPI\Fields\UIDField; +use RESTAPI\Responses\ConflictError; use RESTAPI\Responses\ForbiddenError; use RESTAPI\Responses\ValidationError; use RESTAPI\Validators\RegexValidator; @@ -116,7 +117,7 @@ class CertificateAuthority extends Model { public function _delete(): void { # Do not allow this CertificateAuthority to be deleted if it is in use if (ca_in_use($this->refid->value)) { - throw new ForbiddenError( + throw new ConflictError( message: 'Certificate authority cannot be deleted because it is in use.', response_id: 'CERTIFICATE_AUTHORITY_CANNOT_BE_DELETED_WHILE_IN_USE', ); From 9d924a9977feb885060e5e6549f0b6984acf13af Mon Sep 17 00:00:00 2001 From: Jared Hendrickson Date: Sat, 14 Mar 2026 10:16:18 -0600 Subject: [PATCH 3/6] test(CertificateAuthority): ensure CAs can't be deleted while in use #856 --- .../APIModelsCertificateAuthorityTestCase.inc | 27 ++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Tests/APIModelsCertificateAuthorityTestCase.inc b/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Tests/APIModelsCertificateAuthorityTestCase.inc index d07f8a770..8d5d21799 100644 --- a/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Tests/APIModelsCertificateAuthorityTestCase.inc +++ b/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Tests/APIModelsCertificateAuthorityTestCase.inc @@ -3,6 +3,7 @@ namespace RESTAPI\Tests; use RESTAPI\Core\Command; +use RESTAPI\Core\Model; use RESTAPI\Core\TestCase; use RESTAPI\Models\CertificateAuthority; @@ -127,6 +128,30 @@ R02Pul8ulWQ8Kl3Q3pou8As7W1mMzA2DxQ== $ca->delete(); } - # TODO: Need test to ensure CA cannot be deleted while in use + /** + * Checks that we cannot delete a CA that is in use. + */ + public function test_cannot_delete_ca_in_use(): void + { + # Create a CA to test with + $ca = new CertificateAuthority( + descr: 'test', + crt: self::EXAMPLE_CRT, + prv: self::EXAMPLE_PRV, + ); + $ca->create(); + + # Mock an OpenVPN server using this CA to be in use + Model::set_config(path: "openvpn/openvpn-server/0/caref", value: $ca->refid->value); + + # Ensure an error is thrown if we try to delete the CA while it's in use + $this->assert_throws_response( + response_id: 'CERTIFICATE_AUTHORITY_CANNOT_BE_DELETED_WHILE_IN_USE', + code: 409, + callable: function () use ($ca) { + $ca->delete(); + }, + ); + } # TODO: Need test to ensure crt must be CA capable } From 9da348ccac2480ea62728cdcb383e7e7d063eae8 Mon Sep 17 00:00:00 2001 From: Jared Hendrickson Date: Sat, 14 Mar 2026 10:16:41 -0600 Subject: [PATCH 4/6] style: run prettier on changed files --- .../Tests/APIModelsCertificateAuthorityTestCase.inc | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Tests/APIModelsCertificateAuthorityTestCase.inc b/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Tests/APIModelsCertificateAuthorityTestCase.inc index 8d5d21799..c04365967 100644 --- a/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Tests/APIModelsCertificateAuthorityTestCase.inc +++ b/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Tests/APIModelsCertificateAuthorityTestCase.inc @@ -131,18 +131,13 @@ R02Pul8ulWQ8Kl3Q3pou8As7W1mMzA2DxQ== /** * Checks that we cannot delete a CA that is in use. */ - public function test_cannot_delete_ca_in_use(): void - { + public function test_cannot_delete_ca_in_use(): void { # Create a CA to test with - $ca = new CertificateAuthority( - descr: 'test', - crt: self::EXAMPLE_CRT, - prv: self::EXAMPLE_PRV, - ); + $ca = new CertificateAuthority(descr: 'test', crt: self::EXAMPLE_CRT, prv: self::EXAMPLE_PRV); $ca->create(); # Mock an OpenVPN server using this CA to be in use - Model::set_config(path: "openvpn/openvpn-server/0/caref", value: $ca->refid->value); + Model::set_config(path: 'openvpn/openvpn-server/0/caref', value: $ca->refid->value); # Ensure an error is thrown if we try to delete the CA while it's in use $this->assert_throws_response( From eed8d1b91c01f53288671e4fe0d00e39dd36a689 Mon Sep 17 00:00:00 2001 From: Jared Hendrickson Date: Sun, 22 Mar 2026 12:27:38 -0600 Subject: [PATCH 5/6] fix: allow select crl fields to be editable #857 --- .../usr/local/pkg/RESTAPI/Models/CertificateRevocationList.inc | 3 --- 1 file changed, 3 deletions(-) diff --git a/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Models/CertificateRevocationList.inc b/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Models/CertificateRevocationList.inc index 031bf96a8..7f8ca96ae 100644 --- a/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Models/CertificateRevocationList.inc +++ b/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Models/CertificateRevocationList.inc @@ -40,7 +40,6 @@ class CertificateRevocationList extends Model { $this->descr = new StringField( required: true, unique: true, - editable: false, validators: [new RegexValidator(pattern: "/[\?\>\<\&\/\\\"\']/", invert: true)], help_text: 'The unique name/description for this CRL.', ); @@ -59,7 +58,6 @@ class CertificateRevocationList extends Model { ); $this->lifetime = new IntegerField( default: 730, - editable: false, minimum: 1, maximum: 8381, conditions: ['method' => 'internal'], @@ -67,7 +65,6 @@ class CertificateRevocationList extends Model { ); $this->serial = new IntegerField( default: 0, - editable: false, conditions: ['method' => 'internal'], help_text: 'The serial number of the CRL.', ); From 3308b44e6f7f0ef87fa6eb7589f1fb08246c7e93 Mon Sep 17 00:00:00 2001 From: Jared Hendrickson Date: Sun, 22 Mar 2026 19:59:25 -0600 Subject: [PATCH 6/6] feat: add ACMECertificateDomain fields for Technitium DNS #846 --- .../RESTAPI/Models/ACMECertificateDomain.inc | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Models/ACMECertificateDomain.inc b/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Models/ACMECertificateDomain.inc index 4604efb76..95d7638f7 100644 --- a/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Models/ACMECertificateDomain.inc +++ b/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Models/ACMECertificateDomain.inc @@ -305,6 +305,8 @@ class ACMECertificateDomain extends Model { public StringField $zone_username; public StringField $zone_key; public StringField $zilore_key; + public StringField $technitium_server; + public StringField $technitium_token; public StringField $anydnschallengealias; public BooleanField $anydnschallengedomain; @@ -2524,6 +2526,21 @@ class ACMECertificateDomain extends Model { conditions: ['method' => 'dns_zilore'], help_text: 'Zilore API Key', ); + $this->technitium_server = new StringField( + default: '', + allow_empty: true, + internal_name: 'dns_technitiumtechnitium_server', + conditions: ['method' => 'dns_technitium'], + help_text: 'Technitium DNS Server address', + ); + $this->technitium_token = new StringField( + default: '', + allow_empty: true, + sensitive: true, + internal_name: 'dns_technitiumtechnitium_token', + conditions: ['method' => 'dns_technitium'], + help_text: 'Technitium DNS Server API Token', + ); $this->anydnschallengealias = new StringField( default: '', allow_empty: true,