Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
Ian Eiloart
Sympl
Commits
24a14e8d
Commit
24a14e8d
authored
Oct 23, 2019
by
Paul Cammish
Browse files
Merge branch 'buster-testing' into 'buster'
Buster testing -> Buster See merge request
sympl/sympl!144
parents
73f14ea5
8936bad9
Changes
22
Hide whitespace changes
Inline
Side-by-side
core/debian/changelog
View file @
24a14e8d
sympl-core (10.0.191017.0) stable; urgency=medium
* Updated sympl-ssl to use Let's Encrypt ACME v02 API
-- Paul Cammish <sympl@kelduum.net> Thu, 17 Oct 2019 13:45:01 +0100
sympl-core (10.0.190908.0) stable; urgency=medium
* Set default threshold for LE cert renewal to 30 days.
...
...
core/lib/acme/client.rb
View file @
24a14e8d
...
...
@@ -7,12 +7,12 @@ require 'digest'
require
'forwardable'
require
'base64'
require
'time'
require
'uri'
module
Acme
;
end
class
Acme::Client
;
end
require
'acme/client/version'
require
'acme/client/certificate'
require
'acme/client/certificate_request'
require
'acme/client/self_sign_certificate'
require
'acme/client/resources'
...
...
@@ -22,15 +22,14 @@ require 'acme/client/error'
require
'acme/client/util'
class
Acme::Client
DEFAULT_ENDPOINT
=
'http://127.0.0.1:4000'
.
freeze
DIRECTORY_DEFAULT
=
{
'new-authz'
=>
'/acme/new-authz'
,
'new-cert'
=>
'/acme/new-cert'
,
'new-reg'
=>
'/acme/new-reg'
,
'revoke-cert'
=>
'/acme/revoke-cert'
}.
freeze
def
initialize
(
jwk:
nil
,
private_key:
nil
,
endpoint:
DEFAULT_ENDPOINT
,
directory_uri:
nil
,
connection_options:
{})
DEFAULT_DIRECTORY
=
'http://127.0.0.1:4000/directory'
.
freeze
repo_url
=
'https://github.com/unixcharles/acme-client'
USER_AGENT
=
"Acme::Client v
#{
Acme
::
Client
::
VERSION
}
(
#{
repo_url
}
)"
.
freeze
CONTENT_TYPES
=
{
pem:
'application/pem-certificate-chain'
}
def
initialize
(
jwk:
nil
,
kid:
nil
,
private_key:
nil
,
directory:
DEFAULT_DIRECTORY
,
connection_options:
{},
bad_nonce_retry:
0
)
if
jwk
.
nil?
&&
private_key
.
nil?
raise
ArgumentError
,
'must specify jwk or private_key'
end
...
...
@@ -41,93 +40,269 @@ class Acme::Client
Acme
::
Client
::
JWK
.
from_private_key
(
private_key
)
end
@endpoint
,
@directory_uri
,
@connection_options
=
endpoint
,
directory_uri
,
connection_options
@kid
,
@connection_options
=
kid
,
connection_options
@bad_nonce_retry
=
bad_nonce_retry
@directory
=
Acme
::
Client
::
Resources
::
Directory
.
new
(
URI
(
directory
),
@connection_options
)
@nonces
||=
[]
load_directory!
end
attr_reader
:jwk
,
:nonces
,
:endpoint
,
:directory_uri
,
:operation_endpoints
attr_reader
:jwk
,
:nonces
def
register
(
contact
:
)
def
new_account
(
contact
:,
terms_of_service_agreed:
nil
)
payload
=
{
resource:
'new-reg'
,
contact:
Array
(
contact
)
contact:
Array
(
contact
)
}
response
=
connection
.
post
(
@operation_endpoints
.
fetch
(
'new-reg'
),
payload
)
::
Acme
::
Client
::
Resources
::
Registration
.
new
(
self
,
response
)
if
terms_of_service_agreed
payload
[
:termsOfServiceAgreed
]
=
terms_of_service_agreed
end
response
=
post
(
endpoint_for
(
:new_account
),
payload:
payload
,
mode: :jws
)
@kid
=
response
.
headers
.
fetch
(
:location
)
if
response
.
body
.
nil?
||
response
.
body
.
empty?
account
else
arguments
=
attributes_from_account_response
(
response
)
Acme
::
Client
::
Resources
::
Account
.
new
(
self
,
url:
@kid
,
**
arguments
)
end
end
def
authorize
(
domain
:)
payload
=
{
resource:
'new-authz'
,
identifier:
{
type:
'dns'
,
value:
domain
}
}
def
account_update
(
contact:
nil
,
terms_of_service_agreed:
nil
)
payload
=
{}
payload
[
:contact
]
=
Array
(
contact
)
if
contact
payload
[
:termsOfServiceAgreed
]
=
terms_of_service_agreed
if
terms_of_service_agreed
response
=
connection
.
post
(
@operation_endpoints
.
fetch
(
'new-authz'
),
payload
)
::
Acme
::
Client
::
Resources
::
Authorization
.
new
(
self
,
response
.
headers
[
'Location'
],
response
)
response
=
post
(
kid
,
payload:
payload
)
arguments
=
attributes_from_account_response
(
response
)
Acme
::
Client
::
Resources
::
Account
.
new
(
self
,
url:
kid
,
**
arguments
)
end
def
fetch_authorization
(
uri
)
response
=
connection
.
get
(
uri
)
::
Acme
::
Client
::
Resources
::
Authorization
.
new
(
self
,
uri
,
response
)
def
account_deactivate
response
=
post
(
kid
,
payload:
{
status:
'deactivated'
})
arguments
=
attributes_from_account_response
(
response
)
Acme
::
Client
::
Resources
::
Account
.
new
(
self
,
url:
kid
,
**
arguments
)
end
def
new_certificate
(
csr
)
payload
=
{
res
ource:
'new-cert'
,
csr:
Base64
.
urlsafe_encode64
(
csr
.
to_der
)
}
def
account
@kid
||=
begin
res
ponse
=
post
(
endpoint_for
(
:new_account
),
payload:
{
onlyReturnExisting:
true
},
mode: :jwk
)
response
.
headers
.
fetch
(
:location
)
end
response
=
connection
.
post
(
@operation_endpoints
.
fetch
(
'new-cert'
),
payload
)
::
Acme
::
Client
::
Certificate
.
new
(
OpenSSL
::
X509
::
Certificate
.
new
(
response
.
body
),
response
.
headers
[
'location'
],
fetch_chain
(
response
),
csr
)
response
=
post
(
@kid
)
arguments
=
attributes_from_account_response
(
response
)
Acme
::
Client
::
Resources
::
Account
.
new
(
self
,
url:
@kid
,
**
arguments
)
end
def
revoke_certificate
(
certificate
)
payload
=
{
resource:
'revoke-cert'
,
certificate:
Base64
.
urlsafe_encode64
(
certificate
.
to_der
)
}
endpoint
=
@operation_endpoints
.
fetch
(
'revoke-cert'
)
response
=
connection
.
post
(
endpoint
,
payload
)
response
.
success?
def
kid
@kid
||=
account
.
kid
end
def
new_order
(
identifiers
:,
not_before:
nil
,
not_after:
nil
)
payload
=
{}
payload
[
'identifiers'
]
=
if
identifiers
.
is_a?
(
Hash
)
identifiers
else
Array
(
identifiers
).
map
do
|
identifier
|
{
type:
'dns'
,
value:
identifier
}
end
end
payload
[
'notBefore'
]
=
not_before
if
not_before
payload
[
'notAfter'
]
=
not_after
if
not_after
response
=
post
(
endpoint_for
(
:new_order
),
payload:
payload
)
arguments
=
attributes_from_order_response
(
response
)
Acme
::
Client
::
Resources
::
Order
.
new
(
self
,
**
arguments
)
end
def
self
.
revoke_certificate
(
certificate
,
*
arguments
)
client
=
new
(
*
arguments
)
client
.
revoke_certificate
(
certificate
)
def
order
(
url
:)
response
=
get
(
url
)
arguments
=
attributes_from_order_response
(
response
)
Acme
::
Client
::
Resources
::
Order
.
new
(
self
,
**
arguments
.
merge
(
url:
url
))
end
def
connection
@connection
||=
Faraday
.
new
(
@endpoint
,
**
@connection_options
)
do
|
configuration
|
configuration
.
use
Acme
::
Client
::
FaradayMiddleware
,
client:
self
configuration
.
adapter
Faraday
.
default_adapter
def
finalize
(
url
:,
csr
:)
unless
csr
.
respond_to?
(
:to_der
)
raise
ArgumentError
,
'csr must respond to `#to_der`'
end
base64_der_csr
=
Acme
::
Client
::
Util
.
urlsafe_base64
(
csr
.
to_der
)
response
=
post
(
url
,
payload:
{
csr:
base64_der_csr
})
arguments
=
attributes_from_order_response
(
response
)
Acme
::
Client
::
Resources
::
Order
.
new
(
self
,
**
arguments
)
end
def
certificate
(
url
:)
response
=
download
(
url
,
format: :pem
)
response
.
body
end
def
authorization
(
url
:)
response
=
get
(
url
)
arguments
=
attributes_from_authorization_response
(
response
)
Acme
::
Client
::
Resources
::
Authorization
.
new
(
self
,
url:
url
,
**
arguments
)
end
def
deactivate_authorization
(
url
:)
response
=
post
(
url
,
payload:
{
status:
'deactivated'
})
arguments
=
attributes_from_authorization_response
(
response
)
Acme
::
Client
::
Resources
::
Authorization
.
new
(
self
,
url:
url
,
**
arguments
)
end
def
challenge
(
url
:)
response
=
get
(
url
)
arguments
=
attributes_from_challenge_response
(
response
)
Acme
::
Client
::
Resources
::
Challenges
.
new
(
self
,
**
arguments
)
end
def
request_challenge_validation
(
url
:,
key_authorization
:)
response
=
post
(
url
,
payload:
{
keyAuthorization:
key_authorization
})
arguments
=
attributes_from_challenge_response
(
response
)
Acme
::
Client
::
Resources
::
Challenges
.
new
(
self
,
**
arguments
)
end
def
revoke
(
certificate
:,
reason:
nil
)
der_certificate
=
if
certificate
.
respond_to?
(
:to_der
)
certificate
.
to_der
else
OpenSSL
::
X509
::
Certificate
.
new
(
certificate
).
to_der
end
base64_der_certificate
=
Acme
::
Client
::
Util
.
urlsafe_base64
(
der_certificate
)
payload
=
{
certificate:
base64_der_certificate
}
payload
[
:reason
]
=
reason
unless
reason
.
nil?
response
=
post
(
endpoint_for
(
:revoke_certificate
),
payload:
payload
)
response
.
success?
end
def
get_nonce
connection
=
new_connection
(
endpoint:
endpoint_for
(
:new_nonce
))
response
=
connection
.
head
(
nil
,
nil
,
'User-Agent'
=>
USER_AGENT
)
nonces
<<
response
.
headers
[
'replay-nonce'
]
true
end
def
meta
@directory
.
meta
end
def
terms_of_service
@directory
.
terms_of_service
end
def
website
@directory
.
website
end
def
caa_identities
@directory
.
caa_identities
end
def
external_account_required
@directory
.
external_account_required
end
private
def
attributes_from_account_response
(
response
)
extract_attributes
(
response
.
body
,
:status
,
[
:term_of_service
,
'termsOfServiceAgreed'
],
:contact
)
end
def
attributes_from_order_response
(
response
)
attributes
=
extract_attributes
(
response
.
body
,
:status
,
:expires
,
[
:finalize_url
,
'finalize'
],
[
:authorization_urls
,
'authorizations'
],
[
:certificate_url
,
'certificate'
],
:identifiers
)
attributes
[
:url
]
=
response
.
headers
[
:location
]
if
response
.
headers
[
:location
]
attributes
end
def
attributes_from_authorization_response
(
response
)
extract_attributes
(
response
.
body
,
:identifier
,
:status
,
:expires
,
:challenges
,
:wildcard
)
end
def
attributes_from_challenge_response
(
response
)
extract_attributes
(
response
.
body
,
:status
,
:url
,
:token
,
:type
,
:error
)
end
def
extract_attributes
(
input
,
*
attributes
)
attributes
.
map
{
|
fields
|
Array
(
fields
)
}
.
each_with_object
({})
{
|
(
key
,
field
),
hash
|
field
||=
key
.
to_s
hash
[
key
]
=
input
[
field
]
}
end
def
post
(
url
,
payload:
{},
mode: :kid
)
connection
=
connection_for
(
url:
url
,
mode:
mode
)
connection
.
post
(
url
,
payload
)
end
def
get
(
url
,
mode: :kid
)
connection
=
connection_for
(
url:
url
,
mode:
mode
)
connection
.
get
(
url
)
end
def
download
(
url
,
format
:)
connection
=
connection_for
(
url:
url
,
mode: :download
)
connection
.
get
do
|
request
|
request
.
url
(
url
)
request
.
headers
[
'Accept'
]
=
CONTENT_TYPES
.
fetch
(
format
)
end
end
def
connection_for
(
url
:,
mode
:)
uri
=
URI
(
url
)
endpoint
=
"
#{
uri
.
scheme
}
://
#{
uri
.
hostname
}
:
#{
uri
.
port
}
"
@connections
||=
{}
@connections
[
mode
]
||=
{}
@connections
[
mode
][
endpoint
]
||=
new_acme_connection
(
endpoint:
endpoint
,
mode:
mode
)
end
def
new_acme_connection
(
endpoint
:,
mode
:)
new_connection
(
endpoint:
endpoint
)
do
|
configuration
|
configuration
.
use
Acme
::
Client
::
FaradayMiddleware
,
client:
self
,
mode:
mode
end
end
def
new_connection
(
endpoint
:)
Faraday
.
new
(
endpoint
,
**
@connection_options
)
do
|
configuration
|
if
@bad_nonce_retry
>
0
configuration
.
request
(
:retry
,
max:
@bad_nonce_retry
,
methods:
Faraday
::
Connection
::
METHODS
,
exceptions:
[
Acme
::
Client
::
Error
::
BadNonce
])
end
yield
(
configuration
)
if
block_given?
configuration
.
adapter
Faraday
.
default_adapter
end
end
def
fetch_chain
(
response
,
limit
=
10
)
links
=
response
.
headers
[
'link'
]
if
limit
.
zero?
||
links
.
nil?
||
links
[
'up'
].
nil?
[]
else
issuer
=
connection
.
get
(
links
[
'up'
])
issuer
=
get
(
links
[
'up'
])
[
OpenSSL
::
X509
::
Certificate
.
new
(
issuer
.
body
),
*
fetch_chain
(
issuer
,
limit
-
1
)]
end
end
def
load_directory!
@operation_endpoints
=
if
@directory_uri
response
=
connection
.
get
(
@directory_uri
)
body
=
response
.
body
{
'new-reg'
=>
body
.
fetch
(
'new-reg'
),
'new-authz'
=>
body
.
fetch
(
'new-authz'
),
'new-cert'
=>
body
.
fetch
(
'new-cert'
),
'revoke-cert'
=>
body
.
fetch
(
'revoke-cert'
),
}
else
DIRECTORY_DEFAULT
end
def
endpoint_for
(
key
)
@directory
.
endpoint_for
(
key
)
end
end
core/lib/acme/client/certificate.rb
deleted
100644 → 0
View file @
73f14ea5
class
Acme::Client::Certificate
extend
Forwardable
attr_reader
:x509
,
:x509_chain
,
:request
,
:private_key
,
:url
def_delegators
:x509
,
:to_pem
,
:to_der
def
initialize
(
certificate
,
url
,
chain
,
request
)
@x509
=
certificate
@url
=
url
@x509_chain
=
chain
@request
=
request
end
def
chain_to_pem
x509_chain
.
map
(
&
:to_pem
).
join
end
def
x509_fullchain
[
x509
,
*
x509_chain
]
end
def
fullchain_to_pem
x509_fullchain
.
map
(
&
:to_pem
).
join
end
def
common_name
x509
.
subject
.
to_a
.
find
{
|
name
,
_
,
_
|
name
==
'CN'
}[
1
]
end
end
core/lib/acme/client/certificate_request.rb
View file @
24a14e8d
...
...
@@ -104,8 +104,6 @@ class Acme::Client::CertificateRequest
end
def
add_extension
(
csr
)
return
if
@names
.
size
<=
1
extension
=
OpenSSL
::
X509
::
ExtensionFactory
.
new
.
create_extension
(
'subjectAltName'
,
@names
.
map
{
|
name
|
"DNS:
#{
name
}
"
}.
join
(
', '
),
false
)
...
...
core/lib/acme/client/error.rb
View file @
24a14e8d
class
Acme::Client::Error
<
StandardError
class
NotFound
<
Acme
::
Client
::
Error
;
end
class
BadCSR
<
Acme
::
Client
::
Error
;
end
class
BadNonce
<
Acme
::
Client
::
Error
;
end
class
Connection
<
Acme
::
Client
::
Error
;
end
class
Dnssec
<
Acme
::
Client
::
Error
;
end
class
Malformed
<
Acme
::
Client
::
Error
;
end
class
ServerInternal
<
Acme
::
Client
::
Error
;
end
class
Acme::Tls
<
Acme
::
Client
::
Error
;
end
class
Unauthorized
<
Acme
::
Client
::
Error
;
end
class
UnknownHost
<
Acme
::
Client
::
Error
;
end
class
Timeout
<
Acme
::
Client
::
Error
;
end
class
RateLimited
<
Acme
::
Client
::
Error
;
end
class
RejectedIdentifier
<
Acme
::
Client
::
Error
;
end
class
UnsupportedIdentifier
<
Acme
::
Client
::
Error
;
end
class
ClientError
<
Acme
::
Client
::
Error
;
end
class
InvalidDirectory
<
ClientError
;
end
class
UnsupportedOperation
<
ClientError
;
end
class
UnsupportedChallengeType
<
ClientError
;
end
class
NotFound
<
ClientError
;
end
class
CertificateNotReady
<
ClientError
;
end
class
ServerError
<
Acme
::
Client
::
Error
;
end
class
BadCSR
<
ServerError
;
end
class
BadNonce
<
ServerError
;
end
class
BadSignatureAlgorithm
<
ServerError
;
end
class
InvalidContact
<
ServerError
;
end
class
UnsupportedContact
<
ServerError
;
end
class
ExternalAccountRequired
<
ServerError
;
end
class
AccountDoesNotExist
<
ServerError
;
end
class
Malformed
<
ServerError
;
end
class
RateLimited
<
ServerError
;
end
class
RejectedIdentifier
<
ServerError
;
end
class
ServerInternal
<
ServerError
;
end
class
Unauthorized
<
ServerError
;
end
class
UnsupportedIdentifier
<
ServerError
;
end
class
UserActionRequired
<
ServerError
;
end
class
BadRevocationReason
<
ServerError
;
end
class
Caa
<
ServerError
;
end
class
Dns
<
ServerError
;
end
class
Connection
<
ServerError
;
end
class
Tls
<
ServerError
;
end
class
IncorrectResponse
<
ServerError
;
end
ACME_ERRORS
=
{
'urn:ietf:params:acme:error:badCSR'
=>
BadCSR
,
'urn:ietf:params:acme:error:badNonce'
=>
BadNonce
,
'urn:ietf:params:acme:error:badSignatureAlgorithm'
=>
BadSignatureAlgorithm
,
'urn:ietf:params:acme:error:invalidContact'
=>
InvalidContact
,
'urn:ietf:params:acme:error:unsupportedContact'
=>
UnsupportedContact
,
'urn:ietf:params:acme:error:externalAccountRequired'
=>
ExternalAccountRequired
,
'urn:ietf:params:acme:error:accountDoesNotExist'
=>
AccountDoesNotExist
,
'urn:ietf:params:acme:error:malformed'
=>
Malformed
,
'urn:ietf:params:acme:error:rateLimited'
=>
RateLimited
,
'urn:ietf:params:acme:error:rejectedIdentifier'
=>
RejectedIdentifier
,
'urn:ietf:params:acme:error:serverInternal'
=>
ServerInternal
,
'urn:ietf:params:acme:error:unauthorized'
=>
Unauthorized
,
'urn:ietf:params:acme:error:unsupportedIdentifier'
=>
UnsupportedIdentifier
,
'urn:ietf:params:acme:error:userActionRequired'
=>
UserActionRequired
,
'urn:ietf:params:acme:error:badRevocationReason'
=>
BadRevocationReason
,
'urn:ietf:params:acme:error:caa'
=>
Caa
,
'urn:ietf:params:acme:error:dns'
=>
Dns
,
'urn:ietf:params:acme:error:connection'
=>
Connection
,
'urn:ietf:params:acme:error:tls'
=>
Tls
,
'urn:ietf:params:acme:error:incorrectResponse'
=>
IncorrectResponse
}
end
core/lib/acme/client/faraday_middleware.rb
View file @
24a14e8d
...
...
@@ -3,20 +3,25 @@
class
Acme::Client::FaradayMiddleware
<
Faraday
::
Middleware
attr_reader
:env
,
:response
,
:client
repo_url
=
'https://github.com/unixcharles/acme-client'
USER_AGENT
=
"Acme::Client v
#{
Acme
::
Client
::
VERSION
}
(
#{
repo_url
}
)"
.
freeze
CONTENT_TYPE
=
'application/jose+json'
def
initialize
(
app
,
client
:)
def
initialize
(
app
,
client
:
,
mode
:
)
super
(
app
)
@client
=
client
@mode
=
mode
end
def
call
(
env
)
@env
=
env
@env
[
:request_headers
][
'User-Agent'
]
=
USER_AGENT
@env
.
body
=
client
.
jwk
.
jws
(
header:
{
nonce:
pop_nonce
},
payload:
env
.
body
)
@env
[
:request_headers
][
'User-Agent'
]
=
Acme
::
Client
::
USER_AGENT
@env
[
:request_headers
][
'Content-Type'
]
=
CONTENT_TYPE
if
@env
.
method
!=
:get
@env
.
body
=
client
.
jwk
.
jws
(
header:
jws_header
,
payload:
env
.
body
)
end
@app
.
call
(
env
).
on_complete
{
|
response_env
|
on_complete
(
response_env
)
}
rescue
Faraday
::
TimeoutError
rescue
Faraday
::
TimeoutError
,
Faraday
::
ConnectionFailed
raise
Acme
::
Client
::
Error
::
Timeout
end
...
...
@@ -35,6 +40,12 @@ class Acme::Client::FaradayMiddleware < Faraday::Middleware
private
def
jws_header
headers
=
{
nonce:
pop_nonce
,
url:
env
.
url
.
to_s
}
headers
[
:kid
]
=
client
.
kid
if
@mode
==
:kid
headers
end
def
raise_on_not_found!
raise
Acme
::
Client
::
Error
::
NotFound
,
env
.
url
.
to_s
if
env
.
status
==
404
end
...
...
@@ -52,30 +63,19 @@ class Acme::Client::FaradayMiddleware < Faraday::Middleware
end
def
error_class
if
error_name
&&
!
error_name
.
empty?
&&
Acme
::
Client
::
Error
.
const_defined?
(
error_name
)
Object
.
const_get
(
"Acme::Client::Error::
#{
error_name
}
"
)
else
Acme
::
Client
::
Error
end
Acme
::
Client
::
Error
::
ACME_ERRORS
.
fetch
(
error_name
,
Acme
::
Client
::
Error
)
end
def
error_name
@error_name
||=
begin
return
unless
env
.
body
.
is_a?
(
Hash
)
return
unless
env
.
body
.
key?
(
'type'
)
error_type_to_klass
env
.
body
[
'type'
]
end
end
def
error_type_to_klass
(
type
)
type
.
gsub
(
'urn:acme:error:'
,
''
).
split
(
/[_-]/
).
map
{
|
type_part
|
type_part
[
0
].
upcase
+
type_part
[
1
..-
1
]
}.
join
return
unless
env
.
body
.
is_a?
(
Hash
)
return
unless
env
.
body
.
key?
(
'type'
)
env
.
body
[
'type'
]
end
def
decode_body
content_type
=
env
.
response_headers
[
'Content-Type'
]
content_type
=
env
.
response_headers
[
'Content-Type'
]
.
to_s
if
content_type
==
'application/json'
||
content_type
==
'application/problem+json'
if
content_type
.
start_with?
(
'application/json'
,
'application/problem+json'
)
JSON
.
load
(
env
.
body
)
else
env
.
body
...
...
@@ -97,20 +97,20 @@ class Acme::Client::FaradayMiddleware < Faraday::Middleware
end
def
store_nonce
nonces
<<
env
.
response_headers
[
'replay-nonce'
]
nonce
=
env
.
response_headers
[
'replay-nonce'
]
nonces
<<
nonce
if
nonce
end
def
pop_nonce
if
nonces
.
empty?
get_nonce
else
nonces
.
pop
end
nonces
.
pop
end
def
get_nonce
response
=
Faraday
.
head
(
env
.
url
,
nil
,
'User-Agent'
=>
USER_AGENT
)
response
.
headers
[
'replay-nonce'
]
client
.
get_nonce
end
def
nonces
...
...
core/lib/acme/client/jwk/base.rb
View file @
24a14e8d
...
...
@@ -15,7 +15,7 @@ class Acme::Client::JWK::Base
#
# Returns a JSON String.
def
jws
(
header:
{},
payload:
{})
header
=
jws_header
.
merge
(
header
)
header
=
jws_header
(
header
)
encoded_header
=
Acme
::
Client
::
Util
.
urlsafe_base64
(
header
.
to_json
)
encoded_payload
=
Acme
::
Client
::
Util
.
urlsafe_base64
(
payload
.
to_json
)
...
...
@@ -56,12 +56,13 @@ class Acme::Client::JWK::Base
# typ: - Value for the `typ` field. Default 'JWT'.
#
# Returns a Hash.
def
jws_header