descriptions.go 4.87 KB
Newer Older
1
2
3
4
5
package irmago

import (
	"encoding/xml"

6
7
	"errors"

8
9
10
11
12
	"github.com/mhe/gabi"
)

// SchemeManager describes a scheme manager.
type SchemeManager struct {
13
14
	ID                string           `xml:"Id"`
	Name              TranslatedString `xml:"Name"`
15
16
17
18
19
20
21
22
23
24
25
	URL               string           `xml:"Contact"`
	Description       TranslatedString
	KeyshareServer    string
	KeyshareWebsite   string
	KeyshareAttribute string
	XMLVersion        int      `xml:"version,attr"`
	XMLName           xml.Name `xml:"SchemeManager"`
}

// Issuer describes an issuer.
type Issuer struct {
26
27
28
29
30
31
32
33
	ID              string           `xml:"ID"`
	Name            TranslatedString `xml:"Name"`
	ShortName       TranslatedString `xml:"ShortName"`
	SchemeManagerID string           `xml:"SchemeManager"`
	ContactAddress  string
	ContactEMail    string
	URL             string `xml:"baseURL"`
	XMLVersion      int    `xml:"version,attr"`
34
35
36
37
}

// CredentialType is a description of a credential type, specifying (a.o.) its name, issuer, and attributes.
type CredentialType struct {
38
39
40
41
42
43
44
45
46
47
	ID              string           `xml:"CredentialID"`
	Name            TranslatedString `xml:"Name"`
	ShortName       TranslatedString `xml:"ShortName"`
	IssuerID        string           `xml:"IssuerID"`
	SchemeManagerID string           `xml:"SchemeManager"`
	IsSingleton     bool             `xml:"ShouldBeSingleton"`
	Description     TranslatedString
	Attributes      []AttributeDescription `xml:"Attributes>Attribute"`
	XMLVersion      int                    `xml:"version,attr"`
	XMLName         xml.Name               `xml:"IssueSpecification"`
48
49
}

50
51
// ContainsAttribute tests whether the specified attribute is contained in this
// credentialtype.
52
func (ct *CredentialType) ContainsAttribute(ai AttributeTypeIdentifier) bool {
53
	if ai.CredentialTypeIdentifier().String() != ct.Identifier().String() {
54
55
56
57
58
59
60
61
62
63
		return false
	}
	for _, desc := range ct.Attributes {
		if desc.ID == ai.Name() {
			return true
		}
	}
	return false
}

64
65
66
67
68
69
70
// AttributeDescription is a description of an attribute within a credential type.
type AttributeDescription struct {
	ID          string `xml:"id,attr"`
	Name        TranslatedString
	Description TranslatedString
}

Sietse Ringers's avatar
Sietse Ringers committed
71
72
// IndexOf returns the index of the specified attribute if present,
// or an error (and -1) if not present.
73
74
75
76
77
78
79
80
81
82
83
84
func (ct CredentialType) IndexOf(ai AttributeTypeIdentifier) (int, error) {
	if ai.CredentialTypeIdentifier() != ct.Identifier() {
		return -1, errors.New("Wrong credential type")
	}
	for i, description := range ct.Attributes {
		if description.ID == ai.Name() {
			return i, nil
		}
	}
	return -1, errors.New("Attribute identifier not found")
}

Sietse Ringers's avatar
Sietse Ringers committed
85
86
// TranslatedString is a map of translated strings.
type TranslatedString map[string]string
87

Sietse Ringers's avatar
Sietse Ringers committed
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
// UnmarshalXML unmarshals an XML tag containing a string translated to multiple languages,
// for example: <Foo><en>Hello world</en><nl>Hallo wereld</nl></Foo>
// into a TranslatedString: { "en": "Hello world" , "nl": "Hallo wereld" }
func (ts *TranslatedString) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
	if map[string]string(*ts) == nil {
		*ts = TranslatedString(make(map[string]string))
	}
	temp := &struct {
		Translations []struct {
			XMLName xml.Name
			Text    string `xml:",chardata"`
		} `xml:",any"`
	}{}
	if err := d.DecodeElement(temp, &start); err != nil {
		return err
	}
	for _, translation := range temp.Translations {
		(*ts)[translation.XMLName.Local] = translation.Text
106
	}
Sietse Ringers's avatar
Sietse Ringers committed
107
	return nil
108
109
110
}

// Identifier returns the identifier of the specified credential type.
111
112
func (ct *CredentialType) Identifier() CredentialTypeIdentifier {
	return NewCredentialTypeIdentifier(ct.SchemeManagerID + "." + ct.IssuerID + "." + ct.ID)
113
114
115
}

// IssuerIdentifier returns the issuer identifier of the specified credential type.
116
117
func (ct *CredentialType) IssuerIdentifier() IssuerIdentifier {
	return NewIssuerIdentifier(ct.SchemeManagerID + "." + ct.IssuerID)
118
119
120
}

// Identifier returns the identifier of the specified issuer description.
121
122
123
124
125
126
127
func (id *Issuer) Identifier() IssuerIdentifier {
	return NewIssuerIdentifier(id.SchemeManagerID + "." + id.ID)
}

// Identifier returns the identifier of the specified scheme manager.
func (sm *SchemeManager) Identifier() SchemeManagerIdentifier {
	return NewSchemeManagerIdentifier(sm.ID)
128
129
}

130
// Distributed indicates if this scheme manager uses a keyshare server.
Sietse Ringers's avatar
Sietse Ringers committed
131
132
133
134
func (sm *SchemeManager) Distributed() bool {
	return len(sm.KeyshareServer) > 0
}

135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
// CurrentPublicKey returns the latest known public key of the issuer identified by this instance.
func (id *Issuer) CurrentPublicKey() *gabi.PublicKey {
	keys := MetaStore.PublicKeys[id.Identifier()]
	if keys == nil || len(keys) == 0 {
		return nil
	}
	return keys[len(keys)-1]
}

// PublicKey returns the specified public key of the issuer identified by this instance.
func (id *Issuer) PublicKey(index int) *gabi.PublicKey {
	keys := MetaStore.PublicKeys[id.Identifier()]
	if keys == nil || index >= len(keys) {
		return nil
	}
	return keys[index]
}