Commit 91166ae1 authored by Sietse Ringers's avatar Sietse Ringers
Browse files

Document server and library api

parent b77e2db6
......@@ -13,16 +13,26 @@ import (
var Logger *logrus.Logger = logrus.StandardLogger()
// Configuration contains configuration for the irmarequestor library and irmaserver.
type Configuration struct {
IrmaConfigurationPath string `json:"irmaconf" mapstructure:"irmaconf"`
IssuerPrivateKeysPath string `json:"privatekeys" mapstructure:"privatekeys"`
CachePath string `json:"cachepath" mapstructure:"cachepath"`
Url string `json:"url" mapstructure:"url"`
Logger *logrus.Logger `json:"-"`
IssuerPrivateKeys map[irma.IssuerIdentifier]*gabi.PrivateKey `json:"-"`
IrmaConfiguration *irma.Configuration `json:"-"`
// irma_configuration. If not given, this will be popupated using IrmaConfigurationPath.
IrmaConfiguration *irma.Configuration `json:"-"`
// Path to schemes to parse (only used if IrmaConfiguration is not given)
IrmaConfigurationPath string `json:"irmaconf" mapstructure:"irmaconf"`
// Path to writable dir to write cache to (only used if IrmaConfiguration is not give)
CachePath string `json:"cachepath" mapstructure:"cachepath"`
// Path to issuer private keys to parse
IssuerPrivateKeysPath string `json:"privatekeys" mapstructure:"privatekeys"`
// Issuer private keys
IssuerPrivateKeys map[irma.IssuerIdentifier]*gabi.PrivateKey `json:"-"`
// URL at which the IRMA app can reach this server during sessions
URL string `json:"url" mapstructure:"url"`
// Logging
Logger *logrus.Logger `json:"-"`
}
// SessionResult contains session information such as the session status, type, possible errors,
// and disclosed attributes or attribute-based signature if appropriate to the session type.
type SessionResult struct {
Token string
Status Status
......@@ -44,6 +54,7 @@ const (
StatusTimeout Status = "TIMEOUT" // Session timed out
)
// RemoteError converts an error and an explaining message to an *irma.RemoteError.
func RemoteError(err Error, message string) *irma.RemoteError {
stack := string(debug.Stack())
Logger.Errorf("Error: %d %s %s\n%s", err.Status, err.Type, message, stack)
......@@ -56,6 +67,8 @@ func RemoteError(err Error, message string) *irma.RemoteError {
}
}
// JsonResponse JSON-marshals the specified object or error
// and returns it along with a suitable HTTP status code
func JsonResponse(v interface{}, err *irma.RemoteError) (int, []byte) {
msg := v
status := http.StatusOK
......@@ -71,14 +84,17 @@ func JsonResponse(v interface{}, err *irma.RemoteError) (int, []byte) {
return status, b
}
// WriteError writes the specified error and explaining message as JSON to the http.ResponseWriter.
func WriteError(w http.ResponseWriter, err Error, msg string) {
WriteResponse(w, nil, RemoteError(err, msg))
}
// WriteJson writes the specified object as JSON to the http.ResponseWriter.
func WriteJson(w http.ResponseWriter, object interface{}) {
WriteResponse(w, object, nil)
}
// WriteResponse writes the specified object or error as JSON to the http.ResponseWriter.
func WriteResponse(w http.ResponseWriter, object interface{}, rerr *irma.RemoteError) {
status, bts := JsonResponse(object, rerr)
w.Header().Set("Content-Type", "application/json")
......@@ -86,12 +102,16 @@ func WriteResponse(w http.ResponseWriter, object interface{}, rerr *irma.RemoteE
w.Write(bts)
}
// WriteString writes the specified string to the http.ResponseWriter.
func WriteString(w http.ResponseWriter, str string) {
w.Header().Set("Content-Type", "text/plain")
w.WriteHeader(http.StatusOK)
w.Write([]byte(str))
}
// ParseSessionRequest tries to parse the specified bytes as an
// disclosure request, a signature request, and an issuance request, in that order.
// Returns an error if none of the attempts work.
func ParseSessionRequest(bts []byte) (request irma.SessionRequest, err error) {
request = &irma.DisclosureRequest{}
if err = irma.UnmarshalValidate(bts, request); err == nil {
......
......@@ -93,9 +93,9 @@ func Initialize(configuration *server.Configuration) error {
}
}
if conf.Url != "" {
if !strings.HasSuffix(conf.Url, "/") {
conf.Url = conf.Url + "/"
if conf.URL != "" {
if !strings.HasSuffix(conf.URL, "/") {
conf.URL = conf.URL + "/"
}
} else {
conf.Logger.Warn("No url parameter specified in configuration; unless an url is elsewhere prepended in the QR, the IRMA client will not be able to connect")
......@@ -128,7 +128,7 @@ func StartSession(request irma.SessionRequest) (*irma.Qr, string, error) {
conf.Logger.Infof("%s session started, token %s", action, session.token)
return &irma.Qr{
Type: action,
URL: conf.Url + session.token,
URL: conf.URL + session.token,
}, session.token, nil
}
......
package server
// Error represents an error that occured during an IRMA sessions.
type Error struct {
Type ErrorType `json:"error"`
Status int `json:"status"`
......
......@@ -9,14 +9,20 @@ import (
"github.com/privacybydesign/irmago/server/backend"
)
// SessionHandler is a function that can handle a session result
// once an IRMA session has completed.
type SessionHandler func(*server.SessionResult)
var handlers = make(map[string]SessionHandler)
// Initialize sets configuration.
func Initialize(configuration *server.Configuration) error {
return backend.Initialize(configuration)
}
// StartSession starts an IRMA session, running the handler on completion, if specified.
// The session token (the second return parameter) can be used in GetSessionResult()
// and CancelSession().
func StartSession(request irma.SessionRequest, handler SessionHandler) (*irma.Qr, string, error) {
qr, token, err := backend.StartSession(request)
if err != nil {
......@@ -28,17 +34,28 @@ func StartSession(request irma.SessionRequest, handler SessionHandler) (*irma.Qr
return qr, token, nil
}
// GetSessionResult retrieves the result of the specified IRMA session.
func GetSessionResult(token string) *server.SessionResult {
return backend.GetSessionResult(token)
}
// CancelSession cancels the specified IRMA session.
func CancelSession(token string) error {
return backend.CancelSession(token)
}
func HttpHandlerFunc(prefix string) http.HandlerFunc {
if len(prefix) != 0 && prefix[0] != '/' {
prefix = "/" + prefix
// HttpHandlerFunc returns a http.HandlerFunc that handles the IRMA protocol
// with IRMA apps. Initialize() must be called before this.
//
// Example usage:
// http.HandleFunc("/irma/", irmarequestor.HttpHandlerFunc("/irma/"))
//
// The IRMA app can then perform IRMA sessions at https://example.com/irma.
// Note that the two strings must be equal, i.e. you must pass the pattern at which
// you register the handler.
func HttpHandlerFunc(pattern string) http.HandlerFunc {
if len(pattern) != 0 && pattern[0] != '/' {
pattern = "/" + pattern
}
return func(w http.ResponseWriter, r *http.Request) {
var message []byte
......@@ -47,7 +64,7 @@ func HttpHandlerFunc(prefix string) http.HandlerFunc {
w.WriteHeader(http.StatusInternalServerError)
return
}
path := r.URL.Path[len(prefix):]
path := r.URL.Path[len(pattern):]
status, response, result := backend.HandleProtocolMessage(path, r.Method, r.Header, message)
w.WriteHeader(status)
w.Write(response)
......
......@@ -144,7 +144,7 @@ func configure() error {
IrmaConfigurationPath: viper.GetString("irmaconf"),
IssuerPrivateKeysPath: viper.GetString("privatekeys"),
CachePath: viper.GetString("cachepath"),
Url: viper.GetString("url"),
URL: viper.GetString("url"),
Logger: logger,
},
Port: viper.GetInt("port"),
......@@ -158,7 +158,7 @@ func configure() error {
}
// replace "port" in url with actual port
replace := "$1:" + strconv.Itoa(conf.Port)
conf.Url = string(regexp.MustCompile("(https?://[^/]*):port").ReplaceAll([]byte(conf.Url), []byte(replace)))
conf.URL = string(regexp.MustCompile("(https?://[^/]*):port").ReplaceAll([]byte(conf.URL), []byte(replace)))
// Handle global permissions
if len(viper.GetStringMap("permissions")) > 0 { // First read config file
......
......@@ -152,11 +152,11 @@ func (conf *Configuration) initialize() error {
}
}
if conf.Url != "" {
if !strings.HasSuffix(conf.Url, "/") {
conf.Url = conf.Url + "/"
if conf.URL != "" {
if !strings.HasSuffix(conf.URL, "/") {
conf.URL = conf.URL + "/"
}
conf.Url = conf.Url + "irma/"
conf.URL = conf.URL + "irma/"
}
return nil
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment