github.com/ActiveState/cli@v0.0.0-20240508170324-6801f60cd051/pkg/platform/api/secrets/secrets.go (about)

     1  package secrets
     2  
     3  import (
     4  	"fmt"
     5  
     6  	httptransport "github.com/go-openapi/runtime/client"
     7  	"github.com/go-openapi/strfmt"
     8  
     9  	"github.com/ActiveState/cli/internal/errs"
    10  	"github.com/ActiveState/cli/internal/locale"
    11  	"github.com/ActiveState/cli/internal/logging"
    12  	"github.com/ActiveState/cli/internal/retryhttp"
    13  	"github.com/ActiveState/cli/pkg/platform/api"
    14  	"github.com/ActiveState/cli/pkg/platform/api/mono/mono_models"
    15  	"github.com/ActiveState/cli/pkg/platform/api/secrets/secrets_client"
    16  	secretsapiClient "github.com/ActiveState/cli/pkg/platform/api/secrets/secrets_client/secrets"
    17  	secretsModels "github.com/ActiveState/cli/pkg/platform/api/secrets/secrets_models"
    18  	"github.com/ActiveState/cli/pkg/platform/authentication"
    19  )
    20  
    21  var (
    22  	ErrNotFound   = errs.New("Secret not found")
    23  	ErKeypairSave = errs.New("Could not save keypair")
    24  )
    25  
    26  // Scope covers what scope a secret belongs to
    27  type Scope string
    28  
    29  var (
    30  	// ScopeUser is the user scope
    31  	ScopeUser Scope = "user"
    32  
    33  	// ScopeProject is the project scope
    34  	ScopeProject Scope = "project"
    35  )
    36  
    37  var persistentClient *Client
    38  
    39  // Client encapsulates a Secrets Service API client and its configuration
    40  type Client struct {
    41  	*secrets_client.Secrets
    42  	BaseURI string
    43  	auth    *authentication.Auth
    44  }
    45  
    46  // GetClient gets the cached (if any) client instance that was initialized using our default settings
    47  func GetClient(auth *authentication.Auth) *Client {
    48  	if persistentClient == nil {
    49  		persistentClient = NewDefaultClient(auth)
    50  	}
    51  	return persistentClient
    52  }
    53  
    54  // Reset will reset the client cache
    55  func Reset() {
    56  	persistentClient = nil
    57  }
    58  
    59  // NewClient creates a new SecretsAPI client instance using the provided HTTP settings.
    60  // It also expects to receive the actual Bearer token value that will be passed in each
    61  // API request in order to authenticate each request.
    62  func NewClient(schema, host, basePath string, auth *authentication.Auth) *Client {
    63  	logging.Debug("secrets-api scheme=%s host=%s base_path=%s", schema, host, basePath)
    64  	transportRuntime := httptransport.New(host, basePath, []string{schema})
    65  	transportRuntime.Transport = api.NewRoundTripper(retryhttp.DefaultClient.StandardClient().Transport)
    66  	//transportRuntime.SetDebug(true)
    67  	secretsClient := &Client{
    68  		Secrets: secrets_client.New(transportRuntime, strfmt.Default),
    69  		BaseURI: fmt.Sprintf("%s://%s%s", schema, host, basePath),
    70  		auth:    auth,
    71  	}
    72  	return secretsClient
    73  }
    74  
    75  // NewDefaultClient creates a new Client using constants SecretsAPISchema, -Host, and -Path and
    76  // a provided Bearer-token value.
    77  func NewDefaultClient(auth *authentication.Auth) *Client {
    78  	serviceURL := api.GetServiceURL(api.ServiceSecrets)
    79  	return NewClient(serviceURL.Scheme, serviceURL.Host, serviceURL.Path, auth)
    80  }
    81  
    82  // DefaultClient represents a secretsapi Client instance that can be accessed by any package
    83  // needing it. DefaultClient should be set by a call to InitializeClient; this, it can be nil.
    84  var DefaultClient *Client
    85  
    86  // InitializeClient will create new Client using defaults, including the api.BearerToken value.
    87  // This new Client instance will be accessible as secretapi.DefaultClient afterwards. Calling
    88  // this function multiple times will redefine the DefaultClient value using the defaults/constants
    89  // available to it at the time of the call; thus, the DefaultClient can be re-initialized this way.
    90  // Because this function is dependent on a runtime-value from pkg/platform/api, we are not relying on
    91  // the init() function for instantiation; this must be called explicitly.
    92  func InitializeClient(auth *authentication.Auth) *Client {
    93  	DefaultClient = NewDefaultClient(auth)
    94  	return DefaultClient
    95  }
    96  
    97  // Get is an alias for InitializeClient used to persist our Get() pattern used throughout the codebase
    98  func Get(auth *authentication.Auth) *Client {
    99  	return InitializeClient(auth)
   100  }
   101  
   102  // AuthenticatedUserID will check with the Secrets Service to ensure the current Bearer token
   103  // is a valid one and return the user's UID in the response. Otherwise, this function will return
   104  // a Failure.
   105  func (client *Client) AuthenticatedUserID() (strfmt.UUID, error) {
   106  	resOk, err := client.Authentication.GetWhoami(nil, client.auth.ClientAuth())
   107  	if err != nil {
   108  		if api.ErrorCode(err) == 401 {
   109  			return "", locale.NewExternalError("err_api_not_authenticated")
   110  		}
   111  		return "", errs.Wrap(err, "Whoami failed")
   112  	}
   113  	return *resOk.Payload.UID, nil
   114  }
   115  
   116  // Persist will make the current client the persistentClient
   117  func (client *Client) Persist() {
   118  	persistentClient = client
   119  }
   120  
   121  // FetchAll fetchs the current user's secrets for an organization.
   122  func FetchAll(client *Client, org *mono_models.Organization) ([]*secretsModels.UserSecret, error) {
   123  	params := secretsapiClient.NewGetAllUserSecretsParams()
   124  	params.OrganizationID = org.OrganizationID
   125  	getOk, err := client.Secrets.Secrets.GetAllUserSecrets(params, client.auth.ClientAuth())
   126  	if err != nil {
   127  		switch statusCode := api.ErrorCode(err); statusCode {
   128  		case 401:
   129  			return nil, locale.NewExternalError("err_api_not_authenticated")
   130  		default:
   131  			return nil, errs.Wrap(err, "GetAllUserSecrets failed")
   132  		}
   133  	}
   134  	return getOk.Payload, nil
   135  }
   136  
   137  // FetchDefinitions fetchs the secret definitions for a given project.
   138  func FetchDefinitions(client *Client, projectID strfmt.UUID) ([]*secretsModels.SecretDefinition, error) {
   139  	params := secretsapiClient.NewGetDefinitionsParams()
   140  	params.ProjectID = projectID
   141  	getOk, err := client.Secrets.Secrets.GetDefinitions(params, client.auth.ClientAuth())
   142  	if err != nil {
   143  		switch statusCode := api.ErrorCode(err); statusCode {
   144  		case 401:
   145  			return nil, locale.NewExternalError("err_api_not_authenticated")
   146  		default:
   147  			return nil, errs.Wrap(err, "GetDefinitions failed")
   148  		}
   149  	}
   150  	return getOk.Payload, nil
   151  }
   152  
   153  func SaveSecretShares(client *Client, org *mono_models.Organization, user *mono_models.User, shares []*secretsModels.UserSecretShare) error {
   154  	params := secretsapiClient.NewShareUserSecretsParams()
   155  	params.OrganizationID = org.OrganizationID
   156  	params.UserID = user.UserID
   157  	params.UserSecrets = shares
   158  	_, err := client.Secrets.Secrets.ShareUserSecrets(params, client.auth.ClientAuth())
   159  	if err != nil {
   160  		logging.Debug("error sharing user secrets with %s: %v", user.Username, err)
   161  		return locale.WrapError(err, "secrets_err_save", "", err.Error())
   162  	}
   163  	return nil
   164  }