main.go 5.12 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
81
82
83
84
	// Configuration file
	viper.SetConfigName("config")
	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 {
Sietse Ringers's avatar
Sietse Ringers committed
103
		logger.Info("No configuration file found")
104
	} else {
Sietse Ringers's avatar
Sietse Ringers committed
105
		logger.Info("Config file: ", viper.ConfigFileUsed())
106
107
108
109
	}

	// Read configuration from flags and/or environmental variables
	conf = &irmaserver.Configuration{
Sietse Ringers's avatar
Sietse Ringers committed
110
		Configuration: &server.Configuration{
111
112
			IrmaConfigurationPath: viper.GetString("irmaconf"),
			IssuerPrivateKeysPath: viper.GetString("privatekeys"),
Sietse Ringers's avatar
Sietse Ringers committed
113
			Logger:                logger,
114
		},
115
116
117
118
119
120
		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
121
122
		Verbose:                        viper.GetBool("verbose"),
		VVerbose:                       viper.GetBool("vverbose"),
123
124
	}

125
126
	// Handle global permissions
	if len(viper.GetStringMap("permissions")) > 0 { // First read config file
127
		if err := viper.UnmarshalKey("permissions", &conf.GlobalPermissions); err != nil {
Sietse Ringers's avatar
Sietse Ringers committed
128
			return errors.WrapPrefix(err, "Failed to unmarshal permissions from config file", 0)
129
130
		}
	}
131
132
133
134
135
136
137
	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
138
			return errors.WrapPrefix(err, "Failed to unmarshal requestors from config file", 0)
139
140
141
		}
	}
	requestors := viper.GetString("requestors") // Read flag or env var
142
143
	if len(requestors) > 0 {
		if err := json.Unmarshal([]byte(requestors), &conf.Requestors); err != nil {
Sietse Ringers's avatar
Sietse Ringers committed
144
			return errors.WrapPrefix(err, "Failed to unmarshal requestors from json", 0)
145
146
147
148
		}
	}

	bts, _ := json.MarshalIndent(conf, "", "   ")
Sietse Ringers's avatar
Sietse Ringers committed
149
150
	logger.Debug(string(bts), "\n")
	logger.Debug("Done configuring")
151
152

	return nil
153
}
154
155
156
157
158
159
160
161
162
163

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