package acme import ( "fmt" "net" "time" "github.com/square/go-jose" ) const ( // LEV1 Let's Encrytpt V1 LEV1 = `https://acme-v01.api.letsencrypt.org/directory` // LES Let's Encrypt Staging LES = `https://acme-staging.api.letsencrypt.org/directory` ) // Directory ... type Directory struct { NewReg string `json:"new-reg"` RecoverReg string `json:"recover-reg"` NewAuthz string `json:"new-authz"` NewCert string `json:"new-cert"` RevokeCert string `json:"revoke-cert"` } // Registration Objects type Registration struct { Resource Resource `json:"resource"` // new-reg Contact Contacts `json:"contact,omitempty"` Agreement string `json:"agreement,omitempty"` Authorizations string `json:"authorizations,omitempty"` Certificates string `json:"certificates,omitempty"` ID int `json:"id,omitempty"` Key *jose.JsonWebKey `json:"key,omitempty"` InitialIP *net.IP `json:"initialIp,omitempty"` // not in draft CreatedAt *time.Time `json:"createdAt,omitempty"` } // Authorization request type Authorization struct { Resource Resource `json:"resource"` // new-authz Identifier Identifier `json:"identifier"` Status Status `json:"status,omitempty"` // e.g. valid Expires *time.Time `json:"expires,omitempty"` Challenges []Challenge `json:"challenges,omitempty"` Combinations [][]int `json:"combinations,omitempty"` } // Identifier ... type Identifier struct { Type IdentType `json:"type"` // dns Value string `json:"value"` // example.com } // Challege ... type Challenge struct { Resource Resource `json:"resource"` // challenge Type ChallengeType `json:"type"` Token string `json:"token,omitempty"` Status Status `json:"status,omitempty"` // e.g. valid URI string `json:"uri,omitempty"` Validated *time.Time `json:"validated,omitempty"` KeyAuthorization string `json:"keyAuthorization,omitempty"` Err *Problem `json:"error,omitempty"` Solver `json:"-"` } // Problem description type Problem struct { Type string `json:"type"` Detail string `json:"detail"` Instance string `json:"instance"` Err error `json:"-"` } func (p Problem) Error() string { return p.Detail } // Status of request type Status int // Statuses const ( StatusUnknown Status = iota + 1 StatusPending StatusProcessing StatusValid StatusInvalid StatusRevoked ) var status = map[Status]string{ StatusUnknown: "unknown", StatusPending: "pending", StatusProcessing: "processing", StatusValid: "valid", StatusInvalid: "invalid", StatusRevoked: "revoked", } // UnmarshalText implemets json interface for status decoding func (s *Status) UnmarshalText(b []byte) error { for k, v := range status { if v == string(b) { *s = k return nil } } return fmt.Errorf("unknown status %v", string(b)) } func (s Status) String() string { return status[s] } type Resource int const ( ResNewReg Resource = iota + 1 ResRecoverReg ResNewAuthz ResNewCert ResRevokeCert ResReg ResAuthz ResChallenge ResCert ) var resources = map[Resource]string{ ResNewReg: "new-reg", ResRecoverReg: "recover-reg", ResNewAuthz: "new-authz", ResNewCert: "new-cert", ResRevokeCert: "revoke-cert", ResReg: "reg", ResAuthz: "authz", ResChallenge: "challenge", ResCert: "cert", } func (r Resource) String() string { return resources[r] } // MarshalText implements text encoding marshaller func (r Resource) MarshalText() ([]byte, error) { return []byte(r.String()), nil } type IdentType int const IdentDNS IdentType = iota + 1 var identTypes = map[IdentType]string{ IdentDNS: "dns", } func (i IdentType) String() string { return identTypes[i] } func (i IdentType) MarshalText() ([]byte, error) { return []byte(i.String()), nil } func (i *IdentType) UnmarshalText(b []byte) error { for k, v := range identTypes { if v == string(b) { *i = k return nil } } return fmt.Errorf("unknown type %v", string(b)) } type ChallengeType int const ( ChallengeHTTP ChallengeType = iota + 1 ChallengeTLS ChallengePOP ChallengeDNS ) var challenges = map[ChallengeType]string{ ChallengeHTTP: "http-01", ChallengeTLS: "tls-sni-01", ChallengePOP: "proofOfPossession-01", ChallengeDNS: "dns-01", } func (c ChallengeType) String() string { return challenges[c] } func (c ChallengeType) MarshalText() ([]byte, error) { return []byte(c.String()), nil } func (c *ChallengeType) UnmarshalText(b []byte) error { for k, v := range challenges { if v == string(b) { *c = k return nil } } return fmt.Errorf("unknown challenge %v", string(b)) } type CSR struct { Resource Resource `json:"resource"` // new-cert CSR string `json:"csr"` }