...
 
Commits (237)
*.test
.idea/
testdata/storage/*
!testdata/storage/cardemu.xml
testdata/tmp/*
!testdata/tmp/cardemu.xml
errors_*.go
vendor/
\ No newline at end of file
image: privacybydesign/golang_dep:latest
image: privacybydesign/golang_sql:latest
cache:
key: $CI_COMMIT_REF_SLUG
paths:
- vendor/
- vendor/go/pkg/mod/
stages:
- test
- build
variables:
GOFLAGS: -mod=readonly
GOPATH: ${CI_PROJECT_DIR}/vendor/go
PACKAGE_NAME: github.com/privacybydesign/irmago
PLATFORMS: linux/amd64 darwin/amd64 windows/amd64 linux/arm linux/arm64
before_script:
- set -euxo pipefail
- mkdir -p "$GOPATH/src/$(dirname "$PACKAGE_NAME")"
- ln -s "$CI_PROJECT_DIR" "$GOPATH/src/$PACKAGE_NAME"
- cd "$GOPATH/src/$PACKAGE_NAME"
- dep ensure -v
- service mysql start
- mysql -e "create database test"
- mysql -e "grant all privileges on *.* to 'testuser'@'localhost' identified by 'testpassword'"
- mysql -e "flush privileges"
unit_tests:
stage: test
......@@ -28,6 +30,8 @@ unit_tests:
binaries:
stage: build
artifacts:
# Disabling artifact expiry is not supported yet, so make
expire_in: 100 year
paths:
- artifacts/*
script:
......
This diff is collapsed.
# Gopkg.toml example
#
# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
# for detailed Gopkg.toml documentation.
#
# required = ["github.com/user/thing/cmd/thing"]
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
#
# [[constraint]]
# name = "github.com/user/project"
# version = "1.0.0"
#
# [[constraint]]
# name = "github.com/user/project2"
# branch = "dev"
# source = "github.com/myfork/project2"
#
# [[override]]
# name = "github.com/x/y"
# version = "2.4.0"
#
# [prune]
# non-go = false
# go-tests = true
# unused-packages = true
[[constraint]]
branch = "master"
name = "github.com/getsentry/raven-go"
[[constraint]]
name = "github.com/go-errors/errors"
version = "1.0.0"
[[constraint]]
branch = "master"
name = "github.com/privacybydesign/gabi"
[[constraint]]
name = "github.com/pkg/errors"
version = "0.8.0"
[[constraint]]
name = "github.com/spf13/cobra"
version = "0.0.1"
[[constraint]]
name = "github.com/stretchr/testify"
version = "1.2.1"
[[constraint]]
name = "github.com/spf13/viper"
source = "github.com/sietseringers/viper"
branch = "add-file-key-replacer"
[[override]]
name = "github.com/spf13/pflag"
source = "github.com/sietseringers/pflag"
branch = "headers-in-flag-usage"
[[constraint]]
branch = "master"
name = "github.com/timshannon/bolthold"
[prune]
go-tests = true
unused-packages = true
......@@ -13,16 +13,11 @@ Technical documentation of all components of `irmago` and more can be found at h
## Installing
go get -d -u github.com/privacybydesign/irmago
git clone https://github.com/privacybydesign/irmago
`irmago` and its subpackages use Go modules for their dependencies. The `go` command will automatically download dependencies when needed.
`irmago` and its subpackages uses [`dep`](https://github.com/golang/dep) for its dependencies. After [Installing `dep`](https://golang.github.io/dep/docs/installation.html) if necesssary, run
cd $GOPATH/src/github.com/privacybydesign/irmago
dep ensure
to download and [`vendor`](https://golang.org/cmd/go/#hdr-Vendor_Directories) the correct version of
each dependency. To install the `irma` command line tool:
To install the `irma` command line tool:
go install ./irma
......
......@@ -4,6 +4,7 @@ import (
"crypto/sha256"
"encoding/binary"
"encoding/hex"
"errors"
"time"
"github.com/privacybydesign/gabi"
......@@ -42,6 +43,7 @@ type MetadataAttribute struct {
type AttributeList struct {
*MetadataAttribute `json:"-"`
Ints []*big.Int
Revoked bool `json:",omitempty"`
strings []TranslatedString
attrMap map[AttributeTypeIdentifier]TranslatedString
info *CredentialInfo
......@@ -50,16 +52,18 @@ type AttributeList struct {
// NewAttributeListFromInts initializes a new AttributeList from a list of bigints.
func NewAttributeListFromInts(ints []*big.Int, conf *Configuration) *AttributeList {
return &AttributeList{
al := &AttributeList{
Ints: ints,
MetadataAttribute: MetadataFromInt(ints[0], conf),
}
return al
}
func (al *AttributeList) Info() *CredentialInfo {
if al.info == nil {
al.info = NewCredentialInfo(al.Ints, al.Conf)
}
al.info.Revoked = al.Revoked
return al.info
}
......@@ -97,6 +101,9 @@ func (al *AttributeList) Map(conf *Configuration) map[AttributeTypeIdentifier]Tr
ctid := al.CredentialType().Identifier()
attrTypes := conf.CredentialTypes[ctid].AttributeTypes
for i, val := range al.Strings() {
if attrTypes[i].RevocationAttribute {
continue
}
al.attrMap[attrTypes[i].GetAttributeTypeIdentifier()] = val
}
}
......@@ -233,15 +240,15 @@ func (attr *MetadataAttribute) SigningDate() time.Time {
}
func (attr *MetadataAttribute) setSigningDate() {
attr.setField(signingDateField, shortToByte(int(time.Now().Unix()/ExpiryFactor)))
attr.setField(signingDateField, shortToByte(uint(time.Now().Unix()/ExpiryFactor)))
}
// KeyCounter return the public key counter of the metadata attribute
func (attr *MetadataAttribute) KeyCounter() int {
return int(binary.BigEndian.Uint16(attr.field(keyCounterField)))
func (attr *MetadataAttribute) KeyCounter() uint {
return uint(binary.BigEndian.Uint16(attr.field(keyCounterField)))
}
func (attr *MetadataAttribute) setKeyCounter(i int) {
func (attr *MetadataAttribute) setKeyCounter(i uint) {
attr.setField(keyCounterField, shortToByte(i))
}
......@@ -250,12 +257,14 @@ func (attr *MetadataAttribute) ValidityDuration() int {
return int(binary.BigEndian.Uint16(attr.field(validityField)))
}
func (attr *MetadataAttribute) setValidityDuration(weeks int) {
func (attr *MetadataAttribute) setValidityDuration(weeks uint) {
attr.setField(validityField, shortToByte(weeks))
}
func (attr *MetadataAttribute) setDefaultValidityDuration() {
attr.setExpiryDate(nil)
// setExpiryDate only errors if setting the expiry date before the signing date,
// which never happens here
_ = attr.setExpiryDate(nil)
}
func (attr *MetadataAttribute) setExpiryDate(timestamp *Timestamp) error {
......@@ -266,7 +275,10 @@ func (attr *MetadataAttribute) setExpiryDate(timestamp *Timestamp) error {
expiry = time.Time(*timestamp).Unix()
}
signing := attr.SigningDate().Unix()
attr.setValidityDuration(int((expiry - signing) / ExpiryFactor))
if expiry-signing < 0 {
return errors.New("cannot set expired date")
}
attr.setValidityDuration(uint((expiry - signing) / ExpiryFactor))
return nil
}
......@@ -337,8 +349,11 @@ func (attr *MetadataAttribute) setField(field metadataField, value []byte) {
attr.Int.SetBytes(bytes)
}
func shortToByte(x int) []byte {
func shortToByte(x uint) []byte {
bytes := make([]byte, 2)
if x > 1<<16 {
panic("overflow uint16")
}
binary.BigEndian.PutUint16(bytes, uint16(x))
return bytes
}
......@@ -17,6 +17,7 @@ type CredentialInfo struct {
Expires Timestamp // Unix timestamp
Attributes map[AttributeTypeIdentifier]TranslatedString // Human-readable rendered attributes
Hash string // SHA256 hash over the attributes
Revoked bool // If the credential has been revoked
}
// A CredentialInfoList is a list of credentials (implements sort.Interface).
......
......@@ -6,7 +6,7 @@ import (
"path/filepath"
"github.com/go-errors/errors"
"github.com/privacybydesign/irmago/internal/fs"
"github.com/privacybydesign/irmago/internal/common"
)
// This file contains data types for scheme managers, issuers, credential types
......@@ -57,19 +57,22 @@ type Issuer struct {
// CredentialType is a description of a credential type, specifying (a.o.) its name, issuer, and attributes.
type CredentialType struct {
ID string `xml:"CredentialID"`
Name TranslatedString `xml:"Name"`
ShortName TranslatedString `xml:"ShortName"`
IssuerID string `xml:"IssuerID"`
SchemeManagerID string `xml:"SchemeManager"`
IsSingleton bool `xml:"ShouldBeSingleton"`
DisallowDelete bool `xml:"DisallowDelete"`
Description TranslatedString
AttributeTypes []*AttributeType `xml:"Attributes>Attribute" json:"-"`
XMLVersion int `xml:"version,attr"`
XMLName xml.Name `xml:"IssueSpecification"`
IssueURL TranslatedString `xml:"IssueURL"`
DeprecatedSince Timestamp
ID string `xml:"CredentialID"`
Name TranslatedString `xml:"Name"`
ShortName TranslatedString `xml:"ShortName"`
IssuerID string `xml:"IssuerID"`
SchemeManagerID string `xml:"SchemeManager"`
IsSingleton bool `xml:"ShouldBeSingleton"`
DisallowDelete bool `xml:"DisallowDelete"`
Description TranslatedString
AttributeTypes []*AttributeType `xml:"Attributes>Attribute" json:"-"`
RevocationServers []string `xml:"RevocationServers>RevocationServer"`
RevocationUpdateCount uint64
RevocationUpdateSpeed uint64
RevocationIndex int `xml:"-"`
XMLVersion int `xml:"version,attr"`
XMLName xml.Name `xml:"IssueSpecification"`
IssueURL TranslatedString `xml:"IssueURL"`
Valid bool `xml:"-"`
}
......@@ -84,6 +87,8 @@ type AttributeType struct {
Index int `xml:"-"`
DisplayIndex *int `xml:"displayIndex,attr" json:",omitempty"`
RevocationAttribute bool `xml:"revocation,attr" json:",omitempty"`
// Taken from containing CredentialType
CredentialTypeID string `xml:"-"`
IssuerID string `xml:"-"`
......@@ -98,6 +103,10 @@ func (ad AttributeType) IsOptional() bool {
return ad.Optional == "true"
}
func (ct *CredentialType) RevocationSupported() bool {
return len(ct.RevocationServers) > 0
}
// ContainsAttribute tests whether the specified attribute is contained in this
// credentialtype.
func (ct *CredentialType) ContainsAttribute(ai AttributeTypeIdentifier) bool {
......@@ -190,7 +199,7 @@ func (ct *CredentialType) SchemeManagerIdentifier() SchemeManagerIdentifier {
func (ct *CredentialType) Logo(conf *Configuration) string {
path := filepath.Join(conf.Path, ct.SchemeManagerID, ct.IssuerID, "Issues", ct.ID, "logo.png")
exists, err := fs.PathExists(path)
exists, err := common.PathExists(path)
if err != nil || !exists {
return ""
}
......
module github.com/privacybydesign/irmago
go 1.13
require (
astuart.co/go-sse v0.0.0-20200223201439-6cc042ab6f6d
github.com/BurntSushi/toml v0.3.1 // indirect
github.com/alexandrevicenzi/go-sse v1.3.1-0.20200117161408-7b23d5ff7420
github.com/bwesterb/go-atum v1.0.0
github.com/bwesterb/go-exptable v1.0.0 // indirect
github.com/certifi/gocertifi v0.0.0-20180118203423-deb3ae2ef261 // indirect
github.com/dgrijalva/jwt-go v3.2.0+incompatible
github.com/fxamacker/cbor v1.5.0
github.com/getsentry/raven-go v0.0.0-20180121060056-563b81fc02b7
github.com/go-chi/chi v3.3.3+incompatible
github.com/go-chi/cors v1.0.0
github.com/go-errors/errors v1.0.0
github.com/go-sql-driver/mysql v1.5.0 // indirect
github.com/hashicorp/go-multierror v1.0.0
github.com/hashicorp/go-retryablehttp v0.6.2
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/jasonlvhit/gocron v0.0.0-20180312192515-54194c9749d4
github.com/jinzhu/gorm v1.9.12
github.com/lib/pq v1.3.0 // indirect
github.com/magiconair/properties v1.8.0 // indirect
github.com/mattn/go-colorable v0.0.9 // indirect
github.com/mattn/go-isatty v0.0.4 // indirect
github.com/mdp/qrterminal v1.0.1
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect
github.com/minio/sha256-simd v0.1.1 // indirect
github.com/mitchellh/mapstructure v1.1.2
github.com/multiformats/go-multihash v0.0.11 // indirect
github.com/onsi/ginkgo v1.12.0 // indirect
github.com/onsi/gomega v1.9.0 // indirect
github.com/pelletier/go-toml v1.2.0 // indirect
github.com/pkg/errors v0.8.0
github.com/privacybydesign/gabi v0.0.0-20200304102013-9df3e395ec4d
github.com/sirupsen/logrus v1.2.0
github.com/spf13/afero v1.2.0 // indirect
github.com/spf13/cast v1.3.0
github.com/spf13/cobra v0.0.1
github.com/spf13/jwalterweatherman v1.0.0 // indirect
github.com/spf13/pflag v1.0.4-0.20190111213756-a45bfec10d59
github.com/spf13/viper v1.0.1-0.20200205174444-d996804203c7
github.com/stretchr/testify v1.2.2
github.com/timshannon/bolthold v0.0.0-20190812165541-a85bcc049a2e // indirect
github.com/x-cray/logrus-prefixed-formatter v0.5.2
github.com/x448/float16 v0.8.4 // indirect
go.etcd.io/bbolt v1.3.2
golang.org/x/crypto v0.0.0-20200204104054-c9f3fb736b72 // indirect
)
replace astuart.co/go-sse => github.com/sietseringers/go-sse v0.0.0-20200223201439-6cc042ab6f6d
replace github.com/spf13/pflag => github.com/sietseringers/pflag v1.0.4-0.20190111213756-a45bfec10d59
replace github.com/spf13/viper => github.com/sietseringers/viper v1.0.1-0.20200205174444-d996804203c7
This diff is collapsed.
package irma
import (
"database/sql/driver" // only imported to refer to the driver.Value type
"fmt"
"strings"
"github.com/fxamacker/cbor"
"github.com/go-errors/errors"
"github.com/jinzhu/gorm"
)
type metaObjectIdentifier string
func (oi *metaObjectIdentifier) UnmarshalCBOR(data []byte) error {
return cbor.Unmarshal(data, (*string)(oi))
}
func (oi metaObjectIdentifier) MarshalCBOR() (data []byte, err error) {
return cbor.Marshal(string(oi), cbor.EncOptions{})
}
// SchemeManagerIdentifier identifies a scheme manager. Equal to its ID. For example "irma-demo".
type SchemeManagerIdentifier struct {
metaObjectIdentifier
......@@ -45,7 +58,7 @@ type IrmaIdentifierSet struct {
SchemeManagers map[SchemeManagerIdentifier]struct{}
Issuers map[IssuerIdentifier]struct{}
CredentialTypes map[CredentialTypeIdentifier]struct{}
PublicKeys map[IssuerIdentifier][]int
PublicKeys map[IssuerIdentifier][]uint
AttributeTypes map[AttributeTypeIdentifier]struct{}
}
......@@ -54,7 +67,7 @@ func newIrmaIdentifierSet() *IrmaIdentifierSet {
SchemeManagers: map[SchemeManagerIdentifier]struct{}{},
Issuers: map[IssuerIdentifier]struct{}{},
CredentialTypes: map[CredentialTypeIdentifier]struct{}{},
PublicKeys: map[IssuerIdentifier][]int{},
PublicKeys: map[IssuerIdentifier][]uint{},
AttributeTypes: map[AttributeTypeIdentifier]struct{}{},
}
}
......@@ -201,7 +214,7 @@ func (set *IrmaIdentifierSet) join(other *IrmaIdentifierSet) {
}
for issuer := range other.PublicKeys {
if len(set.PublicKeys[issuer]) == 0 {
set.PublicKeys[issuer] = make([]int, 0, len(other.PublicKeys[issuer]))
set.PublicKeys[issuer] = make([]uint, 0, len(other.PublicKeys[issuer]))
}
set.PublicKeys[issuer] = append(set.PublicKeys[issuer], other.PublicKeys[issuer]...)
}
......@@ -267,3 +280,30 @@ func (set *IrmaIdentifierSet) String() string {
func (set *IrmaIdentifierSet) Empty() bool {
return len(set.SchemeManagers) == 0 && len(set.Issuers) == 0 && len(set.CredentialTypes) == 0 && len(set.PublicKeys) == 0 && len(set.AttributeTypes) == 0
}
func (oi metaObjectIdentifier) Value() (driver.Value, error) {
return oi.String(), nil
}
func (oi *metaObjectIdentifier) Scan(src interface{}) error {
switch s := src.(type) {
case string:
*oi = metaObjectIdentifier(s)
return nil
case []byte:
*oi = metaObjectIdentifier(s)
return nil
}
return errors.New("cannot convert source: not a string or []byte")
}
func (metaObjectIdentifier) GormDataType(dialect gorm.Dialect) string {
switch dialect.GetName() {
case "postgres":
return "text"
case "mysql":
return "varchar(255)"
default:
return ""
}
}
package fs
package common
import (
"crypto/rand"
"encoding/base64"
"encoding/hex"
"fmt"
"io/ioutil"
"os"
"path"
"path/filepath"
"github.com/pkg/errors"
"github.com/go-errors/errors"
"github.com/privacybydesign/gabi/big"
"github.com/sirupsen/logrus"
)
var Logger *logrus.Logger
// AssertPathExists returns nil only if it has been successfully
// verified that all specified paths exists.
func AssertPathExists(paths ...string) error {
......@@ -42,49 +47,47 @@ func AssertPathNotExists(paths ...string) error {
// PathExists checks if the specified path exists.
func PathExists(path string) (bool, error) {
_, err := os.Stat(path)
_, exists, err := Stat(path)
return exists, err
}
func Stat(path string) (os.FileInfo, bool, error) {
info, err := os.Lstat(path)
if err == nil {
return true, nil
return info, true, nil
}
if os.IsNotExist(err) {
return false, nil
return nil, false, nil
}
return true, err
return nil, false, err
}
func EnsureDirectoryExists(path string) error {
exists, err := PathExists(path)
info, exists, err := Stat(path)
if err != nil {
return err
}
if exists {
return nil
if !exists {
return os.MkdirAll(path, 0700)
}
return os.MkdirAll(path, 0700)
}
func Empty(path string) bool {
matches, _ := filepath.Glob(filepath.Join(path, "*"))
return len(matches) == 0
}
func Copy(src, dest string) error {
exists, err := PathExists(src)
if err != nil || !exists {
return err
}
bts, err := ioutil.ReadFile(src)
if err != nil {
return err
if !info.IsDir() {
return errors.New("path exists but is not a directory")
}
return SaveFile(dest, bts)
return nil
}
// Save the filecontents at the specified path atomically:
// - first save the content in a temp file with a random filename in the same dir
// - then rename the temp file to the specified filepath, overwriting the old file
func SaveFile(fpath string, content []byte) (err error) {
dir := path.Dir(fpath)
Logger.Debug("writing ", fpath)
info, exists, err := Stat(fpath)
if err != nil {
return err
}
if exists && (info.IsDir() || !info.Mode().IsRegular()) {
return errors.New("invalid destination path")
}
// Read random data for filename and convert to hex
randBytes := make([]byte, 16)
......@@ -95,6 +98,7 @@ func SaveFile(fpath string, content []byte) (err error) {
tempfilename := hex.EncodeToString(randBytes)
// Create temp file
dir := path.Dir(fpath)
err = ioutil.WriteFile(filepath.Join(dir, tempfilename), content, 0600)
if err != nil {
return
......@@ -109,33 +113,35 @@ func CopyDirectory(src, dest string) error {
return err
}
return filepath.Walk(src, filepath.WalkFunc(
func(path string, info os.FileInfo, err error) error {
if path == src {
return nil
return filepath.Walk(src, func(path string, info os.FileInfo, err error) (e error) {
if err != nil {
return err
}
if path == src {
return
}
subpath := path[len(src):]
if info.IsDir() {
if err := EnsureDirectoryExists(dest + subpath); err != nil {
return err
}
subpath := path[len(src):]
if info.IsDir() {
if err := EnsureDirectoryExists(dest + subpath); err != nil {
return err
}
} else {
srcfile, err := os.Open(path)
if err != nil {
return err
}
defer srcfile.Close()
bts, err := ioutil.ReadAll(srcfile)
if err != nil {
return err
}
if err := SaveFile(dest+subpath, bts); err != nil {
return err
}
} else {
srcfile, err := os.Open(path)
if err != nil {
return err
}
return nil
}),
)
defer func() { e = srcfile.Close() }()
bts, err := ioutil.ReadAll(srcfile)
if err != nil {
return err
}
if err := SaveFile(dest+subpath, bts); err != nil {
return err
}
}
return
})
}
// ReadKey returns either the content of the file specified at path, if it exists,
......@@ -153,11 +159,14 @@ func ReadKey(key, path string) ([]byte, error) {
} else {
stat, err := os.Stat(path)
if err != nil {
return nil, errors.New("no key found at specified path")
return nil, errors.WrapPrefix(err, "failed to stat key", 0)
}
if stat.IsDir() {
return nil, errors.New("cannot read key from a directory")
}
if !stat.Mode().IsRegular() {
return nil, errors.New("cannot read key from nonregular file")
}
bts, err = ioutil.ReadFile(path)
if err != nil {
return nil, err
......@@ -232,3 +241,15 @@ func WalkDir(path string, handler func(string, os.FileInfo) error) error {
return handler(p, info)
})
}
func RandomBigInt(limit *big.Int) *big.Int {
res, err := big.RandInt(rand.Reader, limit)
if err != nil {
panic(fmt.Sprintf("big.RandInt failed: %v", err))
}
return res
}
type SSECtx struct {
Component, Arg string
}
This diff is collapsed.
......@@ -13,12 +13,17 @@ import (
)
type TestClientHandler struct {
t *testing.T
c chan error
t *testing.T
c chan error
revoked *irma.CredentialIdentifier
storage string
}
func (i *TestClientHandler) UpdateConfiguration(new *irma.IrmaIdentifierSet) {}
func (i *TestClientHandler) UpdateAttributes() {}
func (i *TestClientHandler) Revoked(cred *irma.CredentialIdentifier) {
i.revoked = cred
}
func (i *TestClientHandler) EnrollmentSuccess(manager irma.SchemeManagerIdentifier) {
select {
case i.c <- nil: // nop
......@@ -67,6 +72,7 @@ type TestHandler struct {
c chan *SessionResult
client *irmaclient.Client
expectedServerName irma.TranslatedString
wait time.Duration
result string
}
......@@ -91,7 +97,6 @@ func (th TestHandler) Cancelled() {
th.Failure(&irma.SessionError{Err: errors.New("Cancelled")})
}
func (th TestHandler) Failure(err *irma.SessionError) {
th.t.Logf("Session failed: %+v\n", *err)
select {
case th.c <- &SessionResult{Err: err}:
default:
......@@ -112,6 +117,9 @@ func (th TestHandler) RequestVerificationPermission(request *irma.DisclosureRequ
if len(th.expectedServerName) != 0 {
require.Equal(th.t, th.expectedServerName, ServerName)
}
if th.wait != 0 {
time.Sleep(th.wait)
}
callback(true, &choice)
}
func (th TestHandler) RequestIssuancePermission(request *irma.IssuanceRequest, candidates [][][]*irma.AttributeIdentifier, ServerName irma.TranslatedString, callback irmaclient.PermissionHandler) {
......
......@@ -22,12 +22,12 @@ func TestManualKeyshareSession(t *testing.T) {
}
func TestRequestorIssuanceKeyshareSession(t *testing.T) {
testRequestorIssuance(t, true)
testRequestorIssuance(t, true, nil)
}
func TestKeyshareRegister(t *testing.T) {
client, handler := parseStorage(t)
defer test.ClearTestStorage(t)
defer test.ClearTestStorage(t, handler.storage)
require.NoError(t, client.KeyshareRemoveAll())
require.NoError(t, client.RemoveStorage())
......@@ -45,8 +45,8 @@ func TestKeyshareRegister(t *testing.T) {
// in a keyshare session of each session type.
// Use keyshareuser.sql to enroll the user at the keyshare server.
func TestKeyshareSessions(t *testing.T) {
client, _ := parseStorage(t)
defer test.ClearTestStorage(t)
client, handler := parseStorage(t)
defer test.ClearTestStorage(t, handler.storage)
keyshareSessions(t, client)
}
......@@ -79,10 +79,31 @@ func TestIssuanceCombinedMultiSchemeSession(t *testing.T) {
sessionHelper(t, irma.NewIssuanceRequest([]*irma.CredentialRequest{
{
CredentialTypeID: irma.NewCredentialTypeIdentifier("test.test.email"),
CredentialTypeID: irma.NewCredentialTypeIdentifier("test.test.mijnirma"),
Attributes: map[string]string{
"email": "example@example.com",
},
},
}, irma.NewAttributeTypeIdentifier("irma-demo.RU.studentCard.studentID")), "issue", nil)
}
func TestKeyshareRevocation(t *testing.T) {
t.Run("Keyshare", func(t *testing.T) {
startRevocationServer(t, true)
defer stopRevocationServer()
client, handler := parseStorage(t)
defer test.ClearTestStorage(t, handler.storage)
testRevocation(t, revKeyshareTestAttr, client, handler)
})
t.Run("Both", func(t *testing.T) {
startRevocationServer(t, true)
defer stopRevocationServer()
client, handler := parseStorage(t)
defer test.ClearTestStorage(t, handler.storage)
testRevocation(t, revKeyshareTestAttr, client, handler)
testRevocation(t, revocationTestAttr, client, handler)
})
}
package sessiontest
import (
"testing"
irma "github.com/privacybydesign/irmago"
"github.com/privacybydesign/irmago/internal/test"
"github.com/stretchr/testify/require"
"testing"
)
func TestSessionUsingLegacyStorage(t *testing.T) {
test.SetTestStorageDir("legacy_teststorage")
defer test.SetTestStorageDir("teststorage")
test.SetTestStorageDir("client_legacy")
defer test.SetTestStorageDir("client")
client, _ := parseStorage(t)
defer test.ClearTestStorage(t)
client, handler := parseStorage(t)
defer test.ClearTestStorage(t, handler.storage)
// Test whether credential from legacy storage is still usable
idStudentCard := irma.NewAttributeTypeIdentifier("irma-demo.RU.studentCard.studentID")
......@@ -23,12 +24,12 @@ func TestSessionUsingLegacyStorage(t *testing.T) {
sessionHelper(t, getMultipleIssuanceRequest(), "issue", client)
// Test whether credential is still there
idRoot := irma.NewAttributeTypeIdentifier("irma-demo.MijnOverheid.root.BSN")
idRoot := irma.NewAttributeTypeIdentifier("irma-demo.MijnOverheid.fullName.familyname")
sessionHelper(t, getDisclosureRequest(idRoot), "verification", client)
// Re-open client
require.NoError(t, client.Close())
client, _ = parseExistingStorage(t)
client, handler = parseExistingStorage(t, handler.storage)
// Test whether credential is still there after the storage has been reloaded
sessionHelper(t, getDisclosureRequest(idRoot), "verification", client)
......
......@@ -9,7 +9,8 @@ import (
)
func TestLogging(t *testing.T) {
client, _ := parseStorage(t)
client, handler := parseStorage(t)
defer test.ClearTestStorage(t, handler.storage)
logs, err := client.LoadNewestLogs(100)
oldLogLength := len(logs)
......@@ -27,7 +28,7 @@ func TestLogging(t *testing.T) {
// Check whether newly issued credential is actually stored
require.NoError(t, client.Close())
client, _ = parseExistingStorage(t)
client, handler = parseExistingStorage(t, handler.storage)
logs, err = client.LoadNewestLogs(100)
require.NoError(t, err)
require.True(t, len(logs) == oldLogLength+1)
......@@ -51,7 +52,7 @@ func TestLogging(t *testing.T) {
// Check whether log entry for disclosing session is actually stored
require.NoError(t, client.Close())
client, _ = parseExistingStorage(t)
client, handler = parseExistingStorage(t, handler.storage)
logs, err = client.LoadNewestLogs(100)
require.NoError(t, err)
require.True(t, len(logs) == oldLogLength+2)
......@@ -83,7 +84,7 @@ func TestLogging(t *testing.T) {
// Check whether log entry for signature session is actually stored
require.NoError(t, client.Close())
client, _ = parseExistingStorage(t)
client, handler = parseExistingStorage(t, handler.storage)
logs, err = client.LoadNewestLogs(100)
require.NoError(t, err)
require.True(t, len(logs) == oldLogLength+3)
......@@ -99,6 +100,4 @@ func TestLogging(t *testing.T) {
require.Equal(t, irma.ProofStatusValid, status)
require.NotEmpty(t, attrs)
require.Equal(t, attrid, attrs[0][0].Identifier)
test.ClearTestStorage(t)
}
......@@ -27,24 +27,25 @@ func init() {
func TestMain(m *testing.M) {
// Create HTTP server for scheme managers
test.StartSchemeManagerHttpServer()
defer test.StopSchemeManagerHttpServer()
test.CreateTestStorage(nil)
defer test.ClearTestStorage(nil)
retval := m.Run()
os.Exit(m.Run())
test.StopSchemeManagerHttpServer()
test.ClearAllTestStorage()
os.Exit(retval)
}
func parseStorage(t *testing.T) (*irmaclient.Client, *TestClientHandler) {
test.SetupTestStorage(t)
return parseExistingStorage(t)
storage := test.SetupTestStorage(t)
return parseExistingStorage(t, storage)
}
func parseExistingStorage(t *testing.T) (*irmaclient.Client, *TestClientHandler) {
handler := &TestClientHandler{t: t, c: make(chan error)}
func parseExistingStorage(t *testing.T, storage string) (*irmaclient.Client, *TestClientHandler) {
handler := &TestClientHandler{t: t, c: make(chan error), storage: storage}
path := test.FindTestdataFolder(t)
client, err := irmaclient.New(
filepath.Join(path, "storage", "test"),
filepath.Join(storage, "client"),
filepath.Join(path, "irma_configuration"),
handler,
)
......@@ -112,9 +113,11 @@ func getMultipleIssuanceRequest() *irma.IssuanceRequest {
request := getIssuanceRequest(false)
request.Credentials = append(request.Credentials, &irma.CredentialRequest{
Validity: request.Credentials[0].Validity,
CredentialTypeID: irma.NewCredentialTypeIdentifier("irma-demo.MijnOverheid.root"),
CredentialTypeID: irma.NewCredentialTypeIdentifier("irma-demo.MijnOverheid.fullName"),
Attributes: map[string]string{
"BSN": "299792458",
"firstnames": "Johan Pieter",
"firstname": "Johan",
"familyname": "Stuivezand",
},
})
return request
......@@ -201,8 +204,9 @@ func getJwt(t *testing.T, request irma.SessionRequest, sessiontype string, alg j
func sessionHelper(t *testing.T, request irma.SessionRequest, sessiontype string, client *irmaclient.Client) {
if client == nil {
client, _ = parseStorage(t)
defer test.ClearTestStorage(t)
var handler *TestClientHandler
client, handler = parseStorage(t)
defer test.ClearTestStorage(t, handler.storage)
}
if TestType == "irmaserver" || TestType == "irmaserver-jwt" || TestType == "irmaserver-hmac-jwt" {
......
......@@ -25,8 +25,9 @@ func createManualSessionHandler(t *testing.T, client *irmaclient.Client) *Manual
func manualSessionHelper(t *testing.T, client *irmaclient.Client, h *ManualTestHandler, request, verifyAs irma.SessionRequest, corrupt bool) ([][]*irma.DisclosedAttribute, irma.ProofStatus) {
if client == nil {
client, _ = parseStorage(t)
defer test.ClearTestStorage(t)
var handler *TestClientHandler
client, handler = parseStorage(t)
defer test.ClearTestStorage(t, handler.storage)
}
bts, err := json.Marshal(request)
......@@ -110,8 +111,8 @@ func TestManualSessionInvalidAttributeValue(t *testing.T) {
}
func TestManualSessionMultiProof(t *testing.T) {
client, _ := parseStorage(t)
defer test.ClearTestStorage(t)
client, handler := parseStorage(t)
defer test.ClearTestStorage(t, handler.storage)
// First, we need to issue an extra credential (BSN)
sessionHelper(t, getMultipleIssuanceRequest(), "issue", client)
......@@ -119,7 +120,7 @@ func TestManualSessionMultiProof(t *testing.T) {
// Request to sign with both BSN and StudentID
request := irma.NewSignatureRequest("I owe you everything",
irma.NewAttributeTypeIdentifier("irma-demo.RU.studentCard.studentID"),
irma.NewAttributeTypeIdentifier("irma-demo.MijnOverheid.root.BSN"))
irma.NewAttributeTypeIdentifier("irma-demo.MijnOverheid.fullName.familyname"))
ms := createManualSessionHandler(t, client)
......
......@@ -6,8 +6,8 @@ import (
"io/ioutil"
"net/http"
"reflect"
"testing"
"time"
"github.com/privacybydesign/irmago"
"github.com/privacybydesign/irmago/internal/test"
......@@ -22,6 +22,9 @@ const (
sessionOptionUpdatedIrmaConfiguration sessionOption = 1 << iota
sessionOptionUnsatisfiableRequest
sessionOptionRetryPost
sessionOptionIgnoreError
sessionOptionReuseServer
sessionOptionClientWait
)
type requestorSessionResult struct {
......@@ -29,14 +32,26 @@ type requestorSessionResult struct {
Missing irmaclient.MissingAttributes
}
func processOptions(options ...sessionOption) sessionOption {
var opts sessionOption = 0
for _, o := range options {
opts |= o
}
return opts
}
func requestorSessionHelper(t *testing.T, request irma.SessionRequest, client *irmaclient.Client, options ...sessionOption) *requestorSessionResult {
if client == nil {
client, _ = parseStorage(t)
defer test.ClearTestStorage(t)
var handler *TestClientHandler
client, handler = parseStorage(t)
defer test.ClearTestStorage(t, handler.storage)
}
StartIrmaServer(t, len(options) == 1 && options[0] == sessionOptionUpdatedIrmaConfiguration)
defer StopIrmaServer()
opts := processOptions(options...)
if opts&sessionOptionReuseServer == 0 {
StartIrmaServer(t, opts&sessionOptionUpdatedIrmaConfiguration > 0)
defer StopIrmaServer()
}
clientChan := make(chan *SessionResult)
serverChan := make(chan *server.SessionResult)
......@@ -46,27 +61,26 @@ func requestorSessionHelper(t *testing.T, request irma.SessionRequest, client *i
})
require.NoError(t, err)
opts := 0
for _, o := range options {
opts |= int(o)
}
var h irmaclient.Handler
if opts&int(sessionOptionUnsatisfiableRequest) > 0 {
h = &UnsatisfiableTestHandler{TestHandler{t, clientChan, client, nil, ""}}
if opts&sessionOptionUnsatisfiableRequest > 0 {
h = &UnsatisfiableTestHandler{TestHandler{t, clientChan, client, nil, 0, ""}}
} else {
h = &TestHandler{t, clientChan, client, nil, ""}
var wait time.Duration = 0
if opts&sessionOptionClientWait > 0 {
wait = 2 * time.Second
}
h = &TestHandler{t, clientChan, client, nil, wait, ""}
}
j, err := json.Marshal(qr)
require.NoError(t, err)
client.NewSession(string(j), h)
clientResult := <-clientChan
if clientResult != nil {
if opts&sessionOptionIgnoreError == 0 && clientResult != nil {
require.NoError(t, clientResult.Err)
}
if opts&int(sessionOptionUnsatisfiableRequest) > 0 {
if opts&sessionOptionUnsatisfiableRequest > 0 {
require.NotNil(t, clientResult)
return &requestorSessionResult{nil, clientResult.Missing}
}
......@@ -74,7 +88,7 @@ func requestorSessionHelper(t *testing.T, request irma.SessionRequest, client *i
serverResult := <-serverChan
require.Equal(t, token, serverResult.Token)
if opts&int(sessionOptionRetryPost) > 0 {
if opts&sessionOptionRetryPost > 0 {
req, err := http.NewRequest(http.MethodPost,
qr.URL+"/proofs",
bytes.NewBuffer([]byte(h.(*TestHandler).result)),
......@@ -120,7 +134,8 @@ func TestRequestorDoubleGET(t *testing.T) {
}
func TestRequestorSignatureSession(t *testing.T) {
client, _ := parseStorage(t)
client, handler := parseStorage(t)
defer test.ClearTestStorage(t, handler.storage)
id := irma.NewAttributeTypeIdentifier("irma-demo.RU.studentCard.studentID")
var serverResult *requestorSessionResult
......@@ -175,7 +190,7 @@ func testRequestorDisclosure(t *testing.T, request *irma.DisclosureRequest, opti
}
func TestRequestorIssuanceSession(t *testing.T) {
testRequestorIssuance(t, false)
testRequestorIssuance(t, false, nil)
}
func TestRequestorCombinedSessionMultipleAttributes(t *testing.T) {
......@@ -184,7 +199,7 @@ func TestRequestorCombinedSessionMultipleAttributes(t *testing.T) {
"type":"issuing",
"credentials": [
{
"credential":"irma-demo.MijnOverheid.root",
"credential":"irma-demo.MijnOverheid.singleton",
"attributes" : {
"BSN":"12345"
}
......@@ -209,7 +224,7 @@ func TestRequestorCombinedSessionMultipleAttributes(t *testing.T) {
require.Equal(t, server.StatusDone, requestorSessionHelper(t, &ir, nil).Status)
}
func testRequestorIssuance(t *testing.T, keyshare bool) {
func testRequestorIssuance(t *testing.T, keyshare bool, client *irmaclient.Client) {
attrid := irma.NewAttributeTypeIdentifier("irma-demo.RU.studentCard.studentID")
request := irma.NewIssuanceRequest([]*irma.CredentialRequest{{
CredentialTypeID: irma.NewCredentialTypeIdentifier("irma-demo.RU.studentCard"),
......@@ -220,9 +235,11 @@ func testRequestorIssuance(t *testing.T, keyshare bool) {
"level": "42",
},
}, {
CredentialTypeID: irma.NewCredentialTypeIdentifier("irma-demo.MijnOverheid.root"),
CredentialTypeID: irma.NewCredentialTypeIdentifier("irma-demo.MijnOverheid.fullName"),
Attributes: map[string]string{
"BSN": "299792458",
"firstnames": "Johan Pieter",
"firstname": "Johan",
"familyname": "Stuivezand",
},
}}, attrid)
if keyshare {
......@@ -232,7 +249,7 @@ func testRequestorIssuance(t *testing.T, keyshare bool) {
})
}
result := requestorSessionHelper(t, request, nil)
result := requestorSessionHelper(t, request, client)
require.Nil(t, result.Err)
require.Equal(t, irma.ProofStatusValid, result.ProofStatus)
require.NotEmpty(t, result.Disclosed)
......@@ -241,7 +258,8 @@ func testRequestorIssuance(t *testing.T, keyshare bool) {
}
func TestConDisCon(t *testing.T) {
client, _ := parseStorage(t)
client, handler := parseStorage(t)
defer test.ClearTestStorage(t, handler.storage)
ir := getMultipleIssuanceRequest()
ir.Credentials = append(ir.Credentials, &irma.CredentialRequest{
Validity: ir.Credentials[0].Validity,
......@@ -280,7 +298,8 @@ func TestConDisCon(t *testing.T) {
}
func TestOptionalDisclosure(t *testing.T) {
client, _ := parseStorage(t)
client, handler := parseStorage(t)
defer test.ClearTestStorage(t, handler.storage)
university := irma.NewAttributeTypeIdentifier("irma-demo.RU.studentCard.university")
studentid := irma.NewAttributeTypeIdentifier("irma-demo.RU.studentCard.studentID")
......
This diff is collapsed.
......@@ -17,17 +17,23 @@ import (
)
var (
httpServer *http.Server
irmaServer *irmaserver.Server
requestorServer *requestorserver.Server
httpServer *http.Server
irmaServer *irmaserver.Server
irmaServerConfiguration *server.Configuration
requestorServer *requestorserver.Server
logger = logrus.New()
testdata = test.FindTestdataFolder(nil)
)
func init() {
logger.Level = logrus.ErrorLevel
logger.Formatter = &prefixed.TextFormatter{ForceFormatting: true, ForceColors: true}
logger.Level = logrus.FatalLevel
logger.Formatter = &prefixed.TextFormatter{
ForceFormatting: true,
ForceColors: true,
FullTimestamp: true,
TimestampFormat: "15:04:05.000000",
}
}
func StartRequestorServer(configuration *requestorserver.Configuration) {
......@@ -54,28 +60,31 @@ func StartIrmaServer(t *testing.T, updatedIrmaConf bool) {
irmaconf += "_updated"
}
logger := logrus.New()
logger.Level = logrus.ErrorLevel
logger.Formatter = &logrus.TextFormatter{}
var err error
irmaServer, err = irmaserver.New(&server.Configuration{
URL: "http://localhost:48680",
Logger: logger,
SchemesPath: filepath.Join(testdata, irmaconf),
})
irmaServerConfiguration = &server.Configuration{
URL: "http://localhost:48680",
Logger: logger,
DisableSchemesUpdate: true,
SchemesPath: filepath.Join(testdata, irmaconf),
RevocationSettings: irma.RevocationSettings{
revocationTestCred: {RevocationServerURL: "http://localhost:48683", SSE: true},
revKeyshareTestCred: {RevocationServerURL: "http://localhost:48683"},
},
}
irmaServer, err = irmaserver.New(irmaServerConfiguration)
require.NoError(t, err)
mux := http.NewServeMux()
mux.HandleFunc("/", irmaServer.HandlerFunc())
httpServer = &http.Server{Addr: ":48680", Handler: mux}
httpServer = &http.Server{Addr: "localhost:48680", Handler: mux}
go func() {
_ = httpServer.ListenAndServe()
}()
}
func StopIrmaServer() {
irmaServer.Stop()
_ = httpServer.Close()
}
......@@ -83,23 +92,49 @@ var IrmaServerConfiguration = &requestorserver.Configuration{
Configuration: &server.Configuration{
URL: "http://localhost:48682/irma",
Logger: logger,
DisableSchemesUpdate: true,
SchemesPath: filepath.Join(testdata, "irma_configuration"),
IssuerPrivateKeysPath: filepath.Join(testdata, "privatekeys"),
RevocationSettings: irma.RevocationSettings{
revocationTestCred: {RevocationServerURL: "http://localhost:48683"},
revKeyshareTestCred: {RevocationServerURL: "http://localhost:48683"},
},
},
DisableRequestorAuthentication: true,
Port: 48682,
ListenAddress: "localhost",
Port: 48682,
}
var JwtServerConfiguration = &requestorserver.Configuration{
Configuration: &server.Configuration{
URL: "http://localhost:48682/irma",
Logger: logger,
DisableSchemesUpdate: true,
SchemesPath: filepath.Join(testdata, "irma_configuration"),
IssuerPrivateKeysPath: filepath.Join(testdata, "privatekeys"),
RevocationSettings: irma.RevocationSettings{
revocationTestCred: {RevocationServerURL: "http://localhost:48683"},
revKeyshareTestCred: {RevocationServerURL: "http://localhost:48683"},
},
JwtPrivateKeyFile: filepath.Join(testdata, "jwtkeys", "sk.pem"),
StaticSessions: map[string]interface{}{
"staticsession": irma.ServiceProviderRequest{
RequestorBaseRequest: irma.RequestorBaseRequest{
CallbackURL: "http://localhost:48685",
},
Request: &irma.DisclosureRequest{
BaseRequest: irma.BaseRequest{LDContext: irma.LDContextDisclosureRequest},
Disclose: irma.AttributeConDisCon{
{{irma.NewAttributeRequest("irma-demo.RU.studentCard.level")}},
},
},
},
},
},
Port: 48682,
ListenAddress: "localhost",
Port: 48682,
DisableRequestorAuthentication: false,
MaxRequestAge: 3,
MaxRequestAge: 3,
Permissions: requestorserver.Permissions{
Disclosing: []string{"*"},
Signing: []string{"*"},
......@@ -119,18 +154,4 @@ var JwtServerConfiguration = &requestorserver.Configuration{
AuthenticationKey: "eGE2PSomOT84amVVdTU+LmYtJXJWZ2BmNjNwSGltCg==",
},
},
StaticSessions: map[string]interface{}{
"staticsession": irma.ServiceProviderRequest{
RequestorBaseRequest: irma.RequestorBaseRequest{
CallbackURL: "http://localhost:48685",
},
Request: &irma.DisclosureRequest{
BaseRequest: irma.BaseRequest{LDContext: irma.LDContextDisclosureRequest},
Disclose: irma.AttributeConDisCon{
{{irma.NewAttributeRequest("irma-demo.RU.studentCard.level")}},
},
},
},
},
JwtPrivateKeyFile: filepath.Join(testdata, "jwtkeys", "sk.pem"),
}
This diff is collapsed.
......@@ -6,13 +6,14 @@ import (
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"net/http"
"os"
"path/filepath"
"testing"
"time"
"github.com/privacybydesign/irmago/internal/fs"
"github.com/privacybydesign/irmago/internal/common"
"github.com/stretchr/testify/require"
)
......@@ -30,24 +31,24 @@ func checkError(t *testing.T, err error) {
var schemeServer *http.Server
var badServer *http.Server
var badServerCount int
var testStorageDir = "teststorage"
var testStorageDir = "client"
func StartSchemeManagerHttpServer() {
path := FindTestdataFolder(nil)
schemeServer = &http.Server{Addr: ":48681", Handler: http.FileServer(http.Dir(path))}
schemeServer = &http.Server{Addr: "localhost:48681", Handler: http.FileServer(http.Dir(path))}
go func() {
schemeServer.ListenAndServe()
_ = schemeServer.ListenAndServe()
}()
time.Sleep(100 * time.Millisecond) // Give server time to start
}
func StopSchemeManagerHttpServer() {
schemeSer