Skip to content

Commit

Permalink
credential properties index
Browse files Browse the repository at this point in the history
  • Loading branch information
reinkrul committed Nov 19, 2023
1 parent 606b954 commit eb54df9
Show file tree
Hide file tree
Showing 13 changed files with 373 additions and 248 deletions.
8 changes: 4 additions & 4 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -176,9 +176,9 @@ The following options can be configured on the server:
:widths: 20 30 50
:class: options-table

==================================== =============================================================================================================================================================================================================================================================================================================== ==================================================================================================================================================================================================================================
==================================== =============================================================================================================================================================================================================================================================================================================== =======================================================================================================================================================================================================================================
Key Default Description
==================================== =============================================================================================================================================================================================================================================================================================================== ==================================================================================================================================================================================================================================
==================================== =============================================================================================================================================================================================================================================================================================================== =======================================================================================================================================================================================================================================
configfile nuts.yaml Nuts config file
cpuprofile When set, a CPU profile is written to the given path. Ignored when strictmode is set.
datadir ./data Directory where the node stores its files.
Expand Down Expand Up @@ -252,12 +252,12 @@ The following options can be configured on the server:
storage.redis.sentinel.password Password for authenticating to Redis Sentinels.
storage.redis.sentinel.username Username for authenticating to Redis Sentinels.
storage.redis.tls.truststorefile PEM file containing the trusted CA certificate(s) for authenticating remote Redis servers. Can only be used when connecting over TLS (use 'rediss://' as scheme in address).
storage.sql.connection Connection string for the SQL database. If not set, it defaults to a SQLite database stored inside the configured data directory
storage.sql.connection Connection string for the SQL database. If not set, it defaults to a SQLite database stored inside the configured data directory. If specifying a SQLite database, make sure to enable foreign keys with the '_foreign_keys=on' option.
**VCR**
vcr.openid4vci.definitionsdir Directory with the additional credential definitions the node could issue (experimental, may change without notice).
vcr.openid4vci.enabled true Enable issuing and receiving credentials over OpenID4VCI.
vcr.openid4vci.timeout 30s Time-out for OpenID4VCI HTTP client operations.
==================================== =============================================================================================================================================================================================================================================================================================================== ==================================================================================================================================================================================================================================
==================================== =============================================================================================================================================================================================================================================================================================================== =======================================================================================================================================================================================================================================

