mirror of
https://github.com/nextcloud/all-in-one.git
synced 2026-05-21 10:50:10 +00:00
Compare commits
4 Commits
7598f6534d
...
7281c9b7c8
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7281c9b7c8 | ||
|
|
cb48bc5db0 | ||
|
|
83129d6a55 | ||
|
|
68df1dd857 |
@@ -20,7 +20,8 @@
|
|||||||
"NC_DOMAIN=%NC_DOMAIN%",
|
"NC_DOMAIN=%NC_DOMAIN%",
|
||||||
"APACHE_PORT=%APACHE_PORT%",
|
"APACHE_PORT=%APACHE_PORT%",
|
||||||
"APACHE_IP_BINDING=%APACHE_IP_BINDING%",
|
"APACHE_IP_BINDING=%APACHE_IP_BINDING%",
|
||||||
"NEXTCLOUD_EXPORTER_CADDY_PASSWORD=%NEXTCLOUD_EXPORTER_CADDY_PASSWORD%"
|
"NEXTCLOUD_EXPORTER_CADDY_PASSWORD=%NEXTCLOUD_EXPORTER_CADDY_PASSWORD%",
|
||||||
|
"DESEC_TOKEN=%DESEC_TOKEN%"
|
||||||
],
|
],
|
||||||
"volumes": [
|
"volumes": [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -182,7 +182,9 @@ $app->get('/containers', function (Request $request, Response $response, array $
|
|||||||
'community_containers_enabled' => $configurationManager->aioCommunityContainers,
|
'community_containers_enabled' => $configurationManager->aioCommunityContainers,
|
||||||
'bypass_container_update' => $bypass_container_update,
|
'bypass_container_update' => $bypass_container_update,
|
||||||
'desec_email' => $configurationManager->desecEmail,
|
'desec_email' => $configurationManager->desecEmail,
|
||||||
|
'desec_password' => $configurationManager->getDesecPassword(),
|
||||||
'is_desec_domain' => $configurationManager->isDesecDomain(),
|
'is_desec_domain' => $configurationManager->isDesecDomain(),
|
||||||
|
'desec_account_registered' => $configurationManager->isDesecAccountRegistered(),
|
||||||
]);
|
]);
|
||||||
})->setName('profile');
|
})->setName('profile');
|
||||||
$app->get('/login', function (Request $request, Response $response, array $args) use ($container) {
|
$app->get('/login', function (Request $request, Response $response, array $args) use ($container) {
|
||||||
|
|||||||
@@ -36,10 +36,19 @@ readonly class DesecController {
|
|||||||
return $response->withStatus(422);
|
return $response->withStatus(422);
|
||||||
}
|
}
|
||||||
|
|
||||||
$email = trim((string)($request->getParsedBody()['desec_email'] ?? ''));
|
// When a deSEC account was already registered (token exists) but domain creation previously
|
||||||
if ($email === '' || filter_var($email, FILTER_VALIDATE_EMAIL) === false) {
|
// failed, we skip account registration and re-use the stored token and email.
|
||||||
$response->getBody()->write('Please provide a valid email address.');
|
$accountAlreadyRegistered = $this->configurationManager->isDesecAccountRegistered();
|
||||||
return $response->withStatus(422);
|
|
||||||
|
if ($accountAlreadyRegistered) {
|
||||||
|
$token = $this->configurationManager->getDesecToken();
|
||||||
|
// email is already stored; no need to validate or update it
|
||||||
|
} else {
|
||||||
|
$email = trim((string)($request->getParsedBody()['desec_email'] ?? ''));
|
||||||
|
if ($email === '' || filter_var($email, FILTER_VALIDATE_EMAIL) === false) {
|
||||||
|
$response->getBody()->write('Please provide a valid email address.');
|
||||||
|
return $response->withStatus(422);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$slug = trim((string)($request->getParsedBody()['desec_slug'] ?? ''));
|
$slug = trim((string)($request->getParsedBody()['desec_slug'] ?? ''));
|
||||||
@@ -52,17 +61,28 @@ readonly class DesecController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Register an account at deSEC and obtain an API token
|
if (!$accountAlreadyRegistered) {
|
||||||
$password = bin2hex(random_bytes(24));
|
// Register an account at deSEC and obtain an API token.
|
||||||
$token = $this->registerDesecAccount($email, $password);
|
// The password is stored so the user can log in to desec.io directly if needed.
|
||||||
|
// 24 random bytes encoded as hex produce a 48-character password.
|
||||||
|
$password = bin2hex(random_bytes(24));
|
||||||
|
$token = $this->registerDesecAccount($email, $password);
|
||||||
|
|
||||||
|
// Persist the token, password and email immediately so that a subsequent
|
||||||
|
// domain-registration failure leaves the account credentials stored and allows
|
||||||
|
// the user to retry.
|
||||||
|
$this->configurationManager->startTransaction();
|
||||||
|
$this->configurationManager->setDesecToken($token);
|
||||||
|
$this->configurationManager->setDesecPassword($password);
|
||||||
|
$this->configurationManager->desecEmail = $email;
|
||||||
|
$this->configurationManager->commitTransaction();
|
||||||
|
}
|
||||||
|
|
||||||
// Register a free dedyn.io subdomain
|
// Register a free dedyn.io subdomain
|
||||||
$domain = $this->registerDesecDomain($token, $slug);
|
$domain = $this->registerDesecDomain($token, $slug);
|
||||||
|
|
||||||
// Persist the credentials and auto-enable caddy as the reverse proxy
|
// Auto-enable caddy and dnsmasq (idempotent — safe to call even on retry)
|
||||||
$this->configurationManager->startTransaction();
|
$this->configurationManager->startTransaction();
|
||||||
$this->configurationManager->setDesecToken($token);
|
|
||||||
$this->configurationManager->desecEmail = $email;
|
|
||||||
$enabled = array_values(array_filter(
|
$enabled = array_values(array_filter(
|
||||||
$this->configurationManager->aioCommunityContainers,
|
$this->configurationManager->aioCommunityContainers,
|
||||||
fn(string $cc): bool => $cc !== '',
|
fn(string $cc): bool => $cc !== '',
|
||||||
|
|||||||
@@ -221,6 +221,22 @@ class ConfigurationManager
|
|||||||
: '';
|
: '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores the deSEC account password in the secrets store so the user can log in at desec.io.
|
||||||
|
*/
|
||||||
|
public function setDesecPassword(string $password): void {
|
||||||
|
$secrets = $this->get('secrets', []);
|
||||||
|
$secrets['DESEC_PASSWORD'] = $password;
|
||||||
|
$this->set('secrets', $secrets);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDesecPassword(): string {
|
||||||
|
$secrets = $this->get('secrets', []);
|
||||||
|
return isset($secrets['DESEC_PASSWORD']) && is_string($secrets['DESEC_PASSWORD'])
|
||||||
|
? $secrets['DESEC_PASSWORD']
|
||||||
|
: '';
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true when the configured domain is a deSEC dedyn.io subdomain and a token is stored.
|
* Returns true when the configured domain is a deSEC dedyn.io subdomain and a token is stored.
|
||||||
*/
|
*/
|
||||||
@@ -228,6 +244,15 @@ class ConfigurationManager
|
|||||||
return str_ends_with($this->domain, '.dedyn.io') && $this->getDesecToken() !== '';
|
return str_ends_with($this->domain, '.dedyn.io') && $this->getDesecToken() !== '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true when a deSEC account token is stored but no domain has been configured yet.
|
||||||
|
* This happens when account registration succeeded but domain registration subsequently failed.
|
||||||
|
* In this state the user can retry domain registration with a different slug.
|
||||||
|
*/
|
||||||
|
public function isDesecAccountRegistered(): bool {
|
||||||
|
return $this->getDesecToken() !== '' && $this->desecEmail !== '' && $this->domain === '';
|
||||||
|
}
|
||||||
|
|
||||||
public string $apachePort {
|
public string $apachePort {
|
||||||
get => $this->getEnvironmentalVariableOrConfig('APACHE_PORT', 'apache_port', '443');
|
get => $this->getEnvironmentalVariableOrConfig('APACHE_PORT', 'apache_port', '443');
|
||||||
set { $this->set('apache_port', $value); }
|
set { $this->set('apache_port', $value); }
|
||||||
|
|||||||
@@ -132,18 +132,29 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
<p><strong>Hint:</strong> If the domain validation fails but you are completely sure that you've configured everything correctly, you may skip the domain validation by following <a target="_blank" href="https://github.com/nextcloud/all-in-one#how-to-skip-the-domain-validation">this documentation</a>.</p>
|
<p><strong>Hint:</strong> If the domain validation fails but you are completely sure that you've configured everything correctly, you may skip the domain validation by following <a target="_blank" href="https://github.com/nextcloud/all-in-one#how-to-skip-the-domain-validation">this documentation</a>.</p>
|
||||||
</details>
|
</details>
|
||||||
<details>
|
<details{% if desec_account_registered %} open{% endif %}>
|
||||||
<summary>Don't have a domain? Get a free one from deSEC</summary>
|
<summary>Don't have a domain? Get a free one from deSEC</summary>
|
||||||
<p><a target="_blank" href="https://desec.io">deSEC</a> offers free dynamic DNS subdomains under <strong>dedyn.io</strong>. AIO can register an account and a subdomain for you automatically. The <strong>caddy</strong> community container will be enabled as a reverse proxy, the <strong>dnsmasq</strong> container will be enabled for local DNS resolution, and the mastercontainer will keep your DNS record up to date automatically.</p>
|
<p><a target="_blank" href="https://desec.io">deSEC</a> offers free dynamic DNS subdomains under <strong>dedyn.io</strong>. AIO can register an account and a subdomain for you automatically. The <strong>caddy</strong> community container will be enabled as a reverse proxy, the <strong>dnsmasq</strong> container will be enabled for local DNS resolution, and the mastercontainer will keep your DNS record up to date automatically.</p>
|
||||||
<p>Please enter your email address. You can also enter a desired subdomain slug (the part before <code>.dedyn.io</code>); leave it blank for a random one.</p>
|
{% if desec_account_registered %}
|
||||||
<form method="POST" action="api/desec/register" class="xhr">
|
<p>Your deSEC account (<strong>{{ desec_email }}</strong>) was registered successfully but the domain could not be registered. Please enter a desired subdomain slug (the part before <code>.dedyn.io</code>) and try again, or leave it blank for a random one.</p>
|
||||||
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
|
<p>Your deSEC login credentials (for <a target="_blank" href="https://desec.io">desec.io</a>): Email: <strong>{{ desec_email }}</strong>. <details style="display:inline"><summary>Reveal deSEC password</summary><strong>{{ desec_password }}</strong></details>. Please save these in a safe place.</p>
|
||||||
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
|
<form method="POST" action="api/desec/register" class="xhr">
|
||||||
<input type="email" name="desec_email" placeholder="your@email.com" required />
|
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
|
||||||
<input type="text" name="desec_slug" placeholder="my-nextcloud (optional)" pattern="[a-z0-9]([a-z0-9\-]{0,61}[a-z0-9])?" title="Only lowercase letters, digits and hyphens (1–63 characters). No leading or trailing hyphen." />
|
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
|
||||||
<input type="submit" value="Register free domain via deSEC" />
|
<input type="text" name="desec_slug" placeholder="my-nextcloud (optional)" pattern="[a-z0-9]([a-z0-9\-]{0,61}[a-z0-9])?" title="Only lowercase letters, digits and hyphens (1–63 characters). No leading or trailing hyphen." />
|
||||||
</form>
|
<input type="submit" value="Register free domain via deSEC" />
|
||||||
<p><strong>Note:</strong> By submitting this form you agree to the <a target="_blank" href="https://desec.io/terms">deSEC terms of service</a>. The registered domain and your deSEC account credentials are stored in the AIO configuration. After registration, set your router's DHCP DNS server to this machine's local IP address so LAN devices resolve the domain locally (see the <a target="_blank" href="https://github.com/nextcloud/all-in-one/tree/main/community-containers/dnsmasq">dnsmasq documentation</a>). Alternatively adjust the hosts files on your clients so that they can reach the server using the local ip-address.</p>
|
</form>
|
||||||
|
{% else %}
|
||||||
|
<p>Please enter your email address. You can also enter a desired subdomain slug (the part before <code>.dedyn.io</code>); leave it blank for a random one.</p>
|
||||||
|
<form method="POST" action="api/desec/register" class="xhr">
|
||||||
|
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
|
||||||
|
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
|
||||||
|
<input type="email" name="desec_email" placeholder="your@email.com" required />
|
||||||
|
<input type="text" name="desec_slug" placeholder="my-nextcloud (optional)" pattern="[a-z0-9]([a-z0-9\-]{0,61}[a-z0-9])?" title="Only lowercase letters, digits and hyphens (1–63 characters). No leading or trailing hyphen." />
|
||||||
|
<input type="submit" value="Register free domain via deSEC" />
|
||||||
|
</form>
|
||||||
|
<p><strong>Note:</strong> By submitting this form you agree to the <a target="_blank" href="https://desec.io/terms">deSEC terms of service</a>. The registered domain and your deSEC account credentials are stored in the AIO configuration. After registration, set your router's DHCP DNS server to this machine's local IP address so LAN devices resolve the domain locally (see the <a target="_blank" href="https://github.com/nextcloud/all-in-one/tree/main/community-containers/dnsmasq">dnsmasq documentation</a>). Alternatively adjust the hosts files on your clients so that they can reach the server using the local ip-address.</p>
|
||||||
|
{% endif %}
|
||||||
</details>
|
</details>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
@@ -388,6 +399,14 @@
|
|||||||
|
|
||||||
{% if was_start_button_clicked == true %}
|
{% if was_start_button_clicked == true %}
|
||||||
|
|
||||||
|
{% if is_desec_domain %}
|
||||||
|
<h2>deSEC account credentials</h2>
|
||||||
|
<p>Your domain <strong>{{ domain }}</strong> is managed via <a target="_blank" href="https://desec.io">deSEC</a>. Below are your deSEC account credentials. You can use them to log in at <a target="_blank" href="https://desec.io">desec.io</a> to manage your domain directly.</p>
|
||||||
|
<p>Email: <strong>{{ desec_email }}</strong></p>
|
||||||
|
<p>Password: <details style="display:inline"><summary>Reveal deSEC password</summary><strong>{{ desec_password }}</strong></details></p>
|
||||||
|
<p>Please save these credentials in a safe place.</p>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{% if is_backup_section_enabled == false %}
|
{% if is_backup_section_enabled == false %}
|
||||||
<h2>Backup and restore</h2>
|
<h2>Backup and restore</h2>
|
||||||
<p>The backup section is disabled via environmental variable.</p>
|
<p>The backup section is disabled via environmental variable.</p>
|
||||||
|
|||||||
Reference in New Issue
Block a user