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 attachments and directives #72

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
45 changes: 45 additions & 0 deletions directives.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package iden3comm

// Iden3DirectiveType represents the type of directive
type Iden3DirectiveType string

// Constants for Iden3DirectiveType
const (
TransparentPaymentDirectiveType Iden3DirectiveType = "TransparentPaymentDirective"
)

// TransparentPaymentCredential represents credential information
type TransparentPaymentCredential struct {
Type string `json:"type"`
Context string `json:"context"`
}

// TransparentPaymentRequestData represents payment request information
type TransparentPaymentRequestData struct {
Recipient string `json:"recipient"`
Amount string `json:"amount"`
Token string `json:"token,omitempty"`
Expiration string `json:"expiration"`
Nonce string `json:"nonce"`
Metadata string `json:"metadata"`
}

// TransparentPaymentDirectivePayload represents the payload for a transparent payment directive
type TransparentPaymentDirectivePayload struct {
Credential TransparentPaymentCredential `json:"credential"`
PaymentData TransparentPaymentRequestData `json:"paymentData"`
PermitSignature string `json:"permitSignature"`
Description string `json:"description,omitempty"`
}

// TransparentPaymentDirective represents a complete transparent payment directive
type TransparentPaymentDirective struct {
Type Iden3DirectiveType `json:"type"`
Purpose ProtocolMessage `json:"purpose,omitempty"`
Context string `json:"context,omitempty"`
Data []TransparentPaymentDirectivePayload `json:"data"`
}

// Iden3Directive is currently an alias for TransparentPaymentDirective
// Can be expanded to a union type using interfaces if more directive types are added
type Iden3Directive = TransparentPaymentDirective
177 changes: 177 additions & 0 deletions directives_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
package iden3comm_test

import (
"reflect"
"testing"

"github.com/iden3/iden3comm/v2"
)

func TestExtractDirectiveFromMessage(t *testing.T) {
tests := []struct {
name string
message iden3comm.BasicMessage
expected []iden3comm.Iden3Directive
}{
{
name: "No directive attachments",
message: iden3comm.BasicMessage{
Attachments: iden3comm.Attachments{
{Type: "otherType"},
},
},
expected: nil,
},
{
name: "With directive attachments",
message: iden3comm.BasicMessage{
Attachments: iden3comm.Attachments{
{
Type: iden3comm.Iden3DirectiveAttachmentType,
Data: []iden3comm.Iden3Directive{
{
Type: iden3comm.TransparentPaymentDirectiveType,
},
},
},
},
},
expected: []iden3comm.Iden3Directive{
{
Type: iden3comm.TransparentPaymentDirectiveType,
},
},
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := tt.message.Attachments.ExtractDirectives()
if !reflect.DeepEqual(result, tt.expected) {
t.Errorf("expected %v, got %v", tt.expected, result)
}
})
}
}

func TestPropagateDirectiveIntoMessage(t *testing.T) {
tests := []struct {
name string
message iden3comm.BasicMessage
incomingDirective []iden3comm.Iden3Directive
expected iden3comm.BasicMessage
}{
{
name: "No incoming directives",
message: iden3comm.BasicMessage{
ID: "test",
},
incomingDirective: []iden3comm.Iden3Directive{},
expected: iden3comm.BasicMessage{
ID: "test",
},
},
{
name: "No existing attachments",
message: iden3comm.BasicMessage{
ID: "test",
},
incomingDirective: []iden3comm.Iden3Directive{
{
Type: iden3comm.TransparentPaymentDirectiveType,
},
},
expected: iden3comm.BasicMessage{
ID: "test",
Attachments: iden3comm.Attachments{
{
Type: iden3comm.Iden3DirectiveAttachmentType,
Data: []iden3comm.Iden3Directive{
{
Type: iden3comm.TransparentPaymentDirectiveType,
},
},
},
},
},
},
{
name: "With existing directive attachments",
message: iden3comm.BasicMessage{
ID: "test",
Attachments: iden3comm.Attachments{
{
Type: iden3comm.Iden3DirectiveAttachmentType,
Data: []iden3comm.Iden3Directive{
{
Type: iden3comm.TransparentPaymentDirectiveType,
},
},
},
},
},
incomingDirective: []iden3comm.Iden3Directive{
{
Type: iden3comm.TransparentPaymentDirectiveType,
},
},
expected: iden3comm.BasicMessage{
ID: "test",
Attachments: iden3comm.Attachments{
{
Type: iden3comm.Iden3DirectiveAttachmentType,
Data: []iden3comm.Iden3Directive{
{
Type: iden3comm.TransparentPaymentDirectiveType,
},
{
Type: iden3comm.TransparentPaymentDirectiveType,
},
},
},
},
},
},
{
name: "With existing directive attachments and other attachments",
message: iden3comm.BasicMessage{
ID: "test",
Attachments: iden3comm.Attachments{
{
Type: "otherType",
},
},
},
incomingDirective: []iden3comm.Iden3Directive{
{
Type: iden3comm.TransparentPaymentDirectiveType,
},
},
expected: iden3comm.BasicMessage{
ID: "test",
Attachments: iden3comm.Attachments{
{
Type: "otherType",
},
{
Type: iden3comm.Iden3DirectiveAttachmentType,
Data: []iden3comm.Iden3Directive{
{
Type: iden3comm.TransparentPaymentDirectiveType,
},
},
},
},
},
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.message.Attachments.AddDirectives(tt.incomingDirective)
if !reflect.DeepEqual(tt.message, tt.expected) {
t.Errorf("expected %v, got %v", tt.expected, tt.message)
}
})
}
}
68 changes: 65 additions & 3 deletions message.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,67 @@
package iden3comm

