Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Add DidComm Discovery Protocol Query/Disclosure message #71

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 5 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
25 changes: 25 additions & 0 deletions packager.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ type Packer interface {
Unpack(envelope []byte) (*BasicMessage, error)
// MediaType returns content type of message
MediaType() MediaType
// GetSupportedProfiles returns supported accept profiles
GetSupportedProfiles() []string
// IsProfileSupported checks if profile is supported by packer
IsProfileSupported(profile string) bool
}

// PackerParams mock interface for packer params
Expand Down Expand Up @@ -99,6 +103,27 @@ func (r *PackageManager) unpackSafeEnvelope(mediaType MediaType, envelope []byte
return msg, nil
}

// GetSupportedProfiles retrieves all unique supported profiles.
func (r *PackageManager) GetSupportedProfiles() []string {
var acceptProfiles []string
for _, p := range r.packers {
profiles := p.GetSupportedProfiles()
acceptProfiles = append(acceptProfiles, profiles...)
Copy link
Contributor

Choose a reason for hiding this comment

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

Is it a chance that two packers would have profiles with the same name and we would return duplicate entries?

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 shouldn't be that way; otherwise, the first packer that matches the envelope would handle the pack()

}
return acceptProfiles
}

// IsProfileSupported checks if profile is supported by packer manager
func (r *PackageManager) IsProfileSupported(profile string) bool {
for _, p := range r.packers {
isSupported := p.IsProfileSupported(profile)
if isSupported {
return true
}
}
return false
}

type envelopeStub struct {
Protected string `json:"protected"`
}
Expand Down
7 changes: 7 additions & 0 deletions packager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,13 @@ func TestUnpackWithType(t *testing.T) {
assert.Equal(t, unpackedMsg.Typ, packers.MediaTypeZKPMessage)
}

func TestGetSupportedProfiles(t *testing.T) {
pm := initPackageManager(t)
profiles := pm.GetSupportedProfiles()
assert.Contains(t, profiles, "iden3comm/v1;env=application/iden3comm-plain-json")
assert.Contains(t, profiles, "iden3comm/v1;env=application/iden3-zkp-json&alg=groth16&circuitIds=authV2")
}

