Giter Club home page Giter Club logo

yaac's Introduction

yaac - Yet another ACME client

Written in PHP, this client aims to be a simplified and decoupled Let’s Encrypt client, based on ACME V2.

Decoupled from a filesystem or webserver

Instead of, for example writing the certificate to the disk under an nginx configuration, this client just returns the data (the certificate and private key).

Why

Why would I need this package? At Afosto we run our software in a multi-tenant setup, as any other SaaS would do, and therefore we cannot make use of the many clients that are already out there.

Almost all clients are coupled to a type of webserver or a fixed (set of) domain(s). This package can be extremely useful in case you need to dynamically fetch and install certificates.

Requirements

  • PHP7+
  • openssl
  • Flysystem (any adapter would do) - to store the Lets Encrypt account information

Getting started

Getting started is easy. First install the client, then you need to construct a flysystem filesystem, instantiate the client and you can start requesting certificates.

Installation

Installing this package is done easily with composer.

composer require afosto/yaac

Instantiate the client

To start the client you need 3 things; a username for your Let’s Encrypt account, a bootstrapped Flysystem and you need to decide whether you want to issue Fake LE Intermediate X1 (staging: MODE_STAGING) or Let's Encrypt Authority X3 (live: MODE_LIVE, use for production) certificates.

use League\Flysystem\Filesystem;
use League\Flysystem\Adapter\Local;
use Afosto\Acme\Client;
 
//Prepare flysystem
$adapter = new Local('data');
$filesystem = new Filesystem($adapter);
 
//Construct the client
$client = new Client([
    'username' => '[email protected]',
    'fs'       => $filesystem,
    'mode'     => Client::MODE_STAGING,
]);

While you instantiate the client, when needed a new Let’s Encrypt account is created and then agrees to the TOS.

Create an order

To start retrieving certificates, we need to create an order first. This is done as follows:

$order = $client->createOrder(['example.org', 'www.example.org']);

In the example above the primary domain is followed by a secondary domain(s). Make sure that for each domain you are able to prove ownership. As a result the certificate will be valid for all provided domains.

Prove ownership

Before you can obtain a certificate for a given domain you need to prove that you own the given domain(s). We request the authorizations to prove ownership. Obtain the authorizations for order. For each domain supplied in the create order request an authorization is returned.

$authorizations = $client->authorize($order);

You now have an array of Authorization objects. These have the challenges you can use (both DNS and HTTP) to provide proof of ownership.

HTTP validation

