Ask for email when generating LetsEncrypt SSLs (#452)

This commit is contained in:
Saeed Vaziry 2025-01-29 21:00:43 +01:00 committed by GitHub
parent 270928af13
commit 53e20cbc2a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 59 additions and 5 deletions

View File

@ -30,6 +30,7 @@ public function create(Site $site, array $input): void
'pk' => $input['private'] ?? null, 'pk' => $input['private'] ?? null,
'expires_at' => $input['type'] === SslType::LETSENCRYPT ? now()->addMonths(3) : $input['expires_at'], 'expires_at' => $input['type'] === SslType::LETSENCRYPT ? now()->addMonths(3) : $input['expires_at'],
'status' => SslStatus::CREATING, 'status' => SslStatus::CREATING,
'email' => $input['email'] ?? null,
]); ]);
$ssl->domains = [$site->domain]; $ssl->domains = [$site->domain];
if (isset($input['aliases']) && $input['aliases']) { if (isset($input['aliases']) && $input['aliases']) {
@ -69,6 +70,12 @@ public static function rules(array $input): array
'after_or_equal:'.now(), 'after_or_equal:'.now(),
]; ];
} }
if (isset($input['type']) && $input['type'] == SslType::LETSENCRYPT) {
$rules['email'] = [
'required',
'email',
];
}
return $rules; return $rules;
} }

View File

@ -20,6 +20,7 @@
* @property string $ca_path * @property string $ca_path
* @property ?array $domains * @property ?array $domains
* @property int $log_id * @property int $log_id
* @property string $email
* @property ?ServerLog $log * @property ?ServerLog $log
*/ */
class Ssl extends AbstractModel class Ssl extends AbstractModel
@ -36,6 +37,7 @@ class Ssl extends AbstractModel
'status', 'status',
'domains', 'domains',
'log_id', 'log_id',
'email',
]; ];
protected $casts = [ protected $casts = [
@ -143,4 +145,13 @@ public function log(): BelongsTo
{ {
return $this->belongsTo(ServerLog::class); return $this->belongsTo(ServerLog::class);
} }
public function getEmailAttribute(?string $value): string
{
if ($value) {
return $value;
}
return $this->site->server->creator->email;
}
} }

View File

@ -168,7 +168,7 @@ public function setupSSL(Ssl $ssl): void
$domains .= ' -d '.$domain; $domains .= ' -d '.$domain;
} }
$command = view('ssh.services.webserver.nginx.create-letsencrypt-ssl', [ $command = view('ssh.services.webserver.nginx.create-letsencrypt-ssl', [
'email' => $ssl->site->server->creator->email, 'email' => $ssl->email,
'domain' => $ssl->site->domain, 'domain' => $ssl->site->domain,
'domains' => $domains, 'domains' => $domains,
]); ]);

View File

