Commit 9cfd42ff authored by Sietse Ringers's avatar Sietse Ringers
Browse files

Split HTTP routing and handling from IRMA session handling in server backend

parent 502b6c9d
......@@ -83,7 +83,8 @@ func HandleProtocolMessage(
matches := pattern.FindStringSubmatch(path)
if len(matches) != 3 {
conf.Logger.Warnf("Invalid URL: %s", path)
return failSession(nil, irmaserver.ErrorInvalidRequest, "")
status, output = responseJson(nil, getError(irmaserver.ErrorInvalidRequest, ""))
return
}
// Fetch the session
......@@ -92,55 +93,76 @@ func HandleProtocolMessage(
session := sessions.get(token)
if session == nil {
conf.Logger.Warnf("Session not found: %s", token)
return failSession(nil, irmaserver.ErrorSessionUnknown, "")
status, output = responseJson(nil, getError(irmaserver.ErrorSessionUnknown, ""))
return
}
defer func() {
if session.result != nil {
result = session.result
}
}()
// Route to handler
switch len(verb) {
case 0:
if method == "DELETE" {
return handleDelete(session)
session.handleDelete()
status = http.StatusOK
return
}
if method == "GET" {
h := http.Header(headers)
min := &irma.ProtocolVersion{}
max := &irma.ProtocolVersion{}
if err := json.Unmarshal([]byte(h.Get(irma.MinVersionHeader)), min); err != nil {
return failSession(session, irmaserver.ErrorMalformedInput, err.Error())
status, output = responseJson(nil, session.fail(irmaserver.ErrorMalformedInput, err.Error()))
return
}
if err := json.Unmarshal([]byte(h.Get(irma.MaxVersionHeader)), max); err != nil {
return failSession(session, irmaserver.ErrorMalformedInput, err.Error())
status, output = responseJson(nil, session.fail(irmaserver.ErrorMalformedInput, err.Error()))
return
}
return handleGetSession(session, min, max)
status, output = responseJson(session.handleGetSession(min, max))
return
}
return failSession(session, irmaserver.ErrorInvalidRequest, "")
status, output = responseJson(nil, session.fail(irmaserver.ErrorInvalidRequest, ""))
return
default:
if method == "POST" {
if verb == "commitments" && session.action == irma.ActionIssuing {
commitments := &gabi.IssueCommitmentMessage{}
if err := irma.UnmarshalValidate(message, commitments); err != nil {
return failSession(session, irmaserver.ErrorMalformedInput, "")
status, output = responseJson(nil, session.fail(irmaserver.ErrorMalformedInput, ""))
return
}
return handlePostCommitments(session, commitments)
status, output = responseJson(session.handlePostCommitments(commitments))
return
}
if verb == "proofs" && session.action == irma.ActionDisclosing {
proofs := gabi.ProofList{}
if err := irma.UnmarshalValidate(message, &proofs); err != nil {
return failSession(session, irmaserver.ErrorMalformedInput, "")
status, output = responseJson(nil, session.fail(irmaserver.ErrorMalformedInput, ""))
return
}
return handlePostProofs(session, proofs)
status, output = responseJson(session.handlePostProofs(proofs))
return
}
if verb == "proofs" && session.action == irma.ActionSigning {
signature := &irma.SignedMessage{}
if err := irma.UnmarshalValidate(message, signature); err != nil {
return failSession(session, irmaserver.ErrorMalformedInput, "")
status, output = responseJson(nil, session.fail(irmaserver.ErrorMalformedInput, ""))
return
}
return handlePostSignature(session, signature)
status, output = responseJson(session.handlePostSignature(signature))
return
}
}
if method == "GET" && verb == "status" {
return handleGetStatus(session)
status, output = responseJson(handleGetStatus(session), nil)
return
}
return failSession(session, irmaserver.ErrorInvalidRequest, "")
status, output = responseJson(nil, session.fail(irmaserver.ErrorInvalidRequest, ""))
return
}
}
......@@ -12,63 +12,50 @@ import (
var conf *irmaserver.Configuration
func handleDelete(session *session) (int, []byte, *irmaserver.SessionResult) {
var res *irmaserver.SessionResult
if session.alive() {
res = &irmaserver.SessionResult{Token: session.token} // TODO what to return here?
func (session *session) handleDelete() {
if !session.alive() {
return
}
session.result = &irmaserver.SessionResult{Token: session.token} // TODO what to return here?
session.status = irmaserver.StatusCancelled
return http.StatusOK, nil, res
}
func handleGetSession(session *session, min, max *irma.ProtocolVersion) (int, []byte, *irmaserver.SessionResult) {
func (session *session) handleGetSession(min, max *irma.ProtocolVersion) (irma.SessionRequest, *irma.RemoteError) {
var err error
session.status = irmaserver.StatusConnected
if session.version, err = chooseProtocolVersion(min, max); err != nil {
return failSession(session, irmaserver.ErrorProtocolVersion, "")
return nil, session.fail(irmaserver.ErrorProtocolVersion, "")
}
session.request.SetVersion(session.version)
s, b := responseJson(session.request)
return s, b, nil
return session.request, nil
}
func handleGetStatus(session *session) (int, []byte, *irmaserver.SessionResult) {
b, _ := json.Marshal(session.status)
return http.StatusOK, b, nil
func handleGetStatus(session *session) irmaserver.Status {
return session.status
}
func handlePostCommitments(session *session, commitments *gabi.IssueCommitmentMessage) (int, []byte, *irmaserver.SessionResult) {
return session.issue(commitments)
}
func handlePostSignature(session *session, signature *irma.SignedMessage) (int, []byte, *irmaserver.SessionResult) {
func (session *session) handlePostSignature(signature *irma.SignedMessage) (irma.ProofStatus, *irma.RemoteError) {
session.signature = signature
session.disclosed, session.proofStatus = signature.Verify(conf.IrmaConfiguration, session.request.(*irma.SignatureRequest))
s, b := responseJson(session.proofStatus)
return s, b, finishSession(session)
session.finish()
return session.proofStatus, nil
}
func handlePostProofs(session *session, proofs gabi.ProofList) (int, []byte, *irmaserver.SessionResult) {
func (session *session) handlePostProofs(proofs gabi.ProofList) (irma.ProofStatus, *irma.RemoteError) {
session.disclosed, session.proofStatus = irma.ProofList(proofs).Verify(conf.IrmaConfiguration, session.request.(*irma.DisclosureRequest))
s, b := responseJson(session.proofStatus)
return s, b, finishSession(session)
session.finish()
return session.proofStatus, nil
}
func responseJson(v interface{}) (int, []byte) {
b, err := json.Marshal(v)
if err != nil {
return http.StatusInternalServerError, nil // TODO
}
return http.StatusOK, b
}
// Session helpers
func (session *session) alive() bool {
return session.status != irmaserver.StatusDone && session.status != irmaserver.StatusCancelled
}
func finishSession(session *session) *irmaserver.SessionResult {
func (session *session) finish() {
session.status = irmaserver.StatusDone
return &irmaserver.SessionResult{
session.result = &irmaserver.SessionResult{
Token: session.token,
Status: session.proofStatus,
Disclosed: session.disclosed,
......@@ -76,23 +63,38 @@ func finishSession(session *session) *irmaserver.SessionResult {
}
}
func failSession(session *session, err irmaserver.Error, message string) (int, []byte, *irmaserver.SessionResult) {
rerr := &irma.RemoteError{
func (session *session) fail(err irmaserver.Error, message string) *irma.RemoteError {
rerr := getError(err, message)
session.status = irmaserver.StatusCancelled
session.result = &irmaserver.SessionResult{Err: rerr, Token: session.token}
return rerr
}
// Output helpers
func getError(err irmaserver.Error, message string) *irma.RemoteError {
stack := string(debug.Stack())
conf.Logger.Errorf("Error: %d %s %s\n%s", err.Status, err.Type, message, stack)
return &irma.RemoteError{
Status: err.Status,
Description: err.Description,
ErrorName: string(err.Type),
Message: message,
Stacktrace: string(debug.Stack()),
Stacktrace: stack,
}
conf.Logger.Errorf("Error: %d %s %s\n%s", rerr.Status, rerr.ErrorName, rerr.Message, rerr.Stacktrace)
}
var res *irmaserver.SessionResult
if session != nil {
if session.alive() {
res = &irmaserver.SessionResult{Err: rerr, Token: session.token}
}
session.status = irmaserver.StatusCancelled
func responseJson(v interface{}, err *irma.RemoteError) (int, []byte) {
msg := v
status := http.StatusOK
if err != nil {
msg = err
status = err.Status
}
b, e := json.Marshal(msg)
if e != nil {
conf.Logger.Error("Failed to serialize response:", e.Error())
return http.StatusInternalServerError, nil
}
b, _ := json.Marshal(rerr)
return err.Status, b, res
return status, b
}
......@@ -83,18 +83,18 @@ func (session *session) getProofP(commitments *gabi.IssueCommitmentMessage, sche
return session.kssProofs[scheme], nil
}
func (session *session) issue(commitments *gabi.IssueCommitmentMessage) (int, []byte, *irmaserver.SessionResult) {
func (session *session) handlePostCommitments(commitments *gabi.IssueCommitmentMessage) ([]*gabi.IssueSignatureMessage, *irma.RemoteError) {
request := session.request.(*irma.IssuanceRequest)
discloseCount := len(request.Disclose)
if len(commitments.Proofs) != len(request.Credentials)+discloseCount {
return failSession(session, irmaserver.ErrorAttributesMissing, "")
return nil, session.fail(irmaserver.ErrorAttributesMissing, "")
}
// Compute list of public keys against which to verify the received proofs
disclosureproofs := irma.ProofList(commitments.Proofs[:discloseCount])
pubkeys, err := disclosureproofs.ExtractPublicKeys(conf.IrmaConfiguration)
if err != nil {
return failSession(session, irmaserver.ErrorInvalidProofs, err.Error())
return nil, session.fail(irmaserver.ErrorInvalidProofs, err.Error())
}
for _, cred := range request.Credentials {
iss := cred.CredentialTypeID.IssuerIdentifier()
......@@ -109,7 +109,7 @@ func (session *session) issue(commitments *gabi.IssueCommitmentMessage) (int, []
if conf.IrmaConfiguration.SchemeManagers[schemeid].Distributed() {
proofP, err := session.getProofP(commitments, schemeid)
if err != nil {
failSession(session, irmaserver.ErrorKeyshareProofMissing, err.Error())
session.fail(irmaserver.ErrorKeyshareProofMissing, err.Error())
}
proof.MergeProofP(proofP, pubkey)
}
......@@ -119,7 +119,7 @@ func (session *session) issue(commitments *gabi.IssueCommitmentMessage) (int, []
session.disclosed, session.proofStatus = irma.ProofList(commitments.Proofs).VerifyAgainstDisjunctions(
conf.IrmaConfiguration, request.Disclose, request.Context, request.Nonce, pubkeys, false)
if session.proofStatus != irma.ProofStatusValid {
return failSession(session, irmaserver.ErrorInvalidProofs, "")
return nil, session.fail(irmaserver.ErrorInvalidProofs, "")
}
// Compute CL signatures
......@@ -131,15 +131,15 @@ func (session *session) issue(commitments *gabi.IssueCommitmentMessage) (int, []
proof := commitments.Proofs[i+discloseCount].(*gabi.ProofU)
attributes, err := cred.AttributeList(conf.IrmaConfiguration, 0x03)
if err != nil {
return failSession(session, irmaserver.ErrorUnknown, err.Error())
return nil, session.fail(irmaserver.ErrorUnknown, err.Error())
}
sig, err := issuer.IssueSignature(proof.U, attributes.Ints, commitments.Nonce2)
if err != nil {
return failSession(session, irmaserver.ErrorUnknown, err.Error())
return nil, session.fail(irmaserver.ErrorUnknown, err.Error())
}
sigs = append(sigs, sig)
}
s, b := responseJson(sigs)
return s, b, finishSession(session)
session.finish()
return sigs, nil
}
......@@ -26,6 +26,7 @@ type session struct {
proofStatus irma.ProofStatus
disclosed []*irma.DisclosedAttribute
signature *irma.SignedMessage
result *irmaserver.SessionResult
kssProofs map[irma.SchemeManagerIdentifier]*gabi.ProofP
}
......
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