Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

feat: Add equivalent ID to also known as for did:web #1446

Merged
merged 1 commit into from
Aug 24, 2022
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
46 changes: 44 additions & 2 deletions pkg/document/webresolver/resolvehandler.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,13 @@ func (r *ResolveHandler) ResolveDocument(id string) (*document.ResolutionResult,

orbDID := getOrbDID(localResponse)

equivalentID, err := getEquivalentID(localResponse)
if err != nil {
return nil, err
}

// replace did:web ID with did:orb ID in also known as; if did:web ID is not found then add did:orb ID anyway
didWebDoc, err = updateAlsoKnownAs(didWebDoc, webDID, orbDID)
didWebDoc, err = updateAlsoKnownAs(didWebDoc, webDID, orbDID, equivalentID)
if err != nil {
return nil, err
}
Expand All @@ -101,7 +106,7 @@ func (r *ResolveHandler) ResolveDocument(id string) (*document.ResolutionResult,
return &document.ResolutionResult{Document: didWebDoc, Context: localResponse.Context}, nil
}

func updateAlsoKnownAs(didWebDoc document.Document, webDID, orbDID string) (document.Document, error) {
func updateAlsoKnownAs(didWebDoc document.Document, webDID, orbDID string, equivalentID []string) (document.Document, error) { //nolint:lll
alsoKnownAs, err := getAlsoKnownAs(didWebDoc)
if err != nil {
return nil, err
Expand All @@ -114,6 +119,16 @@ func updateAlsoKnownAs(didWebDoc document.Document, webDID, orbDID string) (docu
updatedAlsoKnownAs = append(updatedAlsoKnownAs, orbDID)
}

// unpublished doc has 1 equivalent ID, and published has 2+ (first one is canonical)
const maxEquivalentIDLength = 2
count := minimum(maxEquivalentIDLength, len(equivalentID))

for i := 0; i < count; i++ {
if !contains(updatedAlsoKnownAs, equivalentID[i]) {
updatedAlsoKnownAs = append(updatedAlsoKnownAs, equivalentID[i])
}
}

didWebDoc[document.AlsoKnownAs] = updatedAlsoKnownAs

return didWebDoc, nil
Expand Down Expand Up @@ -180,6 +195,25 @@ func getAlsoKnownAs(doc document.Document) ([]string, error) {
return nil, fmt.Errorf("unexpected interface '%T' for also known as", alsoKnownAsObj)
}

func getEquivalentID(result *document.ResolutionResult) ([]string, error) {
equivalentIDObj, ok := result.DocumentMetadata[document.EquivalentIDProperty]
if !ok {
return nil, nil
}

equivalentIDArr, ok := equivalentIDObj.([]interface{})
if ok {
return document.StringArray(equivalentIDArr), nil
}

equivalentIDStrArr, ok := equivalentIDObj.([]string)
if ok {
return equivalentIDStrArr, nil
}

return nil, fmt.Errorf("unexpected interface '%T' for equivalentId", equivalentIDObj)
}

func getDeactivatedFlag(result *document.ResolutionResult) bool {
deactivatedObj, ok := result.DocumentMetadata[document.DeactivatedProperty]
if ok {
Expand All @@ -201,3 +235,11 @@ func contains(values []string, value string) bool {

return false
}

func minimum(a, b int) int {
if a < b {
return a
}

return b
}
88 changes: 84 additions & 4 deletions pkg/document/webresolver/resolvehandler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,11 @@ func TestResolveHandler_Resolve(t *testing.T) {
require.NotNil(t, response)

require.Equal(t, "did:web:orb.domain1.com:scid:"+testSuffix, response.Document.ID())
require.True(t, contains(response.Document[document.AlsoKnownAs].([]string),
"did:orb:uEiAZPHwtTJ7-rG0nBeD6nqyL3Xsg1IA2BX1n9iGlv5yBJQ:EiBmPHOGe4f8L4_ZVgBg5V343_nDSSX3l6X-9VKRhE57Tw"))
require.Equal(t, response.Document[document.AlsoKnownAs].([]string)[0], "https://myblog.example/")
require.Equal(t, response.Document[document.AlsoKnownAs].([]string)[1],
"did:orb:uEiAZPHwtTJ7-rG0nBeD6nqyL3Xsg1IA2BX1n9iGlv5yBJQ:EiBmPHOGe4f8L4_ZVgBg5V343_nDSSX3l6X-9VKRhE57Tw")
require.Equal(t, response.Document[document.AlsoKnownAs].([]string)[2],
"did:orb:hl:uEiAZPHwtTJ7-rG0nBeD6nqyL3Xsg1IA2BX1n9iGlv5yBJQ:uoQ-CeEtodHRwczovL29yYi5kb21haW4xLmNvbS9jYXMvdUVpQVpQSHd0VEo3LXJHMG5CZUQ2bnF5TDNYc2cxSUEyQlgxbjlpR2x2NXlCSlF4QmlwZnM6Ly9iYWZrcmVpYXpocjZjMnRlNjcyd2cyanlmNGQ1ajVsZWwzdjVzYnZlYWd5Y3gyejd3ZWdzMzdoZWJldQ:EiBmPHOGe4f8L4_ZVgBg5V343_nDSSX3l6X-9VKRhE57Tw") //nolint:lll

responseBytes, err := json.Marshal(response)
require.NoError(t, err)
Expand All @@ -76,8 +79,17 @@ func TestResolveHandler_Resolve(t *testing.T) {
require.NotNil(t, response)

require.Equal(t, "did:web:orb.domain1.com:scid:"+testUnpublishedSuffix, response.Document.ID())
require.True(t, contains(response.Document[document.AlsoKnownAs].([]string),
"did:orb:uAAA:EiBmPHOGe4f8L4_ZVgBg5V343_nDSSX3l6X-9VKRhE57Tw"))
require.Equal(t, 3, len(response.Document[document.AlsoKnownAs].([]string)))
require.Equal(t, response.Document[document.AlsoKnownAs].([]string)[0], "https://myblog.example/")
require.Equal(t, response.Document[document.AlsoKnownAs].([]string)[1],
"did:orb:uAAA:EiBmPHOGe4f8L4_ZVgBg5V343_nDSSX3l6X-9VKRhE57Tw")
require.Equal(t, response.Document[document.AlsoKnownAs].([]string)[2],
"did:orb:https:orb.domain1.com:uAAA:EiBmPHOGe4f8L4_ZVgBg5V343_nDSSX3l6X-9VKRhE57Tw")

responseBytes, err := json.Marshal(response)
require.NoError(t, err)

fmt.Println(string(responseBytes))
})

t.Run("success - published did but domain not in alsoKnownAs (orb canonical ID added to also known as)", func(t *testing.T) { //nolint:lll
Expand Down Expand Up @@ -124,6 +136,55 @@ func TestResolveHandler_Resolve(t *testing.T) {
"did:orb:uEiAZPHwtTJ7-rG0nBeD6nqyL3Xsg1IA2BX1n9iGlv5yBJQ:EiBmPHOGe4f8L4_ZVgBg5V343_nDSSX3l6X-9VKRhE57Tw"))
})

t.Run("success - equivalent ID does not exist in the document", func(t *testing.T) {
rr, err := getTestResolutionResult()
require.NoError(t, err)

delete(rr.DocumentMetadata, document.EquivalentIDProperty)

orbResolver := &mocks.OrbResolver{}
orbResolver.ResolveDocumentReturns(rr, nil)

handler := NewResolveHandler(testDomainURL,
orbPrefix, orbUnpublishedLabel, orbResolver,
&orbmocks.MetricsProvider{})

response, err := handler.ResolveDocument(testSuffix)
require.NoError(t, err)
require.NotNil(t, response)

require.Equal(t, "did:web:orb.domain1.com:scid:"+testSuffix, response.Document.ID())
require.Equal(t, 2, len(response.Document[document.AlsoKnownAs].([]string)))
require.Equal(t, response.Document[document.AlsoKnownAs].([]string)[0], "https://myblog.example/")
require.Equal(t, response.Document[document.AlsoKnownAs].([]string)[1],
"did:orb:uEiAZPHwtTJ7-rG0nBeD6nqyL3Xsg1IA2BX1n9iGlv5yBJQ:EiBmPHOGe4f8L4_ZVgBg5V343_nDSSX3l6X-9VKRhE57Tw")
})

t.Run("success - equivalent ID is string array", func(t *testing.T) {
rr, err := getTestResolutionResult()
require.NoError(t, err)

rr.DocumentMetadata[document.EquivalentIDProperty] = []string{"https://test.com"}

orbResolver := &mocks.OrbResolver{}
orbResolver.ResolveDocumentReturns(rr, nil)

handler := NewResolveHandler(testDomainURL,
orbPrefix, orbUnpublishedLabel, orbResolver,
&orbmocks.MetricsProvider{})

response, err := handler.ResolveDocument(testSuffix)
require.NoError(t, err)
require.NotNil(t, response)

require.Equal(t, "did:web:orb.domain1.com:scid:"+testSuffix, response.Document.ID())
require.Equal(t, 3, len(response.Document[document.AlsoKnownAs].([]string)))
require.Equal(t, response.Document[document.AlsoKnownAs].([]string)[0], "https://myblog.example/")
require.Equal(t, response.Document[document.AlsoKnownAs].([]string)[1],
"did:orb:uEiAZPHwtTJ7-rG0nBeD6nqyL3Xsg1IA2BX1n9iGlv5yBJQ:EiBmPHOGe4f8L4_ZVgBg5V343_nDSSX3l6X-9VKRhE57Tw")
require.Equal(t, response.Document[document.AlsoKnownAs].([]string)[2], "https://test.com")
})

t.Run("success - current domain not listed in also known as(string array version)", func(t *testing.T) {
rr, err := getTestResolutionResult()
require.NoError(t, err)
Expand Down Expand Up @@ -182,6 +243,25 @@ func TestResolveHandler_Resolve(t *testing.T) {
require.Contains(t, err.Error(), "unexpected interface 'float64' for also known as")
})

t.Run("error - equivalent ID is an unexpected interface", func(t *testing.T) {
rr, err := getTestResolutionResult()
require.NoError(t, err)

rr.DocumentMetadata[document.EquivalentIDProperty] = 123

orbResolver := &mocks.OrbResolver{}
orbResolver.ResolveDocumentReturns(rr, nil)

handler := NewResolveHandler(testDomainURL,
orbPrefix, orbUnpublishedLabel, orbResolver,
&orbmocks.MetricsProvider{})

response, err := handler.ResolveDocument(testSuffix)
require.Error(t, err)
require.Nil(t, response)
require.Contains(t, err.Error(), "unexpected interface 'int' for equivalentId")
})

t.Run("error - orb resolver error", func(t *testing.T) {
orbResolver := &mocks.OrbResolver{}
orbResolver.ResolveDocumentReturns(nil, fmt.Errorf("orb resolver error"))
Expand Down