Skip to content
This repository has been archived by the owner on Dec 12, 2024. It is now read-only.

Fixing Cred Suspension Bug #487

Merged
merged 7 commits into from
May 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 15 additions & 9 deletions integration/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,24 +107,30 @@ func CreateKYCSchema() (string, error) {
}

type credInputParams struct {
IssuerID string
IssuerKID string
SchemaID string
SubjectID string
IssuerID string
IssuerKID string
SchemaID string
SubjectID string
Revocable bool
Suspendable bool
}

func CreateVerifiableCredential(credentialInput credInputParams, revocable bool) (string, error) {
func CreateVerifiableCredential(credentialInput credInputParams) (string, error) {
logrus.Println("\n\nCreate a verifiable credential")

if credentialInput.SubjectID == "" {
credentialInput.SubjectID = credentialInput.IssuerID
}

fileName := "credential-input.json"
if revocable {
fileName = "credential-revocable-input.json"
if credentialInput.Revocable {
credentialInput.Revocable = true
}
credentialJSON, err := resolveTemplate(credentialInput, fileName)

if credentialInput.Suspendable {
credentialInput.Suspendable = true
}

credentialJSON, err := resolveTemplate(credentialInput, "credential-input.json")
if err != nil {
return "", err
}
Expand Down
2 changes: 1 addition & 1 deletion integration/credential_manifest_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ func TestCreateVerifiableCredentialIntegration(t *testing.T) {
IssuerKID: issuerKID.(string),
SchemaID: schemaID.(string),
SubjectID: issuerDID.(string),
}, false)
})
assert.NoError(t, err)
assert.NotEmpty(t, vcOutput)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ func TestCreateRevocationVerifiableCredentialIntegration(t *testing.T) {
assert.NoError(t, err)
assert.NotEmpty(t, schemaID)

vcOutput, err := CreateVerifiableCredential(credInputParams{IssuerID: issuerDID, IssuerKID: issuerKID, SchemaID: schemaID, SubjectID: issuerDID}, true)
vcOutput, err := CreateVerifiableCredential(credInputParams{IssuerID: issuerDID, IssuerKID: issuerKID, SchemaID: schemaID, SubjectID: issuerDID, Revocable: true})
assert.NoError(t, err)
assert.NotEmpty(t, vcOutput)

Expand Down Expand Up @@ -68,7 +68,7 @@ func TestCreateRevocationVerifiableCredentialShareStatusListIntegration(t *testi
assert.NoError(t, err)
assert.NotEmpty(t, schemaID)

vcOutput, err := CreateVerifiableCredential(credInputParams{IssuerID: issuerDID, IssuerKID: issuerKID, SchemaID: schemaID, SubjectID: issuerDID}, true)
vcOutput, err := CreateVerifiableCredential(credInputParams{IssuerID: issuerDID, IssuerKID: issuerKID, SchemaID: schemaID, SubjectID: issuerDID, Revocable: true})
assert.NoError(t, err)
assert.NotEmpty(t, vcOutput)

Expand All @@ -82,7 +82,7 @@ func TestCreateRevocationVerifiableCredentialShareStatusListIntegration(t *testi
assert.NotEmpty(t, credStatusListURL)
assert.Contains(t, credStatusListURL, "http")

vcOutputTwo, err := CreateVerifiableCredential(credInputParams{IssuerID: issuerDID, IssuerKID: issuerKID, SchemaID: schemaID, SubjectID: issuerDID}, true)
vcOutputTwo, err := CreateVerifiableCredential(credInputParams{IssuerID: issuerDID, IssuerKID: issuerKID, SchemaID: schemaID, SubjectID: issuerDID, Revocable: true})
assert.NoError(t, err)
assert.NotEmpty(t, vcOutputTwo)

Expand Down Expand Up @@ -135,7 +135,7 @@ func TestConcurrencyRevocationVerifiableCredentialIntegration(t *testing.T) {
go func() {
defer wg.Done()

vcOutput, err := CreateVerifiableCredential(credInputParams{IssuerID: issuerDID, IssuerKID: issuerKID, SchemaID: schemaID, SubjectID: issuerDID}, true)
vcOutput, err := CreateVerifiableCredential(credInputParams{IssuerID: issuerDID, IssuerKID: issuerKID, SchemaID: schemaID, SubjectID: issuerDID, Revocable: true})

// We're hammering the DB, so some calls might fail due to internal timeouts or similar. Upon failure, we
// shouldn't check any assertions, since we know they'll fail.
Expand Down
36 changes: 35 additions & 1 deletion integration/credential_revocation_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,8 @@ func TestRevocationCreateVerifiableCredentialIntegration(t *testing.T) {
IssuerKID: issuerKID.(string),
SchemaID: schemaID.(string),
SubjectID: issuerDID.(string),
}, true)
Revocable: true,
})
assert.NoError(t, err)
assert.NotEmpty(t, vcOutput)

Expand Down Expand Up @@ -195,3 +196,36 @@ func TestRevocationValidateCredentialInStatusListIntegration(t *testing.T) {
assert.NoError(t, err)
assert.True(t, valid)
}

func TestRevocationUnRevokeCredential(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test")
}

credStatusURL, err := GetValue(credentialRevocationContext, "credStatusURL")
assert.NoError(t, err)
assert.NotEmpty(t, credStatusURL)

credStatusOutput, err := get(credStatusURL.(string))
assert.NoError(t, err)
assert.NotEmpty(t, credStatusOutput)

revoked, err := getJSONElement(credStatusOutput, "$.revoked")
assert.NoError(t, err)
assert.Equal(t, "true", revoked)

revokedOutput, err := put(credStatusURL.(string), `{"revoked":false}`)
assert.NoError(t, err)

revoked, err = getJSONElement(revokedOutput, "$.revoked")
assert.NoError(t, err)
assert.Equal(t, "false", revoked)

credStatusOutput, err = get(credStatusURL.(string))
assert.NoError(t, err)
assert.NotEmpty(t, credStatusOutput)

revoked, err = getJSONElement(credStatusOutput, "$.revoked")
assert.NoError(t, err)
assert.Equal(t, "false", revoked)
}
234 changes: 234 additions & 0 deletions integration/credential_suspension_integration_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
package integration
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could this be combined into a credential_status_integration_test?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it could be, but I opted for a fresh flow, fresh creds, making sure suspension works, didnt want like a revokable cred flow to 'init' something so a suspension would work

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm worried about scaling this once we move to a generic status - and not needing to support specific statuses. But fine to save that until we impl that change.


import (
"fmt"
"testing"

"github.com/TBD54566975/ssi-sdk/credential"
"github.com/TBD54566975/ssi-sdk/credential/status"
"github.com/goccy/go-json"
"github.com/stretchr/testify/assert"
)

var credentialSuspensionContext = NewTestContext("CredentialSuspension")

func TestSuspensionCreateIssuerDIDKeyIntegration(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test")
}

didKeyOutput, err := CreateDIDKey()
assert.NoError(t, err)

issuerDID, err := getJSONElement(didKeyOutput, "$.did.id")
assert.NoError(t, err)
assert.Contains(t, issuerDID, "did:key")
SetValue(credentialSuspensionContext, "issuerDID", issuerDID)

issuerKID, err := getJSONElement(didKeyOutput, "$.did.verificationMethod[0].id")
assert.NoError(t, err)
assert.NotEmpty(t, issuerKID)
SetValue(credentialSuspensionContext, "issuerKID", issuerKID)
}

