aboutsummaryrefslogtreecommitdiff
path: root/provider.go
diff options
context:
space:
mode:
authorDimitri Sokolyuk <demon@dim13.org>2016-01-05 20:33:22 +0100
committerDimitri Sokolyuk <demon@dim13.org>2016-01-05 20:33:22 +0100
commit32a12e8249253abe4e5486a44ddee42f7b8c991d (patch)
tree95456feea842033f84612ca7134f6d870552a489 /provider.go
parent6acc0d0b818ec6a660926f0856d52ccabc58239b (diff)
Refactor
Diffstat (limited to 'provider.go')
-rw-r--r--provider.go209
1 files changed, 106 insertions, 103 deletions
diff --git a/provider.go b/provider.go
index 040f713..0c896e7 100644
--- a/provider.go
+++ b/provider.go
@@ -8,12 +8,8 @@ import (
"io/ioutil"
"log"
"net/http"
- "net/url"
"regexp"
- "strconv"
"time"
-
- "github.com/mgutz/ansi"
)
// Provider ...
@@ -39,16 +35,15 @@ func (p Provider) Nonce() (string, error) {
}
}
-func (p Provider) nonce(r *http.Response) {
- if rn := r.Header.Get("Replay-Nonce"); rn != "" {
- p.nonces <- rn
- }
-}
-
// NewProvider fetches directory and initializes nonce
func NewProvider(directory string) (*Provider, error) {
p := &Provider{nonces: make(chan string, 10)}
- if _, err := p.get(directory, &p.Directory); err != nil {
+ resp, err := http.Get(directory)
+ if err != nil {
+ return nil, err
+ }
+ _, err = p.parse(resp, &p.Directory)
+ if err != nil {
return nil, err
}
return p, nil
@@ -73,47 +68,66 @@ func NewProvider(directory string) (*Provider, error) {
// request is used for
// new-reg, new-authz, challenge, new-cert
+
func (p *Provider) post(uri string, s Signer, v interface{}) (*http.Response, error) {
- body, err := json.Marshal(v)
+ signed, err := s.Sign(v, p)
if err != nil {
return nil, err
}
- log.Println(ansi.Color("POST", "red+b"), uri, string(body))
+ return http.Post(uri, "application/json", signed)
+}
- signed, err := s.Sign(body, p)
- if err != nil {
- return nil, err
+type nextStep struct {
+ Link map[string]string
+ Location string
+}
+
+var linksRe = regexp.MustCompile(`^<(.*)>;rel="(.*)"`)
+
+func (p *Provider) parse(resp *http.Response, v interface{}) (ns nextStep, err error) {
+ if lo, _ := resp.Location(); lo != nil {
+ log.Println(lo)
+ ns.Location = lo.String()
+ }
+
+ ns.Link = make(map[string]string)
+ for _, li := range resp.Header["Link"] {
+ re := linksRe.FindStringSubmatch(li)
+ if len(re) == 3 {
+ ns.Link[re[2]] = re[1]
+ }
+ }
+
+ if rn := resp.Header.Get("Replay-Nonce"); rn != "" {
+ p.nonces <- rn
}
- resp, err := http.Post(uri, "application/json", signed)
+ body, err := ioutil.ReadAll(resp.Body)
if err != nil {
- return nil, err
+ return ns, err
}
- p.nonce(resp)
- log.Println(ansi.Color("STATUS", "yellow"), resp.Status)
+ defer resp.Body.Close()
+
+ log.Println(string(body))
switch resp.Header.Get("Content-Type") {
case "application/problem+json":
- defer resp.Body.Close()
- return resp, problem(resp)
+ var p Problem
+ if err := json.Unmarshal(body, &p); err != nil {
+ return ns, err
+ }
+ if err, ok := urnErrors[p.Type]; ok {
+ p.Err = err
+ }
+ err = p
case "application/json":
- defer resp.Body.Close()
- return resp, json.NewDecoder(resp.Body).Decode(v)
+ err = json.Unmarshal(body, v)
case "application/pkix-cert":
- return resp, nil
+ v, err = x509.ParseCertificate(body)
default:
- return resp, errContentType
+ err = errContentType
}
-}
-
-func (p *Provider) get(uri string, v interface{}) (*http.Response, error) {
- resp, err := http.Get(uri)
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
- p.nonce(resp)
- return resp, json.NewDecoder(resp.Body).Decode(v)
+ return ns, err
}
func problem(resp *http.Response) error {
@@ -127,40 +141,6 @@ func problem(resp *http.Response) error {
return p
}
-type nextStep struct {
- Link map[string]string
- Location *url.URL
- RetryAfter time.Duration
-}
-
-var linksRe = regexp.MustCompile(`^<(.*)>;rel="(.*)"`)
-
-func parseHeader(r *http.Response) nextStep {
- var ns nextStep
-
- if lo, err := r.Location(); err == nil {
- ns.Location = lo
- }
-
- ns.Link = make(map[string]string)
- for _, li := range r.Header["Link"] {
- re := linksRe.FindStringSubmatch(li)
- if len(re) == 3 {
- ns.Link[re[2]] = re[1]
- }
- }
-
- if ra := r.Header.Get("Retry-After"); ra != "" {
- n, err := strconv.Atoi(ra)
- if err == nil {
- ns.RetryAfter = time.Second * time.Duration(n)
- }
- }
-
- log.Println(ansi.Color("NEXT", "cyan"), ns)
- return ns
-}
-
/*
directory
.
@@ -185,31 +165,34 @@ func (p *Provider) Register(s Signer, c Contacts) error {
Resource: ResNewReg,
Contact: c,
}
+
resp, err := p.post(p.NewReg, s, r)
+ if err != nil {
+ return err
+ }
+
+ ns, err := p.parse(resp, r)
+
if err != nil && err.(Problem).Err != ErrMalformed {
return err
}
- ns := parseHeader(resp)
- switch resp.StatusCode {
- case http.StatusConflict:
- // Query Location
- r = &Registration{Resource: ResReg}
- resp, err = p.post(ns.Location.String(), s, r)
- if err != nil {
- return err
- }
- fallthrough
- case http.StatusCreated:
- // Agree to TOS
- if tos := ns.Link["terms-of-service"]; tos != "" {
- r = &Registration{
- Resource: ResReg,
- Contact: c,
- Agreement: tos,
- }
- _, err = p.post(ns.Location.String(), s, r)
- }
+
+ r = &Registration{
+ Resource: ResReg,
+ Contact: c,
+ }
+
+ if tos := ns.Link["terms-of-service"]; tos != "" {
+ r.Agreement = tos
+ }
+
+ resp, err = p.post(ns.Location, s, r)
+ if err != nil {
+ return err
}
+
+ _, err = p.parse(resp, r)
+
return err
}
@@ -227,10 +210,16 @@ func (p *Provider) Authorize(s ThumbSigner, domain string) error {
Resource: ResNewAuthz,
Identifier: NewIdent(domain),
}
+
resp, err := p.post(p.NewAuthz, s, r)
if err != nil {
return err
}
+ _, err = p.parse(resp, r)
+ if err != nil {
+ return err
+ }
+
switch resp.StatusCode {
case http.StatusCreated:
n, ch := pickChallenge(r.Challenges)
@@ -244,7 +233,16 @@ func (p *Provider) Authorize(s ThumbSigner, domain string) error {
Type: ch.Type,
KeyAuthorization: ka,
}
- _, err = p.post(ch.URI, s, ans)
+
+ resp, err = p.post(ch.URI, s, ans)
+ if err != nil {
+ return err
+ }
+
+ ns, err := p.parse(resp, ans)
+ if err != nil {
+ return err
+ }
var sol Solver
@@ -259,15 +257,14 @@ func (p *Provider) Authorize(s ThumbSigner, domain string) error {
return err
}
- ns := parseHeader(resp)
done := make(chan bool)
errc := make(chan error)
- log.Println(ansi.Color("NEXT", "green"), ns)
+
ticker := time.NewTicker(time.Second)
defer ticker.Stop()
go func() {
for range ticker.C {
- err := p.queryStatus(ns.Location.String(), n, done)
+ err := p.queryStatus(ns.Location, done)
if err != nil {
errc <- err
return
@@ -285,12 +282,17 @@ func (p *Provider) Authorize(s ThumbSigner, domain string) error {
return err
}
-func (p *Provider) queryStatus(url string, n int, done chan bool) error {
- r := &Authorization{}
- if _, err := p.get(url, r); err != nil {
+func (p *Provider) queryStatus(url string, done chan bool) error {
+ r := &Challenge{}
+ resp, err := http.Get(url)
+ if err != nil {
return err
}
- if r.Challenges[n].Status == StatusValid {
+ _, err = p.parse(resp, r)
+ if err != nil {
+ return err
+ }
+ if r.Status == StatusValid {
done <- true
}
return nil
@@ -305,16 +307,17 @@ func (p *Provider) Cert(s Signer, altnames []string, key *rsa.PrivateKey) (*x509
Resource: ResNewCert,
CSR: csr,
}
+
resp, err := p.post(p.NewCert, s, r)
if err != nil {
return nil, err
}
- defer resp.Body.Close()
- ns := parseHeader(resp)
- log.Println(ansi.Color("NEXT", "green"), ns)
- der, err := ioutil.ReadAll(resp.Body)
+
+ crt := new(x509.Certificate)
+ _, err = p.parse(resp, crt)
if err != nil {
return nil, err
}
- return x509.ParseCertificate(der)
+
+ return crt, nil
}