main.go 5.31 KB
Newer Older
1
2
3
package main

import (
4
	"encoding/json"
Sietse Ringers's avatar
Sietse Ringers committed
5
	"io/ioutil"
6
7
	"os"

8
	"github.com/Sirupsen/logrus"
9
	"github.com/go-errors/errors"
Sietse Ringers's avatar
Sietse Ringers committed
10
11
	"github.com/privacybydesign/irmago/server"
	"github.com/privacybydesign/irmago/server/irmaserver"
12
13
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
14
15
)

Sietse Ringers's avatar
Sietse Ringers committed
16
var logger = logrus.StandardLogger()
17
18
var conf *irmaserver.Configuration

19
func main() {
20
21
22
23
24
25
26
27
28
29
30
31
	var cmd = &cobra.Command{
		Use:   "irmaserver",
		Short: "IRMA server for verifying and issuing attributes",
		Run: func(command *cobra.Command, args []string) {
			if err := configure(); err != nil {
				die(errors.WrapPrefix(err, "Failed to configure server", 0))
			}
			if err := irmaserver.Start(conf); err != nil {
				die(errors.WrapPrefix(err, "Failed to start server", 0))
			}
		},
	}
32

Sietse Ringers's avatar
Sietse Ringers committed
33
34
35
36
37
	logger.Level = logrus.InfoLevel
	logger.SetFormatter(&logrus.TextFormatter{
		FullTimestamp: true,
	})

38
39
	if err := setFlags(cmd); err != nil {
		die(errors.WrapPrefix(err, "Failed to attach flags", 0))
40
41
	}

42
43
	if err := cmd.Execute(); err != nil {
		die(errors.WrapPrefix(err, "Failed to execute command", 0))
44
	}
45
46
47
}

func die(err *errors.Error) {
Sietse Ringers's avatar
Sietse Ringers committed
48
	logger.Error(err.Error())
Sietse Ringers's avatar
Sietse Ringers committed
49
	logger.Trace(string(err.Stack()))
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
	os.Exit(1)
}

func setFlags(cmd *cobra.Command) error {
	flags := cmd.Flags()
	flags.SortFlags = false

	flags.StringP("irmaconf", "i", "./irma_configuration", "path to irma_configuration")
	flags.StringP("privatekeys", "k", "", "path to IRMA private keys")
	flags.StringP("jwtissuer", "j", "irmaserver", "JWT issuer")
	flags.StringP("jwtprivatekey", "w", "", "JWT private key or path to it")
	flags.IntP("port", "p", 8088, "Port at which to listen")
	flags.Bool("noauth", false, "Whether or not to authenticate requestors")
	flags.String("requestors", "", "Requestor configuration (in JSON)")

65
66
67
68
69
70
71
	flags.StringSlice("disclosing", nil, "Comma-separated list of attributes that all requestors may verify")
	flags.StringSlice("signing", nil, "Comma-separated list of attributes that all requestors may request in signatures")
	flags.StringSlice("issuing", nil, "Comma-separated list of attributes that all requestors may issue")
	flags.Lookup("disclosing").NoOptDefVal = "*"
	flags.Lookup("signing").NoOptDefVal = "*"
	flags.Lookup("issuing").NoOptDefVal = "*"

Sietse Ringers's avatar
Sietse Ringers committed
72
73
74
	flags.BoolP("verbose", "v", false, "verbose")
	flags.Bool("vverbose", false, "more verbose")
	flags.BoolP("quiet", "q", false, "quiet")
75
76
77
78

	// Environment variables
	viper.SetEnvPrefix("IRMASERVER")
	viper.AutomaticEnv()
79

80
	// Configuration file
81
	viper.SetConfigName("irmaserver")
82
83
84
	viper.AddConfigPath(".")
	viper.AddConfigPath("/etc/irmaserver/")
	viper.AddConfigPath("$HOME/.irmaserver")
Sietse Ringers's avatar
Sietse Ringers committed
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102

	return viper.BindPFlags(flags)
}

