Skip to content

Commit

Permalink
feat: refresh service (#58)
Browse files Browse the repository at this point in the history
* feat: refresh service

* feat: drop id

* feat: as url

* feat: compare details

* feat: check ld

* feat: uset typedid

* feat: with

* fix: did

* fix: tests

* fix: refresh service
  • Loading branch information
skynet2 authored Aug 13, 2024
1 parent 8cb417a commit c7c2ade
Show file tree
Hide file tree
Showing 6 changed files with 77 additions and 18 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ require (
github.com/tidwall/gjson v1.14.3
github.com/tidwall/sjson v1.1.4
github.com/trustbloc/bbs-signature-go v1.0.2
github.com/trustbloc/did-go v1.2.1
github.com/trustbloc/did-go v1.2.2-0.20240812150654-c7d31e666f96
github.com/trustbloc/kms-go v1.1.2
github.com/veraison/go-cose v1.1.1-0.20240126165338-2300d5c96dbd
github.com/xeipuuv/gojsonschema v1.2.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -132,8 +132,8 @@ github.com/tidwall/sjson v1.1.4 h1:bTSsPLdAYF5QNLSwYsKfBKKTnlGbIuhqL3CpRsjzGhg=
github.com/tidwall/sjson v1.1.4/go.mod h1:wXpKXu8CtDjKAZ+3DrKY5ROCorDFahq8l0tey/Lx1fg=
github.com/trustbloc/bbs-signature-go v1.0.2 h1:gepEsbLiZHv/vva9FKG5gF38mGtOIyGez7desZxiI1o=
github.com/trustbloc/bbs-signature-go v1.0.2/go.mod h1:xYotcXHAbcE0TO+SteW0J6XI3geQaXq4wdnXR2k+XCU=
github.com/trustbloc/did-go v1.2.1 h1:SEOmPX+x2JlE6+jjjJp82yCCusoJ4/67zQ2ST6ytfSc=
github.com/trustbloc/did-go v1.2.1/go.mod h1:packTRoBoo8DrwOE7QKsI98xXS3Vf6ovUXYD4FUAcB4=
github.com/trustbloc/did-go v1.2.2-0.20240812150654-c7d31e666f96 h1:LpX6reFIcahgTxuDLrV9yro1gENtXQLv2NsneX5hWkc=
github.com/trustbloc/did-go v1.2.2-0.20240812150654-c7d31e666f96/go.mod h1:packTRoBoo8DrwOE7QKsI98xXS3Vf6ovUXYD4FUAcB4=
github.com/trustbloc/kms-go v1.1.2 h1:nAlhDoHkSyX1eQFRz/sJsdgmJuNadyX7FJEy/9ROwys=
github.com/trustbloc/kms-go v1.1.2/go.mod h1:OKOtsLbE6W5s4mpjWkvk8XEqcmt9vTgVmDNkHELpWO0=
github.com/veraison/go-cose v1.1.1-0.20240126165338-2300d5c96dbd h1:QhdCHSW1/oosJbzBTEYLU6xcKxXbQzzqFnhCtW2UWbA=
Expand Down
2 changes: 1 addition & 1 deletion presexch/definition_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2613,7 +2613,7 @@ type credentialProto struct {
Schemas []verifiable.TypedID
Evidence verifiable.Evidence
TermsOfUse []verifiable.TypedID
RefreshService []verifiable.TypedID
RefreshService *verifiable.TypedID
SDJWTHashAlg *crypto.Hash

CustomFields verifiable.CustomFields
Expand Down
12 changes: 7 additions & 5 deletions verifiable/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,9 +117,10 @@ func (ja JWSAlgorithm) Name() (string, error) {
}

type jsonldCredentialOpts struct {
jsonldDocumentLoader ld.DocumentLoader
externalContext []string
jsonldOnlyValidRDF bool
jsonldDocumentLoader ld.DocumentLoader
externalContext []string
jsonldOnlyValidRDF bool
jsonldIncludeDetailedStructureDiffOnError bool
}

// Proof defines embedded proof of Verifiable Credential.
Expand All @@ -130,8 +131,9 @@ type Proof map[string]interface{}
type CustomFields map[string]interface{}

const (
jsonFldTypedIDID = "id"
jsonFldTypedIDType = "type"
jsonFldTypedIDID = "id"
jsonFldTypedIDType = "type"
jsonFldTypedURLType = "url"
)

// TypedID defines a flexible structure with id and name fields and arbitrary extra fields
Expand Down
61 changes: 55 additions & 6 deletions verifiable/credential.go
Original file line number Diff line number Diff line change
Expand Up @@ -497,7 +497,7 @@ type CredentialContents struct {
Schemas []TypedID
Evidence Evidence
TermsOfUse []TypedID
RefreshService []TypedID
RefreshService *TypedID
SDJWTHashAlg *crypto.Hash
}

Expand Down Expand Up @@ -859,6 +859,13 @@ func WithJSONLDOnlyValidRDF() CredentialOpt {
}
}

// WithJSONLDIncludeDetailedStructureDiffOnError indicates the need to include detailed structure diff.
func WithJSONLDIncludeDetailedStructureDiffOnError() CredentialOpt {
return func(opts *credentialOpts) {
opts.jsonldIncludeDetailedStructureDiffOnError = true
}
}

// parseIssuer parses raw issuer.
//
// Issuer can be defined by:
Expand Down Expand Up @@ -1021,7 +1028,7 @@ func ParseCredential(vcData []byte, opts ...CredentialOpt) (*Credential, error)
vc, err = parser.Parse(vcData, vcOpts)

if err != nil {
if err.Error() == jsonLDStructureErrStr {
if strings.HasPrefix(err.Error(), jsonLDStructureErrStr) {
return nil, err
}

Expand Down Expand Up @@ -1153,11 +1160,21 @@ func validateBaseContextWithExtendedValidation(vcJSON JSONObject, vcc *Credentia

func validateJSONLD(vcJSON JSONObject, vcOpts *credentialOpts) error {
// TODO: docjsonld.ValidateJSONLDMap has bug that it modify contexts of input vcJSON. Fix in did-go
return docjsonld.ValidateJSONLDMap(jsonutil.ShallowCopyObj(vcJSON),
validateOpts := []docjsonld.ValidateOpts{
docjsonld.WithDocumentLoader(vcOpts.jsonldCredentialOpts.jsonldDocumentLoader),
docjsonld.WithExternalContext(vcOpts.jsonldCredentialOpts.externalContext),
docjsonld.WithStrictValidation(vcOpts.strictValidation),
docjsonld.WithStrictContextURIPosition(baseContext),
}

if vcOpts.jsonldIncludeDetailedStructureDiffOnError {
validateOpts = append(validateOpts,
docjsonld.WithJSONLDIncludeDetailedStructureDiffOnError(),
)
}

return docjsonld.ValidateJSONLDMap(jsonutil.ShallowCopyObj(vcJSON),
validateOpts...,
)
}

Expand Down Expand Up @@ -1197,7 +1214,7 @@ func parseCredentialContents(raw JSONObject, isSDJWT bool) (*CredentialContents,
return nil, fmt.Errorf("fill credential terms of use from raw: %w", err)
}

refreshService, err := parseTypedID(raw[jsonFldRefreshService])
refreshService, err := parseRefreshService(raw[jsonFldRefreshService])
if err != nil {
return nil, fmt.Errorf("fill credential refresh service from raw: %w", err)
}
Expand Down Expand Up @@ -1250,6 +1267,19 @@ func parseCredentialContents(raw JSONObject, isSDJWT bool) (*CredentialContents,
}, nil
}

func parseRefreshService(typeIDRaw interface{}) (*TypedID, error) {
typed, err := parseTypedID(typeIDRaw)
if err != nil {
return nil, fmt.Errorf("parse refresh service: %w", err)
}

if len(typed) == 0 {
return nil, nil
}

return &typed[0], nil
}

func parseTypedID(typeIDRaw interface{}) ([]TypedID, error) {
if typeIDRaw == nil {
return nil, nil
Expand Down Expand Up @@ -1853,8 +1883,8 @@ func serializeCredentialContents(vcc *CredentialContents, proofs []Proof) (JSONO
vcJSON[jsonFldEvidence] = vcc.Evidence
}

if len(vcc.RefreshService) > 0 {
vcJSON[jsonFldRefreshService] = typedIDsToRaw(vcc.RefreshService)
if vcc.RefreshService != nil {
vcJSON[jsonFldRefreshService] = serializeTypedIDObj(*vcc.RefreshService)
}

if len(vcc.TermsOfUse) > 0 {
Expand Down Expand Up @@ -2072,6 +2102,25 @@ func (vc *Credential) WithModifiedStatus(status *TypedID) *Credential {
}
}

// WithModifiedRefreshService creates new credential with modified status and without proofs as they become invalid.
func (vc *Credential) WithModifiedRefreshService(refreshService *TypedID) *Credential {
newCredJSON := copyCredentialJSONWithoutProofs(vc.credentialJSON)
newContents := vc.Contents()

newContents.RefreshService = refreshService

if refreshService != nil {
newCredJSON[jsonFldRefreshService] = serializeTypedIDObj(*refreshService)
} else {
delete(newCredJSON, jsonFldRefreshService)
}

return &Credential{
credentialJSON: newCredJSON,
credentialContents: newContents,
}
}

// WithModifiedIssuer creates new credential with modified issuer and without proofs as they become invalid.
func (vc *Credential) WithModifiedIssuer(issuer *Issuer) *Credential {
newCredJSON := copyCredentialJSONWithoutProofs(vc.credentialJSON)
Expand Down
14 changes: 11 additions & 3 deletions verifiable/credential_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,8 +136,8 @@ func TestParseCredential(t *testing.T) {

// check refresh service
require.NotNil(t, vcc.RefreshService)
require.Equal(t, "https://example.edu/refresh/3732", vcc.RefreshService[0].ID)
require.Equal(t, "ManualRefreshService2018", vcc.RefreshService[0].Type)
require.Equal(t, "https://example.edu/refresh/3732", vcc.RefreshService.ID)
require.Equal(t, "ManualRefreshService2018", vcc.RefreshService.Type)

require.NotNil(t, vcc.Evidence)

Expand Down Expand Up @@ -2296,6 +2296,10 @@ func TestCredential_WithModified(t *testing.T) {
ID: "newID",
Type: "newType",
}).
WithModifiedRefreshService(&TypedID{
ID: "12345",
Type: "SomeRefreshService",
}).
WithModifiedExpired(afgotime.NewTime(expired)).
WithModifiedIssued(afgotime.NewTime(now))

Expand All @@ -2307,13 +2311,16 @@ func TestCredential_WithModified(t *testing.T) {
require.Equal(t, "newType", cred.Contents().Status.Type)
require.EqualValues(t, now, cred.Contents().Issued.Time)
require.EqualValues(t, expired, cred.Contents().Expired.Time)
require.EqualValues(t, "12345", cred.Contents().RefreshService.ID)
require.EqualValues(t, "SomeRefreshService", cred.Contents().RefreshService.Type)

cred = cred.
WithModifiedID("").
WithModifiedSubject(nil).
WithModifiedIssuer(nil).
WithModifiedContext(nil).
WithModifiedStatus(nil)
WithModifiedStatus(nil).
WithModifiedRefreshService(nil)

require.Empty(t, cred.Contents().ID)
require.Empty(t, cred.Contents().Subject)
Expand All @@ -2328,4 +2335,5 @@ func TestCredential_WithModified(t *testing.T) {
require.NotContains(t, raw, jsonFldIssuer)
require.NotContains(t, raw, jsonFldContext)
require.NotContains(t, raw, jsonFldStatus)
require.NotContains(t, raw, jsonFldRefreshService)
}

0 comments on commit c7c2ade

Please sign in to comment.