Skip to content
Snippets Groups Projects
client.go 4.11 KiB
Newer Older
  • Learn to ignore specific revisions
  • Yordan Kinkov's avatar
    Yordan Kinkov committed
    package ocm
    
    import (
    
    Yordan Kinkov's avatar
    Yordan Kinkov committed
    	"context"
    	"encoding/json"
    	"fmt"
    	"io"
    	"net/http"
    
    Yordan Kinkov's avatar
    Yordan Kinkov committed
    	"net/url"
    
    Yordan Kinkov's avatar
    Yordan Kinkov committed
    	"strings"
    
    Yordan Kinkov's avatar
    Yordan Kinkov committed
    )
    
    const (
    
    	proofOutOfBandPath        = "/v1/out-of-band-proof"
    	proofOutOfBandRequestPath = "/v1/send-out-of-band-presentation-request"
    	proofPresentationPath     = "/v1/find-by-presentation-id"
    
    Yordan Kinkov's avatar
    Yordan Kinkov committed
    )
    
    // Client is the OCM service client
    type Client struct {
    
    	proofManagerAddr string
    	httpClient       *http.Client
    
    Yordan Kinkov's avatar
    Yordan Kinkov committed
    }
    
    // New initializes an OCM service client given the OCM service address
    
    func New(proofManagerAddr string, opts ...Option) *Client {
    
    Yordan Kinkov's avatar
    Yordan Kinkov committed
    	c := &Client{
    
    		proofManagerAddr: proofManagerAddr,
    		httpClient:       http.DefaultClient,
    
    Yordan Kinkov's avatar
    Yordan Kinkov committed
    	}
    
    	for _, opt := range opts {
    		opt(c)
    	}
    
    	return c
    }
    
    // GetLoginProofInvitation calls the "invitation" endpoint on
    
    Yordan Kinkov's avatar
    Yordan Kinkov committed
    // the "out-of-band" protocol in the OCM.
    
    Yordan Kinkov's avatar
    Yordan Kinkov committed
    func (c *Client) GetLoginProofInvitation(ctx context.Context, credTypes []string) (*LoginProofInvitationResponse, error) {
    
    	req, err := http.NewRequestWithContext(ctx, "POST", c.proofManagerAddr+proofOutOfBandPath, nil)
    
    Yordan Kinkov's avatar
    Yordan Kinkov committed
    	if err != nil {
    		return nil, err
    	}
    
    
    Yordan Kinkov's avatar
    Yordan Kinkov committed
    	v := url.Values{}
    
    Yordan Kinkov's avatar
    Yordan Kinkov committed
    	v.Add("type", strings.Join(credTypes, ","))
    
    Yordan Kinkov's avatar
    Yordan Kinkov committed
    	req.URL.RawQuery = v.Encode()
    
    
    Yordan Kinkov's avatar
    Yordan Kinkov committed
    	resp, err := c.httpClient.Do(req)
    	if err != nil {
    		return nil, err
    	}
    	defer resp.Body.Close() // nolint:errcheck
    
    	if resp.StatusCode != http.StatusCreated && resp.StatusCode != http.StatusOK {
    
    Yordan Kinkov's avatar
    Yordan Kinkov committed
    		return nil, fmt.Errorf("unexpected response code: %s", resp.Status)
    
    Yordan Kinkov's avatar
    Yordan Kinkov committed
    	}
    
    	bytes, err := io.ReadAll(resp.Body)
    	if err != nil {
    		return nil, err
    	}
    
    	var response LoginProofInvitationResponse
    	if err := json.Unmarshal(bytes, &response); err != nil {
    		return nil, err
    	}
    
    	return &response, nil
    }
    
    
    // SendOutOfBandRequest calls the "send out of band presentation request" endpoint on
    // the "out-of-band" protocol in the OCM.
    func (c *Client) SendOutOfBandRequest(ctx context.Context, r map[string]interface{}) (*LoginProofInvitationResponse, error) {
    	body, err := json.Marshal(r)
    
    Yordan Kinkov's avatar
    Yordan Kinkov committed
    	if err != nil {
    		return nil, err
    	}
    
    
    	req, err := http.NewRequestWithContext(ctx, "POST", c.proofManagerAddr+proofOutOfBandRequestPath, bytes.NewBuffer(body))
    	if err != nil {
    		return nil, err
    	}
    	req.Header.Set("Content-Type", "application/json")
    
    Yordan Kinkov's avatar
    Yordan Kinkov committed
    	resp, err := c.httpClient.Do(req)
    	if err != nil {
    		return nil, err
    	}
    	defer resp.Body.Close() // nolint:errcheck
    
    
    	if resp.StatusCode != http.StatusCreated && resp.StatusCode != http.StatusOK {
    
    Yordan Kinkov's avatar
    Yordan Kinkov committed
    		return nil, fmt.Errorf("unexpected response code: %s", resp.Status)
    
    Yordan Kinkov's avatar
    Yordan Kinkov committed
    	}
    
    	bytes, err := io.ReadAll(resp.Body)
    	if err != nil {
    		return nil, err
    	}
    
    
    	var response LoginProofInvitationResponse
    
    Yordan Kinkov's avatar
    Yordan Kinkov committed
    	if err := json.Unmarshal(bytes, &response); err != nil {
    
    Yordan Kinkov's avatar
    Yordan Kinkov committed
    		return nil, err
    	}
    
    
    Yordan Kinkov's avatar
    Yordan Kinkov committed
    	return &response, nil
    
    Yordan Kinkov's avatar
    Yordan Kinkov committed
    }
    
    
    // GetLoginProofResult calls the "find-by-presentation-id" endpoint in the OCM.
    func (c *Client) GetLoginProofResult(ctx context.Context, presentationID string) (*LoginProofResultResponse, error) {
    	resBytes, err := c.findByPresentationID(ctx, presentationID)
    	if err != nil {
    		return nil, err
    	}
    
    	var response LoginProofResultResponse
    	if err := json.Unmarshal(resBytes, &response); err != nil {
    		return nil, err
    	}
    
    	return &response, nil
    }
    
    // GetRawLoginProofResult calls the "find-by-presentation-id" endpoint in the OCM and returns the raw result.
    func (c *Client) GetRawLoginProofResult(ctx context.Context, presentationID string) (map[string]interface{}, error) {
    	resBytes, err := c.findByPresentationID(ctx, presentationID)
    	if err != nil {
    		return nil, err
    	}
    
    	var response map[string]interface{}
    	if err := json.Unmarshal(resBytes, &response); err != nil {
    		return nil, err
    	}
    
    	return response, nil
    }
    
    func (c *Client) findByPresentationID(ctx context.Context, presentationID string) ([]byte, error) {
    	req, err := http.NewRequestWithContext(ctx, "GET", c.proofManagerAddr+proofPresentationPath, nil)
    	if err != nil {
    		return nil, err
    	}
    
    	v := url.Values{}
    	v.Add("presentationId", presentationID)
    	req.URL.RawQuery = v.Encode()
    
    	resp, err := c.httpClient.Do(req)
    	if err != nil {
    		return nil, err
    	}
    	defer resp.Body.Close() // nolint:errcheck
    
    	if resp.StatusCode != http.StatusOK {
    		return nil, fmt.Errorf("unexpected response code: %s", resp.Status)
    	}
    
    	return io.ReadAll(resp.Body)
    }