Skip to content

Commit

Permalink
feat: Add support for VCDM 2 - EnvelopedVerifiableCredential type
Browse files Browse the repository at this point in the history
Signed-off-by: Bob Stasyszyn <bob.stasyszyn@gendigital.com>
  • Loading branch information
bstasyszyn committed Oct 21, 2024
1 parent a587591 commit 28e0c19
Show file tree
Hide file tree
Showing 9 changed files with 495 additions and 65 deletions.
50 changes: 50 additions & 0 deletions verifiable/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ package verifiable
import (
"errors"
"fmt"
"strings"

"github.com/piprate/json-gold/ld"
util "github.com/trustbloc/did-go/doc/util/time"
Expand Down Expand Up @@ -371,3 +372,52 @@ func mapSlice2[T any, U any](slice []T, mapFN func(T) (U, error)) ([]U, error) {

return result, nil
}

// MediaType specifies the media type of the data.
type MediaType string

// Encoding specifies the encoding of the data.
type Encoding string

// NewDataURL returns a new Data URL given the media type, encoding, and data.
// The URL will be in the format "data:<media type>[;base64],<data>".
// See https://www.rfc-editor.org/rfc/rfc2397.
func NewDataURL(mediaType MediaType, encoding Encoding, data string) string {
if encoding == "" {
return fmt.Sprintf("data:%s,%s", mediaType, data)
}

return fmt.Sprintf("data:%s;%s,%s", mediaType, encoding, data)
}

// ParseDataURL parses the given data URL and returns the media type, encoding, and data.
// The URL must be in the format "data:<media type>[;base64],<data>".
// See https://www.rfc-editor.org/rfc/rfc2397.
func ParseDataURL(url string) (MediaType, Encoding, string, error) {
if !strings.HasPrefix(url, "data:") {
return "", "", "", fmt.Errorf("invalid data URL format: %s", url)
}

url = url[5:] // Remove "data:" prefix
commaIndex := strings.Index(url, ",")
if commaIndex == -1 {
return "", "", "", fmt.Errorf("invalid data URL format: %s", url)
}

fullMediaType := url[:commaIndex]
if fullMediaType == "" {
return "", "", "", fmt.Errorf("media type is required")
}

data := url[commaIndex+1:]

semicolonIndex := strings.Index(fullMediaType, ";")
if semicolonIndex == -1 {
return MediaType(fullMediaType), "", data, nil
}

mediaType := MediaType(fullMediaType[:semicolonIndex])
encoding := Encoding(fullMediaType[semicolonIndex+1:])

return mediaType, encoding, data, nil
}
41 changes: 41 additions & 0 deletions verifiable/common_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,47 @@ func Test_parseLDProof(t *testing.T) {
})
}

func TestParseDataURL(t *testing.T) {
t.Run("Valid data URL with media type and encoding", func(t *testing.T) {
url := "data:text/plain;base64,SGVsbG8sIFdvcmxkIQ=="
mediaType, encoding, data, err := ParseDataURL(url)
require.NoError(t, err)
require.Equal(t, MediaType("text/plain"), mediaType)
require.Equal(t, Encoding("base64"), encoding)
require.Equal(t, "SGVsbG8sIFdvcmxkIQ==", data)
})

t.Run("Valid data URL with media type only", func(t *testing.T) {
url := "data:text/plain,HelloWorld"
mediaType, encoding, data, err := ParseDataURL(url)
require.NoError(t, err)
require.Equal(t, MediaType("text/plain"), mediaType)
require.Empty(t, encoding)
require.Equal(t, "HelloWorld", data)
})

t.Run("Invalid data URL without media type", func(t *testing.T) {
url := "data:,HelloWorld"
_, _, _, err := ParseDataURL(url)
require.Error(t, err)
require.Contains(t, err.Error(), "media type is required")
})

t.Run("Invalid data URL without comma", func(t *testing.T) {
url := "data:text/plain;base64SGVsbG8sIFdvcmxkIQ=="
_, _, _, err := ParseDataURL(url)
require.Error(t, err)
require.Contains(t, err.Error(), "invalid data URL format")
})

t.Run("Invalid data URL without prefix", func(t *testing.T) {
url := "text/plain;base64,SGVsbG8sIFdvcmxkIQ=="
_, _, _, err := ParseDataURL(url)
require.Error(t, err)
require.Contains(t, err.Error(), "invalid data URL format")
})
}

// toArray convert array to array of json objects.
func toArray[T any](v []T) ([]interface{}, error) {
maps := make([]interface{}, len(v))
Expand Down
Loading

0 comments on commit 28e0c19

Please sign in to comment.