forked from go-acme/lego
-
Notifications
You must be signed in to change notification settings - Fork 0
/
account.go
134 lines (109 loc) · 3.41 KB
/
account.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
package main
import (
"crypto"
"encoding/json"
"io/ioutil"
"os"
"path"
"github.com/xenolf/lego/acme"
"github.com/xenolf/lego/log"
)
// Account represents a users local saved credentials
type Account struct {
Email string `json:"email"`
key crypto.PrivateKey
Registration *acme.RegistrationResource `json:"registration"`
conf *Configuration
}
// NewAccount creates a new account for an email address
func NewAccount(email string, conf *Configuration) *Account {
accKeysPath := conf.AccountKeysPath(email)
// TODO: move to function in configuration?
accKeyPath := accKeysPath + string(os.PathSeparator) + email + ".key"
if err := checkFolder(accKeysPath); err != nil {
log.Fatalf("Could not check/create directory for account %s: %v", email, err)
}
var privKey crypto.PrivateKey
if _, err := os.Stat(accKeyPath); os.IsNotExist(err) {
log.Printf("No key found for account %s. Generating a curve P384 EC key.", email)
privKey, err = generatePrivateKey(accKeyPath)
if err != nil {
log.Fatalf("Could not generate RSA private account key for account %s: %v", email, err)
}
log.Printf("Saved key to %s", accKeyPath)
} else {
privKey, err = loadPrivateKey(accKeyPath)
if err != nil {
log.Fatalf("Could not load RSA private key from file %s: %v", accKeyPath, err)
}
}
accountFile := path.Join(conf.AccountPath(email), "account.json")
if _, err := os.Stat(accountFile); os.IsNotExist(err) {
return &Account{Email: email, key: privKey, conf: conf}
}
fileBytes, err := ioutil.ReadFile(accountFile)
if err != nil {
log.Fatalf("Could not load file for account %s -> %v", email, err)
}
var acc Account
err = json.Unmarshal(fileBytes, &acc)
if err != nil {
log.Fatalf("Could not parse file for account %s -> %v", email, err)
}
acc.key = privKey
acc.conf = conf
if acc.Registration == nil || acc.Registration.Body.Status == "" {
reg, err := tryRecoverAccount(privKey, conf)
if err != nil {
log.Fatalf("Could not load account for %s. Registration is nil -> %#v", email, err)
}
acc.Registration = reg
err = acc.Save()
if err != nil {
log.Fatalf("Could not save account for %s. Registration is nil -> %#v", email, err)
}
}
if acc.conf == nil {
log.Fatalf("Could not load account for %s. Configuration is nil.", email)
}
return &acc
}
func tryRecoverAccount(privKey crypto.PrivateKey, conf *Configuration) (*acme.RegistrationResource, error) {
// couldn't load account but got a key. Try to look the account up.
serverURL := conf.context.GlobalString("server")
client, err := acme.NewClient(serverURL, &Account{key: privKey, conf: conf}, acme.RSA2048)
if err != nil {
return nil, err
}
reg, err := client.ResolveAccountByKey()
if err != nil {
return nil, err
}
return reg, nil
}
/** Implementation of the acme.User interface **/
// GetEmail returns the email address for the account
func (a *Account) GetEmail() string {
return a.Email
}
// GetPrivateKey returns the private RSA account key.
func (a *Account) GetPrivateKey() crypto.PrivateKey {
return a.key
}
// GetRegistration returns the server registration
func (a *Account) GetRegistration() *acme.RegistrationResource {
return a.Registration
}
/** End **/
// Save the account to disk
func (a *Account) Save() error {
jsonBytes, err := json.MarshalIndent(a, "", "\t")
if err != nil {
return err
}
return ioutil.WriteFile(
path.Join(a.conf.AccountPath(a.Email), "account.json"),
jsonBytes,
0600,
)
}