github.com/hyperledger/aries-framework-go@v0.3.2/pkg/client/issuecredential/rfc0593/middleware.go (about)

     1  /*
     2  Copyright SecureKey Technologies Inc. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package rfc0593
     8  
     9  import (
    10  	"errors"
    11  	"fmt"
    12  
    13  	"github.com/hyperledger/aries-framework-go/pkg/didcomm/protocol/decorator"
    14  	"github.com/hyperledger/aries-framework-go/pkg/didcomm/protocol/issuecredential"
    15  	"github.com/hyperledger/aries-framework-go/spi/storage"
    16  )
    17  
    18  // Middleware is the RFC0593 issuecredential.Middleware that can be injected into the protocol service.
    19  type Middleware issuecredential.Middleware
    20  
    21  // RegisterMiddleware registers the Middleware in the IssueCredentialService looked up from the ServiceProvider.
    22  //
    23  // See also: NewMiddleware.
    24  func RegisterMiddleware(mw Middleware, p ServiceProvider) error {
    25  	typelessSvc, err := p.Service(issuecredential.Name)
    26  	if err != nil {
    27  		return fmt.Errorf("failed to lookup issuecredential service: %w", err)
    28  	}
    29  
    30  	svc, ok := typelessSvc.(IssueCredentialService)
    31  	if !ok {
    32  		return errors.New("unable to cast the issuecredential service to the required interface type")
    33  	}
    34  
    35  	svc.AddMiddleware(issuecredential.Middleware(mw))
    36  
    37  	return nil
    38  }
    39  
    40  // NewMiddleware returns a new Middleware that can be used with the issuecredential protocol service
    41  // in conjunction with AutoExecute when the protocol needs to be started with a request-credential
    42  // message.
    43  //
    44  // Usage:
    45  //     framework, err := aries.New()
    46  //     if err != nil {
    47  //         panic(err)
    48  //     }
    49  //     ctx, err := framework.Context()
    50  //     if err != nil {
    51  //         panic(err)
    52  //     }
    53  //     mw, err := NewMiddleware(ctx)
    54  //     if err != nil {
    55  //         panic(err)
    56  //     }
    57  //     err = RegisterMiddleware(mw, ctx)
    58  //     if err != nil {
    59  //         panic(err)
    60  //     }
    61  //     client := issuecredential.Client = ...
    62  //     events = make(chan service.DIDCommAction)
    63  //     err := client.RegisterActionEvent(events)
    64  //     if err != nil {
    65  //         panic(err)
    66  //     }
    67  //     next := make(chan service.DIDCommAction)
    68  //     go AutoExecute(ctx, next)(events)
    69  //     for event := range next {
    70  //         // handle events from issue-credential that do not conform to RFC0593
    71  //     }
    72  //
    73  // See also: AutoExecute.
    74  func NewMiddleware(p TransientStorage) (Middleware, error) {
    75  	s, err := p.ProtocolStateStorageProvider().OpenStore(StoreName)
    76  	if err != nil {
    77  		return nil, fmt.Errorf("rfc0593: failed to open store: %w", err)
    78  	}
    79  
    80  	return func(next issuecredential.Handler) issuecredential.Handler {
    81  		return &handler{
    82  			next:  next,
    83  			store: s,
    84  		}
    85  	}, nil
    86  }
    87  
    88  type handler struct {
    89  	next  issuecredential.Handler
    90  	store storage.Store
    91  }
    92  
    93  // Handle the issuecredential.Metadata.
    94  func (h *handler) Handle(md issuecredential.Metadata) error {
    95  	var (
    96  		formats     []issuecredential.Format
    97  		attachments []decorator.Attachment
    98  		err         error
    99  	)
   100  
   101  	switch md.Message().Type() {
   102  	case issuecredential.RequestCredentialMsgTypeV2:
   103  		p := &issuecredential.RequestCredentialV2{}
   104  		err = md.Message().Decode(p)
   105  		formats = p.Formats
   106  		attachments = p.RequestsAttach
   107  	default:
   108  		return h.next.Handle(md)
   109  	}
   110  
   111  	if err != nil {
   112  		return fmt.Errorf("rfc0593: failed to decode msg type %s: %w", md.Message().Type(), err)
   113  	}
   114  
   115  	attachment, err := FindAttachment(ProofVCDetailFormat, formats, attachments)
   116  	if errors.Is(err, ErrRFC0593NotApplicable) {
   117  		return h.next.Handle(md)
   118  	}
   119  
   120  	if err != nil {
   121  		return fmt.Errorf("rfc0593: failed to fetch attachment: %w", err)
   122  	}
   123  
   124  	spec := &CredentialSpec{}
   125  
   126  	err = unmarshalAttachmentContents(attachment, spec)
   127  	if err != nil {
   128  		return fmt.Errorf("rfc0593: failed to unmarshal attachment contents: %w", err)
   129  	}
   130  
   131  	err = saveOptionsIfNoError(nil, h.store, md.Message(), spec.Options)
   132  	if err != nil {
   133  		return fmt.Errorf("rfc0593: failed to save credential spec options: %w", err)
   134  	}
   135  
   136  	return h.next.Handle(md)
   137  }