package acme import ( "io" "io/ioutil" "net" "net/http" "os" "path" "sync" ) const wellKnown = `/.well-known/acme-challenge/` func init() { registerChallenge(ChallengeHTTP) } type httpChallenge struct { Challenge Addr string wg sync.WaitGroup } func (c *httpChallenge) ServeHTTP(w http.ResponseWriter, r *http.Request) { if r.URL.Path == path.Join(wellKnown, c.Token) { io.WriteString(w, c.KeyAuthorization) c.wg.Done() } } func (c *httpChallenge) Solve() error { l, err := net.Listen("tcp", c.Addr) if err != nil { return err } defer l.Close() c.wg.Add(1) go http.Serve(l, c) c.wg.Wait() return nil } func (c *httpChallenge) Abort() error { c.wg.Done() return nil } type webRoot struct { Challenge Webroot string } func (c *webRoot) Solve() error { file := path.Join(c.Webroot, wellKnown, c.Token) if err := os.MkdirAll(path.Dir(file), 0755); err != nil { return err } return ioutil.WriteFile(file, []byte(c.KeyAuthorization), 0644) } func (c *webRoot) Abort() error { file := path.Join(c.Webroot, wellKnown, c.Token) return os.Remove(file) }