@ -3,7 +3,9 @@
namespace App\Web\Pages\Servers\Sites\Pages\SSL; namespace App\Web\Pages\Servers\Sites\Pages\SSL;
use App\Actions\SSL\CreateSSL; use App\Actions\SSL\CreateSSL;
use App\Enums\SslType;
use App\Models\Ssl; use App\Models\Ssl;
use App\Web\Fields\AlertField;
use App\Web\Pages\Servers\Sites\Page; use App\Web\Pages\Servers\Sites\Page;
use Filament\Actions\Action; use Filament\Actions\Action;
use Filament\Actions\CreateAction; use Filament\Actions\CreateAction;
@ -11,6 +13,7 @@
use Filament\Forms\Components\DatePicker; use Filament\Forms\Components\DatePicker;
use Filament\Forms\Components\Select; use Filament\Forms\Components\Select;
use Filament\Forms\Components\Textarea; use Filament\Forms\Components\Textarea;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Get; use Filament\Forms\Get;
use Filament\Support\Enums\MaxWidth; use Filament\Support\Enums\MaxWidth;
@ -45,25 +48,32 @@ protected function getHeaderActions(): array
->label('New Certificate') ->label('New Certificate')
->icon('heroicon-o-lock-closed') ->icon('heroicon-o-lock-closed')
->form([ ->form([
AlertField::make('letsencrypt-info')
->warning()
->message('Let\'s Encrypt has rate limits. Read more about them <a href="https://letsencrypt.org/docs/rate-limits/" target="_blank" class="underline">here</a>.'),
Select::make('type') Select::make('type')
->options( ->options(
collect(config('core.ssl_types'))->mapWithKeys(fn ($type) => [$type => $type]) collect(config('core.ssl_types'))->mapWithKeys(fn ($type) => [$type => $type])
) )
->rules(fn (Get $get) => CreateSSL::rules($get())['type']) ->rules(fn (Get $get) => CreateSSL::rules($get())['type'])
->reactive(), ->reactive(),
TextInput::make('email')
->rules(fn (Get $get) => CreateSSL::rules($get())['email'] ?? [])
->visible(fn (Get $get) => $get('type') === SslType::LETSENCRYPT)
->helperText('Email address to provide to Certbot.'),
Textarea::make('certificate') Textarea::make('certificate')
->rows(5) ->rows(5)
->rules(fn (Get $get) => CreateSSL::rules($get())['certificate']) ->rules(fn (Get $get) => CreateSSL::rules($get())['certificate'])
->visible(fn (Get $get) => $get('type') === 'custom'), ->visible(fn (Get $get) => $get('type') === SslType::CUSTOM),
Textarea::make('private') Textarea::make('private')
->label('Private Key') ->label('Private Key')
->rows(5) ->rows(5)
->rules(fn (Get $get) => CreateSSL::rules($get())['private']) ->rules(fn (Get $get) => CreateSSL::rules($get())['private'])
->visible(fn (Get $get) => $get('type') === 'custom'), ->visible(fn (Get $get) => $get('type') === SslType::CUSTOM),
DatePicker::make('expires_at') DatePicker::make('expires_at')
->format('Y-m-d') ->format('Y-m-d')
->rules(fn (Get $get) => CreateSSL::rules($get())['expires_at']) ->rules(fn (Get $get) => CreateSSL::rules($get())['expires_at'])
->visible(fn (Get $get) => $get('type') === 'custom'), ->visible(fn (Get $get) => $get('type') === SslType::CUSTOM),
Checkbox::make('aliases') Checkbox::make('aliases')
->label("Set SSL for site's aliases as well"), ->label("Set SSL for site's aliases as well"),
]) ])

View File

@ -0,0 +1,22 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::table('ssls', function (Blueprint $table) {
$table->string('email')->nullable();
});
}
public function down(): void
{
Schema::table('ssls', function (Blueprint $table) {
$table->dropColumn('email');
});
}
};

View File

@ -3,7 +3,7 @@
<div <div
class="border-{{ $getColor() }}-500 bg-{{ $getColor() }}-100 text-{{ $getColor() }}-700 dark:bg-{{ $getColor() }}-500 dark:text-{{ $getColor() }}-500 rounded-lg border border-l-4 px-4 py-3 dark:bg-opacity-10" class="border-{{ $getColor() }}-500 bg-{{ $getColor() }}-100 text-{{ $getColor() }}-700 dark:bg-{{ $getColor() }}-500 dark:text-{{ $getColor() }}-500 rounded-lg border border-l-4 px-4 py-3 dark:bg-opacity-10"
> >
{{ $getMessage() }} {!! $getMessage() !!}
</div> </div>
</div> </div>
</div> </div>

View File

@ -44,6 +44,7 @@ public function test_letsencrypt_ssl()
]) ])
->callAction('create', [ ->callAction('create', [
'type' => SslType::LETSENCRYPT, 'type' => SslType::LETSENCRYPT,
'email' => 'ssl@example.com',
]) ])
->assertSuccessful(); ->assertSuccessful();
@ -52,6 +53,7 @@ public function test_letsencrypt_ssl()
'type' => SslType::LETSENCRYPT, 'type' => SslType::LETSENCRYPT,
'status' => SslStatus::CREATED, 'status' => SslStatus::CREATED,
'domains' => json_encode([$this->site->domain]), 'domains' => json_encode([$this->site->domain]),
'email' => 'ssl@example.com',
]); ]);
} }
@ -67,6 +69,7 @@ public function test_letsencrypt_ssl_with_aliases()
]) ])
->callAction('create', [ ->callAction('create', [
'type' => SslType::LETSENCRYPT, 'type' => SslType::LETSENCRYPT,
'email' => 'ssl@example.com',
'aliases' => true, 'aliases' => true,
]) ])
->assertSuccessful(); ->assertSuccessful();
@ -76,6 +79,7 @@ public function test_letsencrypt_ssl_with_aliases()
'type' => SslType::LETSENCRYPT, 'type' => SslType::LETSENCRYPT,
'status' => SslStatus::CREATED, 'status' => SslStatus::CREATED,
'domains' => json_encode(array_merge([$this->site->domain], $this->site->aliases)), 'domains' => json_encode(array_merge([$this->site->domain], $this->site->aliases)),
'email' => 'ssl@example.com',
]); ]);
} }