Skip to content

Commit

Permalink
Add attachment and directives
Browse files Browse the repository at this point in the history
  • Loading branch information
Kolezhniuk committed Jan 8, 2025
1 parent 93b1094 commit 073256e
Show file tree
Hide file tree
Showing 12 changed files with 356 additions and 49 deletions.
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

0 comments on commit 073256e

Please sign in to comment.