diff --git a/src/middlewared/middlewared/api/v25_04_0/acme_dns_authenticator.py b/src/middlewared/middlewared/api/v25_04_0/acme_dns_authenticator.py index 6ed6a842033a1..4656d5919e56a 100644 --- a/src/middlewared/middlewared/api/v25_04_0/acme_dns_authenticator.py +++ b/src/middlewared/middlewared/api/v25_04_0/acme_dns_authenticator.py @@ -14,7 +14,7 @@ 'ACMEDNSAuthenticatorUpdateArgs', 'ACMEDNSAuthenticatorUpdateResult', 'ACMEDNSAuthenticatorDeleteArgs', 'ACMEDNSAuthenticatorDeleteResult', 'ACMEDNSAuthenticatorSchemasArgs', 'ACMEDNSAuthenticatorSchemasResult', 'ACMEDNSAuthenticatorPerformChallengeArgs', 'ACMEDNSAuthenticatorPerformChallengeResult', 'Route53SchemaArgs', - 'ACMECustomDNSAuthenticatorReturns', 'CloudFlareSchemaArgs', 'OVHSchemaArgs', 'ShellSchemaArgs', + 'ACMECustomDNSAuthenticatorReturns', 'CloudFlareSchemaArgs', 'DigitalOceanSchemaArgs', 'OVHSchemaArgs', 'ShellSchemaArgs', 'TrueNASConnectSchemaArgs', ] @@ -54,6 +54,16 @@ class CloudFlareSchemaArgs(CloudFlareSchema): pass +class DigitalOceanSchema(BaseModel): + authenticator: Literal['digitalocean'] + digitalocean_token: Secret[NonEmptyString] = Field(description='DigitalOcean Token') + + +@single_argument_args('attributes') +class DigitalOceanSchemaArgs(DigitalOceanSchema): + pass + + class OVHSchema(BaseModel): authenticator: Literal['OVH'] application_key: NonEmptyString = Field(description='OVH Application Key') @@ -92,7 +102,7 @@ class ShellSchemaArgs(ShellSchema): AuthType: TypeAlias = Annotated[ - CloudFlareSchema | OVHSchema | Route53Schema | ShellSchema, + CloudFlareSchema | DigitalOceanSchema | OVHSchema | Route53Schema | ShellSchema, Field(discriminator='authenticator') ] diff --git a/src/middlewared/middlewared/plugins/acme_protocol_/authenticators/digitalocean.py b/src/middlewared/middlewared/plugins/acme_protocol_/authenticators/digitalocean.py new file mode 100644 index 0000000000000..4d480f0d0eae1 --- /dev/null +++ b/src/middlewared/middlewared/plugins/acme_protocol_/authenticators/digitalocean.py @@ -0,0 +1,33 @@ +import logging + +from certbot_dns_digitalocean._internal.dns_digitalocean import _DigitalOceanClient + +from middlewared.api.current import DigitalOceanSchemaArgs + +from .base import Authenticator + + +logger = logging.getLogger(__name__) + + +class DigitalOceanAuthenticator(Authenticator): + + NAME = 'digitalocean' + PROPAGATION_DELAY = 60 + SCHEMA_MODEL = DigitalOceanSchemaArgs + + def initialize_credentials(self): + self.digitalocean_token = self.attributes.get('digitalocean_token') + + @staticmethod + async def validate_credentials(middleware, data): + return data + + def _perform(self, domain, validation_name, validation_content): + self.get_client().add_txt_record(domain, validation_name, validation_content, 600) + + def get_client(self): + return _DigitalOceanClient(self.digitalocean_token) + + def _cleanup(self, domain, validation_name, validation_content): + self.get_client().del_txt_record(domain, validation_name, validation_content) diff --git a/src/middlewared/middlewared/plugins/acme_protocol_/authenticators/factory.py b/src/middlewared/middlewared/plugins/acme_protocol_/authenticators/factory.py index e65597f32c7d0..5971996257061 100644 --- a/src/middlewared/middlewared/plugins/acme_protocol_/authenticators/factory.py +++ b/src/middlewared/middlewared/plugins/acme_protocol_/authenticators/factory.py @@ -3,6 +3,7 @@ from middlewared.service_exception import CallError from .cloudflare import CloudFlareAuthenticator +from .digitalocean import DigitalOceanAuthenticator from .ovh import OVHAuthenticator from .route53 import Route53Authenticator from .shell import ShellAuthenticator @@ -29,6 +30,7 @@ def get_authenticators(self, include_internal=False): auth_factory = AuthenticatorFactory() for authenticator in [ CloudFlareAuthenticator, + DigitalOceanAuthenticator, Route53Authenticator, OVHAuthenticator, ShellAuthenticator,