func TestSuspensionCreateSchemaIntegration(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test")
}

output, err := CreateKYCSchema()
assert.NoError(t, err)

schemaID, err := getJSONElement(output, "$.id")
assert.NoError(t, err)
assert.NotEmpty(t, schemaID)
SetValue(credentialSuspensionContext, "schemaID", schemaID)
}

func TestSuspensionCreateVerifiableCredentialIntegration(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test")
}

issuerDID, err := GetValue(credentialSuspensionContext, "issuerDID")
assert.NoError(t, err)
assert.NotEmpty(t, issuerDID)

issuerKID, err := GetValue(credentialSuspensionContext, "issuerKID")
assert.NoError(t, err)
assert.NotEmpty(t, issuerKID)

schemaID, err := GetValue(credentialSuspensionContext, "schemaID")
assert.NoError(t, err)
assert.NotEmpty(t, schemaID)

vcOutput, err := CreateVerifiableCredential(credInputParams{
IssuerID: issuerDID.(string),
IssuerKID: issuerKID.(string),
SchemaID: schemaID.(string),
SubjectID: issuerDID.(string),
Suspendable: true,
})
assert.NoError(t, err)
assert.NotEmpty(t, vcOutput)

cred, err := getJSONElement(vcOutput, "$.credential")
assert.NoError(t, err)
assert.NotEmpty(t, cred)
SetValue(credentialSuspensionContext, "cred", cred)