func configure() error {
	err := viper.ReadInConfig() // Hold error checking until we know how much of it to log
	if viper.GetBool("verbose") {
		logger.Level = logrus.DebugLevel
	}
	if viper.GetBool("vverbose") {
		logger.Level = logrus.TraceLevel
	}
	if viper.GetBool("quiet") {
		logger.Out = ioutil.Discard
	}

	logger.Debugf("Configuring")
	if err != nil {
103
104
105
106
107
		if _, notfound := err.(viper.ConfigFileNotFoundError); notfound {
			logger.Info("No configuration file found")
		} else {
			die(errors.WrapPrefix(err, "Failed to unmarshal configuration file at "+viper.ConfigFileUsed(), 0))
		}
108
	} else {
Sietse Ringers's avatar
Sietse Ringers committed
109
		logger.Info("Config file: ", viper.ConfigFileUsed())
110
111
112
113
	}

	// Read configuration from flags and/or environmental variables
	conf = &irmaserver.Configuration{
Sietse Ringers's avatar
Sietse Ringers committed
114
		Configuration: &server.Configuration{
115
116
			IrmaConfigurationPath: viper.GetString("irmaconf"),
			IssuerPrivateKeysPath: viper.GetString("privatekeys"),
Sietse Ringers's avatar
Sietse Ringers committed
117
			Logger:                logger,
118
		},
119
120
121
122
123
124
		Port: viper.GetInt("port"),
		DisableRequestorAuthentication: viper.GetBool("noauth"),
		Requestors:                     make(map[string]irmaserver.Requestor),
		GlobalPermissions:              irmaserver.Permissions{},
		JwtIssuer:                      viper.GetString("jwtissuer"),
		JwtPrivateKey:                  viper.GetString("jwtprivatekey"),
Sietse Ringers's avatar
Sietse Ringers committed
125
126
		Verbose:                        viper.GetBool("verbose"),
		VVerbose:                       viper.GetBool("vverbose"),
127
128
	}

129
130
	// Handle global permissions
	if len(viper.GetStringMap("permissions")) > 0 { // First read config file
131
		if err := viper.UnmarshalKey("permissions", &conf.GlobalPermissions); err != nil {
Sietse Ringers's avatar
Sietse Ringers committed
132
			return errors.WrapPrefix(err, "Failed to unmarshal permissions from config file", 0)
133
134
		}
	}
135
136
137
138
139
140
141
	handlePermission(&conf.GlobalPermissions.Disclosing, "disclosing") // Read flag or env var
	handlePermission(&conf.GlobalPermissions.Signing, "signing")
	handlePermission(&conf.GlobalPermissions.Issuing, "issuing")

	// Handle requestors
	if len(viper.GetStringMap("requestors")) > 0 { // First read config file
		if err := viper.UnmarshalKey("requestors", &conf.Requestors); err != nil {
Sietse Ringers's avatar
Sietse Ringers committed
142
			return errors.WrapPrefix(err, "Failed to unmarshal requestors from config file", 0)
143
144
145
		}
	}
	requestors := viper.GetString("requestors") // Read flag or env var
146
147
	if len(requestors) > 0 {
		if err := json.Unmarshal([]byte(requestors), &conf.Requestors); err != nil {
Sietse Ringers's avatar
Sietse Ringers committed
148
			return errors.WrapPrefix(err, "Failed to unmarshal requestors from json", 0)
149
150
151
152
		}
	}

	bts, _ := json.MarshalIndent(conf, "", "   ")
Sietse Ringers's avatar
Sietse Ringers committed
153
154
	logger.Debug(string(bts), "\n")
	logger.Debug("Done configuring")
155
156

	return nil
157
}
158
159
160
161
162
163
164
165
166
167

func handlePermission(conf *[]string, typ string) {
	if viper.GetString(typ) == "*" {
		*conf = []string{"*"}
	}
	perms := viper.GetStringSlice(typ)
	if len(perms) > 0 {
		*conf = perms
	}
}