Commit 2bb5e341 authored by Sietse Ringers's avatar Sietse Ringers
Browse files

Simplify log structure

parent fbfb8574
......@@ -48,7 +48,7 @@ type MetadataAttribute struct {
type AttributeList struct {
*MetadataAttribute `json:"-"`
Ints []*big.Int
strings []string
strings []TranslatedString
info *CredentialInfo
}
......@@ -77,29 +77,41 @@ func (al *AttributeList) hash() string {
}
// Strings converts the current instance to human-readable strings.
func (al *AttributeList) Strings() []string {
func (al *AttributeList) Strings() []TranslatedString {
if al.strings == nil {
al.strings = make([]string, len(al.Ints)-1)
al.strings = make([]TranslatedString, len(al.Ints)-1)
for index, num := range al.Ints[1:] { // skip metadata
al.strings[index] = string(num.Bytes())
al.strings[index] = map[string]string{"en": string(num.Bytes()), "nl": string(num.Bytes())} // TODO
}
}
return al.strings
}
// Attribute returns the content of the specified attribute, or "" if not present in this attribute list.
func (al *AttributeList) Attribute(identifier AttributeTypeIdentifier) string {
func (al *AttributeList) untranslatedAttribute(identifier AttributeTypeIdentifier) string {
if al.CredentialType().Identifier() != identifier.CredentialTypeIdentifier() {
return ""
}
for i, desc := range al.CredentialType().Attributes {
if desc.ID == string(identifier.Name()) {
return al.Strings()[i]
return string(al.Ints[i+1].Bytes())
}
}
return ""
}
// Attribute returns the content of the specified attribute, or "" if not present in this attribute list.
func (al *AttributeList) Attribute(identifier AttributeTypeIdentifier) TranslatedString {
if al.CredentialType().Identifier() != identifier.CredentialTypeIdentifier() {
return nil
}
for i, desc := range al.CredentialType().Attributes {
if desc.ID == string(identifier.Name()) {
return al.Strings()[i]
}
}
return nil
}
// MetadataFromInt wraps the given Int
func MetadataFromInt(i *big.Int, store *ConfigurationStore) *MetadataAttribute {
return &MetadataAttribute{Int: i, store: store}
......
......@@ -16,6 +16,8 @@ import (
func TestMain(m *testing.M) {
retCode := m.Run()
// TODO make testdata/storage
err := os.RemoveAll("testdata/storage/test")
if err != nil {
fmt.Println("Could not delete test storage")
......@@ -197,9 +199,13 @@ func TestUnmarshaling(t *testing.T) {
sessionjwt, _, err := entry.Jwt()
require.NoError(t, err)
require.Equal(t, "testip", sessionjwt.(*IdentityProviderJwt).ServerName)
require.NoError(t, err)
require.NotEmpty(t, entry.Disclosed)
require.NotEmpty(t, entry.Received)
response, err := entry.GetResponse()
require.NoError(t, err)
require.NotEmpty(t, response.(*IssuanceLog).Proofs)
require.NotNil(t, response)
require.IsType(t, &gabi.IssueCommitmentMessage{}, response)
teardown(t)
}
......
......@@ -165,33 +165,3 @@ type logSessionInfo struct {
Context *big.Int `json:"context"`
Keys map[string]int `json:"keys"`
}
// TODO remove on protocol upgrade
func (entry *LogEntry) MarshalJSON() ([]byte, error) {
resp := entry.raw
if len(resp) == 0 {
if bytes, err := json.Marshal(entry.Response); err == nil {
resp = json.RawMessage(bytes)
} else {
return nil, err
}
}
temp := &jsonLogEntry{
Type: entry.Type,
Time: entry.Time,
Response: resp,
SessionInfo: &logSessionInfo{
Jwt: entry.SessionInfo.Jwt,
Nonce: entry.SessionInfo.Nonce,
Context: entry.SessionInfo.Context,
Keys: make(map[string]int),
},
}
for iss, count := range entry.SessionInfo.Keys {
temp.SessionInfo.Keys[iss.String()] = count
}
return json.Marshal(temp)
}
......@@ -10,70 +10,82 @@ import (
)
type LogEntry struct {
// General info
Type Action
Time Timestamp // Time at which the session was completed
SessionInfo *SessionInfo // Message that started the session
Response interface{} // Session-type specific info, parsed on-demand, use .GetResponse()
raw json.RawMessage
}
type RemovalLog struct {
Credential CredentialTypeIdentifier
}
type VerificationLog struct {
Proofs []*gabi.ProofD
}
// Session type-specific info
RemovedCredential CredentialTypeIdentifier // In case of credential removal
Disclosed map[CredentialTypeIdentifier]map[int]TranslatedString // Any session type
Received map[CredentialTypeIdentifier][]TranslatedString // In case of issuance session
SignedMessage []byte // In case of signature sessions
SignedMessageType string // In case of signature sessions
type IssuanceLog struct {
Proofs []*gabi.ProofD
AttributeList []*AttributeList
response interface{} // Our response (ProofList or IssueCommitmentMessage)
rawResponse json.RawMessage // Unparsed []byte version of response
}
type SigningLog struct {
Proofs []*gabi.ProofD
Message []byte
MessageType string
}
func (session *session) createLogEntry(response gabi.ProofList) (*LogEntry, error) {
func (session *session) createLogEntry(response interface{}) (*LogEntry, error) {
entry := &LogEntry{
Type: session.Action,
Time: Timestamp(time.Now()),
SessionInfo: session.info,
response: response,
}
proofs := []*gabi.ProofD{}
for _, proof := range response {
if proofd, isproofd := proof.(*gabi.ProofD); isproofd {
proofs = append(proofs, proofd)
}
}
// Populate session type-specific fields of the log entry (except for .Disclosed which is handled below)
var prooflist gabi.ProofList
var ok bool
switch entry.Type {
case ActionSigning:
entry.SignedMessage = []byte(session.jwt.(*SignatureRequestorJwt).Request.Request.Message)
entry.SignedMessageType = session.jwt.(*SignatureRequestorJwt).Request.Request.MessageType
fallthrough
case ActionDisclosing:
item := &VerificationLog{Proofs: proofs}
entry.Response = item
if prooflist, ok = response.(gabi.ProofList); !ok {
return nil, errors.New("Response was not a ProofList")
}
case ActionIssuing:
item := &IssuanceLog{Proofs: proofs}
if entry.Received == nil {
entry.Received = map[CredentialTypeIdentifier][]TranslatedString{}
}
for _, req := range session.jwt.(*IdentityProviderJwt).Request.Request.Credentials {
list, err := req.AttributeList(session.credManager.ConfigurationStore)
if err != nil {
continue // TODO?
}
item.AttributeList = append(item.AttributeList, list)
entry.Received[list.CredentialType().Identifier()] = list.Strings()
}
var msg *gabi.IssueCommitmentMessage
if msg, ok = response.(*gabi.IssueCommitmentMessage); ok {
prooflist = msg.Proofs
} else {
return nil, errors.New("Response was not a *IssueCommitmentMessage")
}
entry.Response = item
case ActionSigning:
item := SigningLog{Proofs: proofs}
item.Message = []byte(session.jwt.(*SignatureRequestorJwt).Request.Request.Message)
item.MessageType = session.jwt.(*SignatureRequestorJwt).Request.Request.MessageType
entry.Response = item
default:
return nil, errors.New("Invalid log type")
}
// Populate the list of disclosed attributes .Disclosed
for _, proof := range prooflist {
if proofd, isproofd := proof.(*gabi.ProofD); isproofd {
if entry.Disclosed == nil {
entry.Disclosed = map[CredentialTypeIdentifier]map[int]TranslatedString{}
}
meta := MetadataFromInt(proofd.ADisclosed[1], session.credManager.ConfigurationStore)
id := meta.CredentialType().Identifier()
entry.Disclosed[id] = map[int]TranslatedString{}
for i, attr := range proofd.ADisclosed {
if i == 1 {
continue
}
val := string(attr.Bytes())
entry.Disclosed[id][i] = TranslatedString{"en": val, "nl": val}
}
}
}
return entry, nil
}
......@@ -82,33 +94,40 @@ func (entry *LogEntry) Jwt() (RequestorJwt, string, error) {
}
func (entry *LogEntry) GetResponse() (interface{}, error) {
if entry.Response == nil {
if entry.response == nil {
switch entry.Type {
case Action("removal"):
return nil, nil
case ActionSigning:
fallthrough
case ActionDisclosing:
entry.Response = &VerificationLog{}
entry.response = []*gabi.ProofD{}
case ActionIssuing:
entry.Response = &IssuanceLog{}
case ActionSigning:
entry.Response = &SigningLog{}
case Action("removal"):
entry.Response = &RemovalLog{}
entry.response = &gabi.IssueCommitmentMessage{}
default:
return nil, errors.New("Invalid log type")
}
err := json.Unmarshal(entry.raw, entry.Response)
err := json.Unmarshal(entry.rawResponse, entry.response)
if err != nil {
return nil, err
}
}
return entry.Response, nil
return entry.response, nil
}
type jsonLogEntry struct {
Type Action
Time Timestamp
SessionInfo *logSessionInfo
Response json.RawMessage
RemovedCredential string `json:",omitempty"`
Disclosed map[CredentialTypeIdentifier]map[int]TranslatedString `json:",omitempty"`
Received map[CredentialTypeIdentifier][]TranslatedString `json:",omitempty"`
SignedMessage []byte `json:",omitempty"`
SignedMessageType string `json:",omitempty"`
Response json.RawMessage
}
func (entry *LogEntry) UnmarshalJSON(bytes []byte) error {
......@@ -127,7 +146,12 @@ func (entry *LogEntry) UnmarshalJSON(bytes []byte) error {
Context: temp.SessionInfo.Context,
Keys: make(map[IssuerIdentifier]int),
},
raw: temp.Response,
RemovedCredential: NewCredentialTypeIdentifier(temp.RemovedCredential),
Disclosed: temp.Disclosed,
Received: temp.Received,
SignedMessage: temp.SignedMessage,
SignedMessageType: temp.SignedMessageType,
rawResponse: temp.Response,
}
// TODO remove on protocol upgrade
......@@ -137,3 +161,38 @@ func (entry *LogEntry) UnmarshalJSON(bytes []byte) error {
return nil
}
func (entry *LogEntry) MarshalJSON() ([]byte, error) {
// If the entry was created using createLogEntry(), then entry.rawResponse == nil
if len(entry.rawResponse) == 0 && entry.response != nil {
if bytes, err := json.Marshal(entry.response); err == nil {
entry.rawResponse = json.RawMessage(bytes)
} else {
return nil, err
}
}
temp := &jsonLogEntry{
Type: entry.Type,
Time: entry.Time,
Response: entry.rawResponse,
SessionInfo: &logSessionInfo{
Jwt: entry.SessionInfo.Jwt,
Nonce: entry.SessionInfo.Nonce,
Context: entry.SessionInfo.Context,
Keys: make(map[string]int),
},
RemovedCredential: entry.RemovedCredential.String(),
Disclosed: entry.Disclosed,
Received: entry.Received,
SignedMessage: entry.SignedMessage,
SignedMessageType: entry.SignedMessageType,
}
// TODO remove on protocol upgrade
for iss, count := range entry.SessionInfo.Keys {
temp.SessionInfo.Keys[iss.String()] = count
}
return json.Marshal(temp)
}
......@@ -166,7 +166,7 @@ func (cm *CredentialManager) Candidates(disjunction *AttributeDisjunction) []*At
candidates = append(candidates, id)
} else {
attrs := cred.AttributeList()
val := attrs.Attribute(attribute)
val := attrs.untranslatedAttribute(attribute)
if val == "" { // This won't handle empty attributes correctly
continue
}
......
......@@ -273,7 +273,7 @@ func (session *session) sendResponse(message interface{}) {
session.fail(&Error{Err: err, ErrorCode: ErrorCrypto})
return
}
log, err = session.createLogEntry(message.(*gabi.IssueCommitmentMessage).Proofs) // TODO err
log, err = session.createLogEntry(message) // TODO err
}
session.credManager.addLogEntry(log) // TODO err
......
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