mirror of
https://github.com/nextcloud/all-in-one.git
synced 2026-09-20 02:00:23 +00:00
feat(desec): add deSEC account + domain registration backend
Add the server-side deSEC (dedyn.io) free dynamic-DNS flow so users without a domain can obtain one from the AIO interface. - DesecManager drives the full flow against the deSEC API, matching its real semantics: account creation returns HTTP 202 + email verification (no token), a token is obtained via /auth/login/ only after the email is verified, domain registration handles 201/409, and a wildcard CNAME rrset is created for new accounts. Existing accounts can be used by supplying a password. - The "awaiting verification" step is derived from the stored credentials (email + generated password but no token and no domain yet), not a separate flag. register() returns false for that state so the controller can re-render the awaiting-verification UI instead of surfacing it as an error. - DesecController exposes POST /api/desec/register; DependencyInjection wires the manager; account credentials (email, generated password, token) are stored in the AIO configuration and DESEC_TOKEN is exposed to the caddy container. - The dynamic-DNS record is refreshed with the current public IP on container start (DockerController) and via the cron path (Cron/UpdateDesecIp, cron.sh). - Fix an undefined-variable bug in the desecToken/desecPassword config setters that prevented credentials from being persisted. Co-Authored-By: szaimen <42591237+szaimen@users.noreply.github.com> Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: Simon L. <szaimen@e.mail.de>
This commit is contained in:
co-authored by
szaimen
Claude Opus 4.8
parent
03bc7ebded
commit
f7987b26ac
@@ -11,6 +11,8 @@ use GuzzleHttp\Exception\TransferException;
|
||||
|
||||
class ConfigurationManager
|
||||
{
|
||||
public const string DEDYN_SUFFIX = '.dedyn.io';
|
||||
|
||||
private array $secrets = [];
|
||||
|
||||
private array $config = [];
|
||||
@@ -206,6 +208,72 @@ class ConfigurationManager
|
||||
set { $this->set('turn_domain', $value); }
|
||||
}
|
||||
|
||||
public string $desecEmail {
|
||||
get => $this->get('desec_email', '');
|
||||
set { $this->set('desec_email', $value); }
|
||||
}
|
||||
|
||||
/**
|
||||
* Base URL of the deSEC API. Configurable via the 'desec_api_base' config key
|
||||
* (configuration.json) only — intentionally NOT an environment variable — so the
|
||||
* endpoint can be pointed at a mock during automated tests without any risk of a
|
||||
* stray env var redirecting it in production.
|
||||
*/
|
||||
public string $desecApiBase {
|
||||
get => $this->get('desec_api_base', 'https://desec.io/api/v1');
|
||||
}
|
||||
|
||||
/**
|
||||
* Base URL of the deSEC dynamic-DNS update endpoint. Configurable via the
|
||||
* 'desec_update_url' config key (configuration.json) only — see desecApiBase.
|
||||
*/
|
||||
public string $desecUpdateUrl {
|
||||
get => $this->get('desec_update_url', 'https://update.dedyn.io/');
|
||||
}
|
||||
|
||||
public string $desecToken {
|
||||
get {
|
||||
$secrets = $this->get('secrets', []);
|
||||
return isset($secrets['DESEC_TOKEN']) && is_string($secrets['DESEC_TOKEN']) ? $secrets['DESEC_TOKEN'] : '';
|
||||
}
|
||||
set {
|
||||
$secrets = $this->get('secrets', []);
|
||||
$secrets['DESEC_TOKEN'] = $value;
|
||||
$this->set('secrets', $secrets);
|
||||
}
|
||||
}
|
||||
|
||||
public string $desecPassword {
|
||||
get {
|
||||
$secrets = $this->get('secrets', []);
|
||||
return isset($secrets['DESEC_PASSWORD']) && is_string($secrets['DESEC_PASSWORD']) ? $secrets['DESEC_PASSWORD'] : '';
|
||||
}
|
||||
set {
|
||||
$secrets = $this->get('secrets', []);
|
||||
$secrets['DESEC_PASSWORD'] = $value;
|
||||
$this->set('secrets', $secrets);
|
||||
}
|
||||
}
|
||||
|
||||
public function isDesecDomain(): bool {
|
||||
return str_ends_with($this->domain, self::DEDYN_SUFFIX) && $this->desecToken !== '';
|
||||
}
|
||||
|
||||
public function isDesecAccountRegistered(): bool {
|
||||
return $this->desecToken !== '' && $this->desecEmail !== '' && $this->domain === '';
|
||||
}
|
||||
|
||||
/**
|
||||
* True when a new deSEC account was created (email + generated password stored) but
|
||||
* its email has not been verified yet, so no API token could be obtained and no
|
||||
* domain is set. Derived from the stored credentials rather than a separate flag:
|
||||
* once verification succeeds a token is stored and isDesecAccountRegistered() takes
|
||||
* over; once a domain is set the deSEC setup is complete.
|
||||
*/
|
||||
public function isDesecAwaitingVerification(): bool {
|
||||
return $this->desecToken === '' && $this->desecEmail !== '' && $this->desecPassword !== '' && $this->domain === '';
|
||||
}
|
||||
|
||||
public string $apachePort {
|
||||
get => $this->getEnvironmentalVariableOrConfig('APACHE_PORT', 'apache_port', '443');
|
||||
set { $this->set('apache_port', $value); }
|
||||
@@ -1119,6 +1187,7 @@ class ConfigurationManager
|
||||
'CADDY_IP_ADDRESS' => in_array('caddy', $this->aioCommunityContainers, true) ? NetworkHelper::resolveHostname('nextcloud-aio-caddy') : '',
|
||||
'WHITEBOARD_ENABLED' => $this->isWhiteboardEnabled ? 'yes' : '',
|
||||
'AIO_VERSION' => $this->getAioVersion(),
|
||||
'DESEC_TOKEN' => $this->desecToken,
|
||||
default => $this->getRegisteredSecret($placeholder),
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user