HTTP validation (where serve specific content at a specific url on the domain, like: example.org/.well-known/acme-challenge/*) is done as follows:

Use the following example to get the HTTP validation going. First obtain the challenges, the next step is to make the challenges accessible from

foreach ($authorizations as $authorization) {
    $file = $authorization->getFile();
    file_put_contents($file->getFilename(), $file->getContents());   
}

If you need a wildcard certificate, you will need to use DNS validation, see below

DNS validation

You can also use DNS validation - to do this, you will need access to an API of your DNS provider to create TXT records for the target domains.

foreach ($authorizations as $authorization) {
    $txtRecord = $authorization->getTxtRecord();
    
    //To get the name of the TXT record call:
    $txtRecord->getName();

    //To get the value of the TXT record call:
    $txtRecord->getValue();
}

Self test

After exposing the challenges (made accessible through HTTP or DNS) we should perform a self test just to be sure it works before asking Let's Encrypt to validate ownership.

For a HTTP challenge test call:

if (!$client->selfTest($authorization, Client::VALIDATION_HTTP)) {
    throw new \Exception('Could not verify ownership via HTTP');
}

For a DNS test call:

if (!$client->selfTest($authorization, Client::VALIDATION_DNS)) {
    throw new \Exception('Could not verify ownership via DNS');
}
sleep(30); // this further sleep is recommended, depending on your DNS provider, see below

With DNS validation, after the selfTest has confirmed that DNS has been updated, it is recommended you wait some additional time before proceeding, e.g. sleep(30);. This is because Let’s Encrypt will perform multiple viewpoint validation, and your DNS provider may not have completed propagating the changes across their network.

If you proceed too soon, Let's Encrypt will fail to validate.

Request validation

Next step is to request validation of ownership. For each authorization (domain) we ask Let’s Encrypt to verify the challenge.

For HTTP validation:

foreach ($authorizations as $authorization) {
    $client->validate($authorization->getHttpChallenge(), 15);
}

For DNS validation:

foreach ($authorizations as $authorization) {
    $client->validate($authorization->getDnsChallenge(), 15);
}

The code above will first perform a self test and, if successful, will do 15 attempts to ask Let’s Encrypt to validate the challenge (with 1 second intervals) and retrieve an updated status (it might take Let’s Encrypt a few seconds to validate the challenge).

Get the certificate

Now to know if we can request a certificate for the order, test if the order is ready as follows:

if ($client->isReady($order)) {
    //The validation was successful.
}

We now know validation was completed and can obtain the certificate. This is done as follows:

$certificate = $client->getCertificate($order);

We now have the certificate, to store it on the filesystem:

//Store the certificate and private key where you need it
file_put_contents('certificate.cert', $certificate->getCertificate());
file_put_contents('private.key', $certificate->getPrivateKey());

To get a seperate intermediate certificate and domain certificate:

$domainCertificate = $certificate->getCertificate(false);
$intermediateCertificate = $certificate->getIntermediate();

Who is using it?

Are you using this package, would love to know. Please send a PR to enlist your project or company.

yaac's People

Contributors

adrorocker avatar aitrex-technologies avatar alexnodex avatar bakkerpeter avatar dependabot[bot] avatar gpibarra avatar lordelph avatar manawyrm avatar mgilfillan avatar mikemunger avatar redelschaap avatar smitpipaliya avatar spekulatius avatar thedevilonline avatar tipswithpunch avatar xolf avatar zagrad avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

yaac's Issues

Certificate chain

Hi,

thank you for amazing job!

P.S.
When I try to add certificate on AWS and I add a private key and certificate using $certificate->getCertificate(false).
AWS asks for a chain: "Provided certificate is not a valid self signed. Please provide either a valid self-signed certificate or certificate chain."

Is there way to get chain?

Laravel version: 8.20.1 : Installation failed

Laravel version: 8.20.1

composer require afosto/yaac

Installation failed

Your requirements could not be resolved to an installable set of packages.

Problem 1
- afosto/yaac[v1.2.0, ..., v1.2.3] require guzzlehttp/guzzle ^6.3 -> found guzzlehttp/guzzle[6.3.0, ..., 6.5.x-dev] but it conflicts with your root composer.json require (^7.0.1).
- Root composer.json requires afosto/yaac ^1.2 -> satisfiable by afosto/yaac[v1.2.0, 1.2.1, 1.2.2, v1.2.3].

How to retrieve order and authorizations at a later time?

Hello. I feel like this will be an obvious answer, so apologies in advance. It is intended that our application will create an order and then we need time to manually add the validation TXT records to DNS. How do we later retrieve the authorizations to pass to $client->validate().

For example, it may be that on day 1 we execute:
$client = new Client([...]);
$order = $client->createOrder([...]);
$authorizations = $client->authorize($order);

Then we need time to modify DNS and for the changes to propagate.

Then on say day 2 we execute:
$client->selfTest($authorization);
$client->validate($authorization);
...
$certificate = $client->getCertificate($order);

But how do we retrieve the authorizations on day 2 when they were generated on the previous day? I see that the Client class has a getOrder() method. Is that at least the correct way to retrieve the order on day 2? I see the Order class has a getAuthorizationURLs() method which internally returns $this->authorizations, but the code docs state that it returns an array of strings. I believe I need an array of Authorization objects in order to generate the certificates?

Unable to serialize Authorizations

I need to authorize and then generate the LetsEncrypt certificate in several separate instances, one after the other.

I.e:

  1. Setup order
  2. Authorization self test
  3. Authorization (real)
  4. Generate Certificate

To achieve this, I need to serialize authorizations so they can be used by the next PHP instance (job).

However, I'm unable to serialize Data/Authorization objects due to the properties within being protected.

What would you suggest? I'm starting a pull request now that I believe fixes this issue... but you might have a solution in mind too! :-)


P.S - This is a tidy client compared to others, highly rate! :-)

Supply private Key with $client->createOrder();

Cheers,

we are trying to implement your ACME client within our infrastructure, thanks for your excellent work. I have a question. You expect the private key to be placed in a certain filesystem location. If the client-Class does not find the key, it creates a new one an stores it on your designated fs-location. It is not transparent to me, if my specific key was used to create the CSR or if the class created a new one in a filesystem location, I've probably not expected (within distributed systems).

Why don't you supply a parameter within $client->createOrder() or within the constructor to supply the private key? This would seem to me much more straightforward as the private key needs special treatment within automated infrastructures. Also, a $client->setPrivateKey() function would be suitable and seems more fail-safe in distributed environments as silently create a new key. Would you accept a pull request or is this utterly out of your scope?

Thank you very much. I appreciate your work.
Sebastian Kraus
ticktoo Systems

[QUESTION] How to integrate this on my website?

I already saw issue #25. I will elaborate on my case. What I want to do is get the info from my user and create a client instance then get the output for DNS validation and display it on my site. Then stop the code there, and when the user puts the DNS records for the domain provided the user has a button (say update DNS status or so) on click Self Test is to be run then once that's done get the certificate using a button (say request SSL cert) once that's there I just display the keys to the user and save a copy in my webserver.
So this is basically split into three parts. How can I do this? Can I create client and order again and again?
Any help would be appreciated!!!

Helper.php: explode PHP_EOL on WINDOWS

class TestAcme2Controller extends ZControlCmd
{

public function file_force_contents( $fullPath, $contents, $flags = 0 ){
    $parts = explode( '/', $fullPath );
    array_pop( $parts );
    $dir = implode( '/', $parts );

    if( !is_dir( $dir ) )
        mkdir( $dir, 0777, true );

    file_put_contents( $fullPath, $contents, $flags );
}

public function actionRun()
{
    //Prepare flysystem
    $adapter = new Local('data');

    $filesystem = new Filesystem($adapter);

    //Construct the client
    $client = new Client([
        'username' => '[email protected]',
        'fs'       => $filesystem,
        'mode'     => Client::MODE_STAGING,
    ]);

    $order = $client->createOrder(['vadeacme.zoft.uz']);

    $authorizations = $client->authorize($order);

    foreach ($authorizations as $authorization) {
        $file = $authorization->getFile();
        file_put_contents($file->getFilename(), $file->getContents());

        $this->file_force_contents( Root.'/execut/web/eyuf/.well-known/acme-challenge/'.$file->getFilename(), $file->getContents(), LOCK_EX );

    }

    if (!$client->selfTest($authorization, Client::VALIDATION_HTTP)) {
        throw new \Exception('Count not verify ownership via HTTP');
    }

    foreach ($authorizations as $authorization) {
        $client->validate($authorization->getHttpChallenge(), 15);
    }

    if ($client->isReady($order)) {
        $certificate = $client->getCertificate($order);  //error here

        file_put_contents('certificate.cert', $certificate->getCertificate());
        $this->file_force_contents( Root.'/execut/web/eyuf/.well-known/acme-challenge/private.key', $certificate->getPrivateKey(), LOCK_EX );
    }

}

}

error:
Exception 'GuzzleHttp\Exception\ClientException' with message 'Client error: POST https://acme-staging-v02.api.letsencrypt.org/acme/finalize/13081845/84000364 resulted in a 400 Bad Request response:
{
"type": "urn:ietf:params:acme:error:malformed",
"detail": "Error parsing certificate request: asn1: syntax error: (truncated...)
'

Integrate on a website

Hi i want to integrate this tool on my website with a frontend for the users to generate certificate .can anyone explain the process to me .Any help will be appreciated Thanks

Exception: Undefined array key "certificate"

An Undefined array key "certificate" got thrown when I want to retrieve the certificate. The HTTP selftest and authorization succeeded. Did someone else had a similar issue so far?

 $certificate = $client->getCertificate($order);

I just did some debugging and I found out that the order returns a ready status but the finalize endpoint has processing as a status.

As mentioned in https://community.letsencrypt.org/t/error-when-finalizing-order/104649 and https://datatracker.ietf.org/doc/html/rfc8555#section-7.4 the Retry-After header should be respected. Within https://github.com/afosto/yaac/blob/master/src/Client.php#L323 I did not found any logic handling the specific header. Is this on purpose or am I the first one stumbling across this kind of behaviour?

Do I need a server?

Okie, this is a weird question because you clearly stated this lib does not need it. However, as I follow the instruction I keep getting error with selfHttpTest. When I look at the code, I don't see anywhere that a server is setup to listen to the incoming request? Am I missing something here?

Example doesn't work for local using flysystem 3

With flysystem 3 Local no longer exists, the new syntax is

// The internal adapter
$adapter = new League\Flysystem\Local\LocalFilesystemAdapter(
    // Determine root directory
    __DIR__.'/root/directory/'
);

// The FilesystemOperator
$filesystem = new League\Flysystem\Filesystem($adapter);

Wrong Expiry Date

Hi,

The expiry date given does not match the actual cert (seen in Chrome). Tested on Live & Staging modes.

$order->getExpiresAt()->format('d-M-Y')

// Expiry shown here is 26-Sep-2022 (code above),
// Chrome shows expiry on 18-Dec-2022

Certificates renewal

Hi,

I really like how this project was built and the documentation is very clear compared to other clients.

But I wasn't able to find how can I renew all my certificates. May you please let me know how to do that?

Thank you!

Lowering Private Key lengh

Hey,
Thanks for building this amazing tool!
Is there any way for me to lower the private key to 2048bits?

I have researched from google but can not fix. is it package's error ?. pleas help me. Error in $client->getCertificate($order)); function

class TestAcme2Controller extends ZControlCmd
{

public function file_force_contents( $fullPath, $contents, $flags = 0 ){
    $parts = explode( '/', $fullPath );
    array_pop( $parts );
    $dir = implode( '/', $parts );

    if( !is_dir( $dir ) )
        mkdir( $dir, 0777, true );

    file_put_contents( $fullPath, $contents, $flags );
}

public function actionRun()
{
    //Prepare flysystem
    $adapter = new Local('data');

    $filesystem = new Filesystem($adapter);

    //Construct the client
    $client = new Client([
        'username' => '[email protected]',
        'fs'       => $filesystem,
        'mode'     => Client::MODE_STAGING,
    ]);

    $order = $client->createOrder(['vadeacme.zoft.uz']);

    $authorizations = $client->authorize($order);

    foreach ($authorizations as $authorization) {
        $file = $authorization->getFile();
        file_put_contents($file->getFilename(), $file->getContents());

        $this->file_force_contents( Root.'/execut/web/eyuf/.well-known/acme-challenge/'.$file->getFilename(), $file->getContents(), LOCK_EX );

    }

    if (!$client->selfTest($authorization, Client::VALIDATION_HTTP)) {
        throw new \Exception('Count not verify ownership via HTTP');
    }

    foreach ($authorizations as $authorization) {
        $client->validate($authorization->getHttpChallenge(), 15);
    }

    if ($client->isReady($order)) {
        $certificate = $client->getCertificate($order);  //error here

        file_put_contents('certificate.cert', $certificate->getCertificate());
        $this->file_force_contents( Root.'/execut/web/eyuf/.well-known/acme-challenge/private.key', $certificate->getPrivateKey(), LOCK_EX );
    }

}

}

error:
Exception 'GuzzleHttp\Exception\ClientException' with message 'Client error: POST https://acme-staging-v02.api.letsencrypt.org/acme/finalize/13081845/84000364 resulted in a 400 Bad Request response:
{
"type": "urn:ietf:params:acme:error:malformed",
"detail": "Error parsing certificate request: asn1: syntax error: (truncated...)
'

Not valid certificate

This certificate cannot be verified up to trusted certification authority
Issued by: Artificial Apricot R3

Debugging repeated validation failure

When everything works except for validate() it's quite hard to debug the actual http validation. This is failing but I can't see why. Self test is fine.

foreach ($authorizations as $authorization) {
    $client->validate($authorization->getHttpChallenge(), 15);
}

Would it be better to expose underlying errors with validate's requests to help debug issues?

HTTP-01 challenge not working on MODE_LIVE for subdomain

I want to authorize my order of a subdomain with http validation.
When creating my code with MODE_STAGING, all works fine and got my certificate.
Changing it MODE_LIVE, I have an empty response while requesting for file ($authorization->getFile())

When looking into it deeper, I found that the challenge type changes depending on which mode it uses.

Below you find the object of the authorization response:

MODE_STAGING:
[challenges:protected] => Array ( [0] => Afosto\Acme\Data\Challenge Object ( [authorizationURL:protected] => https://acme-staging-v02.api.letsencrypt.org/acme/authz-v3/4839077173 [type:protected] => http-01 ...)

MODE_LIVE:
[challenges:protected] => Array ( [0] => Afosto\Acme\Data\Challenge Object ( [authorizationURL:protected] => https://acme-v02.api.letsencrypt.org/acme/authz-v3/192215046117 [type:protected] => dns-01 ...)

As you can see 'type' changes.
Both 'status' are valid, but empty getFile object when MODE_LIVE.

Set source IP

Would you accept a pull request to set the source IP?

Letsencrypt has limits on the number of requests from a single IP address over a 3 hour period. If you have an infrastructure with a lot of domains and accompanying IP addresses this can become impossible to manage. Guzzle allows setting the source IP via curl options so an IP could be passed to the client constructor to send the request from that IP address?

Support for guzzle 6 or 7

Guzzle 7 has released, and in order for users to be able to use yaac with projects on the leading edge of dependency upgrades (such as Laravel 8 requiring guzzle ^7.0), it would probably be a good idea to check the feasibility of updating yaac dependencies to something like "guzzlehttp/guzzle": "^6.3|^7.0"

However, guzzle 7 does require "php": "^7.2.5" so this might create a case for a 2.0 of yaac so it doesn't break unexpectedly for users on php 7.0/7.1. Even php 7.2 is EOL after Nov 30, 2020.

MODE_LIVE not working

First off thanks for making this, it's really useful and not bloated like many of the other clients out there.

So I have been successful with the MODE_STAGING and the cert is being generated properly, however when I try to use MODE_LIVE, $client->isReady($order) always reports false, even after a do while false to wait for it to be ready with a usleep and total allowing a minute for processing (note that MODE_STAGING is almost instant).

I am using $ok = $client->validate($authorization->getHttpChallenge(), 15). I'm not sure if I need to allow for longer processing especially with LE now validating domains from multiple locations or if there is something else going on. I do see the PEM for the LE account being created (test creation both with MODE_STAGING and MODE_LIVE -- same PEM which makes sense) so I know at least that part is working.

Steps to implement not entirely clear

I'm a bit lost on how to correctly implement this package. I obviously followed the ReadMe section, but am not clear how to fully integrate this into my Laravel app. That's my current code snippet:

$adapter = new Local('data');
$filesystem = new Filesystem($adapter);

$client = new Client([
    'username' => $user->email,
    'fs' => $filesystem,
    'mode' => Client::MODE_STAGING,
]);

$order = $client->createOrder($domain);
$authorizations = $client->authorize($order);

foreach ($authorizations as $authorization) {
    $txtRecord = $authorization->getTxtRecord();
    $txtRecord->getName();
    $txtRecord->getValue();

    DB::table('domain_validations')->updateOrInsert(
        [
            'user_id' => auth()->id(),
            'base_id' => $base->id
        ],
        [
            'domain' => preg_replace("(^https?://)", "", $request->custom_url),
            'cname' => $cnameProperty,
            'txt' => serialize([$txtRecord->getName(), $txtRecord->getValue()]),
            'cname_validated' => 0
        ]
    );
}

This basically creates the order and stores the txt name and value into the database so I can show the users what to enter in their DNS settings. At this point, the page has been refreshed.

My idea of the next step was to wait at least 30 minutes after the user saved this and then call an action via cronjob to verify. But at this point, I have no access to the initial $client instance anymore since this was only created once during the store function above. How can I now access the $client instance from above?

You example just shows if ($client->isReady($order)) { ... but this clearly cannot be in the same function as it is suggested to wait at least 30 minutes (sleep(30)). Any help or tip regarding this would be really helpful.

Getting Uncaught GuzzleHttp\Exception\ClientException: Client error: `POST https://acme-v02.api.letsencrypt.org/acme/new-order` resulted in a `400 Bad Request` response:

I am getting below error.
Have deployed this on PHP 7.4 CPanel with SSL using: https://github.com/pompy/yaac-ACME-client-implementation
Any help would be appreiated.
[07-Dec-2021 18:36:40 UTC] PHP Fatal error: Uncaught GuzzleHttp\Exception\ClientException: Client error: POST https://acme-v02.api.letsencrypt.org/acme/new-order` resulted in a 400 Bad Request response:
{
"type": "urn:ietf:params:acme:error:rejectedIdentifier",
"detail": "Error creating new order :: Cannot issue for \ (truncated...)
in /home/bvnqstmw/public_html/ssl/vendor/guzzlehttp/guzzle/src/Exception/RequestException.php:113
Stack trace:
#0 /home/bvnqstmw/public_html/ssl/vendor/guzzlehttp/guzzle/src/Middleware.php(69): GuzzleHttp\Exception\RequestException::create(Object(GuzzleHttp\Psr7\Request), Object(GuzzleHttp\Psr7\Response), NULL, Array, NULL)
#1 /home/bvnqstmw/public_html/ssl/vendor/guzzlehttp/promises/src/Promise.php(204): GuzzleHttp\Middleware::GuzzleHttp{closure}(Object(GuzzleHttp\Psr7\Response))
#2 /home/bvnqstmw/public_html/ssl/vendor/guzzlehttp/promises/src/Promise.php(153): GuzzleHttp\Promise\Promise::callHandler(1, Object(GuzzleHttp\Psr7\Response), NULL)
#3 /home/bvnqstmw/public_html/ssl/vendor/guzzlehttp/promises/src/TaskQue in /home/bvnqstmw/public_html/ssl/vendor/guzzlehttp/guzzle/src/Exception/RequestException.php on line 113`

An unexpected error occurred in validate

Client error: POST https://acme-v02.api.letsencrypt.org/acme/chall-v3/{XXXXXX}/0iQ8bQ resulted in a 400 Bad Request response:
{
"type": "urn:ietf:params:acme:error:malformed",
"detail": "Unable to update challenge :: authorization must be pen (truncated...)

Support for separate certificate chain file (for apache < 2.4.8 support)

Hello, great job so far - this package will definitely make my life easier moving from v1 to v2 acme protocol in our custom lets encrypt integration.

I was wondering if you might be able to add support for a separate intermediate cert chain file for apache versions < 2.4.8.

I have a server on CentOS 7 and apache 2.4.6 is the default version, which does not support a single combined file for cert + intermediate cert. In is not supported until apache 2.4.8 and higher.

So perhaps a new method Certificate->getIntermediateCertificate() or Certificate->getCertificateChain() and then Certificate->getCertificate() might need an optional param to just return the cert without the intermediate something like public function getCertifcate($withIntermideiate=true)

The apache config would look something like this, it has 3 file paths expected - the cert, the chain(intermediate cert), and the private key:
https://ssl-config.mozilla.org/#server=apache&version=2.4.6&config=intermediate&openssl=1.0.2k&guideline=5.4

I could of course parse out the combined cert into the 2 files as a workaround but it would be nice-to-have if this was accounted for in the package.

Thanks a lot!
keep up the good work

Intermediate Certificate

When I pull the Intermediate Certificate it is bringing 2 certificates. I use $certificate->getIntermediate() and it brings back 2 -----BEGIN CERTIFICATE----- / -----END CERTIFICATE----- blocks?

Help with debugging a potential rate limit error

Hi Peter,

I’ve built a tool to help people on GoDaddy shared hosting to get an SSL certificate for free, just by filling a few fields on my website. Here is the tool: https://punchsalad.com/ssl-certificate-generator/ .

The tool is built on top of yaac, which in most cases works great! Once I went live with the tool I started to have issues where people are not able to get verification files for http-01 although their details (domains & email) are correct. I’m able to reproduce the issue from time to time.

It seems the issues happens when a "new client" is created in the code,
so at this stage:
$client = new Client([ 'username' => $emailAddress, 'fs' => $filesystem, 'mode' => Client::MODE_LIVE, ]);

And the whole code fails and I get a response code of 500.
Then after 30-60 mins, it works again without any issue. Also, it seems to happen more often when there are many users using the tool in a short period of time (within 30mins or so).

I’m not able to debug this as I’m not sure which rate limit I’m hitting and there is no error status.
I think it’s either “too many failed authorizations recently” or “too many registrations for this IP”. For the second I’m not sure I’m hitting that limit of 10 accounts per 3 hours. But also I have no way of validating this.

Can you please point me in the right direction to debug this issue?

Thanks,
Robert

Is there anyway to auto-renew certs?

Hi,

Is there anyway to renew certs? Like what if I would like to renew stored certs in my DB before 30 days or so? Is there any function call exists for that or should I simply issue fresh new cert again?

Thanks.
Humayun

cPanel CA Bundle

Hello,
it seems that the CA bunlde is missing:

if ($client->isReady($order))
                {
                    $certificate = $client->getCertificate($order);
        
                    echo '<pre>' . $certificate->getCertificate(false) . '</pre>';
                    echo '<pre>' . $certificate->getPrivateKey() . '</pre>';
                    echo '<pre>' . $certificate->getIntermediate() . '</pre>';
                }

Certificate verification failed! The system did not find the root certificate that corresponds to the supplied Certificate Authority Bundle’s intermediate certificate. Please supply a full Certificate Authority Bundle with the root certificate included.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.