Skip to content

Commit

Permalink
feat: Add equivalent ID to also known as for did:web
Browse files Browse the repository at this point in the history
For unpublished documents there is only one equivalent ID (with domain) so we will use that one.
For published documents we will use first (HL one).

Closes #1441

Signed-off-by: Sandra Vrtikapa <[email protected]>
  • Loading branch information
sandrask committed Aug 24, 2022
1 parent 670839f commit 7c4c596
Show file tree
Hide file tree
Showing 2 changed files with 128 additions and 6 deletions.
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

0 comments on commit 7c4c596

Please sign in to comment.