credStatusURL, err := getJSONElement(vcOutput, "$.credential.credentialStatus.id")
assert.NoError(t, err)
assert.NotEmpty(t, credStatusURL)
assert.Contains(t, credStatusURL, "http")
SetValue(credentialSuspensionContext, "credStatusURL", credStatusURL)

fmt.Print(credStatusURL)

statusListCredentialURL, err := getJSONElement(vcOutput, "$.credential.credentialStatus.statusListCredential")
assert.NoError(t, err)
assert.NotEmpty(t, statusListCredentialURL)
assert.Contains(t, statusListCredentialURL, "http")
SetValue(credentialSuspensionContext, "statusListCredentialURL", statusListCredentialURL)

credStatusListCredentialOutput, err := get(statusListCredentialURL)
assert.NoError(t, err)
assert.NotEmpty(t, credStatusListCredentialOutput)

encodedListOriginal, err := getJSONElement(credStatusListCredentialOutput, "$.credential.credentialSubject.encodedList")
assert.NoError(t, err)
assert.NotEmpty(t, encodedListOriginal)
SetValue(credentialSuspensionContext, "encodedListOriginal", encodedListOriginal)
}

func TestSuspensionCheckStatusIntegration(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test")
}

credStatusURL, err := GetValue(credentialSuspensionContext, "credStatusURL")
assert.NoError(t, err)
assert.NotEmpty(t, credStatusURL)

credStatusOutput, err := get(credStatusURL.(string))
assert.NoError(t, err)
assert.NotEmpty(t, credStatusOutput)

suspended, err := getJSONElement(credStatusOutput, "$.suspended")
assert.NoError(t, err)
assert.Equal(t, "false", suspended)

suspendedOutput, err := put(credStatusURL.(string), getJSONFromFile("suspended-input.json"))
assert.NoError(t, err)

suspended, err = getJSONElement(suspendedOutput, "$.suspended")
assert.NoError(t, err)
assert.Equal(t, "true", suspended)

credStatusOutput, err = get(credStatusURL.(string))
assert.NoError(t, err)
assert.NotEmpty(t, credStatusOutput)

suspended, err = getJSONElement(credStatusOutput, "$.suspended")
assert.NoError(t, err)
assert.Equal(t, "true", suspended)
}

func TestSuspensionCheckStatusListCredentialIntegration(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test")
}

statusListCredentialURL, err := GetValue(credentialSuspensionContext, "statusListCredentialURL")
assert.NoError(t, err)
assert.NotEmpty(t, statusListCredentialURL)

credStatusListCredentialOutput, err := get(statusListCredentialURL.(string))
assert.NoError(t, err)
assert.NotEmpty(t, credStatusListCredentialOutput)

