From 32a12e8249253abe4e5486a44ddee42f7b8c991d Mon Sep 17 00:00:00 2001 From: Dimitri Sokolyuk Date: Tue, 5 Jan 2016 20:33:22 +0100 Subject: Refactor --- provider.go | 209 ++++++++++++++++++++++++++++++------------------------------ 1 file changed, 106 insertions(+), 103 deletions(-) (limited to 'provider.go') 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 } -- cgit v1.2.3