{"id":15514750,"url":"https://github.com/fgasper/p5-net-acme","last_synced_at":"2025-08-11T09:09:02.428Z","repository":{"id":56837135,"uuid":"73576589","full_name":"FGasper/p5-Net-ACME","owner":"FGasper","description":"CPAN Net::ACME","archived":false,"fork":false,"pushed_at":"2019-03-12T11:30:05.000Z","size":166,"stargazers_count":0,"open_issues_count":0,"forks_count":2,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-07-27T02:34:09.317Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Perl","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/FGasper.png","metadata":{"files":{"readme":"README.md","changelog":"Changes","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-11-12T20:26:20.000Z","updated_at":"2019-03-12T11:30:07.000Z","dependencies_parsed_at":"2022-08-31T00:51:25.802Z","dependency_job_id":null,"html_url":"https://github.com/FGasper/p5-Net-ACME","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/FGasper/p5-Net-ACME","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FGasper%2Fp5-Net-ACME","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FGasper%2Fp5-Net-ACME/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FGasper%2Fp5-Net-ACME/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FGasper%2Fp5-Net-ACME/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/FGasper","download_url":"https://codeload.github.com/FGasper/p5-Net-ACME/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FGasper%2Fp5-Net-ACME/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":269857485,"owners_count":24486395,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-11T02:00:10.019Z","response_time":75,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-02T10:00:30.149Z","updated_at":"2025-08-11T09:09:02.400Z","avatar_url":"https://github.com/FGasper.png","language":"Perl","funding_links":[],"categories":[],"sub_categories":[],"readme":"# NAME\n\nNet::ACME - Client for the (old) ACME protocol (e.g., [Let’s Encrypt](http://letsencrypt.org))\n\n  \n\n# SYNOPSIS\n\n    package MyACME::SomeService;\n\n    use constant _HOST =\u003e ...;   #the name of the ACME host\n\n    #See below for full examples.\n\n# END-OF-LIFE WARNING\n\n**WARNING:** Let’s Encrypt has announced [end-of-life for their API\nthat uses this protocol](https://community.letsencrypt.org/t/end-of-life-plan-for-acmev1/88430). All applications that use this module should migrate to\n[Net::ACME2](https://metacpan.org/pod/Net::ACME2). Further use of this module is discouraged.\n\n# DESCRIPTION\n\nThis module implements client logic (including SSL certificate issuance)\nfor the “draft” version of the ACME protocol,\nthe system for automated issuance of SSL certificates used by\n[Let’s Encrypt](http://letsencrypt.org).\n\nFor support of the [IETF](http://ietf.org)-standard version of this\nprotocol, look at [Net::ACME2](https://metacpan.org/pod/Net::ACME2).\n\nThe methods of this class return objects that correspond to the\nrespective ACME resource:\n\n- `register()`: `Net::ACME::Registration`\n- `start_domain_authz()`: `Net::ACME::Authorization::Pending`\n- `get_certificate()`: `Net::ACME::Certificate` or `Net::ACME::Certificate::Pending`\n\n# WHY USE THIS MODULE?\n\n- Closely based on cPanel’s widely-used Let’s Encrypt plugin.\n- Support for both RSA and ECDSA encryption (via [Crypt::Perl](https://metacpan.org/pod/Crypt::Perl)).\n- Thorough error-checking: any deviation from what the ACME protocol\nexpects is reported immediately via an exception.\n- Well-defined object system, including typed, queryable exceptions.\n- Extensive test coverage.\n- Light memory footprint - no Moose/Moo/etc.\n- No careless overwriting of globals like `$@`, `$!`, and `$?`.\n(Hopefully your code isn’t susceptible to this anyway, but it’s just a good\nprecaution.)\n- This is a pure-Perl solution. Most of its dependencies are\neither core modules or pure Perl themselves. XS is necessary to\ncommunicate with the ACME server via TLS; however, most Perl installations\nalready include the necessary logic (i.e., [Net::SSLeay](https://metacpan.org/pod/Net::SSLeay)) for TLS.\n\n    In short, Net::ACME will run anywhere that Perl can speak TLS, which is\n    _almost_ everywhere that Perl runs.\n\n# STATUS\n\nThis module is now well-tested and should be safe for use in your application.\n\n# CUSTOMIZATION\n\n**HTTPS options**: This module uses `HTTP::Tiny` for its network operations.\nIn some instances it is desirable to specify custom `SSL_options` in that\nmodule’s constructor; to do this, populate\n`@Net::ACME::HTTP_Tiny::SSL_OPTIONS`.\n\n# URI vs. URL\n\nThis module uses “uri” for ACME-related objects and “url” for\nHTTP-related ones. This apparent conflict is a result of maintaining\nconsistency with both the ACME specification (“uri”) and [HTTP::Tiny](https://metacpan.org/pod/HTTP::Tiny) (“url”).\n\n# EXAMPLES\n\nSee the `examples` directory in the distribution for complete, interactive\nexample scripts that also illustrate a bit of how ACME works.\n\nSee below for cut-paste-y examples.\n\n# EXAMPLE: REGISTRATION\n\n    my $tos_url = Net::ACME::LetsEncrypt-\u003eget_terms_of_service();\n\n    my $acme = Net::ACME::LetsEncrypt-\u003enew( key =\u003e $reg_rsa_pem );\n\n    #Use this method any time you want to update contact information,\n    #not just when you set up a new account.\n    my $reg = $acme-\u003eregister('mailto:me@example.com', 'mailto:who@example.com');\n\n    $acme-\u003eaccept_tos( $reg-\u003euri(), $tos_url );\n\n# EXAMPLE: DOMAIN AUTHORIZATION \u0026 CERTIFICATE PROCUREMENT\n\n    for my $domain (@domains) {\n        my $authz_p = $acme-\u003estart_domain_authz($domain);\n\n        for my $cmb_ar ( $authz_p-\u003ecombinations() ) {\n\n            #$cmb_ar is a set of challenges that the ACME server will\n            #accept as proof of domain control. As of November 2016, these\n            #sets all contain exactly one challenge each: “http-01”, etc.\n\n            #Each member of @$cmb_ar is an instance of\n            #Net::ACME::Challenge::Pending--maybe a subclass thereof such as\n            #Net::ACME::Challenge::Pending::http_01.\n\n            #At this point, you examine $cmb_ar and determine if this\n            #combination is one that you’re interested in. You might try\n            #something like:\n            #\n            #   next if @$cmb_ar \u003e 1;\n            #   next if $cmb_ar-\u003e[0]-\u003etype() ne 'http-01';\n\n            #Once you’ve examined $cmb_ar and set up the appropriate response(s),\n            #it’s time to tell the ACME server to send its challenge query.\n            $acme-\u003edo_challenge($_) for @$cmb_ar;\n\n            while (1) {\n                if ( $authz_p-\u003eis_time_to_poll() ) {\n                    my $poll = $authz_p-\u003epoll();\n\n                    last if $poll-\u003estatus() eq 'valid';\n\n                    if ( $poll-\u003estatus() eq 'invalid' ) {\n                        my @failed = map { $_-\u003eerror() } $poll-\u003echallenges();\n\n                        warn $_-\u003eto_string() . $/ for @failed;\n\n                        die \"Failed authorization for “$domain”!\";\n                    }\n\n                }\n\n                sleep 1;\n            }\n        }\n    }\n\n    #Make a key and CSR.\n    #Creation of CSRs is well-documented so won’t be discussed here.\n\n    my $cert = $acme-\u003eget_certificate($csr_pem);\n\n    #This shouldn’t actually be necessary for Let’s Encrypt,\n    #but the ACME protocol describes it.\n    while ( !$cert-\u003epem() ) {\n        sleep 1;\n        next if !$cert-\u003eis_time_to_poll();\n        $cert = $cert-\u003epoll() || $cert;\n    }\n\n# TODO\n\n- Once the [ACME specification](https://tools.ietf.org/html/draft-ietf-acme-acme)\nis finalized, update this module to take advantage of the full specification.\nAs Let’s Encrypt’s [Boulder](https://github.com/letsencrypt/boulder) is currently\nthe only widely-used ACME server, and that software is compatible with\n[the first draft of the ACME spec](https://tools.ietf.org/html/draft-ietf-acme-acme-01),\nthere’s little reason to update for the time being.\n\n# THANKS\n\n- cPanel, Inc. for permission to adapt their ACME framework for\npublic consumption.\n- Stephen Ludin for developing and maintaining [Protocol::ACME](https://metacpan.org/pod/Protocol::ACME), from which\nthis module took its inspiration.\n\n# SEE ALSO\n\nFor support of the version of this protocol codified in\n[RFC 8555](https://www.rfc-editor.org/rfc/rfc8555.txt), look at\n[Net::ACME2](https://metacpan.org/pod/Net::ACME2).\n\nI am aware of the following additional CPAN modules that implement\nthe draft ACME protocol:\n\n- [Protocol::ACME](https://metacpan.org/pod/Protocol::ACME)\n- [Crypt::LE](https://metacpan.org/pod/Crypt::LE)\n- [WWW::LetsEncrypt](https://metacpan.org/pod/WWW::LetsEncrypt)\n- [Mojo::ACME](https://metacpan.org/pod/Mojo::ACME)\n\n# REPOSITORY (FEEDBACK/BUGS)\n\n[https://github.com/FGasper/p5-Net-ACME](https://github.com/FGasper/p5-Net-ACME)\n\n# AUTHOR\n\nFelipe Gasper (FELIPE)\n\n# LICENSE\n\nThis module is licensed under the same terms as Perl.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffgasper%2Fp5-net-acme","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffgasper%2Fp5-net-acme","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffgasper%2Fp5-net-acme/lists"}