statusListType, err := getJSONElement(credStatusListCredentialOutput, "$.credential.credentialSubject.type")
assert.NoError(t, err)
assert.NotEmpty(t, statusListType)
assert.Equal(t, "StatusList2021", statusListType)

encodedList, err := getJSONElement(credStatusListCredentialOutput, "$.credential.credentialSubject.encodedList")
assert.NoError(t, err)
assert.NotEmpty(t, encodedList)

encodedListOriginal, err := GetValue(credentialSuspensionContext, "encodedListOriginal")
assert.NoError(t, err)
assert.NotEmpty(t, encodedListOriginal)

assert.NotEqual(t, encodedListOriginal.(string), encodedList)
}

func TestSuspensionValidateCredentialInStatusListIntegration(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test")
}

credJSON, err := GetValue(credentialSuspensionContext, "cred")
assert.NoError(t, err)
assert.NotEmpty(t, credJSON)

var vc credential.VerifiableCredential
err = json.Unmarshal([]byte(credJSON.(string)), &vc)
assert.NoError(t, err)
assert.NotEmpty(t, vc)

statusListCredentialURL, err := GetValue(credentialSuspensionContext, "statusListCredentialURL")
assert.NoError(t, err)
assert.NotEmpty(t, statusListCredentialURL)

credStatusListCredentialOutput, err := get(statusListCredentialURL.(string))
assert.NoError(t, err)
assert.NotEmpty(t, credStatusListCredentialOutput)

credStatusListCredentialJSON, err := getJSONElement(credStatusListCredentialOutput, "$.credential")
assert.NoError(t, err)
assert.NotEmpty(t, credStatusListCredentialJSON)

var vcStatusList credential.VerifiableCredential
err = json.Unmarshal([]byte(credStatusListCredentialJSON), &vcStatusList)
assert.NoError(t, err)
assert.NotEmpty(t, vcStatusList)

// Validate the StatusListIndex in flipped in the credStatusList
valid, err := status.ValidateCredentialInStatusList(vc, vcStatusList)
assert.NoError(t, err)
assert.True(t, valid)
}

func TestSuspensionUnSuspendCredential(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test")
}

credStatusURL, err := GetValue(credentialSuspensionContext, "credStatusURL")
assert.NoError(t, err)
assert.NotEmpty(t, credStatusURL)

credStatusOutput, err := get(credStatusURL.(string))
assert.NoError(t, err)
assert.NotEmpty(t, credStatusOutput)

suspended, err := getJSONElement(credStatusOutput, "$.suspended")
assert.NoError(t, err)
assert.Equal(t, "true", suspended)

suspendedOutput, err := put(credStatusURL.(string), `{"suspended":false}`)
assert.NoError(t, err)

suspended, err = getJSONElement(suspendedOutput, "$.suspended")
assert.NoError(t, err)
assert.Equal(t, "false", suspended)

credStatusOutput, err = get(credStatusURL.(string))
assert.NoError(t, err)
assert.NotEmpty(t, credStatusOutput)

suspended, err = getJSONElement(credStatusOutput, "$.suspended")
assert.NoError(t, err)
assert.Equal(t, "false", suspended)
}
2 changes: 1 addition & 1 deletion integration/didion_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ func TestDIDIONCreateVerifiableCredentialIntegration(t *testing.T) {
IssuerKID: issuerKID.(string),
SchemaID: schemaID.(string),
SubjectID: issuerDID.(string),
}, false)
})
assert.NoError(t, err)
assert.NotEmpty(t, vcOutput)

Expand Down
2 changes: 1 addition & 1 deletion integration/didweb_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ func TestDIDWebCreateVerifiableCredentialIntegration(t *testing.T) {
IssuerKID: issuerKID.(string),
SchemaID: schemaID.(string),
SubjectID: issuerDID.(string),
}, false)
})
assert.NoError(t, err)
assert.NotEmpty(t, vcOutput)

Expand Down
Loading