Commit c80f2f6c authored by Sietse Ringers's avatar Sietse Ringers
Browse files

Merging interactive and manual session structs back into one

Instead we just branch in some functions over whether or not the session is interactive. This solves some code duplication; gives manual sessions the ability to download unknown scheme manager files on the fly, like interactive sessions; and it solves manual sessions missing some calls back to the Handler.
parent e4d97606
...@@ -7,9 +7,9 @@ import ( ...@@ -7,9 +7,9 @@ import (
"math/big" "math/big"
"strconv" "strconv"
"github.com/privacybydesign/irmago"
"github.com/go-errors/errors" "github.com/go-errors/errors"
"github.com/mhe/gabi" "github.com/mhe/gabi"
"github.com/privacybydesign/irmago"
) )
// This file contains an implementation of the client side of the keyshare protocol, // This file contains an implementation of the client side of the keyshare protocol,
......
...@@ -4,9 +4,9 @@ import ( ...@@ -4,9 +4,9 @@ import (
"encoding/json" "encoding/json"
"time" "time"
"github.com/privacybydesign/irmago"
"github.com/go-errors/errors" "github.com/go-errors/errors"
"github.com/mhe/gabi" "github.com/mhe/gabi"
"github.com/privacybydesign/irmago"
) )
// LogEntry is a log entry of a past event. // LogEntry is a log entry of a past event.
...@@ -29,7 +29,7 @@ type LogEntry struct { ...@@ -29,7 +29,7 @@ type LogEntry struct {
const actionRemoval = irma.Action("removal") const actionRemoval = irma.Action("removal")
func (session *interactiveSession) createLogEntry(response interface{}) (*LogEntry, error) { func (session *session) createLogEntry(response interface{}) (*LogEntry, error) {
entry := &LogEntry{ entry := &LogEntry{
Type: session.Action, Type: session.Action,
Time: irma.Timestamp(time.Now()), Time: irma.Timestamp(time.Now()),
......
...@@ -2,8 +2,12 @@ package irmaclient ...@@ -2,8 +2,12 @@ package irmaclient
import ( import (
"fmt" "fmt"
"github.com/privacybydesign/irmago"
"github.com/go-errors/errors"
"testing" "testing"
"github.com/privacybydesign/irmago"
) )
type ManualSessionHandler struct { type ManualSessionHandler struct {
...@@ -69,20 +73,22 @@ func (sh *ManualSessionHandler) RequestSignaturePermission(request irma.Signatur ...@@ -69,20 +73,22 @@ func (sh *ManualSessionHandler) RequestSignaturePermission(request irma.Signatur
} }
// These handlers should not be called, fail test if they are called // These handlers should not be called, fail test if they are called
func (sh *ManualSessionHandler) Cancelled(irmaAction irma.Action) { sh.t.Fail() } func (sh *ManualSessionHandler) Cancelled(irmaAction irma.Action) {
sh.c <- &irma.SessionError{Err: errors.New("Session was cancelled")}
}
func (sh *ManualSessionHandler) MissingKeyshareEnrollment(manager irma.SchemeManagerIdentifier) { func (sh *ManualSessionHandler) MissingKeyshareEnrollment(manager irma.SchemeManagerIdentifier) {
sh.t.Fail() sh.c <- &irma.SessionError{Err: errors.Errorf("Missing keyshare server %s", manager.String())}
} }
func (sh *ManualSessionHandler) RequestIssuancePermission(request irma.IssuanceRequest, issuerName string, ph PermissionHandler) { func (sh *ManualSessionHandler) RequestIssuancePermission(request irma.IssuanceRequest, issuerName string, ph PermissionHandler) {
sh.t.Fail() sh.c <- &irma.SessionError{Err: errors.New("Unexpected session type")}
} }
func (sh *ManualSessionHandler) RequestSchemeManagerPermission(manager *irma.SchemeManager, callback func(proceed bool)) { func (sh *ManualSessionHandler) RequestSchemeManagerPermission(manager *irma.SchemeManager, callback func(proceed bool)) {
sh.t.Fail() sh.c <- &irma.SessionError{Err: errors.New("Unexpected session type")}
} }
func (sh *ManualSessionHandler) RequestVerificationPermission(request irma.DisclosureRequest, verifierName string, ph PermissionHandler) { func (sh *ManualSessionHandler) RequestVerificationPermission(request irma.DisclosureRequest, verifierName string, ph PermissionHandler) {
sh.t.Fail() sh.c <- &irma.SessionError{Err: errors.New("Unexpected session type")}
} }
func (sh *ManualSessionHandler) Failure(irmaAction irma.Action, err *irma.SessionError) { func (sh *ManualSessionHandler) Failure(irmaAction irma.Action, err *irma.SessionError) {
fmt.Println(err.Err) fmt.Println(err.Err)
sh.t.Fail() sh.c <- err
} }
...@@ -9,9 +9,9 @@ import ( ...@@ -9,9 +9,9 @@ import (
"math/big" "math/big"
"github.com/privacybydesign/irmago"
"github.com/go-errors/errors" "github.com/go-errors/errors"
"github.com/mhe/gabi" "github.com/mhe/gabi"
"github.com/privacybydesign/irmago"
) )
// This file contains the client side of the IRMA protocol, as well as the Handler interface // This file contains the client side of the IRMA protocol, as well as the Handler interface
...@@ -46,14 +46,6 @@ type SessionDismisser interface { ...@@ -46,14 +46,6 @@ type SessionDismisser interface {
Dismiss() Dismiss()
} }
// baseSession contains methods generic to both manual and interactive sessions
type baseSession interface {
getBuilders() (gabi.ProofBuilderList, error)
getProof() (interface{}, error)
panicFailure()
checkKeyshareEnrollment() bool
}
type session struct { type session struct {
Action irma.Action Action irma.Action
Handler Handler Handler Handler
...@@ -63,31 +55,17 @@ type session struct { ...@@ -63,31 +55,17 @@ type session struct {
client *Client client *Client
downloaded *irma.IrmaIdentifierSet downloaded *irma.IrmaIdentifierSet
irmaSession irma.IrmaSession irmaSession irma.IrmaSession
} done bool
// We implement baseSessino for a session
var _ baseSession = (*session)(nil)
// A interactiveSession is an interactive IRMA session
type interactiveSession struct {
session
// These are empty on manual sessions
ServerURL string ServerURL string
info *irma.SessionInfo info *irma.SessionInfo
jwt irma.RequestorJwt jwt irma.RequestorJwt
transport *irma.HTTPTransport transport *irma.HTTPTransport
done bool
}
// A manualSession is a session started from a request
type manualSession struct {
session
} }
// We implement the handler for the keyshare protocol // We implement the handler for the keyshare protocol
var _ keyshareSessionHandler = (*interactiveSession)(nil) var _ keyshareSessionHandler = (*session)(nil)
var _ keyshareSessionHandler = (*manualSession)(nil)
// Supported protocol versions. Minor version numbers should be reverse sorted. // Supported protocol versions. Minor version numbers should be reverse sorted.
var supportedVersions = map[int][]int{ var supportedVersions = map[int][]int{
...@@ -129,6 +107,10 @@ func calcVersion(qr *irma.Qr) (string, error) { ...@@ -129,6 +107,10 @@ func calcVersion(qr *irma.Qr) (string, error) {
return "", fmt.Errorf("No supported protocol version between %s and %s", qr.ProtocolVersion, qr.ProtocolMaxVersion) return "", fmt.Errorf("No supported protocol version between %s and %s", qr.ProtocolVersion, qr.ProtocolMaxVersion)
} }
func (session *session) IsInteractive() bool {
return session.ServerURL != ""
}
func (session *session) getBuilders() (gabi.ProofBuilderList, error) { func (session *session) getBuilders() (gabi.ProofBuilderList, error) {
var builders gabi.ProofBuilderList var builders gabi.ProofBuilderList
var err error var err error
...@@ -161,7 +143,8 @@ func (session *session) getProof() (interface{}, error) { ...@@ -161,7 +143,8 @@ func (session *session) getProof() (interface{}, error) {
return message, err return message, err
} }
// Check if we are enrolled into all involved keyshare servers // checkKeyshareEnrollment checks if we are enrolled into all involved keyshare servers,
// and aborts the session if not
func (session *session) checkKeyshareEnrollment() bool { func (session *session) checkKeyshareEnrollment() bool {
for id := range session.irmaSession.Identifiers().SchemeManagers { for id := range session.irmaSession.Identifiers().SchemeManagers {
manager, ok := session.client.Configuration.SchemeManagers[id] manager, ok := session.client.Configuration.SchemeManagers[id]
...@@ -203,14 +186,12 @@ func (client *Client) NewManualSession(sigrequestJSONString string, handler Hand ...@@ -203,14 +186,12 @@ func (client *Client) NewManualSession(sigrequestJSONString string, handler Hand
return return
} }
session := &manualSession{ session := &session{
session: session{ Action: irma.ActionSigning, // TODO hardcoded for now
Action: irma.ActionSigning, // TODO hardcoded for now Handler: handler,
Handler: handler, client: client,
client: client, Version: irma.Version("2"), // TODO hardcoded for now
Version: irma.Version("2"), // TODO hardcoded for now irmaSession: sigrequest,
irmaSession: sigrequest,
},
} }
session.Handler.StatusUpdate(session.Action, irma.StatusManualStarted) session.Handler.StatusUpdate(session.Action, irma.StatusManualStarted)
...@@ -220,6 +201,12 @@ func (client *Client) NewManualSession(sigrequestJSONString string, handler Hand ...@@ -220,6 +201,12 @@ func (client *Client) NewManualSession(sigrequestJSONString string, handler Hand
return return
} }
// Download missing credential types/issuers/public keys from the scheme manager
if session.downloaded, err = session.client.Configuration.Download(session.irmaSession.Identifiers()); err != nil {
session.fail(&irma.SessionError{ErrorType: irma.ErrorConfigurationDownload, Err: err})
return
}
candidates, missing := session.client.CheckSatisfiability(session.irmaSession.ToDisclose()) candidates, missing := session.client.CheckSatisfiability(session.irmaSession.ToDisclose())
if len(missing) > 0 { if len(missing) > 0 {
session.Handler.UnsatisfiableRequest(session.Action, missing) session.Handler.UnsatisfiableRequest(session.Action, missing)
...@@ -238,49 +225,14 @@ func (client *Client) NewManualSession(sigrequestJSONString string, handler Hand ...@@ -238,49 +225,14 @@ func (client *Client) NewManualSession(sigrequestJSONString string, handler Hand
*session.irmaSession.(*irma.SignatureRequest), "E-mail request", callback) *session.irmaSession.(*irma.SignatureRequest), "E-mail request", callback)
} }
func (session *manualSession) do(proceed bool) {
defer session.panicFailure()
if !proceed {
session.Handler.Cancelled(session.Action)
return
}
if !session.irmaSession.Identifiers().Distributed(session.client.Configuration) {
message, err := session.getProof()
if err != nil {
session.Handler.Failure(session.Action, &irma.SessionError{ErrorType: irma.ErrorCrypto, Err: err})
return
}
session.sendResponse(message)
} else {
builders, err := session.getBuilders()
if err != nil {
session.Handler.Failure(session.Action, &irma.SessionError{ErrorType: irma.ErrorCrypto, Err: err})
}
startKeyshareSession(
session,
session.Handler,
builders,
session.irmaSession,
session.client.Configuration,
session.client.keyshareServers,
session.client.state,
)
}
}
// NewSession creates and starts a new interactive IRMA session // NewSession creates and starts a new interactive IRMA session
func (client *Client) NewSession(qr *irma.Qr, handler Handler) SessionDismisser { func (client *Client) NewSession(qr *irma.Qr, handler Handler) SessionDismisser {
session := &interactiveSession{ session := &session{
ServerURL: qr.URL, ServerURL: qr.URL,
transport: irma.NewHTTPTransport(qr.URL), transport: irma.NewHTTPTransport(qr.URL),
session: session{ Action: irma.Action(qr.Type),
Action: irma.Action(qr.Type), Handler: handler,
Handler: handler, client: client,
client: client,
},
} }
if session.Action == irma.ActionSchemeManager { if session.Action == irma.ActionSchemeManager {
...@@ -318,7 +270,7 @@ func (client *Client) NewSession(qr *irma.Qr, handler Handler) SessionDismisser ...@@ -318,7 +270,7 @@ func (client *Client) NewSession(qr *irma.Qr, handler Handler) SessionDismisser
// start retrieves the first message in the IRMA protocol, checks if we can perform // start retrieves the first message in the IRMA protocol, checks if we can perform
// the request, and informs the user of the outcome. // the request, and informs the user of the outcome.
func (session *interactiveSession) start() { func (session *session) start() {
defer session.panicFailure() defer session.panicFailure()
session.Handler.StatusUpdate(session.Action, irma.StatusCommunicating) session.Handler.StatusUpdate(session.Action, irma.StatusCommunicating)
...@@ -355,10 +307,7 @@ func (session *interactiveSession) start() { ...@@ -355,10 +307,7 @@ func (session *interactiveSession) start() {
// Download missing credential types/issuers/public keys from the scheme manager // Download missing credential types/issuers/public keys from the scheme manager
if session.downloaded, err = session.client.Configuration.Download(session.irmaSession.Identifiers()); err != nil { if session.downloaded, err = session.client.Configuration.Download(session.irmaSession.Identifiers()); err != nil {
session.Handler.Failure( session.fail(&irma.SessionError{ErrorType: irma.ErrorConfigurationDownload, Err: err})
session.Action,
&irma.SessionError{ErrorType: irma.ErrorConfigurationDownload, Err: err},
)
return return
} }
...@@ -404,7 +353,7 @@ func (session *interactiveSession) start() { ...@@ -404,7 +353,7 @@ func (session *interactiveSession) start() {
} }
} }
func (session *interactiveSession) do(proceed bool) { func (session *session) do(proceed bool) {
defer session.panicFailure() defer session.panicFailure()
if !proceed { if !proceed {
...@@ -437,36 +386,19 @@ func (session *interactiveSession) do(proceed bool) { ...@@ -437,36 +386,19 @@ func (session *interactiveSession) do(proceed bool) {
} }
} }
func (session *interactiveSession) KeyshareDone(message interface{}) { func (session *session) KeyshareDone(message interface{}) {
session.sendResponse(message) session.sendResponse(message)
} }
func (session *manualSession) KeyshareDone(message interface{}) { func (session *session) KeyshareCancelled() {
messageJson, err := json.Marshal(message)
if err != nil {
session.Handler.Failure(session.Action, &irma.SessionError{ErrorType: irma.ErrorSerialization, Err: err})
return
}
session.Handler.Success(session.Action, string(messageJson))
}
func (session *interactiveSession) KeyshareCancelled() {
session.cancel() session.cancel()
} }
func (session *manualSession) KeyshareCancelled() { func (session *session) KeyshareBlocked(duration int) {
session.Handler.Cancelled(session.Action)
}
func (session *interactiveSession) KeyshareBlocked(duration int) {
session.fail(&irma.SessionError{ErrorType: irma.ErrorKeyshareBlocked, Info: strconv.Itoa(duration)}) session.fail(&irma.SessionError{ErrorType: irma.ErrorKeyshareBlocked, Info: strconv.Itoa(duration)})
} }
func (session *manualSession) KeyshareBlocked(duration int) { func (session *session) KeyshareError(err error) {
session.Handler.Failure(session.Action, &irma.SessionError{ErrorType: irma.ErrorKeyshareBlocked, Info: strconv.Itoa(duration)})
}
func (session *interactiveSession) KeyshareError(err error) {
var serr *irma.SessionError var serr *irma.SessionError
var ok bool var ok bool
if serr, ok = err.(*irma.SessionError); !ok { if serr, ok = err.(*irma.SessionError); !ok {
...@@ -477,17 +409,6 @@ func (session *interactiveSession) KeyshareError(err error) { ...@@ -477,17 +409,6 @@ func (session *interactiveSession) KeyshareError(err error) {
session.fail(serr) session.fail(serr)
} }
func (session *manualSession) KeyshareError(err error) {
var serr *irma.SessionError
var ok bool
if serr, ok = err.(*irma.SessionError); !ok {
serr = &irma.SessionError{ErrorType: irma.ErrorKeyshare, Err: err}
} else {
serr.ErrorType = irma.ErrorKeyshare
}
session.Handler.Failure(session.Action, serr)
}
func (session *session) KeysharePin() { func (session *session) KeysharePin() {
session.Handler.StatusUpdate(session.Action, irma.StatusConnected) session.Handler.StatusUpdate(session.Action, irma.StatusConnected)
} }
...@@ -498,35 +419,44 @@ func (session *session) KeysharePinOK() { ...@@ -498,35 +419,44 @@ func (session *session) KeysharePinOK() {
type disclosureResponse string type disclosureResponse string
func (session *interactiveSession) sendResponse(message interface{}) { func (session *session) sendResponse(message interface{}) {
var log *LogEntry var log *LogEntry
var err error var err error
var messageJson []byte
switch session.Action {
case irma.ActionSigning: if session.IsInteractive() {
fallthrough switch session.Action {
case irma.ActionDisclosing: case irma.ActionSigning:
var response disclosureResponse fallthrough
if err = session.transport.Post("proofs", &response, message); err != nil { case irma.ActionDisclosing:
session.fail(err.(*irma.SessionError)) var response disclosureResponse
return if err = session.transport.Post("proofs", &response, message); err != nil {
} session.fail(err.(*irma.SessionError))
if response != "VALID" { return
session.fail(&irma.SessionError{ErrorType: irma.ErrorRejected, Info: string(response)}) }
return if response != "VALID" {
} session.fail(&irma.SessionError{ErrorType: irma.ErrorRejected, Info: string(response)})
log, _ = session.createLogEntry(message.(gabi.ProofList)) // TODO err return
case irma.ActionIssuing: }
response := []*gabi.IssueSignatureMessage{} log, _ = session.createLogEntry(message.(gabi.ProofList)) // TODO err
if err = session.transport.Post("commitments", &response, message); err != nil { case irma.ActionIssuing:
session.fail(err.(*irma.SessionError)) response := []*gabi.IssueSignatureMessage{}
return if err = session.transport.Post("commitments", &response, message); err != nil {
session.fail(err.(*irma.SessionError))
return
}
if err = session.client.ConstructCredentials(response, session.irmaSession.(*irma.IssuanceRequest)); err != nil {
session.fail(&irma.SessionError{ErrorType: irma.ErrorCrypto, Err: err})
return
}
log, _ = session.createLogEntry(message) // TODO err
} }
if err = session.client.ConstructCredentials(response, session.irmaSession.(*irma.IssuanceRequest)); err != nil { } else {
session.fail(&irma.SessionError{ErrorType: irma.ErrorCrypto, Err: err}) messageJson, err = json.Marshal(message)
if err != nil {
session.fail(&irma.SessionError{ErrorType: irma.ErrorSerialization, Err: err})
return return
} }
log, _ = session.createLogEntry(message) // TODO err
} }
_ = session.client.addLogEntry(log) // TODO err _ = session.client.addLogEntry(log) // TODO err
...@@ -537,20 +467,10 @@ func (session *interactiveSession) sendResponse(message interface{}) { ...@@ -537,20 +467,10 @@ func (session *interactiveSession) sendResponse(message interface{}) {
session.client.handler.UpdateAttributes() session.client.handler.UpdateAttributes()
} }
session.done = true session.done = true
session.Handler.Success(session.Action, "")
}
func (session *manualSession) sendResponse(message interface{}) {
messageJson, err := json.Marshal(message)
if err != nil {
session.Handler.Failure(session.Action, &irma.SessionError{ErrorType: irma.ErrorSerialization, Err: err})
return
}
session.Handler.Success(session.Action, string(messageJson)) session.Handler.Success(session.Action, string(messageJson))
} }
func (session *interactiveSession) managerSession() { func (session *session) managerSession() {
defer func() { defer func() {
if e := recover(); e != nil { if e := recover(); e != nil {
if session.Handler != nil { if session.Handler != nil {
...@@ -611,16 +531,18 @@ func panicToError(e interface{}) *irma.SessionError { ...@@ -611,16 +531,18 @@ func panicToError(e interface{}) *irma.SessionError {
} }
// Idempotently send DELETE to remote server, returning whether or not we did something // Idempotently send DELETE to remote server, returning whether or not we did something
func (session *interactiveSession) delete() bool { func (session *session) delete() bool {
if !session.done { if !session.done {
session.transport.Delete() if session.IsInteractive() {
session.transport.Delete()
}
session.done = true session.done = true
return true return true
} }
return false return false
} }
func (session *interactiveSession) fail(err *irma.SessionError) { func (session *session) fail(err *irma.SessionError) {
if session.delete() { if session.delete() {
err.Err = errors.Wrap(err.Err, 0) err.Err = errors.Wrap(err.Err, 0)
if session.downloaded != nil && !session.downloaded.Empty() { if session.downloaded != nil && !session.downloaded.Empty() {
...@@ -630,7 +552,7 @@ func (session *interactiveSession) fail(err *irma.SessionError) { ...@@ -630,7 +552,7 @@ func (session *interactiveSession) fail(err *irma.SessionError) {
} }
} }
func (session *interactiveSession) cancel() { func (session *session) cancel() {
if session.delete() { if session.delete() {
if session.downloaded != nil && !session.downloaded.Empty() { if session.downloaded != nil && !session.downloaded.Empty() {
session.client.handler.UpdateConfiguration(session.downloaded) session.client.handler.UpdateConfiguration(session.downloaded)
...@@ -639,7 +561,7 @@ func (session *interactiveSession) cancel() { ...@@ -639,7 +561,7 @@ func (session *interactiveSession) cancel() {
} }
} }
func (session *interactiveSession) Dismiss() { func (session *session) Dismiss() {
session.cancel() session.cancel()
} }
......
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