2016-08-18 12:20:11 +00:00
|
|
|
package acme
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/json"
|
|
|
|
"io/ioutil"
|
2017-01-12 10:04:11 +00:00
|
|
|
"os"
|
2018-03-26 12:12:03 +00:00
|
|
|
"regexp"
|
2016-12-30 08:21:13 +00:00
|
|
|
|
|
|
|
"github.com/containous/traefik/log"
|
2018-03-05 19:54:04 +00:00
|
|
|
"github.com/containous/traefik/provider/acme"
|
2016-08-18 12:20:11 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// LocalStore is a store using a file as storage
|
|
|
|
type LocalStore struct {
|
2018-03-05 19:54:04 +00:00
|
|
|
file string
|
2016-08-18 12:20:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// NewLocalStore create a LocalStore
|
|
|
|
func NewLocalStore(file string) *LocalStore {
|
|
|
|
return &LocalStore{
|
2016-09-29 13:36:52 +00:00
|
|
|
file: file,
|
2016-08-18 12:20:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-05 19:54:04 +00:00
|
|
|
// Get loads file into store and returns the Account
|
|
|
|
func (s *LocalStore) Get() (*Account, error) {
|
2016-08-18 12:20:11 +00:00
|
|
|
account := &Account{}
|
2017-01-12 10:04:11 +00:00
|
|
|
|
2018-03-05 19:54:04 +00:00
|
|
|
hasData, err := checkFile(s.file)
|
2017-01-12 10:04:11 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2018-03-05 19:54:04 +00:00
|
|
|
|
|
|
|
if hasData {
|
|
|
|
f, err := os.Open(s.file)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
defer f.Close()
|
|
|
|
|
|
|
|
file, err := ioutil.ReadAll(f)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := json.Unmarshal(file, &account); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2018-03-26 12:12:03 +00:00
|
|
|
|
|
|
|
// Check if ACME Account is in ACME V1 format
|
|
|
|
if account != nil && account.Registration != nil {
|
|
|
|
isOldRegistration, err := regexp.MatchString(acme.RegistrationURLPathV1Regexp, account.Registration.URI)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if isOldRegistration {
|
|
|
|
account.Email = ""
|
|
|
|
account.Registration = nil
|
|
|
|
account.PrivateKey = nil
|
|
|
|
}
|
|
|
|
}
|
2016-08-18 12:20:11 +00:00
|
|
|
}
|
2018-03-26 12:12:03 +00:00
|
|
|
|
2016-08-18 12:20:11 +00:00
|
|
|
return account, nil
|
|
|
|
}
|
|
|
|
|
2018-03-05 19:54:04 +00:00
|
|
|
// ConvertToNewFormat converts old acme.json format to the new one and store the result into the file (used for the backward compatibility)
|
|
|
|
func ConvertToNewFormat(fileName string) {
|
|
|
|
localStore := acme.NewLocalStore(fileName)
|
2018-03-26 12:12:03 +00:00
|
|
|
|
2018-03-05 19:54:04 +00:00
|
|
|
storeAccount, err := localStore.GetAccount()
|
|
|
|
if err != nil {
|
|
|
|
log.Warnf("Failed to read new account, ACME data conversion is not available : %v", err)
|
|
|
|
return
|
|
|
|
}
|
2016-08-18 12:20:11 +00:00
|
|
|
|
2018-03-26 12:12:03 +00:00
|
|
|
storeCertificates, err := localStore.GetCertificates()
|
|
|
|
if err != nil {
|
|
|
|
log.Warnf("Failed to read new certificates, ACME data conversion is not available : %v", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2018-03-05 19:54:04 +00:00
|
|
|
if storeAccount == nil {
|
|
|
|
localStore := NewLocalStore(fileName)
|
2016-08-18 12:20:11 +00:00
|
|
|
|
2018-03-05 19:54:04 +00:00
|
|
|
account, err := localStore.Get()
|
|
|
|
if err != nil {
|
|
|
|
log.Warnf("Failed to read old account, ACME data conversion is not available : %v", err)
|
|
|
|
return
|
|
|
|
}
|
2016-08-18 12:20:11 +00:00
|
|
|
|
2018-03-26 12:12:03 +00:00
|
|
|
// Convert ACME data from old to new format
|
|
|
|
newAccount := &acme.Account{}
|
|
|
|
if account != nil && len(account.Email) > 0 {
|
|
|
|
newAccount = &acme.Account{
|
2018-03-05 19:54:04 +00:00
|
|
|
PrivateKey: account.PrivateKey,
|
|
|
|
Registration: account.Registration,
|
|
|
|
Email: account.Email,
|
|
|
|
}
|
|
|
|
|
|
|
|
var newCertificates []*acme.Certificate
|
|
|
|
for _, cert := range account.DomainsCertificate.Certs {
|
|
|
|
newCertificates = append(newCertificates, &acme.Certificate{
|
|
|
|
Certificate: cert.Certificate.Certificate,
|
|
|
|
Key: cert.Certificate.PrivateKey,
|
|
|
|
Domain: cert.Domains,
|
|
|
|
})
|
|
|
|
}
|
2018-03-26 12:12:03 +00:00
|
|
|
// If account is in the old format, storeCertificates is nil or empty
|
|
|
|
// and has to be initialized
|
|
|
|
storeCertificates = newCertificates
|
2018-03-05 19:54:04 +00:00
|
|
|
}
|
2018-03-26 12:12:03 +00:00
|
|
|
|
|
|
|
// Store the data in new format into the file even if account is nil
|
|
|
|
// to delete Account in ACME v1 format and keeping the certificates
|
|
|
|
newLocalStore := acme.NewLocalStore(fileName)
|
|
|
|
newLocalStore.SaveDataChan <- &acme.StoredData{Account: newAccount, Certificates: storeCertificates}
|
2016-08-18 12:20:11 +00:00
|
|
|
}
|
2018-03-05 19:54:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// FromNewToOldFormat converts new acme.json format to the old one (used for the backward compatibility)
|
|
|
|
func FromNewToOldFormat(fileName string) (*Account, error) {
|
|
|
|
localStore := acme.NewLocalStore(fileName)
|
2016-08-18 12:20:11 +00:00
|
|
|
|
2018-03-05 19:54:04 +00:00
|
|
|
storeAccount, err := localStore.GetAccount()
|
2016-08-18 12:20:11 +00:00
|
|
|
if err != nil {
|
2018-03-05 19:54:04 +00:00
|
|
|
return nil, err
|
2016-08-18 12:20:11 +00:00
|
|
|
}
|
2018-03-05 19:54:04 +00:00
|
|
|
|
|
|
|
storeCertificates, err := localStore.GetCertificates()
|
2016-08-18 12:20:11 +00:00
|
|
|
if err != nil {
|
2018-03-05 19:54:04 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2018-03-26 12:12:03 +00:00
|
|
|
// Convert ACME Account from new to old format
|
|
|
|
// (Needed by the KV stores)
|
|
|
|
var account *Account
|
2018-03-05 19:54:04 +00:00
|
|
|
if storeAccount != nil {
|
2018-03-26 12:12:03 +00:00
|
|
|
account = &Account{
|
|
|
|
Email: storeAccount.Email,
|
|
|
|
PrivateKey: storeAccount.PrivateKey,
|
|
|
|
Registration: storeAccount.Registration,
|
|
|
|
DomainsCertificate: DomainsCertificates{},
|
|
|
|
}
|
|
|
|
}
|
2018-03-05 19:54:04 +00:00
|
|
|
|
2018-03-26 12:12:03 +00:00
|
|
|
// Convert ACME Certificates from new to old format
|
|
|
|
// (Needed by the KV stores)
|
|
|
|
if len(storeCertificates) > 0 {
|
|
|
|
// Account can be nil if data are migrated from new format
|
|
|
|
// with a ACME V1 Account
|
|
|
|
if account == nil {
|
|
|
|
account = &Account{}
|
|
|
|
}
|
2018-03-05 19:54:04 +00:00
|
|
|
for _, cert := range storeCertificates {
|
2018-03-26 12:12:03 +00:00
|
|
|
_, err := account.DomainsCertificate.addCertificateForDomains(&Certificate{
|
2018-03-05 19:54:04 +00:00
|
|
|
Domain: cert.Domain.Main,
|
|
|
|
Certificate: cert.Certificate,
|
|
|
|
PrivateKey: cert.Key,
|
|
|
|
}, cert.Domain)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
2016-08-18 12:20:11 +00:00
|
|
|
}
|
2018-03-26 12:12:03 +00:00
|
|
|
|
|
|
|
return account, nil
|
2016-08-18 12:20:11 +00:00
|
|
|
}
|