Commit 855ea196 authored by Sietse Ringers's avatar Sietse Ringers
Browse files

feat: Breaking change: support conjunctions of disjunctions of conjunctions...

feat: Breaking change: support conjunctions of disjunctions of conjunctions when requesting attributes in any of the three supported session types

Instead of requesting several attributes, one can now request several groups of attributes. Within each such group, attributes belonging to the same credential type always come from the same credential instance. This affects all three session types, as in each of them attributes can be disclosed.
parent f5c59478
...@@ -4,10 +4,8 @@ import ( ...@@ -4,10 +4,8 @@ import (
"crypto/sha256" "crypto/sha256"
"encoding/binary" "encoding/binary"
"encoding/hex" "encoding/hex"
"encoding/json"
"time" "time"
"github.com/go-errors/errors"
"github.com/privacybydesign/gabi" "github.com/privacybydesign/gabi"
"github.com/privacybydesign/gabi/big" "github.com/privacybydesign/gabi/big"
) )
...@@ -328,173 +326,3 @@ func shortToByte(x int) []byte { ...@@ -328,173 +326,3 @@ func shortToByte(x int) []byte {
binary.BigEndian.PutUint16(bytes, uint16(x)) binary.BigEndian.PutUint16(bytes, uint16(x))
return bytes return bytes
} }
// A DisclosureChoice contains the attributes chosen to be disclosed.
type DisclosureChoice struct {
Attributes []*AttributeIdentifier
}
// An AttributeDisjunction encapsulates a list of possible attributes, one
// of which should be disclosed.
type AttributeDisjunction struct {
Label string
Attributes []AttributeTypeIdentifier
Values map[AttributeTypeIdentifier]*string
selected *AttributeTypeIdentifier
value *string
index *int
}
// An AttributeDisjunctionList is a list of AttributeDisjunctions.
type AttributeDisjunctionList []*AttributeDisjunction
// HasValues indicates if the attributes of this disjunction have values
// that should be satisfied.
func (disjunction *AttributeDisjunction) HasValues() bool {
return disjunction.Values != nil && len(disjunction.Values) != 0
}
// attemptSatisfy tries to match the specified attribute type and value against the current disjunction,
// returning true if the disjunction contains the specified attribute type. Note that if the disjunction
// has required values, then it is only considered satisfied by the specified attribute type and value
// if the required value matches the specified value.
func (disjunction *AttributeDisjunction) attemptSatisfy(id AttributeTypeIdentifier, value *string) bool {
var found bool
for index, attr := range disjunction.Attributes {
if attr == id {
found = true
disjunction.selected = &id
disjunction.index = &index
disjunction.value = value
if !disjunction.HasValues() || disjunction.Values[id] == value {
return true
}
}
}
return found
}
// satisfied indicates if this disjunction has a valid attribute type and value selected,
// matching one of the attributes in the disjunction and possibly also the corresponding required value.
func (disjunction *AttributeDisjunction) satisfied() bool {
if disjunction.index == nil {
return false
}
attr := disjunction.Attributes[*disjunction.index]
return !disjunction.HasValues() || disjunction.value == disjunction.Values[attr]
}
// MatchesConfig returns true if all attributes contained in the disjunction are
// present in the specified configuration.
func (disjunction *AttributeDisjunction) MatchesConfig(conf *Configuration) bool {
for ai := range disjunction.Values {
creddescription, exists := conf.CredentialTypes[ai.CredentialTypeIdentifier()]
if !exists {
return false
}
if !creddescription.ContainsAttribute(ai) {
return false
}
}
return true
}
// satisfied indicates whether each contained attribute disjunction has a chosen attribute.
func (dl AttributeDisjunctionList) satisfied() bool {
for _, disjunction := range dl {
if !disjunction.satisfied() {
return false
}
}
return true
}
// Find searches for and returns the disjunction that contains the specified attribute identifier, or nil if not found.
func (dl AttributeDisjunctionList) Find(ai AttributeTypeIdentifier) *AttributeDisjunction {
for _, disjunction := range dl {
for _, attr := range disjunction.Attributes {
if attr == ai {
return disjunction
}
}
}
return nil
}
// MarshalJSON marshals the disjunction to JSON.
func (disjunction *AttributeDisjunction) MarshalJSON() ([]byte, error) {
if !disjunction.HasValues() {
temp := struct {
Label string `json:"label"`
Attributes []AttributeTypeIdentifier `json:"attributes"`
}{
Label: disjunction.Label,
Attributes: disjunction.Attributes,
}
return json.Marshal(temp)
}
temp := struct {
Label string `json:"label"`
Attributes map[AttributeTypeIdentifier]*string `json:"attributes"`
}{
Label: disjunction.Label,
Attributes: disjunction.Values,
}
return json.Marshal(temp)
}
// UnmarshalJSON unmarshals an attribute disjunction from JSON.
func (disjunction *AttributeDisjunction) UnmarshalJSON(bytes []byte) error {
if disjunction.Values == nil {
disjunction.Values = make(map[AttributeTypeIdentifier]*string)
}
if disjunction.Attributes == nil {
disjunction.Attributes = make([]AttributeTypeIdentifier, 0, 3)
}
// We don't know if the json element "attributes" is a list, or a map.
// So we unmarshal it into a temporary struct that has interface{} as the
// type of "attributes", so that we can check which of the two it is.
temp := struct {
Label string `json:"label"`
Attributes interface{} `json:"attributes"`
}{}
if err := json.Unmarshal(bytes, &temp); err != nil {
return err
}
disjunction.Label = temp.Label
switch temp.Attributes.(type) {
case map[string]interface{}:
temp := struct {
Label string `json:"label"`
Attributes map[string]*string `json:"attributes"`
}{}
if err := json.Unmarshal(bytes, &temp); err != nil {
return err
}
for str, value := range temp.Attributes {
id := NewAttributeTypeIdentifier(str)
disjunction.Attributes = append(disjunction.Attributes, id)
disjunction.Values[id] = value
}
case []interface{}:
temp := struct {
Label string `json:"label"`
Attributes []string `json:"attributes"`
}{}
if err := json.Unmarshal(bytes, &temp); err != nil {
return err
}
for _, str := range temp.Attributes {
disjunction.Attributes = append(disjunction.Attributes, NewAttributeTypeIdentifier(str))
}
default:
return errors.New("could not parse attribute disjunction: element 'attributes' was incorrect")
}
return nil
}
...@@ -172,6 +172,24 @@ func (id *AttributeTypeIdentifier) UnmarshalText(text []byte) error { ...@@ -172,6 +172,24 @@ func (id *AttributeTypeIdentifier) UnmarshalText(text []byte) error {
return nil return nil
} }
func (set *IrmaIdentifierSet) join(other *IrmaIdentifierSet) {
for scheme := range other.SchemeManagers {
set.SchemeManagers[scheme] = struct{}{}
}
for issuer := range other.Issuers {
set.Issuers[issuer] = struct{}{}
}
for ct := range other.CredentialTypes {
set.CredentialTypes[ct] = struct{}{}
}
for issuer := range other.PublicKeys {
if len(set.PublicKeys[issuer]) == 0 {
set.PublicKeys[issuer] = make([]int, 0, len(other.PublicKeys[issuer]))
}
set.PublicKeys[issuer] = append(set.PublicKeys[issuer], other.PublicKeys[issuer]...)
}
}
func (set *IrmaIdentifierSet) Distributed(conf *Configuration) bool { func (set *IrmaIdentifierSet) Distributed(conf *Configuration) bool {
for id := range set.SchemeManagers { for id := range set.SchemeManagers {
if conf.SchemeManagers[id].Distributed() { if conf.SchemeManagers[id].Distributed() {
......
...@@ -33,7 +33,7 @@ func (session *session) handleGetRequest(min, max *irma.ProtocolVersion) (irma.S ...@@ -33,7 +33,7 @@ func (session *session) handleGetRequest(min, max *irma.ProtocolVersion) (irma.S
return nil, session.fail(server.ErrorProtocolVersion, "") return nil, session.fail(server.ErrorProtocolVersion, "")
} }
session.conf.Logger.WithFields(logrus.Fields{"session": session.token, "version": session.version.String()}).Debugf("Protocol version negotiated") session.conf.Logger.WithFields(logrus.Fields{"session": session.token, "version": session.version.String()}).Debugf("Protocol version negotiated")
session.request.SetVersion(session.version) session.request.Base().Version = session.version
session.setStatus(server.StatusConnected) session.setStatus(server.StatusConnected)
return session.request, nil return session.request, nil
...@@ -127,7 +127,7 @@ func (session *session) handlePostCommitments(commitments *irma.IssueCommitmentM ...@@ -127,7 +127,7 @@ func (session *session) handlePostCommitments(commitments *irma.IssueCommitmentM
// Verify all proofs and check disclosed attributes, if any, against request // Verify all proofs and check disclosed attributes, if any, against request
session.result.Disclosed, session.result.ProofStatus, err = commitments.Disclosure().VerifyAgainstDisjunctions( session.result.Disclosed, session.result.ProofStatus, err = commitments.Disclosure().VerifyAgainstDisjunctions(
session.conf.IrmaConfiguration, request.Disclose, request.Context, request.Nonce, pubkeys, false) session.conf.IrmaConfiguration, request.Disclose, request.GetContext(), request.GetNonce(), pubkeys, false)
if err != nil { if err != nil {
if err == irma.ErrorMissingPublicKey { if err == irma.ErrorMissingPublicKey {
return nil, session.fail(server.ErrorUnknownPublicKey, "") return nil, session.fail(server.ErrorUnknownPublicKey, "")
......
...@@ -153,10 +153,13 @@ func purgeRequest(request irma.RequestorRequest) irma.RequestorRequest { ...@@ -153,10 +153,13 @@ func purgeRequest(request irma.RequestorRequest) irma.RequestorRequest {
_ = json.Unmarshal(bts, cpy) _ = json.Unmarshal(bts, cpy)
// Remove required attribute values from any attributes to be disclosed // Remove required attribute values from any attributes to be disclosed
attrs := cpy.(irma.RequestorRequest).SessionRequest().ToDisclose() _ = cpy.(irma.RequestorRequest).SessionRequest().Disclosure().Disclose.Iterate(
for _, disjunction := range attrs { func(attr *irma.AttributeRequest) error {
disjunction.Values = nil attr.Value = nil
} return nil
},
)
// Remove attribute values from attributes to be issued // Remove attribute values from attributes to be issued
if isreq, ok := cpy.(*irma.IdentityProviderRequest); ok { if isreq, ok := cpy.(*irma.IdentityProviderRequest); ok {
for _, cred := range isreq.Request.Credentials { for _, cred := range isreq.Request.Credentials {
......
...@@ -162,8 +162,8 @@ func (s *Server) newSession(action irma.Action, request irma.RequestorRequest) * ...@@ -162,8 +162,8 @@ func (s *Server) newSession(action irma.Action, request irma.RequestorRequest) *
s.conf.Logger.WithFields(logrus.Fields{"session": ses.token}).Debug("New session started") s.conf.Logger.WithFields(logrus.Fields{"session": ses.token}).Debug("New session started")
nonce, _ := gabi.RandomBigInt(gabi.DefaultSystemParameters[2048].Lstatzk) nonce, _ := gabi.RandomBigInt(gabi.DefaultSystemParameters[2048].Lstatzk)
ses.request.SetNonce(nonce) ses.request.Base().Nonce = nonce
ses.request.SetContext(one) ses.request.Base().Context = one
s.sessions.add(ses) s.sessions.add(ses)
return ses return ses
......
...@@ -2,7 +2,9 @@ package sessiontest ...@@ -2,7 +2,9 @@ package sessiontest
import ( import (
"encoding/json" "encoding/json"
"math/rand"
"testing" "testing"
"time"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/privacybydesign/irmago" "github.com/privacybydesign/irmago"
...@@ -94,36 +96,32 @@ func (th TestHandler) Failure(err *irma.SessionError) { ...@@ -94,36 +96,32 @@ func (th TestHandler) Failure(err *irma.SessionError) {
th.t.Fatal(err) th.t.Fatal(err)
} }
} }
func (th TestHandler) UnsatisfiableRequest(serverName irma.TranslatedString, missing irma.AttributeDisjunctionList) { func (th TestHandler) UnsatisfiableRequest(serverName irma.TranslatedString, missing map[int]map[int]irma.AttributeCon) {
th.Failure(&irma.SessionError{ th.Failure(&irma.SessionError{
ErrorType: irma.ErrorType("UnsatisfiableRequest"), ErrorType: irma.ErrorType("UnsatisfiableRequest"),
}) })
} }
func (th TestHandler) RequestVerificationPermission(request irma.DisclosureRequest, ServerName irma.TranslatedString, callback irmaclient.PermissionHandler) { func (th TestHandler) RequestVerificationPermission(request *irma.DisclosureRequest, ServerName irma.TranslatedString, callback irmaclient.PermissionHandler) {
choice := &irma.DisclosureChoice{ choice := &irma.DisclosureChoice{
Attributes: []*irma.AttributeIdentifier{}, Attributes: [][]*irma.AttributeIdentifier{},
} }
var candidates []*irma.AttributeIdentifier var candidates [][]*irma.AttributeIdentifier
for _, disjunction := range request.Content { for _, disjunction := range request.Disclose {
candidates = th.client.Candidates(disjunction) candidates, _ = th.client.Candidates(disjunction)
if len(candidates) == 0 { if len(candidates) == 0 {
th.Failure(&irma.SessionError{Err: errors.New("No disclosure candidates found")}) th.Failure(&irma.SessionError{Err: errors.New("No disclosure candidates found")})
} }
choice.Attributes = append(choice.Attributes, candidates[0]) choice.Attributes = append(choice.Attributes, candidates[rand.Intn(len(candidates))])
} }
if len(th.expectedServerName) != 0 { if len(th.expectedServerName) != 0 {
require.Equal(th.t, th.expectedServerName, ServerName) require.Equal(th.t, th.expectedServerName, ServerName)
} }
callback(true, choice) callback(true, choice)
} }
func (th TestHandler) RequestIssuancePermission(request irma.IssuanceRequest, ServerName irma.TranslatedString, callback irmaclient.PermissionHandler) { func (th TestHandler) RequestIssuancePermission(request *irma.IssuanceRequest, ServerName irma.TranslatedString, callback irmaclient.PermissionHandler) {
dreq := irma.DisclosureRequest{ th.RequestVerificationPermission(request.DisclosureRequest, ServerName, callback)
BaseRequest: request.BaseRequest,
Content: request.Disclose,
}
th.RequestVerificationPermission(dreq, ServerName, callback)
} }
func (th TestHandler) RequestSignaturePermission(request irma.SignatureRequest, ServerName irma.TranslatedString, callback irmaclient.PermissionHandler) { func (th TestHandler) RequestSignaturePermission(request *irma.SignatureRequest, ServerName irma.TranslatedString, callback irmaclient.PermissionHandler) {
th.RequestVerificationPermission(request.DisclosureRequest, ServerName, callback) th.RequestVerificationPermission(request.DisclosureRequest, ServerName, callback)
} }
func (th TestHandler) RequestSchemeManagerPermission(manager *irma.SchemeManager, callback func(proceed bool)) { func (th TestHandler) RequestSchemeManagerPermission(manager *irma.SchemeManager, callback func(proceed bool)) {
...@@ -176,10 +174,10 @@ func (th *ManualTestHandler) Success(result string) { ...@@ -176,10 +174,10 @@ func (th *ManualTestHandler) Success(result string) {
th.c <- retval th.c <- retval
} }
func (th *ManualTestHandler) RequestSignaturePermission(request irma.SignatureRequest, requesterName irma.TranslatedString, ph irmaclient.PermissionHandler) { func (th *ManualTestHandler) RequestSignaturePermission(request *irma.SignatureRequest, requesterName irma.TranslatedString, ph irmaclient.PermissionHandler) {
th.RequestVerificationPermission(request.DisclosureRequest, requesterName, ph) th.RequestVerificationPermission(request.DisclosureRequest, requesterName, ph)
} }
func (th *ManualTestHandler) RequestIssuancePermission(request irma.IssuanceRequest, issuerName irma.TranslatedString, ph irmaclient.PermissionHandler) { func (th *ManualTestHandler) RequestIssuancePermission(request *irma.IssuanceRequest, issuerName irma.TranslatedString, ph irmaclient.PermissionHandler) {
ph(true, nil) ph(true, nil)
} }
...@@ -187,10 +185,14 @@ func (th *ManualTestHandler) RequestIssuancePermission(request irma.IssuanceRequ ...@@ -187,10 +185,14 @@ func (th *ManualTestHandler) RequestIssuancePermission(request irma.IssuanceRequ
func (th *ManualTestHandler) RequestSchemeManagerPermission(manager *irma.SchemeManager, callback func(proceed bool)) { func (th *ManualTestHandler) RequestSchemeManagerPermission(manager *irma.SchemeManager, callback func(proceed bool)) {
th.Failure(&irma.SessionError{Err: errors.New("Unexpected session type")}) th.Failure(&irma.SessionError{Err: errors.New("Unexpected session type")})
} }
func (th *ManualTestHandler) RequestVerificationPermission(request irma.DisclosureRequest, verifierName irma.TranslatedString, ph irmaclient.PermissionHandler) { func (th *ManualTestHandler) RequestVerificationPermission(request *irma.DisclosureRequest, verifierName irma.TranslatedString, ph irmaclient.PermissionHandler) {
var choice irma.DisclosureChoice var choice irma.DisclosureChoice
for _, cand := range request.Candidates { for _, cand := range request.Candidates {
choice.Attributes = append(choice.Attributes, cand[0]) choice.Attributes = append(choice.Attributes, cand[0])
} }
ph(true, &choice) ph(true, &choice)
} }
func init() {
rand.Seed(time.Now().UnixNano())
}
...@@ -11,12 +11,12 @@ import ( ...@@ -11,12 +11,12 @@ import (
) )
func TestManualKeyShareSession(t *testing.T) { func TestManualKeyShareSession(t *testing.T) {
request := "{\"nonce\": 0, \"context\": 0, \"type\": \"signing\", \"message\":\"I owe you everything\",\"content\":[{\"label\":\"Student number (RU)\",\"attributes\":[\"test.test.mijnirma.email\"]}]}" request := irma.NewSignatureRequest("I owe you everything", irma.NewAttributeTypeIdentifier("test.test.mijnirma.email"))
ms := createManualSessionHandler(t, nil) ms := createManualSessionHandler(t, nil)
_, status := manualSessionHelper(t, nil, ms, request, request, false) _, status := manualSessionHelper(t, nil, ms, request, request, false)
require.Equal(t, irma.ProofStatusValid, status) require.Equal(t, irma.ProofStatusValid, status)
_, status = manualSessionHelper(t, nil, ms, request, "", false) _, status = manualSessionHelper(t, nil, ms, request, nil, false)
require.Equal(t, irma.ProofStatusValid, status) require.Equal(t, irma.ProofStatusValid, status)
} }
...@@ -44,20 +44,10 @@ func TestKeyshareSessions(t *testing.T) { ...@@ -44,20 +44,10 @@ func TestKeyshareSessions(t *testing.T) {
sessionHelper(t, issuanceRequest, "issue", client) sessionHelper(t, issuanceRequest, "issue", client)
disclosureRequest := getDisclosureRequest(id) disclosureRequest := getDisclosureRequest(id)
disclosureRequest.Content = append(disclosureRequest.Content, disclosureRequest.AddSingle(irma.NewAttributeTypeIdentifier("test.test.mijnirma.email"), nil, nil)
&irma.AttributeDisjunction{
Label: "foo",
Attributes: []irma.AttributeTypeIdentifier{irma.NewAttributeTypeIdentifier("test.test.mijnirma.email")},
},
)
sessionHelper(t, disclosureRequest, "verification", client) sessionHelper(t, disclosureRequest, "verification", client)
sigRequest := getSigningRequest(id) sigRequest := getSigningRequest(id)
sigRequest.Content = append(sigRequest.Content, sigRequest.AddSingle(irma.NewAttributeTypeIdentifier("test.test.mijnirma.email"), nil, nil)
&irma.AttributeDisjunction{
Label: "foo",
Attributes: []irma.AttributeTypeIdentifier{irma.NewAttributeTypeIdentifier("test.test.mijnirma.email")},
},
)
sessionHelper(t, sigRequest, "signature", client) sessionHelper(t, sigRequest, "signature", client)
} }
...@@ -65,8 +65,7 @@ func TestLogging(t *testing.T) { ...@@ -65,8 +65,7 @@ func TestLogging(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, irma.ProofStatusValid, status) require.Equal(t, irma.ProofStatusValid, status)
require.NotEmpty(t, attrs) require.NotEmpty(t, attrs)
require.Equal(t, attrid, attrs[0].Identifier) require.Equal(t, attrid, attrs[0][0].Identifier)
require.Equal(t, "s1234567", attrs[0].Value["en"])
test.ClearTestStorage(t) test.ClearTestStorage(t)
} }
...@@ -49,39 +49,20 @@ func parseStorage(t *testing.T) *irmaclient.Client { ...@@ -49,39 +49,20 @@ func parseStorage(t *testing.T) *irmaclient.Client {
} }
func getDisclosureRequest(id irma.AttributeTypeIdentifier) *irma.DisclosureRequest { func getDisclosureRequest(id irma.AttributeTypeIdentifier) *irma.DisclosureRequest {
return &irma.DisclosureRequest{ return irma.NewDisclosureRequest(id)
BaseRequest: irma.BaseRequest{Type: irma.ActionDisclosing},
Content: irma.AttributeDisjunctionList([]*irma.AttributeDisjunction{{
Label: "foo",
Attributes: []irma.AttributeTypeIdentifier{id},
}}),
}
} }
func getSigningRequest(id irma.AttributeTypeIdentifier) *irma.SignatureRequest { func getSigningRequest(id irma.AttributeTypeIdentifier) *irma.SignatureRequest {
return &irma.SignatureRequest{ return irma.NewSignatureRequest("test", id)
Message: "test",
DisclosureRequest: irma.DisclosureRequest{
BaseRequest: irma.BaseRequest{Type: irma.ActionSigning},
Content: irma.AttributeDisjunctionList([]*irma.AttributeDisjunction{{
Label: "foo",
Attributes: []irma.AttributeTypeIdentifier{id},
}}),
},
}
} }
func getIssuanceRequest(defaultValidity bool) *irma.IssuanceRequest { func getIssuanceRequest(defaultValidity bool) *irma.IssuanceRequest {
temp := irma.Timestamp(irma.FloorToEpochBoundary(time.Now().AddDate(1, 0, 0))) temp := irma.Timestamp(irma.FloorToEpochBoundary(time.Now().AddDate(1, 0, 0)))
var expiry *irma.Timestamp var expiry *irma.Timestamp
if !defaultValidity { if !defaultValidity {
expiry = &temp expiry = &temp
} }
return irma.NewIssuanceRequest([]*irma.CredentialRequest{
return &irma.IssuanceRequest{
BaseRequest: irma.BaseRequest{Type: irma.ActionIssuing},
Credentials: []*irma.CredentialRequest{
{ {
Validity: expiry, Validity: expiry,
CredentialTypeID: irma.NewCredentialTypeIdentifier("irma-demo.RU.studentCard"), CredentialTypeID: irma.NewCredentialTypeIdentifier("irma-demo.RU.studentCard"),
...@@ -92,16 +73,12 @@ func getIssuanceRequest(defaultValidity bool) *irma.IssuanceRequest { ...@@ -92,16 +73,12 @@ func getIssuanceRequest(defaultValidity bool) *irma.IssuanceRequest {
"level": "42", "level": "42",
}, },
}, },
}, })
}
} }
func getNameIssuanceRequest() *irma.IssuanceRequest { func getNameIssuanceRequest() *irma.IssuanceRequest {
expiry := irma.Timestamp(irma.NewMetadataAttribute(0).Expiry()) expiry := irma.Timestamp(irma.NewMetadataAttribute(0).Expiry())
return irma.NewIssuanceRequest([]*irma.CredentialRequest{
req := &irma.IssuanceRequest{
BaseRequest: irma.BaseRequest{Type: irma.ActionIssuing},
Credentials: []*irma.CredentialRequest{
{ {
Validity: &expiry, Validity: &expiry,
CredentialTypeID: irma.NewCredentialTypeIdentifier("irma-demo.MijnOverheid.fullName"), CredentialTypeID: irma.NewCredentialTypeIdentifier("irma-demo.MijnOverheid.fullName"),
...@@ -111,10 +88,8 @@ func getNameIssuanceRequest() *irma.IssuanceRequest { ...@@ -111,10 +88,8 @@ func getNameIssuanceRequest() *irma.IssuanceRequest {
"familyname": "Stuivezand", "familyname": "Stuivezand",
}, },
}, },
}, })
}
return req
} }
func getSpecialIssuanceRequest(defaultValidity bool, attribute string) *irma.IssuanceRequest { func getSpecialIssuanceRequest(defaultValidity bool, attribute string) *irma.IssuanceRequest {
...@@ -125,9 +100,7 @@ func getSpecialIssuanceRequest(defaultValidity bool, attribute string) *irma.Iss ...@@ -125,9 +100,7 @@ func getSpecialIssuanceRequest(defaultValidity bool, attribute string) *irma.Iss
func getCombinedIssuanceRequest(id irma.AttributeTypeIdentifier) *irma.IssuanceRequest { func getCombinedIssuanceRequest(id irma.AttributeTypeIdentifier) *irma.IssuanceRequest {
request := getIssuanceRequest(false) request := getIssuanceRequest(false)
request.Disclose = irma.AttributeDisjunctionList{ request.AddSingle(id, nil, nil)
&irma.AttributeDisjunction{Label: "foo", Attributes: []irma.AttributeTypeIdentifier{id}},
}
return request return request
} }
......
...@@ -23,13 +23,16 @@ func createManualSessionHandler(t *testing.T, client *irmaclient.Client) *Manual ...@@ -23,13 +23,16 @@ func createManualSessionHandler(t *testing.T, client *irmaclient.Client) *Manual
} }
} }