/
config.go
122 lines (106 loc) · 3.53 KB
/
config.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
// util loads a Configuration from a configuration file called 'config.yml'
// in a specified directory. The intended usage is for the user to setup a
// 'development' directory and a 'production' directory containing necessary
// configuration info.
//
// The configuration uses the YAML format.
//
// This code follows the singleton pattern, so that there is one Config
// variable that is used globally. The sync.Once library ensures that the
// variable is configured only once. We follow the pattern shown here:
// https://golangbyexample.com/singleton-design-pattern-go/
package util
import (
"crypto/rsa"
"crypto/x509"
"errors"
"fmt"
"os"
"sync"
"github.com/Usable-Security-and-Privacy-Lab/lets-auth-ca/errorHandler"
"gopkg.in/yaml.v2"
)
var once sync.Once
var cfg *Config
// A Config is a singleton which reads in and stores the configuration file(s)
// needed to run the CA
type Config struct {
Name string `yaml:"name"` // name of the configuration, such as 'development' or 'production'
Host string `yaml:"host"`
Port int `yaml:"port"`
Base string `yaml:"-"`
DbConfig string `yaml:"database config"`
RPDisplayName string `yaml:"RP display name"`
RPID string `yaml:"RP ID"`
RPOrigin string `yaml:"RP origin"`
PublicKeyFile string `yaml:"public key"` // public key file path
PrivateKeyFile string `yaml:"private key"` // private key file path
RootCertificateFile string `yaml:"root certificate"` // location of the root certificate
PublicKey *rsa.PublicKey `yaml:"-"` // public key
PrivateKey *rsa.PrivateKey `yaml:"-"` // private key
RootCertificate *x509.Certificate `yaml:"-"` // root certificate
}
// ConfigInit is called early into the runtime of a program. This function
// initializes the config singleton and reads in all of the referenced files.
// After this function returns, Get() may be called to retrieve a copy of a
// pointer to the singleton.
func ConfigInit(configDir string) {
base := configDir + "/"
fileName := base + "config.yml"
once.Do(
func() {
f, err := os.Open(fileName)
if err != nil {
errorHandler.Fatal(err)
}
defer f.Close()
decoder := yaml.NewDecoder(f)
err = decoder.Decode(&cfg)
if err != nil {
errorHandler.Fatal(err)
}
// set base
cfg.Base = base
// Read/parse root certificate
rootData, err := os.ReadFile(cfg.Base + cfg.RootCertificateFile)
if err != nil {
// we might not have one yet!
// TBD: switch to logger, produce warning
} else {
cfg.RootCertificate, err = UnpackCertFromBytes(rootData)
if err != nil {
errorHandler.Fatal(err)
}
}
fmt.Println("parsed root certificate")
// Read/parse public key
pubKeyData, err := os.ReadFile(cfg.Base + cfg.PublicKeyFile)
if err != nil {
errorHandler.Fatal(err)
}
fmt.Println("unpacking...")
cfg.PublicKey, err = UnpackPublicKeyFromBytes(pubKeyData)
if err != nil {
errorHandler.Fatal(err)
}
fmt.Println("unpacked!")
// Read/parse public key
privKeyData, err := os.ReadFile(cfg.Base + cfg.PrivateKeyFile)
if err != nil {
errorHandler.Fatal(err)
}
cfg.PrivateKey, err = UnpackPrivateKeyFromBytes(privKeyData)
if err != nil {
errorHandler.Fatal(err)
}
fmt.Println("got here")
})
}
// Get returns a pointer to the singleton of the Config object. If Init() has
// not been called or returned an error, this function will return nil.
func GetConfig() *Config {
if cfg == nil {
errorHandler.Fatal(errors.New("Config singleton not initialized"))
}
return cfg
}