diff --git a/CHANGELOG.md b/CHANGELOG.md index 837580da8..6af523452 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,11 +6,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [0.6.0] - 2020-10-14 ### Added -* Support for session binding to prevent shoulder surfing (i.e. make it impossible for someone in close physical proximity to a user to scan the QR code that was meant for the user) - * Introduced new frontend endpoints to manage session binding +* Support for device pairing to prevent shoulder surfing (i.e. make it impossible for someone in close physical proximity to a user to scan the QR code that was meant for the user) + * Introduced new frontend endpoints to manage device pairing * Introduced `irmaclient` protocol version 2.7 including the necessary protocol changes - * The API of the `requestorserver` package has two new functions `SetFrontendOptions` and `BindingCompleted` - * A new server status `"BINDING"` is introduced + * The API of the `requestorserver` package has two new functions `SetFrontendOptions` and `PairingCompleted` + * A new server status `"PAIRING"` is introduced * A new function `SessionStatus` is available in the API of the `requestorserver` to get a channel with status updates of an IRMA session ### Changes diff --git a/internal/common/common.go b/internal/common/common.go index 3bd8454d0..b1a707363 100644 --- a/internal/common/common.go +++ b/internal/common/common.go @@ -27,8 +27,8 @@ var ForceHTTPS = true const ( sessionChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" sessionTokenLength = 20 - bindingCodeChars = "0123456789" - bindingCodeLength = 4 + pairingCodeChars = "0123456789" + pairingCodeLength = 4 ) // AssertPathExists returns nil only if it has been successfully @@ -278,8 +278,8 @@ func NewSessionToken() string { return newRandomString(sessionTokenLength, sessionChars) } -func NewBindingCode() string { - return newRandomString(bindingCodeLength, bindingCodeChars) +func NewPairingCode() string { + return newRandomString(pairingCodeLength, pairingCodeChars) } func newRandomString(count int, characterSet string) string { diff --git a/internal/sessiontest/handlers_test.go b/internal/sessiontest/handlers_test.go index 3d9f8bf00..7acd3b7fa 100644 --- a/internal/sessiontest/handlers_test.go +++ b/internal/sessiontest/handlers_test.go @@ -82,7 +82,7 @@ type TestHandler struct { expectedServerName *irma.RequestorInfo wait time.Duration result string - bindingCodeChan chan string + pairingCodeChan chan string dismisser irmaclient.SessionDismisser frontendTransport *irma.HTTPTransport } @@ -153,14 +153,14 @@ func (th TestHandler) RequestSchemeManagerPermission(manager *irma.SchemeManager func (th TestHandler) RequestPin(remainingAttempts int, callback irmaclient.PinHandler) { callback(true, "12345") } -func (th TestHandler) BindingRequired(bindingCode string) { - // Send binding code via channel to calling test. This is done such that +func (th TestHandler) PairingRequired(pairingCode string) { + // Send pairing code via channel to calling test. This is done such that // calling tests can detect it when this handler is skipped unexpectedly. - if th.bindingCodeChan != nil { - th.bindingCodeChan <- bindingCode + if th.pairingCodeChan != nil { + th.pairingCodeChan <- pairingCode return } - th.Failure(&irma.SessionError{ErrorType: irma.ErrorType("Binding required")}) + th.Failure(&irma.SessionError{ErrorType: irma.ErrorType("Pairing required")}) } type SessionResult struct { diff --git a/internal/sessiontest/legacy_test.go b/internal/sessiontest/legacy_test.go index 89c3d3cab..171c09762 100644 --- a/internal/sessiontest/legacy_test.go +++ b/internal/sessiontest/legacy_test.go @@ -35,7 +35,7 @@ func TestSessionUsingLegacyStorage(t *testing.T) { sessionHelper(t, getDisclosureRequest(idRoot), "verification", client) } -func TestWithoutBindingSupport(t *testing.T) { +func TestWithoutPairingSupport(t *testing.T) { defaultMaxVersion := maxClientVersion defer func() { maxClientVersion = defaultMaxVersion @@ -53,7 +53,7 @@ func TestWithoutBindingSupport(t *testing.T) { t.Run("TestIssuanceOptionalZeroLengthAttributes", TestIssuanceOptionalZeroLengthAttributes) t.Run("TestIssuanceOptionalSetAttributes", TestIssuanceOptionalSetAttributes) t.Run("TestIssuanceSameAttributesNotSingleton", TestIssuanceSameAttributesNotSingleton) - t.Run("TestIssuanceBinding", TestIssuanceBinding) + t.Run("TestIssuancePairing", TestIssuancePairing) t.Run("TestLargeAttribute", TestLargeAttribute) t.Run("TestIssuanceSingletonCredential", TestIssuanceSingletonCredential) t.Run("TestUnsatisfiableDisclosureSession", TestUnsatisfiableDisclosureSession) @@ -68,5 +68,5 @@ func TestWithoutBindingSupport(t *testing.T) { t.Run("TestStaticQRSession", TestStaticQRSession) t.Run("TestIssuedCredentialIsStored", TestIssuedCredentialIsStored) t.Run("TestPOSTSizeLimit", TestPOSTSizeLimit) - t.Run("TestDisableBinding", TestDisableBinding) + t.Run("TestDisablePairing", TestDisablePairing) } diff --git a/internal/sessiontest/main_test.go b/internal/sessiontest/main_test.go index ece16f5ae..0cfedb3f7 100644 --- a/internal/sessiontest/main_test.go +++ b/internal/sessiontest/main_test.go @@ -215,7 +215,7 @@ func sessionHelperWithFrontendOptions( sessiontype string, client *irmaclient.Client, frontendOptionsHandler func(handler *TestHandler), - bindingHandler func(handler *TestHandler), + pairingHandler func(handler *TestHandler), ) { if client == nil { var handler *TestClientHandler @@ -238,8 +238,8 @@ func sessionHelperWithFrontendOptions( expectedServerName: expectedRequestorInfo(t, client.Configuration), } - if frontendOptionsHandler != nil || bindingHandler != nil { - h.bindingCodeChan = make(chan string) + if frontendOptionsHandler != nil || pairingHandler != nil { + h.pairingCodeChan = make(chan string) h.frontendTransport = irma.NewHTTPTransport(qr.URL, false) h.frontendTransport.SetHeader(irma.AuthorizationHeader, string(frontendAuth)) } @@ -251,8 +251,8 @@ func sessionHelperWithFrontendOptions( require.NoError(t, err) h.dismisser = client.NewSession(string(qrjson), h) - if bindingHandler != nil { - bindingHandler(h) + if pairingHandler != nil { + pairingHandler(h) } if result := <-c; result != nil { @@ -277,13 +277,13 @@ func extractPrivateField(i interface{}, field string) interface{} { return reflect.NewAt(rct.Type(), unsafe.Pointer(rct.UnsafeAddr())).Elem().Interface() } -func setBindingMethod(method irma.BindingMethod, handler *TestHandler) string { +func setPairingMethod(method irma.PairingMethod, handler *TestHandler) string { optionsRequest := irma.NewOptionsRequest() - optionsRequest.BindingMethod = method + optionsRequest.PairingMethod = method options := &irma.SessionOptions{} err := handler.frontendTransport.Post("frontend/options", options, optionsRequest) require.NoError(handler.t, err) - return options.BindingCode + return options.PairingCode } func expectedRequestorInfo(t *testing.T, conf *irma.Configuration) *irma.RequestorInfo { diff --git a/internal/sessiontest/session_test.go b/internal/sessiontest/session_test.go index 2682f6407..1c031682d 100644 --- a/internal/sessiontest/session_test.go +++ b/internal/sessiontest/session_test.go @@ -119,32 +119,32 @@ func TestIssuanceSameAttributesNotSingleton(t *testing.T) { require.Equal(t, prevLen+1, len(client.CredentialInfoList())) } -func TestIssuanceBinding(t *testing.T) { +func TestIssuancePairing(t *testing.T) { id := irma.NewAttributeTypeIdentifier("irma-demo.RU.studentCard.studentID") request := getCombinedIssuanceRequest(id) - var bindingCode string + var pairingCode string frontendOptionsHandler := func(handler *TestHandler) { - bindingCode = setBindingMethod(irma.BindingMethodPin, handler) + pairingCode = setPairingMethod(irma.PairingMethodPin, handler) } - bindingHandler := func(handler *TestHandler) { - // Below protocol version 2.7 binding is not supported, so then the binding stage is expected to be skipped. + pairingHandler := func(handler *TestHandler) { + // Below protocol version 2.7 pairing is not supported, so then the pairing stage is expected to be skipped. if extractClientMaxVersion(handler.client).Below(2, 7) { return } - require.Equal(t, bindingCode, <-handler.bindingCodeChan) + require.Equal(t, pairingCode, <-handler.pairingCodeChan) - // Check whether access to request endpoint is denied as long as binding is not finished + // Check whether access to request endpoint is denied as long as pairing is not finished clientTransport := extractClientTransport(handler.dismisser) err := clientTransport.Get("request", struct{}{}) require.Error(t, err) sessionErr := err.(*irma.SessionError) require.Equal(t, irma.ErrorApi, sessionErr.ErrorType) - require.Equal(t, server.ErrorBindingRequired.Status, sessionErr.RemoteError.Status) - require.Equal(t, string(server.ErrorBindingRequired.Type), sessionErr.RemoteError.ErrorName) + require.Equal(t, server.ErrorPairingRequired.Status, sessionErr.RemoteError.Status) + require.Equal(t, string(server.ErrorPairingRequired.Type), sessionErr.RemoteError.ErrorName) - // Check whether binding cannot be disabled again after client is connected. + // Check whether pairing cannot be disabled again after client is connected. request := irma.NewOptionsRequest() result := &irma.SessionOptions{} err = handler.frontendTransport.Post("frontend/options", result, request) @@ -154,10 +154,10 @@ func TestIssuanceBinding(t *testing.T) { require.Equal(t, server.ErrorUnexpectedRequest.Status, sessionErr.RemoteError.Status) require.Equal(t, string(server.ErrorUnexpectedRequest.Type), sessionErr.RemoteError.ErrorName) - err = handler.frontendTransport.Post("frontend/bindingcompleted", nil, nil) + err = handler.frontendTransport.Post("frontend/pairingcompleted", nil, nil) require.NoError(t, err) } - sessionHelperWithFrontendOptions(t, request, "issue", nil, frontendOptionsHandler, bindingHandler) + sessionHelperWithFrontendOptions(t, request, "issue", nil, frontendOptionsHandler, pairingHandler) } func TestLargeAttribute(t *testing.T) { @@ -630,13 +630,13 @@ func TestPOSTSizeLimit(t *testing.T) { require.Equal(t, "http: request body too large", rerr.Message) } -func TestDisableBinding(t *testing.T) { +func TestDisablePairing(t *testing.T) { id := irma.NewAttributeTypeIdentifier("irma-demo.RU.studentCard.studentID") request := getCombinedIssuanceRequest(id) frontendOptionsHandler := func(handler *TestHandler) { - _ = setBindingMethod(irma.BindingMethodPin, handler) - _ = setBindingMethod(irma.BindingMethodNone, handler) + _ = setPairingMethod(irma.PairingMethodPin, handler) + _ = setPairingMethod(irma.PairingMethodNone, handler) } sessionHelperWithFrontendOptions(t, request, "issue", nil, frontendOptionsHandler, nil) } diff --git a/irma/cmd/session.go b/irma/cmd/session.go index 1c5ef849d..7080e3760 100644 --- a/irma/cmd/session.go +++ b/irma/cmd/session.go @@ -61,7 +61,7 @@ irma session --server http://localhost:8088 --authmethod token --key mytoken --d url, _ := cmd.Flags().GetString("url") serverurl, _ := cmd.Flags().GetString("server") noqr, _ := cmd.Flags().GetBool("noqr") - binding, _ := cmd.Flags().GetBool("binding") + pairing, _ := cmd.Flags().GetBool("pairing") if url != defaulturl && serverurl != "" { die("Failed to read configuration", errors.New("--url can't be combined with --server")) @@ -71,12 +71,12 @@ irma session --server http://localhost:8088 --authmethod token --key mytoken --d port, _ := flags.GetInt("port") privatekeysPath, _ := flags.GetString("privkeys") verbosity, _ := cmd.Flags().GetCount("verbose") - result, err = libraryRequest(request, irmaconfig, url, port, privatekeysPath, noqr, verbosity, binding) + result, err = libraryRequest(request, irmaconfig, url, port, privatekeysPath, noqr, verbosity, pairing) } else { authmethod, _ := flags.GetString("authmethod") key, _ := flags.GetString("key") name, _ := flags.GetString("name") - result, err = serverRequest(request, serverurl, authmethod, key, name, noqr, binding) + result, err = serverRequest(request, serverurl, authmethod, key, name, noqr, pairing) } if err != nil { die("Session failed", err) @@ -99,7 +99,7 @@ func libraryRequest( privatekeysPath string, noqr bool, verbosity int, - binding bool, + pairing bool, ) (*server.SessionResult, error) { if err := configureSessionServer(url, port, privatekeysPath, irmaconfig, verbosity); err != nil { return nil, err @@ -115,13 +115,13 @@ func libraryRequest( return nil, errors.WrapPrefix(err, "IRMA session failed", 0) } - // Enable binding if necessary + // Enable pairing if necessary var sessionOptions *irma.SessionOptions - if binding { + if pairing { optionsRequest := irma.NewOptionsRequest() - optionsRequest.BindingMethod = irma.BindingMethodPin + optionsRequest.PairingMethod = irma.PairingMethodPin if sessionOptions, err = irmaServer.SetFrontendOptions(requestorToken, &optionsRequest); err != nil { - return nil, errors.WrapPrefix(err, "Failed to enable binding", 0) + return nil, errors.WrapPrefix(err, "Failed to enable pairing", 0) } } @@ -130,18 +130,18 @@ func libraryRequest( return nil, errors.WrapPrefix(err, "Failed to print QR", 0) } - if binding { + if pairing { // Listen for session status statuschan, err := irmaServer.SessionStatus(requestorToken) if err != nil { return nil, errors.WrapPrefix(err, "Failed to start listening for session statuses", 0) } - _, err = handleBinding(sessionOptions, statuschan, func() error { - return irmaServer.BindingCompleted(requestorToken) + _, err = handlePairing(sessionOptions, statuschan, func() error { + return irmaServer.PairingCompleted(requestorToken) }) if err != nil { - return nil, errors.WrapPrefix(err, "Failed to handle binding", 0) + return nil, errors.WrapPrefix(err, "Failed to handle pairing", 0) } } @@ -153,7 +153,7 @@ func serverRequest( request irma.RequestorRequest, serverurl, authmethod, key, name string, noqr bool, - binding bool, + pairing bool, ) (*server.SessionResult, error) { logger.Debug("Server URL: ", serverurl) @@ -163,17 +163,17 @@ func serverRequest( return nil, err } - // Enable binding if necessary + // Enable pairing if necessary var frontendTransport *irma.HTTPTransport sessionOptions := &irma.SessionOptions{} - if binding { + if pairing { frontendTransport = irma.NewHTTPTransport(qr.URL, false) frontendTransport.SetHeader(irma.AuthorizationHeader, string(frontendAuth)) optionsRequest := irma.NewOptionsRequest() - optionsRequest.BindingMethod = irma.BindingMethodPin + optionsRequest.PairingMethod = irma.PairingMethodPin err = frontendTransport.Post("frontend/options", sessionOptions, optionsRequest) if err != nil { - return nil, errors.WrapPrefix(err, "Failed to enable binding", 0) + return nil, errors.WrapPrefix(err, "Failed to enable pairing", 0) } } @@ -200,20 +200,20 @@ func serverRequest( defer wg.Done() var status irma.ServerStatus - if binding { - status, err = handleBinding(sessionOptions, statuschan, func() error { - err = frontendTransport.Post("frontend/bindingcompleted", nil, nil) + if pairing { + status, err = handlePairing(sessionOptions, statuschan, func() error { + err = frontendTransport.Post("frontend/pairingcompleted", nil, nil) if err != nil { - return errors.WrapPrefix(err, "Failed to complete binding", 0) + return errors.WrapPrefix(err, "Failed to complete pairing", 0) } return nil }) if err != nil { - err = errors.WrapPrefix(err, "Failed to handle binding", 0) + err = errors.WrapPrefix(err, "Failed to handle pairing", 0) return } } else { - // Wait until client connects if binding is disabled + // Wait until client connects if pairing is disabled status := <-statuschan if status != irma.ServerStatusConnected { err = errors.Errorf("Unexpected status: %s", status) @@ -276,21 +276,19 @@ func postRequest(serverurl string, request irma.RequestorRequest, name, authmeth return pkg.SessionPtr, pkg.FrontendAuth, transport, err } -func handleBinding(options *irma.SessionOptions, statusChan chan irma.ServerStatus, completeBinding func() error) ( +func handlePairing(options *irma.SessionOptions, statusChan chan irma.ServerStatus, completePairing func() error) ( irma.ServerStatus, error) { errorChan := make(chan error) - bindingStarted := false for { select { case status := <-statusChan: if status == irma.ServerStatusInitialized { continue - } else if status == irma.ServerStatusBinding { - bindingStarted = true - go requestBindingPermission(options, completeBinding, errorChan) + } else if status == irma.ServerStatusPairing { + go requestPairingPermission(options, completePairing, errorChan) continue - } else if status == irma.ServerStatusConnected && !bindingStarted { - fmt.Println("Binding is not supported by the connected device.") + } else if status == irma.ServerStatusConnected { + fmt.Println("Pairing is not supported by the connected device.") } return status, nil case err := <-errorChan: @@ -299,24 +297,24 @@ func handleBinding(options *irma.SessionOptions, statusChan chan irma.ServerStat } } -func requestBindingPermission(options *irma.SessionOptions, completeBinding func() error, errorChan chan error) { - if options.BindingMethod == irma.BindingMethodPin { - fmt.Println("\nBinding code:", options.BindingCode) - fmt.Println("Press Enter to confirm your device shows the same binding code; otherwise press Ctrl-C.") +func requestPairingPermission(options *irma.SessionOptions, completePairing func() error, errorChan chan error) { + if options.PairingMethod == irma.PairingMethodPin { + fmt.Println("\nPairing code:", options.PairingCode) + fmt.Println("Press Enter to confirm your device shows the same pairing code; otherwise press Ctrl-C.") _, err := bufio.NewReader(os.Stdin).ReadString('\n') if err != nil { errorChan <- err return } - if err = completeBinding(); err != nil { + if err = completePairing(); err != nil { errorChan <- err return } - fmt.Println("Binding completed.") + fmt.Println("Pairing completed.") errorChan <- nil return } - errorChan <- errors.Errorf("Binding method %s is not supported", options.BindingMethod) + errorChan <- errors.Errorf("Pairing method %s is not supported", options.PairingMethod) } // Configuration functions @@ -370,7 +368,7 @@ func init() { flags.StringP("url", "u", defaulturl, "external URL to which IRMA app connects (when not using --server), \":port\" being replaced by --port value") flags.IntP("port", "p", 48680, "port to listen at (when not using --server)") flags.Bool("noqr", false, "Print JSON instead of draw QR") - flags.Bool("binding", false, "Enable explicit binding between server and IRMA app") + flags.Bool("pairing", false, "Let IRMA app first pair, by entering the pairing code, before it can access the session") flags.StringP("request", "r", "", "JSON session request") flags.StringP("privkeys", "k", "", "path to private keys") flags.Bool("disable-schemes-update", false, "disable scheme updates") diff --git a/irmaclient/handlers.go b/irmaclient/handlers.go index 930927769..d51efa6a8 100644 --- a/irmaclient/handlers.go +++ b/irmaclient/handlers.go @@ -83,6 +83,6 @@ func (h *keyshareEnrollmentHandler) KeyshareEnrollmentMissing(manager irma.Schem func (h *keyshareEnrollmentHandler) ClientReturnURLSet(clientReturnURL string) { h.fail(errors.New("Keyshare enrollment session unexpectedly found an external return url")) } -func (h *keyshareEnrollmentHandler) BindingRequired(bindingCode string) { - h.fail(errors.New("Keyshare enrollment session failed: session binding required")) +func (h *keyshareEnrollmentHandler) PairingRequired(pairingCode string) { + h.fail(errors.New("Keyshare enrollment session failed: device pairing required")) } diff --git a/irmaclient/session.go b/irmaclient/session.go index cc767b8bc..87da43a50 100644 --- a/irmaclient/session.go +++ b/irmaclient/session.go @@ -31,7 +31,7 @@ type PinHandler func(proceed bool, pin string) type Handler interface { StatusUpdate(action irma.Action, status irma.ClientStatus) ClientReturnURLSet(clientReturnURL string) - BindingRequired(bindingCode string) + PairingRequired(pairingCode string) Success(result string) Cancelled() Failure(err *irma.SessionError) @@ -108,7 +108,7 @@ var supportedVersions = map[int][]int{ 4, // old protocol with legacy session requests 5, // introduces condiscon feature 6, // introduces nonrevocation proofs - 7, // introduces session binding + 7, // introduces pairing feature }, } @@ -247,7 +247,7 @@ func (client *Client) newQrSession(qr *irma.Qr, handler Handler) SessionDismisse // Core session methods // getSessionInfo retrieves the first message in the IRMA protocol (only in interactive sessions) -// If needed, it also handles binding. +// If needed, it also handles pairing. func (session *session) getSessionInfo() { defer session.recoverFromPanic() @@ -264,9 +264,9 @@ func (session *session) getSessionInfo() { return } - // Check whether binding is needed, and if so, wait for it to be completed. - if cr.Options.BindingMethod != irma.BindingMethodNone { - if err = session.handleBinding(cr.Options.BindingCode); err != nil { + // Check whether pairing is needed, and if so, wait for it to be completed. + if cr.Options.PairingMethod != irma.PairingMethodNone { + if err = session.handlePairing(cr.Options.PairingCode); err != nil { session.fail(err.(*irma.SessionError)) return } @@ -275,19 +275,19 @@ func (session *session) getSessionInfo() { session.processSessionInfo() } -func (session *session) handleBinding(bindingCode string) error { - session.Handler.BindingRequired(bindingCode) +func (session *session) handlePairing(pairingCode string) error { + session.Handler.PairingRequired(pairingCode) statuschan := make(chan irma.ServerStatus) errorchan := make(chan error) - go irma.WaitStatusChanged(session.transport, irma.ServerStatusBinding, statuschan, errorchan) + go irma.WaitStatusChanged(session.transport, irma.ServerStatusPairing, statuschan, errorchan) select { case status := <-statuschan: if status == irma.ServerStatusConnected { return session.transport.Get("request", session.request) } else { - return &irma.SessionError{ErrorType: irma.ErrorBindingRejected} + return &irma.SessionError{ErrorType: irma.ErrorPairingRejected} } case err := <-errorchan: if serr, ok := err.(*irma.SessionError); ok { @@ -295,7 +295,7 @@ func (session *session) handleBinding(bindingCode string) error { } return &irma.SessionError{ ErrorType: irma.ErrorServerResponse, - Info: "Binding aborted by server", + Info: "Pairing aborted by server", Err: err, } } diff --git a/messages.go b/messages.go index 5c4c93e94..d6a2eb318 100644 --- a/messages.go +++ b/messages.go @@ -186,7 +186,7 @@ const ( // Server statuses const ( ServerStatusInitialized ServerStatus = "INITIALIZED" // The session has been started and is waiting for the client - ServerStatusBinding ServerStatus = "BINDING" // The client is waiting for the frontend to give permission to connect + ServerStatusPairing ServerStatus = "PAIRING" // The client is waiting for the frontend to give permission to connect ServerStatusConnected ServerStatus = "CONNECTED" // The client has retrieved the session request, we wait for its response ServerStatusCancelled ServerStatus = "CANCELLED" // The session is cancelled, possibly due to an error ServerStatusDone ServerStatus = "DONE" // The session has completed successfully @@ -219,8 +219,8 @@ const ( ErrorCrypto = ErrorType("crypto") // Error involving revocation or nonrevocation proofs ErrorRevocation = ErrorType("revocation") - // Our binding attempt was rejected by the server - ErrorBindingRejected = ErrorType("bindingRejected") + // Our pairing attempt was rejected by the server + ErrorPairingRejected = ErrorType("pairingRejected") // Server rejected our response (second IRMA message) ErrorRejected = ErrorType("rejected") // (De)serializing of a message failed diff --git a/requests.go b/requests.go index cb372f71f..48805590d 100644 --- a/requests.go +++ b/requests.go @@ -201,17 +201,17 @@ type AttributeRequest struct { NotNull bool `json:"notNull,omitempty"` } -type BindingMethod string +type PairingMethod string const ( - BindingMethodNone = "none" - BindingMethodPin = "pin" + PairingMethodNone = "none" + PairingMethodPin = "pin" ) // An OptionsRequest asks for a options change of a particular session. type OptionsRequest struct { LDContext string `json:"@context,omitempty"` - BindingMethod BindingMethod `json:"bindingMethod"` + PairingMethod PairingMethod `json:"pairingMethod"` } type RevocationRequest struct { @@ -230,8 +230,8 @@ type NonRevocationParameters map[CredentialTypeIdentifier]*NonRevocationRequest type SessionOptions struct { LDContext string `json:"@context,omitempty"` - BindingMethod BindingMethod `json:"bindingMethod"` - BindingCode string `json:"bindingCode,omitempty"` + PairingMethod PairingMethod `json:"pairingMethod"` + PairingCode string `json:"pairingCode,omitempty"` } // ClientRequest contains all information irmaclient needs to know to initiate a session. @@ -1115,7 +1115,7 @@ func NewAttributeRequest(attr string) AttributeRequest { func NewOptionsRequest() OptionsRequest { return OptionsRequest{ LDContext: LDContextOptionsRequest, - BindingMethod: BindingMethodNone, + PairingMethod: PairingMethodNone, } } @@ -1139,7 +1139,7 @@ func (cr *ClientRequest) UnmarshalJSON(data []byte) error { cr.ProtocolVersion = cr.Request.Base().ProtocolVersion cr.Options = &SessionOptions{ LDContext: LDContextSessionOptions, - BindingMethod: BindingMethodNone, + PairingMethod: PairingMethodNone, } return nil } diff --git a/server/errors.go b/server/errors.go index 149aee457..2dab2b9e7 100644 --- a/server/errors.go +++ b/server/errors.go @@ -19,8 +19,8 @@ var ( ErrorAttributesWrong Error = Error{Type: "ATTRIBUTES_WRONG", Status: 400, Description: "Specified attribute(s) do not belong to this credential type or missing attributes"} ErrorCannotIssue Error = Error{Type: "CANNOT_ISSUE", Status: 500, Description: "Cannot issue this credential"} - ErrorClientUnauthorized Error = Error{Type: "UNAUTHORIZED", Status: 403, Description: "You are not authorized to access the session"} - ErrorBindingRequired Error = Error{Type: "BINDING_REQUIRED", Status: 403, Description: "Binding is required first"} + ErrorIrmaUnauthorized Error = Error{Type: "UNAUTHORIZED", Status: 403, Description: "You are not authorized to access the session"} + ErrorPairingRequired Error = Error{Type: "PAIRING_REQUIRED", Status: 403, Description: "Pairing is required first"} ErrorIssuanceFailed Error = Error{Type: "ISSUANCE_FAILED", Status: 500, Description: "Failed to create credential(s)"} ErrorInvalidProofs Error = Error{Type: "INVALID_PROOFS", Status: 400, Description: "Invalid secret key commitments and/or disclosure proofs"} ErrorAttributesMissing Error = Error{Type: "ATTRIBUTES_MISSING", Status: 400, Description: "Not all requested-for attributes were present"} diff --git a/server/irmaserver/api.go b/server/irmaserver/api.go index 00e5fd2ab..6a2b80883 100644 --- a/server/irmaserver/api.go +++ b/server/irmaserver/api.go @@ -117,13 +117,13 @@ func (s *Server) HandlerFunc() http.HandlerFunc { r.Route("/frontend", func(r chi.Router) { r.Use(s.frontendMiddleware) r.Post("/options", s.handleFrontendOptionsPost) - r.Post("/bindingcompleted", s.handleFrontendBindingCompleted) + r.Post("/pairingcompleted", s.handleFrontendPairingCompleted) }) r.Group(func(r chi.Router) { r.Use(s.cacheMiddleware) r.Get("/", s.handleSessionGet) r.Group(func(r chi.Router) { - r.Use(s.bindingMiddleware) + r.Use(s.pairingMiddleware) r.Get("/request", s.handleSessionGetRequest) r.Post("/commitments", s.handleSessionCommitments) r.Post("/proofs", s.handleSessionProofs) @@ -264,17 +264,17 @@ func (s *Server) SetFrontendOptions(requestorToken irma.RequestorToken, request return session.updateFrontendOptions(request) } -// Complete binding between the irma client and the frontend. Returns +// Complete pairing between the irma client and the frontend. Returns // an error when no client is actually connected. -func BindingCompleted(requestorToken irma.RequestorToken) error { - return s.BindingCompleted(requestorToken) +func PairingCompleted(requestorToken irma.RequestorToken) error { + return s.PairingCompleted(requestorToken) } -func (s *Server) BindingCompleted(requestorToken irma.RequestorToken) error { +func (s *Server) PairingCompleted(requestorToken irma.RequestorToken) error { session := s.sessions.get(requestorToken) if session == nil { - return server.LogError(errors.Errorf("can't complete binding of unknown session %s", requestorToken)) + return server.LogError(errors.Errorf("can't complete pairing of unknown session %s", requestorToken)) } - return session.bindingCompleted() + return session.pairingCompleted() } // Revoke revokes the earlier issued credential specified by key. (Can only be used if this server diff --git a/server/irmaserver/handle.go b/server/irmaserver/handle.go index 49c86af6a..652b56205 100644 --- a/server/irmaserver/handle.go +++ b/server/irmaserver/handle.go @@ -50,7 +50,7 @@ func (session *session) handleGetClientRequest(min, max *irma.ProtocolVersion, c // Protocol versions below 2.7 don't include an authorization header. Therefore skip the authorization // header presence check if a lower version is used. if clientAuth == "" && session.version.Above(2, 6) { - return nil, session.fail(server.ErrorClientUnauthorized, "No authorization header provided") + return nil, session.fail(server.ErrorIrmaUnauthorized, "No authorization header provided") } session.clientAuth = clientAuth @@ -71,8 +71,8 @@ func (session *session) handleGetClientRequest(min, max *irma.ProtocolVersion, c logger.WithFields(logrus.Fields{"version": session.version.String()}).Debugf("Protocol version negotiated") session.request.Base().ProtocolVersion = session.version - if session.options.BindingMethod != irma.BindingMethodNone && session.version.Above(2, 6) { - session.setStatus(irma.ServerStatusBinding) + if session.options.PairingMethod != irma.PairingMethodNone && session.version.Above(2, 6) { + session.setStatus(irma.ServerStatusPairing) } else { session.setStatus(irma.ServerStatusConnected) } @@ -342,9 +342,9 @@ func (s *Server) handleFrontendOptionsPost(w http.ResponseWriter, r *http.Reques server.WriteResponse(w, res, nil) } -func (s *Server) handleFrontendBindingCompleted(w http.ResponseWriter, r *http.Request) { +func (s *Server) handleFrontendPairingCompleted(w http.ResponseWriter, r *http.Request) { session := r.Context().Value("session").(*session) - if err := session.bindingCompleted(); err != nil { + if err := session.pairingCompleted(); err != nil { server.WriteError(w, server.ErrorUnexpectedRequest, err.Error()) return } diff --git a/server/irmaserver/helpers.go b/server/irmaserver/helpers.go index 5772e24dd..a89eb0590 100644 --- a/server/irmaserver/helpers.go +++ b/server/irmaserver/helpers.go @@ -66,25 +66,25 @@ func (session *session) updateFrontendOptions(request *irma.OptionsRequest) (*ir if session.status != irma.ServerStatusInitialized { return nil, errors.New("Frontend options cannot be updated when client is already connected") } - if request.BindingMethod == irma.BindingMethodNone { - session.options.BindingCode = "" - } else if request.BindingMethod == irma.BindingMethodPin { - session.options.BindingCode = common.NewBindingCode() + if request.PairingMethod == irma.PairingMethodNone { + session.options.PairingCode = "" + } else if request.PairingMethod == irma.PairingMethodPin { + session.options.PairingCode = common.NewPairingCode() } else { - return nil, errors.New("Binding method unknown") + return nil, errors.New("Pairing method unknown") } - session.options.BindingMethod = request.BindingMethod + session.options.PairingMethod = request.PairingMethod return &session.options, nil } -// Complete the binding process of frontend and irma client -func (session *session) bindingCompleted() error { - if session.status == irma.ServerStatusBinding { +// Complete the pairing process of frontend and irma client +func (session *session) pairingCompleted() error { + if session.status == irma.ServerStatusPairing { session.setStatus(irma.ServerStatusConnected) return nil } - return errors.New("Binding was not enabled") + return errors.New("Pairing was not enabled") } func (session *session) fail(err server.Error, message string) *irma.RemoteError { @@ -305,7 +305,7 @@ func (session *session) getClientRequest() (*irma.ClientRequest, error) { Options: &session.options, } - if session.options.BindingMethod == irma.BindingMethodNone { + if session.options.PairingMethod == irma.PairingMethodNone { request, err := session.getRequest() if err != nil { return nil, err @@ -437,7 +437,7 @@ func (s *Server) frontendMiddleware(next http.Handler) http.Handler { frontendAuth := irma.FrontendAuthorization(r.Header.Get(irma.AuthorizationHeader)) if frontendAuth != session.frontendAuth { - server.WriteError(w, server.ErrorUnauthorized, "") + server.WriteError(w, server.ErrorIrmaUnauthorized, "") return } next.ServeHTTP(w, r) @@ -518,16 +518,16 @@ func (s *Server) sessionMiddleware(next http.Handler) http.Handler { }) } -func (s *Server) bindingMiddleware(next http.Handler) http.Handler { +func (s *Server) pairingMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { session := r.Context().Value("session").(*session) - if session.status == irma.ServerStatusBinding { - server.WriteError(w, server.ErrorBindingRequired, "") + if session.status == irma.ServerStatusPairing { + server.WriteError(w, server.ErrorPairingRequired, "") return } - // Endpoints behind the bindingMiddleware can only be accessed when the client is already connected + // Endpoints behind the pairingMiddleware can only be accessed when the client is already connected // and the request includes the right authorization header to prove we still talk to the same client as before. if session.status != irma.ServerStatusConnected { server.WriteError(w, server.ErrorUnexpectedRequest, "Session not yet started or already finished") @@ -535,7 +535,7 @@ func (s *Server) bindingMiddleware(next http.Handler) http.Handler { } clientAuth := irma.ClientAuthorization(r.Header.Get(irma.AuthorizationHeader)) if session.clientAuth != clientAuth { - server.WriteError(w, server.ErrorClientUnauthorized, "") + server.WriteError(w, server.ErrorIrmaUnauthorized, "") return } diff --git a/server/irmaserver/sessions.go b/server/irmaserver/sessions.go index 71115bb30..aa56ae811 100644 --- a/server/irmaserver/sessions.go +++ b/server/irmaserver/sessions.go @@ -166,7 +166,7 @@ func (s *Server) newSession(action irma.Action, request irma.RequestorRequest) * request: request.SessionRequest(), options: irma.SessionOptions{ LDContext: irma.LDContextSessionOptions, - BindingMethod: irma.BindingMethodNone, + PairingMethod: irma.PairingMethodNone, }, lastActive: time.Now(), requestorToken: requestorToken,