From b96927b21977076346763124820f16917ddef361 Mon Sep 17 00:00:00 2001 From: Matt Jones Date: Wed, 10 Aug 2022 16:08:51 +0100 Subject: [PATCH 1/4] Adding subjectAlternativeNames support --- README.md | 11 ++++++++++ ...ficates_subject_alternative_names.php.stub | 22 +++++++++++++++++++ src/Jobs/RequestCertificate.php | 2 +- src/Models/LetsEncryptCertificate.php | 1 + src/PendingCertificate.php | 18 +++++++++++++++ tests/Facades/LetsEncryptTest.php | 15 +++++++++++++ tests/TestCase.php | 2 ++ 7 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 database/migrations/add_lets_encrypt_certificates_subject_alternative_names.php.stub diff --git a/README.md b/README.md index 7086206..4d8fd18 100644 --- a/README.md +++ b/README.md @@ -111,6 +111,17 @@ $certificate->delete(); $certificate->forceDelete(); ``` + +## Subject Alternative Names + +It's possible to specify Subject Alternative Names as below: + +```php +LetsEncrypt::certificate('mydomain.com') + ->subjectAlternativeNames(['mydomain2.com']) + ->create(); +``` + ## Failure events If one of the jobs fails, one of the following events will be dispatched: diff --git a/database/migrations/add_lets_encrypt_certificates_subject_alternative_names.php.stub b/database/migrations/add_lets_encrypt_certificates_subject_alternative_names.php.stub new file mode 100644 index 0000000..cbb37a6 --- /dev/null +++ b/database/migrations/add_lets_encrypt_certificates_subject_alternative_names.php.stub @@ -0,0 +1,22 @@ +json('subject_alternative_names')->nullable()->after('domain'); + }); + } + + public function down() + { + Schema::table('lets_encrypt_certificates', function (Blueprint $table) { + $table->dropColumn('subject_alternative_names'); + }); + } +} diff --git a/src/Jobs/RequestCertificate.php b/src/Jobs/RequestCertificate.php index 40023fb..d8a794f 100644 --- a/src/Jobs/RequestCertificate.php +++ b/src/Jobs/RequestCertificate.php @@ -38,7 +38,7 @@ public function __construct(LetsEncryptCertificate $certificate, int $tries = nu public function handle() { - $distinguishedName = new DistinguishedName($this->certificate->domain); + $distinguishedName = new DistinguishedName($this->certificate->domain, null, null, null, null, null, null, $this->certificate->subject_alternative_names); $csr = new CertificateRequest($distinguishedName, (new KeyPairGenerator())->generateKeyPair()); $client = LetsEncrypt::createClient(); $certificateResponse = $client->requestCertificate($this->certificate->domain, $csr); diff --git a/src/Models/LetsEncryptCertificate.php b/src/Models/LetsEncryptCertificate.php index ca22d02..df7071d 100644 --- a/src/Models/LetsEncryptCertificate.php +++ b/src/Models/LetsEncryptCertificate.php @@ -42,6 +42,7 @@ class LetsEncryptCertificate extends Model protected $casts = [ 'created' => 'boolean', + 'subject_alternative_names' => 'json', ]; public function newEloquentBuilder($query): LetsEncryptCertificateBuilder diff --git a/src/PendingCertificate.php b/src/PendingCertificate.php index 5d0ad1d..572f883 100644 --- a/src/PendingCertificate.php +++ b/src/PendingCertificate.php @@ -43,6 +43,11 @@ class PendingCertificate */ protected $delay = 0; + /** + * @var array + */ + protected $subjectAlternativeNames = []; + /** * PendingCertificate constructor. * @param string $domain @@ -67,6 +72,7 @@ public function create(): LetsEncryptCertificate $certificate = LetsEncryptCertificate::create([ 'domain' => $this->domain, + 'subject_alternative_names' => $this->subjectAlternativeNames, ]); RegisterAccount::withChain(array_merge([ @@ -118,6 +124,18 @@ public function renew(): LetsEncryptCertificate return $certificate; } + + /** + * @param array $domains + * @return static + */ + public function setSubjectAlternativeNames(array $domains): self + { + $this->subjectAlternativeNames = $domains; + + return $this; + } + /** * @param int $tries * @return static diff --git a/tests/Facades/LetsEncryptTest.php b/tests/Facades/LetsEncryptTest.php index 5eecb97..e979234 100644 --- a/tests/Facades/LetsEncryptTest.php +++ b/tests/Facades/LetsEncryptTest.php @@ -75,4 +75,19 @@ public function test_can_create_pending() RequestCertificate::class, ]); } + + /** @test */ + public function test_can_create_now_with_san() + { + Bus::fake(); + + $certificate = LetsEncrypt::certificate('somedomain.com') + ->setSubjectAlternativeNames(['other.somedomain.com']) + ->create(); + + $this->assertEquals('somedomain.com', $certificate->domain); + $this->assertEquals(['other.somedomain.com'], $certificate->subject_alternative_names); + + Bus::assertDispatched(RegisterAccount::class); + } } diff --git a/tests/TestCase.php b/tests/TestCase.php index d79914c..7282ec2 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -29,6 +29,8 @@ public function getEnvironmentSetUp($app) ]); include_once __DIR__.'/../database/migrations/create_lets_encrypt_certificates_table.php.stub'; + include_once __DIR__.'/../database/migrations/add_lets_encrypt_certificates_subject_alternative_names.php.stub'; (new \CreateLetsEncryptCertificatesTable())->up(); + (new \AddLetsEncryptCertificatesSubjectAlternativeNames())->up(); } } From 884577fd293a4e176439817913e8fd1e3f7ad341 Mon Sep 17 00:00:00 2001 From: Matt Jones Date: Mon, 12 Sep 2022 15:59:27 +0100 Subject: [PATCH 2/4] Correcting documentation function name --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4d8fd18..08436bb 100644 --- a/README.md +++ b/README.md @@ -118,7 +118,7 @@ It's possible to specify Subject Alternative Names as below: ```php LetsEncrypt::certificate('mydomain.com') - ->subjectAlternativeNames(['mydomain2.com']) + ->setSubjectAlternativeNames(['mydomain2.com']) ->create(); ``` From c820748e9ffb08f277a0ad0abfb7eefe44d44383 Mon Sep 17 00:00:00 2001 From: Daanra Date: Fri, 16 Sep 2022 10:29:48 +0000 Subject: [PATCH 3/4] Fix styling --- src/PendingCertificate.php | 1 - src/Traits/Retryable.php | 1 - 2 files changed, 2 deletions(-) diff --git a/src/PendingCertificate.php b/src/PendingCertificate.php index 5d0ad1d..513dc34 100644 --- a/src/PendingCertificate.php +++ b/src/PendingCertificate.php @@ -12,7 +12,6 @@ class PendingCertificate { - /** * @var string */ diff --git a/src/Traits/Retryable.php b/src/Traits/Retryable.php index b21e115..d36732d 100644 --- a/src/Traits/Retryable.php +++ b/src/Traits/Retryable.php @@ -4,7 +4,6 @@ trait Retryable { - /** * The number of times the job may be attempted. * From 76e56122775b53ed6a14cdcb80b25838acc5ebf4 Mon Sep 17 00:00:00 2001 From: Daan Raatjes Date: Fri, 16 Sep 2022 12:58:01 +0200 Subject: [PATCH 4/4] Make SAN migration publishable --- README.md | 2 +- ...encrypt_certificates_subject_alternative_names.php.stub | 2 +- src/LetsEncryptServiceProvider.php | 7 +++++++ src/Models/LetsEncryptCertificate.php | 3 ++- tests/Facades/LetsEncryptTest.php | 1 + 5 files changed, 12 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 08436bb..722d6c6 100644 --- a/README.md +++ b/README.md @@ -114,7 +114,7 @@ $certificate->forceDelete(); ## Subject Alternative Names -It's possible to specify Subject Alternative Names as below: +It's also possible to specify Subject Alternative Names as below (requires >= 0.5.0): ```php LetsEncrypt::certificate('mydomain.com') diff --git a/database/migrations/add_lets_encrypt_certificates_subject_alternative_names.php.stub b/database/migrations/add_lets_encrypt_certificates_subject_alternative_names.php.stub index cbb37a6..12291d9 100644 --- a/database/migrations/add_lets_encrypt_certificates_subject_alternative_names.php.stub +++ b/database/migrations/add_lets_encrypt_certificates_subject_alternative_names.php.stub @@ -9,7 +9,7 @@ class AddLetsEncryptCertificatesSubjectAlternativeNames extends Migration public function up() { Schema::table('lets_encrypt_certificates', function (Blueprint $table) { - $table->json('subject_alternative_names')->nullable()->after('domain'); + $table->json('subject_alternative_names')->default('[]')->after('domain'); }); } diff --git a/src/LetsEncryptServiceProvider.php b/src/LetsEncryptServiceProvider.php index 1d51544..8df3acf 100644 --- a/src/LetsEncryptServiceProvider.php +++ b/src/LetsEncryptServiceProvider.php @@ -26,6 +26,13 @@ public function boot() __DIR__ . "/../database/migrations/{$migrationFileName}.stub" => database_path('migrations/' . date('Y_m_d_His', time()) . '_' . $migrationFileName), ], 'lets-encrypt'); } + + $sanMigrationFileName = 'add_lets_encrypt_certificates_subject_alternative_names.php'; + if (! $this->migrationFileExists($sanMigrationFileName)) { + $this->publishes([ + __DIR__ . "/../database/migrations/{$sanMigrationFileName}.stub" => database_path('migrations/' . date('Y_m_d_His', time() + 1) . '_' . $sanMigrationFileName), + ], ['lets-encrypt', 'lets-encrypt-0.5']); + } } $this->commands([ diff --git a/src/Models/LetsEncryptCertificate.php b/src/Models/LetsEncryptCertificate.php index df7071d..9700494 100644 --- a/src/Models/LetsEncryptCertificate.php +++ b/src/Models/LetsEncryptCertificate.php @@ -20,6 +20,7 @@ * @property \Illuminate\Support\Carbon|null $created_at * @property \Illuminate\Support\Carbon|null $updated_at * @property \Illuminate\Support\Carbon|null $deleted_at + * @property array $subject_alternative_names * @property-read bool $has_expired * @method static \Daanra\LaravelLetsEncrypt\Builders\LetsEncryptCertificateBuilder|\Daanra\LaravelLetsEncrypt\Models\LetsEncryptCertificate query() * @method static \Daanra\LaravelLetsEncrypt\Builders\LetsEncryptCertificateBuilder|\Daanra\LaravelLetsEncrypt\Models\LetsEncryptCertificate newQuery() @@ -42,7 +43,7 @@ class LetsEncryptCertificate extends Model protected $casts = [ 'created' => 'boolean', - 'subject_alternative_names' => 'json', + 'subject_alternative_names' => 'array', ]; public function newEloquentBuilder($query): LetsEncryptCertificateBuilder diff --git a/tests/Facades/LetsEncryptTest.php b/tests/Facades/LetsEncryptTest.php index e979234..e842c07 100644 --- a/tests/Facades/LetsEncryptTest.php +++ b/tests/Facades/LetsEncryptTest.php @@ -69,6 +69,7 @@ public function test_can_create_pending() $certificate = LetsEncrypt::certificate('test.test')->create(); $this->assertEquals('test.test', $certificate->domain); + $this->assertEquals([], $certificate->subject_alternative_names); Queue::assertPushedWithChain(RegisterAccount::class, [ RequestAuthorization::class,