This table is automatically generated using the configuration flags in the core and engines. When they're changed
the options table must be regenerated using the Makefile:
Expand Down
91 changes: 7 additions & 84 deletions discoveryservice/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,60 +53,6 @@ package discoveryservice
// definitions map[string]Definition
//}
//
//func (c *client) Search(serviceID string, query map[string]string) ([]vc.VerifiablePresentation, error) {
// propertyColumns := map[string]string{
// "id": "cred.credential_id",
// "issuer": "cred.credential_issuer",
// "type": "cred.credential_type",
// "credentialSubject.id": "cred.credential_subject_id",
// }
//
// stmt := c.db.Model(&entry{}).
// Where("usecase_id = ?", serviceID).
// Joins("inner join usecase_client_credential cred ON cred.entry_id = usecase_client_entries.id")
// numProps := 0
// for jsonPath, value := range query {
// if value == "*" {
// continue
// }
// // sort out wildcard mode
// var eq = "="
// if strings.HasPrefix(value, "*") {
// value = "%" + value[1:]
// eq = "LIKE"
// }
// if strings.HasSuffix(value, "*") {
// value = value[:len(value)-1] + "%"
// eq = "LIKE"
// }
// if column := propertyColumns[jsonPath]; column != "" {
// stmt = stmt.Where(column+" "+eq+" ?", value)
// } else {
// // This property is not present as column, but indexed as key-value property.
// // Multiple (inner) joins to filter on a dynamic number of properties to filter on is not pretty, but it works
// alias := "p" + strconv.Itoa(numProps)
// numProps++
// stmt = stmt.Joins("inner join usecase_client_credential_props "+alias+" ON "+alias+".id = cred.id AND "+alias+".key = ? AND "+alias+".value "+eq+" ?", jsonPath, value)
// }
// }
//
// var matches []entry
// if err := stmt.Find(&matches).Error; err != nil {
// return nil, err
// }
// var results []vc.VerifiablePresentation
// for _, match := range matches {
// if match.PresentationExpiration <= time.Now().Unix() {
// continue
// }
// presentation, err := vc.ParseVerifiablePresentation(match.PresentationRaw)
// if err != nil {
// return nil, fmt.Errorf("failed to parse presentation '%s': %w", match.PresentationID, err)
// }
// results = append(results, *presentation)
// }
// return results, nil
//}
//
//func (c *client) refreshAll() {
// wg := &sync.WaitGroup{}
Expand All @@ -120,10 +66,10 @@ package discoveryservice
//}
//
//func (c *client) refreshList(definition Definition) error {
// var currentService discoveryService
// var currentService serviceRecord
// if err := c.db.Find(&currentService, "usecase_id = ?", definition.ID).Error; errors.Is(err, gorm.ErrRecordNotFound) {
// // First refresh of the list
// if err := c.db.Create(&discoveryService{ID: definition.ID}).Error; err != nil {
// if err := c.db.Create(&serviceRecord{ID: definition.ID}).Error; err != nil {
// return err
// }
// } else if err != nil {
Expand Down Expand Up @@ -221,10 +167,10 @@ package discoveryservice
// }
// subjectDID, err := curr.SubjectDID()
// if err != nil {
// return fmt.Errorf("invalid credential subject ID for VP '%s': %w", presentation.ID, err)
// return fmt.Errorf("invalid credentialRecord subject ID for VP '%s': %w", presentation.ID, err)
// }
// credentialRecordID := uuid.NewString()
// cred := credential{
// cred := credentialRecord{
// ID: credentialRecordID,
// EntryID: entryID,
// CredentialID: curr.ID.String(),
Expand All @@ -233,16 +179,16 @@ package discoveryservice
// CredentialType: credentialType,
// }
// if len(curr.CredentialSubject) != 1 {
// return errors.New("credential must contain exactly one subject")
// return errors.New("credentialRecord must contain exactly one subject")
// }
// // Store credential properties
// // Store credentialRecord properties
// keys, values := indexJSONObject(curr.CredentialSubject[0].(map[string]interface{}), nil, nil, "credentialSubject")
// for i, key := range keys {
// if key == "credentialSubject.id" {
// // present as column, don't index
// continue
// }
// cred.Properties = append(cred.Properties, credentialProperty{
// cred.Properties = append(cred.Properties, credentialPropertyRecord{
// ID: credentialRecordID,
// Key: key,
// Value: values[i],
Expand All @@ -255,26 +201,3 @@ package discoveryservice
// }
// return nil
//}
//
//// indexJSONObject indexes a JSON object, resulting in a slice of JSON paths and corresponding string values.
//// It only traverses JSON objects and only adds string values to the result.
//func indexJSONObject(target map[string]interface{}, jsonPaths []string, stringValues []string, currentPath string) ([]string, []string) {
// for key, value := range target {
// thisPath := currentPath
// if len(thisPath) > 0 {
// thisPath += "."
// }
// thisPath += key
//
// switch typedValue := value.(type) {
// case string:
// jsonPaths = append(jsonPaths, thisPath)
// stringValues = append(stringValues, typedValue)
// case map[string]interface{}:
// jsonPaths, stringValues = indexJSONObject(typedValue, jsonPaths, stringValues, thisPath)
// default:
// // other values (arrays, booleans, numbers, null) are not indexed
// }
// }
// return jsonPaths, stringValues
//}
16 changes: 8 additions & 8 deletions discoveryservice/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ package discoveryservice
// _ = storageEngine.Shutdown()
// })
//
// t.Run("1 credential", func(t *testing.T) {
// t.Run("1 credentialRecord", func(t *testing.T) {
// c := setupClient(t, storageEngine)
// err := c.writePresentation(c.db, TestDefinition.ID, vpAlice)
// require.NoError(t, err)
Expand All @@ -89,7 +89,7 @@ package discoveryservice
// require.Equal(t, vpAlice.Raw(), entries[0].PresentationRaw)
// require.Equal(t, vpAlice.JWT().Expiration().Unix(), entries[0].PresentationExpiration)
//
// var credentials []credential
// var credentials []credentialRecord
// require.NoError(t, c.db.Find(&credentials, "entry_id = ?", entries[0].ID).Error)
// require.Len(t, credentials, 1)
// cred := credentials[0]
Expand All @@ -107,7 +107,7 @@ package discoveryservice
// }
// for recordID, properties := range expectedProperties {
// for key, value := range properties {
// var prop credentialProperty
// var prop credentialPropertyRecord
// require.NoError(t, c.db.Find(&prop, "id = ? AND key = ?", recordID, key).Error)
// require.Equal(t, value, prop.Value)
// }
Expand Down Expand Up @@ -282,7 +282,7 @@ package discoveryservice
// require.NoError(t, err)
// tables := []schema.Tabler{
// &entry{},
// &credential{},
// &credentialRecord{},
// &list{},
// }
// for _, table := range tables {
Expand Down Expand Up @@ -318,7 +318,7 @@ package discoveryservice
// bobDID = did.MustParseDID("did:example:bob")
// keyPairs[bobDID.String()], _ = ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
//
// vcAlice = createCredentialWithClaims(authorityDID, aliceDID, func() []interface{} {
// vcAlice = createCredentialCustom(authorityDID, aliceDID, func() []interface{} {
// return []interface{}{
// map[string]interface{}{
// "id": aliceDID.String(),
Expand All @@ -333,7 +333,7 @@ package discoveryservice
// // do nothing
// })
// vpAlice = createPresentation(aliceDID, vcAlice)
// vcBob = createCredentialWithClaims(authorityDID, bobDID, func() []interface{} {
// vcBob = createCredentialCustom(authorityDID, bobDID, func() []interface{} {
// return []interface{}{
// map[string]interface{}{
// "id": aliceDID.String(),
Expand All @@ -351,7 +351,7 @@ package discoveryservice
//}
//
//func createCredential(issuerDID did.DID, subjectDID did.DID) vc.VerifiableCredential {
// return createCredentialWithClaims(issuerDID, subjectDID,
// return createCredentialCustom(issuerDID, subjectDID,
// func() []interface{} {
// return []interface{}{
// map[string]interface{}{
Expand All @@ -364,7 +364,7 @@ package discoveryservice
// })
//}
//
//func createCredentialWithClaims(issuerDID did.DID, subjectDID did.DID, credentialSubjectCreator func() []interface{}, claimVisitor func(map[string]interface{})) vc.VerifiableCredential {
//func createCredentialCustom(issuerDID did.DID, subjectDID did.DID, credentialSubjectCreator func() []interface{}, claimVisitor func(map[string]interface{})) vc.VerifiableCredential {
// vcID := did.DIDURL{DID: issuerDID}
// vcID.Fragment = uuid.NewString()
// vcIDURI := vcID.URI()
Expand Down
8 changes: 4 additions & 4 deletions discoveryservice/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,14 +140,14 @@ func (m *Module) Add(serviceID string, presentation vc.VerifiablePresentation) e
func (m *Module) addPresentation(definition Definition, presentation vc.VerifiablePresentation) error {
// Must contain credentials
if len(presentation.VerifiableCredential) == 0 {
return errors.New("presentation must contain at least one credential")
return errors.New("presentation must contain at least one credentialRecord")
}
// VP can't be valid longer than the credential it contains
// VP can't be valid longer than the credentialRecord it contains
expiration := presentation.JWT().Expiration()
for _, cred := range presentation.VerifiableCredential {
exp := cred.JWT().Expiration()
if !exp.IsZero() && expiration.After(exp) {
return fmt.Errorf("presentation is valid longer than the credential(s) it contains")
return fmt.Errorf("presentation is valid longer than the credentialRecord(s) it contains")
}
}
// VP must fulfill the PEX Presentation Definition
Expand All @@ -159,7 +159,7 @@ func (m *Module) addPresentation(definition Definition, presentation vc.Verifiab
}

func (m *Module) addRetraction(serviceID string, presentation vc.VerifiablePresentation) error {
// Presentation might be a retraction (deletion of an earlier credential) must contain no credentials, and refer to the VP being retracted by ID.
// Presentation might be a retraction (deletion of an earlier credentialRecord) must contain no credentials, and refer to the VP being retracted by ID.
// If those conditions aren't met, we don't need to register the retraction.
if len(presentation.VerifiableCredential) > 0 {
return errors.New("retraction presentation must not contain credentials")
Expand Down
Loading

0 comments on commit eb54df9

Please sign in to comment.