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

     1  /*
     2  Copyright SecureKey Technologies Inc. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package didconfig
     8  
     9  import (
    10  	"context"
    11  	"fmt"
    12  	"io"
    13  	"io/ioutil"
    14  	"net/http"
    15  	"time"
    16  
    17  	jsonld "github.com/piprate/json-gold/ld"
    18  
    19  	"github.com/hyperledger/aries-framework-go/pkg/common/log"
    20  	"github.com/hyperledger/aries-framework-go/pkg/doc/did"
    21  	"github.com/hyperledger/aries-framework-go/pkg/doc/didconfig"
    22  	vdrapi "github.com/hyperledger/aries-framework-go/pkg/framework/aries/api/vdr"
    23  )
    24  
    25  var logger = log.New("aries-framework/client/did-config")
    26  
    27  const defaultTimeout = time.Minute
    28  
    29  // Client is a JSON-LD SDK client.
    30  type Client struct {
    31  	httpClient    HTTPClient
    32  	didConfigOpts []didconfig.DIDConfigurationOpt
    33  }
    34  
    35  // New creates new did configuration client.
    36  func New(opts ...Option) *Client {
    37  	client := &Client{
    38  		httpClient: &http.Client{Timeout: defaultTimeout},
    39  	}
    40  
    41  	for _, opt := range opts {
    42  		opt(client)
    43  	}
    44  
    45  	return client
    46  }
    47  
    48  // HTTPClient represents an HTTP client.
    49  type HTTPClient interface {
    50  	Do(req *http.Request) (*http.Response, error)
    51  }
    52  
    53  // Option configures the did configuration client.
    54  type Option func(opts *Client)
    55  
    56  // WithHTTPClient option is for custom http client.
    57  func WithHTTPClient(httpClient HTTPClient) Option {
    58  	return func(opts *Client) {
    59  		opts.httpClient = httpClient
    60  	}
    61  }
    62  
    63  // WithJSONLDDocumentLoader defines a JSON-LD document loader.
    64  func WithJSONLDDocumentLoader(documentLoader jsonld.DocumentLoader) Option {
    65  	return func(opts *Client) {
    66  		opts.didConfigOpts = append(opts.didConfigOpts, didconfig.WithJSONLDDocumentLoader(documentLoader))
    67  	}
    68  }
    69  
    70  type didResolver interface {
    71  	Resolve(did string, opts ...vdrapi.DIDMethodOption) (*did.DocResolution, error)
    72  }
    73  
    74  // WithVDRegistry defines a vdr service.
    75  func WithVDRegistry(didResolver didResolver) Option {
    76  	return func(opts *Client) {
    77  		opts.didConfigOpts = append(opts.didConfigOpts, didconfig.WithVDRegistry(didResolver))
    78  	}
    79  }
    80  
    81  // VerifyDIDAndDomain will verify that there is valid domain linkage credential in did configuration
    82  // for specified did and domain.
    83  func (c *Client) VerifyDIDAndDomain(did, domain string) error {
    84  	endpoint := domain + "/.well-known/did-configuration.json"
    85  
    86  	req, err := http.NewRequestWithContext(context.Background(), http.MethodGet, endpoint, nil)
    87  	if err != nil {
    88  		return fmt.Errorf("new HTTP request: %w", err)
    89  	}
    90  
    91  	resp, err := c.httpClient.Do(req)
    92  	if err != nil {
    93  		return fmt.Errorf("httpClient.Do: %w", err)
    94  	}
    95  
    96  	defer closeResponseBody(resp.Body)
    97  
    98  	responseBytes, err := ioutil.ReadAll(resp.Body)
    99  	if err != nil {
   100  		return fmt.Errorf("failed to read response: %w", err)
   101  	}
   102  
   103  	if resp.StatusCode != http.StatusOK {
   104  		return fmt.Errorf("endpoint %s returned status '%d' and message '%s'",
   105  			endpoint, resp.StatusCode, responseBytes)
   106  	}
   107  
   108  	return didconfig.VerifyDIDAndDomain(responseBytes, did, domain, c.didConfigOpts...)
   109  }
   110  
   111  func closeResponseBody(respBody io.Closer) {
   112  	e := respBody.Close()
   113  	if e != nil {
   114  		logger.Warnf("failed to close response body: %v", e)
   115  	}
   116  }