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

import (
4
	"encoding/json"
5
6
	"os"

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

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

18
func main() {
19
20
21
22
23
24
25
26
27
28
29
30
	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))
			}
		},
	}
31

32
33
	if err := setFlags(cmd); err != nil {
		die(errors.WrapPrefix(err, "Failed to attach flags", 0))
34
35
	}

36
37
	if err := cmd.Execute(); err != nil {
		die(errors.WrapPrefix(err, "Failed to execute command", 0))
38
	}
39
40
41
}

func die(err *errors.Error) {
Sietse Ringers's avatar
Sietse Ringers committed
42
43
	logger.Error(err.Error())
	logger.Debug(string(err.Stack()))
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
	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)")

59
60
61
62
63
64
65
	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 = "*"

66
67
68
69
	return viper.BindPFlags(flags)
}

func configure() error {
Sietse Ringers's avatar
Sietse Ringers committed
70
71
	logger.Level = logrus.TraceLevel
	logger.Debugf("Configuring")
72
73
74
75

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

77
78
79
80
81
82
	// Configuration file
	viper.SetConfigName("config")
	viper.AddConfigPath(".")
	viper.AddConfigPath("/etc/irmaserver/")
	viper.AddConfigPath("$HOME/.irmaserver")
	if err := viper.ReadInConfig(); err != nil {
Sietse Ringers's avatar
Sietse Ringers committed
83
		logger.Info("No configuration file found")
84
	} else {
Sietse Ringers's avatar
Sietse Ringers committed
85
		logger.Info("Config file: ", viper.ConfigFileUsed())
86
87
88
89
	}

	// Read configuration from flags and/or environmental variables
	conf = &irmaserver.Configuration{
Sietse Ringers's avatar
Sietse Ringers committed
90
		Configuration: &server.Configuration{
91
92
			IrmaConfigurationPath: viper.GetString("irmaconf"),
			IssuerPrivateKeysPath: viper.GetString("privatekeys"),
Sietse Ringers's avatar
Sietse Ringers committed
93
			Logger:                logger,
94
		},
95
96
97
98
99
100
101
102
		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"),
	}

103
104
	// Handle global permissions
	if len(viper.GetStringMap("permissions")) > 0 { // First read config file
105
		if err := viper.UnmarshalKey("permissions", &conf.GlobalPermissions); err != nil {
Sietse Ringers's avatar
Sietse Ringers committed
106
			return errors.WrapPrefix(err, "Failed to unmarshal permissions from config file", 0)
107
108
		}
	}
109
110
111
112
113
114
115
	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
116
			return errors.WrapPrefix(err, "Failed to unmarshal requestors from config file", 0)
117
118
119
		}
	}
	requestors := viper.GetString("requestors") // Read flag or env var
120
121
	if len(requestors) > 0 {
		if err := json.Unmarshal([]byte(requestors), &conf.Requestors); err != nil {
Sietse Ringers's avatar
Sietse Ringers committed
122
			return errors.WrapPrefix(err, "Failed to unmarshal requestors from json", 0)
123
124
125
126
		}
	}

	bts, _ := json.MarshalIndent(conf, "", "   ")
Sietse Ringers's avatar
Sietse Ringers committed
127
128
	logger.Debug(string(bts), "\n")
	logger.Debug("Done configuring")
129
130

	return nil
131
}
132
133
134
135
136
137
138
139
140
141

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