import "encoding/json"
import (
"encoding/json"
)

// Iden3AttachmentType represents the type of attachment
type Iden3AttachmentType string

// Constants for Iden3AttachmentType
const (
Iden3DirectiveAttachmentType Iden3AttachmentType = "Iden3Directive"
)

// Attachment is structure for message attachment
type Attachment struct {
Type Iden3AttachmentType `json:"type"`
Data any `json:"data"`
}

// Attachments is a slice of Attachment
type Attachments []*Attachment

// ExtractDirectives extracts directives from a given iden3comm.BasicMessage.
func (a *Attachments) ExtractDirectives() []Iden3Directive {

if a == nil {
return nil
}

var directives []Iden3Directive
for _, attachment := range *a {
if attachment.Type != Iden3DirectiveAttachmentType {
continue
}

d := attachment.Data.([]Iden3Directive)

directives = append(directives, d...)
}

return directives
}

// AddDirectives adds directive to attachments
func (a *Attachments) AddDirectives(d []Iden3Directive) {

if len(d) == 0 {
return
}

// find directive attachment
for _, attachment := range *a {
if attachment.Type == Iden3DirectiveAttachmentType {
attachment.Data = append(attachment.Data.([]Iden3Directive), d...)
return
}
}

*a = append(*a, &Attachment{
Type: Iden3DirectiveAttachmentType,
Data: d,
})
}

// MediaType is media type for iden3comm messages
type MediaType string
Expand All @@ -16,8 +77,9 @@ type BasicMessage struct {
From string `json:"from,omitempty"`
To string `json:"to,omitempty"`

CreatedTime *int64 `json:"created_time,omitempty"`
ExpiresTime *int64 `json:"expires_time,omitempty"`
CreatedTime *int64 `json:"created_time,omitempty"`
ExpiresTime *int64 `json:"expires_time,omitempty"`
Attachments Attachments `json:"attachments,omitempty"`
}

// ProtocolMessage is IDEN3Comm message
Expand Down
10 changes: 6 additions & 4 deletions protocol/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,9 @@ type AuthorizationResponseMessage struct {
From string `json:"from,omitempty"`
To string `json:"to,omitempty"`

CreatedTime *int64 `json:"created_time,omitempty"`
ExpiresTime *int64 `json:"expires_time,omitempty"`
CreatedTime *int64 `json:"created_time,omitempty"`
ExpiresTime *int64 `json:"expires_time,omitempty"`
Attachments iden3comm.Attachments `json:"attachments,omitempty"`
}

// AuthorizationMessageResponseBody is struct the represents authorization response data
Expand All @@ -49,8 +50,9 @@ type AuthorizationRequestMessage struct {
From string `json:"from,omitempty"`
To string `json:"to,omitempty"`

CreatedTime *int64 `json:"created_time,omitempty"`
ExpiresTime *int64 `json:"expires_time,omitempty"`
CreatedTime *int64 `json:"created_time,omitempty"`
ExpiresTime *int64 `json:"expires_time,omitempty"`
Attachments iden3comm.Attachments `json:"attachments,omitempty"`
}

// AuthorizationRequestMessageBody is body for authorization request
Expand Down
5 changes: 3 additions & 2 deletions protocol/contract_invoke.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,9 @@ type ContractInvokeRequestMessage struct {
From string `json:"from,omitempty"`
To string `json:"to,omitempty"`

CreatedTime *int64 `json:"created_time,omitempty"`
ExpiresTime *int64 `json:"expires_time,omitempty"`
CreatedTime *int64 `json:"created_time,omitempty"`
ExpiresTime *int64 `json:"expires_time,omitempty"`
Attachments iden3comm.Attachments `json:"attachments,omitempty"`
}

// ContractInvokeRequestMessageBody is body for contract invoke request
Expand Down
Loading
Loading