diff options
Diffstat (limited to 'vendor/github.com/xenolf/lego/acme/jws.go')
-rw-r--r-- | vendor/github.com/xenolf/lego/acme/jws.go | 93 |
1 files changed, 59 insertions, 34 deletions
diff --git a/vendor/github.com/xenolf/lego/acme/jws.go b/vendor/github.com/xenolf/lego/acme/jws.go index 2a1fc244d..1b4d29d53 100644 --- a/vendor/github.com/xenolf/lego/acme/jws.go +++ b/vendor/github.com/xenolf/lego/acme/jws.go @@ -16,8 +16,7 @@ import ( type jws struct { directoryURL string privKey crypto.PrivateKey - nonces []string - sync.Mutex + nonces nonceManager } func keyAsJWK(key interface{}) *jose.JsonWebKey { @@ -38,19 +37,31 @@ func keyAsJWK(key interface{}) *jose.JsonWebKey { func (j *jws) post(url string, content []byte) (*http.Response, error) { signedContent, err := j.signContent(content) if err != nil { - return nil, err + return nil, fmt.Errorf("Failed to sign content -> %s", err.Error()) } resp, err := httpPost(url, "application/jose+json", bytes.NewBuffer([]byte(signedContent.FullSerialize()))) - if err != nil { - return nil, err + + // Even in case of an error, the response should still contain a nonce. + nonce, nonceErr := getNonceFromResponse(resp) + if nonceErr == nil { + j.nonces.Push(nonce) } - j.Lock() - defer j.Unlock() - j.getNonceFromResponse(resp) + if err != nil { + switch err.(type) { + case NonceError: + // In case of a nonce error - retry once + resp, err = httpPost(url, "application/jose+json", bytes.NewBuffer([]byte(signedContent.FullSerialize()))) + if err != nil { + return nil, fmt.Errorf("Failed to HTTP POST to %s -> %s", url, err.Error()) + } + default: + return nil, fmt.Errorf("Failed to HTTP POST to %s -> %s", url, err.Error()) + } + } - return resp, err + return resp, nil } func (j *jws) signContent(content []byte) (*jose.JsonWebSignature, error) { @@ -69,49 +80,63 @@ func (j *jws) signContent(content []byte) (*jose.JsonWebSignature, error) { signer, err := jose.NewSigner(alg, j.privKey) if err != nil { - return nil, err + return nil, fmt.Errorf("Failed to create jose signer -> %s", err.Error()) } signer.SetNonceSource(j) signed, err := signer.Sign(content) if err != nil { - return nil, err + return nil, fmt.Errorf("Failed to sign content -> %s", err.Error()) } return signed, nil } -func (j *jws) getNonceFromResponse(resp *http.Response) error { - nonce := resp.Header.Get("Replay-Nonce") - if nonce == "" { - return fmt.Errorf("Server did not respond with a proper nonce header.") +func (j *jws) Nonce() (string, error) { + if nonce, ok := j.nonces.Pop(); ok { + return nonce, nil } - j.nonces = append(j.nonces, nonce) - return nil + return getNonce(j.directoryURL) } -func (j *jws) getNonce() error { - resp, err := httpHead(j.directoryURL) - if err != nil { - return err +type nonceManager struct { + nonces []string + sync.Mutex +} + +func (n *nonceManager) Pop() (string, bool) { + n.Lock() + defer n.Unlock() + + if len(n.nonces) == 0 { + return "", false } - return j.getNonceFromResponse(resp) + nonce := n.nonces[len(n.nonces)-1] + n.nonces = n.nonces[:len(n.nonces)-1] + return nonce, true } -func (j *jws) Nonce() (string, error) { - j.Lock() - defer j.Unlock() - nonce := "" - if len(j.nonces) == 0 { - err := j.getNonce() - if err != nil { - return nonce, err - } +func (n *nonceManager) Push(nonce string) { + n.Lock() + defer n.Unlock() + n.nonces = append(n.nonces, nonce) +} + +func getNonce(url string) (string, error) { + resp, err := httpHead(url) + if err != nil { + return "", fmt.Errorf("Failed to get nonce from HTTP HEAD -> %s", err.Error()) } - if len(j.nonces) == 0 { - return "", fmt.Errorf("Can't get nonce") + + return getNonceFromResponse(resp) +} + +func getNonceFromResponse(resp *http.Response) (string, error) { + nonce := resp.Header.Get("Replay-Nonce") + if nonce == "" { + return "", fmt.Errorf("Server did not respond with a proper nonce header.") } - nonce, j.nonces = j.nonces[len(j.nonces)-1], j.nonces[:len(j.nonces)-1] + return nonce, nil } |