func createFetchCredentialMessage(typ iden3comm.MediaType, from, to *w3c.DID) ([]byte, error) {

var msg protocol.CredentialFetchRequestMessage
Expand Down
58 changes: 58 additions & 0 deletions packers/anoncrypt.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,12 @@ package packers

import (
"encoding/json"
"fmt"
"strings"

"github.com/iden3/iden3comm/v2"
"github.com/iden3/iden3comm/v2/protocol"
"github.com/iden3/iden3comm/v2/utils"
"github.com/pkg/errors"
"gopkg.in/go-jose/go-jose.v2"
)
Expand Down Expand Up @@ -91,3 +95,57 @@ func (p *AnoncryptPacker) Unpack(envelope []byte) (*iden3comm.BasicMessage, erro
func (p *AnoncryptPacker) MediaType() iden3comm.MediaType {
return MediaTypeEncryptedMessage
}

// GetSupportedProfiles gets packer envelope (supported profiles) with options
func (p *AnoncryptPacker) GetSupportedProfiles() []string {
return []string{
fmt.Sprintf(
"%s;env=%s&alg=%s",
protocol.ProtocolVersionV1,
p.MediaType(),
strings.Join(p.getSupportedAlgorithms(), ","),
),
}
}

// IsProfileSupported checks if profile is supported by packer
func (p *AnoncryptPacker) IsProfileSupported(profile string) bool {
parsedProfile, err := utils.ParseAcceptProfile(profile)
if err != nil {
return false
}

if parsedProfile.ProtocolVersion != protocol.ProtocolVersionV1 {
return false
}

if parsedProfile.Env != p.MediaType() {
return false
}

if len(parsedProfile.Circuits) > 0 || len(parsedProfile.AcceptJwzAlgorithms) > 0 || len(parsedProfile.AcceptJwsAlgorithms) > 0 {
return false
}

supportedAlgorithms := p.getSupportedAlgorithms()
algSupported := len(parsedProfile.AcceptAnoncryptAlgorithms) == 0
if !algSupported {
for _, alg := range parsedProfile.AcceptAnoncryptAlgorithms {
for _, supportedAlg := range supportedAlgorithms {
if string(alg) == supportedAlg {
algSupported = true
break
}
}
if algSupported {
break
}
}
}

return algSupported
Copy link
Contributor

Choose a reason for hiding this comment

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

a little less indentation and state variables

Suggested change
supportedAlgorithms := p.getSupportedAlgorithms()
algSupported := len(parsedProfile.AcceptAnoncryptAlgorithms) == 0
if !algSupported {
for _, alg := range parsedProfile.AcceptAnoncryptAlgorithms {
for _, supportedAlg := range supportedAlgorithms {
if string(alg) == supportedAlg {
algSupported = true
break
}
}
if algSupported {
break
}
}
}
return algSupported
if len(parsedProfile.AcceptJwsAlgorithms) == 0 {
return true
}
supportedAlgorithms := p.getSupportedAlgorithms()
for _, alg := range parsedProfile.AcceptJwsAlgorithms {
for _, supportedAlg := range supportedAlgorithms {
if string(alg) == supportedAlg {
return true
}
}
}
return false

}

func (p *AnoncryptPacker) getSupportedAlgorithms() []string {
return []string{string(jose.ECDH_ES_A256KW)}
}
57 changes: 57 additions & 0 deletions packers/jws.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"crypto/sha256"
"encoding/hex"
"encoding/json"
"fmt"
"strings"

"github.com/dustinxie/ecc"
Expand All @@ -13,6 +14,8 @@ import (
"github.com/iden3/iden3comm/v2"
"github.com/iden3/iden3comm/v2/packers/providers/bjj"
"github.com/iden3/iden3comm/v2/packers/providers/es256k"
"github.com/iden3/iden3comm/v2/protocol"
"github.com/iden3/iden3comm/v2/utils"
"github.com/lestrrat-go/jwx/v2/jwa"
"github.com/lestrrat-go/jwx/v2/jwk"
"github.com/lestrrat-go/jwx/v2/jws"
Expand Down Expand Up @@ -332,6 +335,60 @@ func (p *JWSPacker) MediaType() iden3comm.MediaType {
return MediaTypeSignedMessage
}

// GetSupportedProfiles gets packer envelope (supported profiles) with options
func (p *JWSPacker) GetSupportedProfiles() []string {
return []string{
fmt.Sprintf(
"%s;env=%s&alg=%s",
protocol.ProtocolVersionV1,
p.MediaType(),
strings.Join(p.getSupportedAlgorithms(), ","),
),
}
}

// IsProfileSupported checks if profile is supported by packer
func (p *JWSPacker) IsProfileSupported(profile string) bool {
parsedProfile, err := utils.ParseAcceptProfile(profile)
if err != nil {
return false
}

if parsedProfile.ProtocolVersion != protocol.ProtocolVersionV1 {
return false
}

if parsedProfile.Env != p.MediaType() {
return false
}

if len(parsedProfile.Circuits) > 0 || len(parsedProfile.AcceptAnoncryptAlgorithms) > 0 || len(parsedProfile.AcceptJwzAlgorithms) > 0 {
return false
}

supportedAlgorithms := p.getSupportedAlgorithms()
algSupported := len(parsedProfile.AcceptJwsAlgorithms) == 0
if !algSupported {
for _, alg := range parsedProfile.AcceptJwsAlgorithms {
for _, supportedAlg := range supportedAlgorithms {
if string(alg) == supportedAlg {
algSupported = true
break
}
}
if algSupported {
break
}
}
}

return algSupported
}

func (p *JWSPacker) getSupportedAlgorithms() []string {
return []string{string(protocol.AcceptJwsAlgorithmsES256K), string(protocol.AcceptJwsAlgorithmsES256KR)}
}

// resolveVerificationMethods looks for all verification methods in the DID document.
func resolveVerificationMethods(didDoc *verifiable.DIDDocument) ([]verifiable.CommonVerificationMethod, error) {
vms := make([]verifiable.CommonVerificationMethod, 0,
Expand Down
6 changes: 6 additions & 0 deletions packers/jws_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,12 @@ func TestLookForKid(t *testing.T) {
}
}

func TestJWSSupportedProfiles(t *testing.T) {
p := JWSPacker{}
acceptProfiles := p.GetSupportedProfiles()
require.Equal(t, []string{"iden3comm/v1;env=application/iden3comm-signed-json&alg=ES256K,ES256K-R"}, acceptProfiles)
}

func loadDIDDoc(fileName string) (*verifiable.DIDDocument, error) {
file, err := os.Open(fmt.Sprintf("testdata/jws/%s", fileName))
if err != nil {
Expand Down
32 changes: 32 additions & 0 deletions packers/plain.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@ package packers

import (
"encoding/json"
"fmt"

"github.com/iden3/iden3comm/v2"
"github.com/iden3/iden3comm/v2/protocol"
"github.com/iden3/iden3comm/v2/utils"
"github.com/pkg/errors"
)

Expand Down Expand Up @@ -46,3 +49,32 @@ func (p *PlainMessagePacker) Unpack(envelope []byte) (*iden3comm.BasicMessage, e
func (p *PlainMessagePacker) MediaType() iden3comm.MediaType {
return MediaTypePlainMessage
}

// GetSupportedProfiles gets packer envelope (supported profiles) with options
func (p *PlainMessagePacker) GetSupportedProfiles() []string {
return []string{
fmt.Sprintf(
"%s;env=%s",
protocol.ProtocolVersionV1,
p.MediaType(),
),
}
}

// IsProfileSupported checks if profile is supported by packer
func (p *PlainMessagePacker) IsProfileSupported(profile string) bool {
parsedProfile, err := utils.ParseAcceptProfile(profile)
if err != nil {
return false
}

if parsedProfile.ProtocolVersion != protocol.ProtocolVersionV1 {
return false
}

if parsedProfile.Env != p.MediaType() {
return false
}

return true
}
13 changes: 13 additions & 0 deletions packers/plain_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package packers

import (
"testing"

"github.com/stretchr/testify/require"
)

func TestPlainSupportedProfiles(t *testing.T) {
p := PlainMessagePacker{}
acceptProfiles := p.GetSupportedProfiles()
require.Equal(t, []string{"iden3comm/v1;env=application/iden3comm-plain-json"}, acceptProfiles)
}
77 changes: 77 additions & 0 deletions packers/zkp.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import (
"github.com/iden3/go-iden3-core/v2/w3c"
"github.com/iden3/go-jwz/v2"
"github.com/iden3/iden3comm/v2"
"github.com/iden3/iden3comm/v2/protocol"
"github.com/iden3/iden3comm/v2/utils"
"github.com/pkg/errors"
)

Expand Down Expand Up @@ -239,6 +241,81 @@ func (p *ZKPPacker) MediaType() iden3comm.MediaType {
return MediaTypeZKPMessage
}

// GetSupportedProfiles gets packer envelope (supported profiles) with options
func (p *ZKPPacker) GetSupportedProfiles() []string {
return []string{
fmt.Sprintf(
"%s;env=%s&alg=%s&circuitIds=%s",
protocol.ProtocolVersionV1,
p.MediaType(),
strings.Join(p.getSupportedAlgorithms(), ","),
strings.Join(p.getSupportedCircuitIDs(), ","),
),
}
}

// IsProfileSupported checks if profile is supported by packer
func (p *ZKPPacker) IsProfileSupported(profile string) bool {
parsedProfile, err := utils.ParseAcceptProfile(profile)
if err != nil {
return false
}

if parsedProfile.ProtocolVersion != protocol.ProtocolVersionV1 {
return false
}

if parsedProfile.Env != p.MediaType() {
return false
}

supportedCircuitIDs := p.getSupportedCircuitIDs()
circuitIDSupported := len(parsedProfile.Circuits) == 0
if !circuitIDSupported {
for _, circuit := range parsedProfile.Circuits {
for _, supportedCircuit := range supportedCircuitIDs {
if string(circuit) == supportedCircuit {
circuitIDSupported = true
break
}
}
if circuitIDSupported {
break
}
}
}

if len(parsedProfile.AcceptAnoncryptAlgorithms) > 0 || len(parsedProfile.AcceptJwsAlgorithms) > 0 {
return false
}

supportedAlgorithms := p.getSupportedAlgorithms()
algSupported := len(parsedProfile.AcceptJwzAlgorithms) == 0
if !algSupported {
for _, alg := range parsedProfile.AcceptJwzAlgorithms {
for _, supportedAlg := range supportedAlgorithms {
if string(alg) == supportedAlg {
algSupported = true
break
}
}
if algSupported {
break
}
}
}

return circuitIDSupported && algSupported
}

func (p *ZKPPacker) getSupportedAlgorithms() []string {
return []string{string(protocol.AcceptJwzAlgorithmsGroth16)}
}

func (p *ZKPPacker) getSupportedCircuitIDs() []string {
return []string{string(protocol.AcceptAuthCircuitsAuthV2)}
}

// DefaultZKPUnpackerOption is a function that sets the default ZKP unpacker options
type DefaultZKPUnpackerOption func(*defaultZKPUnpacker)

Expand Down
7 changes: 7 additions & 0 deletions packers/zkp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"github.com/iden3/iden3comm/v2/mock"
"github.com/iden3/iden3comm/v2/protocol"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestZKPPacker_Pack(t *testing.T) {
Expand Down Expand Up @@ -101,3 +102,9 @@ func TestPlainMessagePacker_Unpack(t *testing.T) {
assert.Len(t, authResponse.Body.Scope, 0)

}

func TestZKPSupportedProfiles(t *testing.T) {
p := ZKPPacker{}
acceptProfiles := p.GetSupportedProfiles()
require.Equal(t, []string{"iden3comm/v1;env=application/iden3-zkp-json&alg=groth16&circuitIds=authV2"}, acceptProfiles)
}
Loading
Loading