Skip to content
This repository has been archived by the owner on Feb 16, 2023. It is now read-only.

Commit

Permalink
Merge pull request #219 from secrethub/release/v0.31.0
Browse files Browse the repository at this point in the history
Release v0.31.0
  • Loading branch information
SimonBarendse authored Sep 7, 2020
2 parents 9cc9510 + be64d87 commit f9c0186
Show file tree
Hide file tree
Showing 15 changed files with 287 additions and 18 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<i>Go Client</i>
</h1>

[![GoDoc](http://img.shields.io/badge/godoc-reference-blue.svg)][godoc]
[![GoDoc](https://img.shields.io/badge/godoc-reference-blue.svg)][godoc]
[![CircleCI](https://circleci.com/gh/secrethub/secrethub-go.svg?style=shield)][circle-ci]
[![Go Report Card](https://goreportcard.com/badge/github.com/secrethub/secrethub-go)][goreportcard]
[![Version]( https://img.shields.io/github/release/secrethub/secrethub-go.svg)][latest-version]
Expand Down Expand Up @@ -148,7 +148,7 @@ If you get stuck or just want advice, come chat with the engineers on [Discord][
[latest-version]: https://github.com/secrethub/secrethub-go/releases/latest
[issues]: https://github.com/secrethub/secrethub-go/issues/new
[pulls]: https://github.com/secrethub/secrethub-go/pulls
[godoc]: http://godoc.org/github.com/secrethub/secrethub-go
[godoc]: https://pkg.go.dev/github.com/secrethub/secrethub-go?tab=overview
[goreportcard]: https://goreportcard.com/report/github.com/secrethub/secrethub-go
[circle-ci]: https://circleci.com/gh/secrethub/secrethub-go
[discord]: https://discord.gg/EQcE87s
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ require (
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550
google.golang.org/api v0.26.0
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940
google.golang.org/grpc v1.28.0
)

go 1.13
10 changes: 10 additions & 0 deletions internals/api/patterns.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ var (
whitelistOrgName = regexp.MustCompile(fmt.Sprintf(`(?i)^(%s{%d,%d})$`, patternUniformNameCharacters, uniformNameMinimumLength, uniformNameMaximumLength))
whitelistFullName = regexp.MustCompile(fmt.Sprintf(`(?i)^(%s{1,128})$`, patternFullName))
whitelistDescription = regexp.MustCompile(fmt.Sprintf(`(?i)^(%s)$`, patternDescription))
whitelistSetupCode = regexp.MustCompile("^su-[a-zA-Z0-9-]{8,64}")

whitelistAtLeastOneAlphanumeric = regexp.MustCompile(fmt.Sprintf("%s{1,}", patternAlphanumeric))

Expand Down Expand Up @@ -89,6 +90,7 @@ var (
ErrInvalidGCPServiceAccountEmail = errAPI.Code("invalid_service_account_email").StatusError("not a valid GCP service account email", http.StatusBadRequest)
ErrNotUserManagerGCPServiceAccountEmail = errAPI.Code("require_user_managed_service_account").StatusError("provided GCP service account email is not for a user-manager service account", http.StatusBadRequest)
ErrInvalidGCPKMSResourceID = errAPI.Code("invalid_key_resource_id").StatusError("not a valid resource ID, expected: projects/PROJECT_ID/locations/LOCATION/keyRings/KEY_RING/cryptoKeys/KEY", http.StatusBadRequest)
ErrInvalidSetupCode = errAPI.Code("invalid_setup_code").StatusError("setup code starts with su- and is followed by groups of letters and numbers separated by dashes", http.StatusBadRequest)
)

// ValidateNamespace validates a username.
Expand Down Expand Up @@ -353,3 +355,11 @@ func ValidateGCPKMSKeyResourceID(v string) error {

return nil
}

// ValidateSetupCode checks whether the given string has the format of a valid setup code.
func ValidateSetupCode(code string) error {
if !whitelistSetupCode.MatchString(code) {
return ErrInvalidSetupCode
}
return nil
}
7 changes: 7 additions & 0 deletions pkg/secrethub/account.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ var (

// AccountService handles operations on SecretHub accounts.
type AccountService interface {
// Me retrieves the authenticated account of the client.
Me() (*api.Account, error)
// Get retrieves an account by name.
Get(name string) (*api.Account, error)
// Keys returns an account key service.
Expand All @@ -30,6 +32,11 @@ type accountService struct {
client *Client
}

// Me retrieves the authenticated account of the client.
func (s accountService) Me() (*api.Account, error) {
return s.client.getMyAccount()
}

// Get retrieves an account by name.
func (s accountService) Get(name string) (*api.Account, error) {
accountName, err := api.NewAccountName(name)
Expand Down
8 changes: 6 additions & 2 deletions pkg/secrethub/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ func NewClient(with ...ClientOption) (*Client, error) {
}

// Try to use default key credentials if none provided explicitly
if client.decrypter == nil {
if !client.httpClient.IsAuthenticated() && client.decrypter == nil {
identityProvider := os.Getenv("SECRETHUB_IDENTITY_PROVIDER")

var provider credentials.Provider
Expand Down Expand Up @@ -207,7 +207,7 @@ func (c *Client) Accounts() AccountService {

// Credentials returns a service used to manage credentials.
func (c *Client) Credentials() CredentialService {
return newCredentialService(c)
return newCredentialService(c, c.httpClient.IsAuthenticated, c.isKeyed)
}

// Dirs returns a service used to manage directories.
Expand Down Expand Up @@ -272,6 +272,10 @@ func (c *Client) DefaultCredential() credentials.Reader {
return c.ConfigDir.Credential()
}

func (c *Client) isKeyed() bool {
return c.decrypter != nil
}

func (c *Client) userAgent() string {
userAgent := userAgentPrefix
for _, info := range c.appInfo {
Expand Down
2 changes: 1 addition & 1 deletion pkg/secrethub/client_version.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ package secrethub

// ClientVersion is the current version of the client
// Do not edit this unless you know what you're doing.
const ClientVersion = "v0.30.0"
const ClientVersion = "v0.31.0"
36 changes: 28 additions & 8 deletions pkg/secrethub/credentials.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package secrethub

import (
"github.com/secrethub/secrethub-go/internals/crypto"
"github.com/secrethub/secrethub-go/pkg/secrethub/iterator"

"github.com/secrethub/secrethub-go/internals/api"
Expand All @@ -17,23 +18,42 @@ type CredentialService interface {
List(_ *CredentialListParams) CredentialIterator
}

func newCredentialService(client *Client) CredentialService {
func newCredentialService(client *Client, isAuthenticated func() bool, isKeyed func() bool) CredentialService {
return credentialService{
client: client,
client: client,
isAuthenticated: isAuthenticated,
isKeyed: isKeyed,
}
}

type credentialService struct {
client *Client
client *Client
isAuthenticated func() bool
isKeyed func() bool
}

// Create a new credential from the credentials.Creator for an existing account.
// This includes a re-encrypted copy the the account key.
// If the account is already keyed, the key is re-encrypted for the new credential.
// If the account is not yet keyed, a new account key is also created.
// Description is optional and can be left empty.
func (s credentialService) Create(creator credentials.Creator, description string) (*api.Credential, error) {
accountKey, err := s.client.getAccountKey()
if err != nil {
return nil, err
if !s.isAuthenticated() {
return nil, ErrNoDecryptionKey
}

var accountKey crypto.RSAPrivateKey
var err error
if !s.isKeyed() {
accountKey, err = generateAccountKey()
if err != nil {
return nil, err
}
} else {
key, err := s.client.getAccountKey()
if err != nil {
return nil, err
}
accountKey = *key
}

err = creator.Create()
Expand All @@ -47,7 +67,7 @@ func (s credentialService) Create(creator credentials.Creator, description strin
return nil, err
}

accountKeyRequest, err := s.client.createAccountKeyRequest(creator.Encrypter(), *accountKey)
accountKeyRequest, err := s.client.createAccountKeyRequest(creator.Encrypter(), accountKey)
if err != nil {
return nil, err
}
Expand Down
33 changes: 33 additions & 0 deletions pkg/secrethub/credentials/setup_code.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package credentials

import (
"fmt"
"net/http"

httpclient "github.com/secrethub/secrethub-go/pkg/secrethub/internals/http"

"github.com/secrethub/secrethub-go/internals/auth"
)

type SetupCode struct {
code string
}

// Provide implements the Provider interface for the setup code.
// Note that no decrypter is ever returned as setup codes cannot be used to decrypt secrets.
func (s *SetupCode) Provide(client *httpclient.Client) (auth.Authenticator, Decrypter, error) {
return s, nil, nil
}

func NewSetupCode(code string) *SetupCode {
return &SetupCode{
code: code,
}
}

// Authenticate authenticates the given request with a setup code, by providing the "SetupCode" tag and the setup code
// in the "Authorization" header.
func (s *SetupCode) Authenticate(r *http.Request) error {
r.Header.Set("Authorization", fmt.Sprintf("%s-%s %s", auth.AuthHeaderVersionV1, "SetupCode", s.code))
return nil
}
6 changes: 6 additions & 0 deletions pkg/secrethub/fakeclient/account.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (

// AccountService is a mock of the AccountService interface.
type AccountService struct {
MeFunc func() (*api.Account, error)
GetFunc func(name string) (*api.Account, error)
AccountKeyService secrethub.AccountKeyService
}
Expand All @@ -21,3 +22,8 @@ func (s *AccountService) Keys() secrethub.AccountKeyService {
func (s *AccountService) Get(name string) (*api.Account, error) {
return s.GetFunc(name)
}

// Me implements the AccountService interface Me function.
func (s *AccountService) Me() (*api.Account, error) {
return s.MeFunc()
}
16 changes: 14 additions & 2 deletions pkg/secrethub/fakeclient/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,21 @@ package fakeclient

import "github.com/secrethub/secrethub-go/pkg/secrethub"

var _ secrethub.ClientInterface = (*Client)(nil)

// Client implements the secrethub.Client interface.
type Client struct {
AccessRuleService *AccessRuleService
AccountService *AccountService
CredentialService *CredentialService
DirService *DirService
IDPLinkService *IDPLinkService
MeService *MeService
OrgService *OrgService
RepoService *RepoService
SecretService *SecretService
ServiceService *ServiceService
UserService *UserService
secrethub.ClientInterface
}

// AccessRules implements the secrethub.Client interface.
Expand All @@ -36,7 +40,7 @@ func (c Client) Dirs() secrethub.DirService {

// Me implements the secrethub.Client interface.
func (c Client) Me() secrethub.MeService {
return nil
return c.MeService
}

// Orgs implements the secrethub.Client interface.
Expand All @@ -63,3 +67,11 @@ func (c Client) Services() secrethub.ServiceService {
func (c Client) Users() secrethub.UserService {
return c.UserService
}

func (c Client) IDPLinks() secrethub.IDPLinkService {
return c.IDPLinkService
}

func (c Client) Credentials() secrethub.CredentialService {
return c.CredentialService
}
45 changes: 45 additions & 0 deletions pkg/secrethub/fakeclient/credentials.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package fakeclient

import (
"github.com/secrethub/secrethub-go/internals/api"
"github.com/secrethub/secrethub-go/pkg/secrethub"
"github.com/secrethub/secrethub-go/pkg/secrethub/credentials"
"github.com/secrethub/secrethub-go/pkg/secrethub/iterator"
)

type CredentialService struct {
CreateFunc func(credentials.Creator, string) (*api.Credential, error)
DisableFunc func(fingerprint string) error
ListFunc func(_ *secrethub.CredentialListParams) secrethub.CredentialIterator
}

func (c *CredentialService) Create(creator credentials.Creator, description string) (*api.Credential, error) {
return c.CreateFunc(creator, description)
}

func (c *CredentialService) Disable(fingerprint string) error {
return c.DisableFunc(fingerprint)
}

func (c *CredentialService) List(credentialListParams *secrethub.CredentialListParams) secrethub.CredentialIterator {
return c.ListFunc(credentialListParams)
}

type CredentialIterator struct {
Credentials []*api.Credential
CurrentIndex int
Err error
}

func (c *CredentialIterator) Next() (api.Credential, error) {
if c.Err != nil {
return api.Credential{}, c.Err
}

currentIndex := c.CurrentIndex
if currentIndex >= len(c.Credentials) {
return api.Credential{}, iterator.Done
}
c.CurrentIndex++
return *c.Credentials[currentIndex], nil
}
68 changes: 68 additions & 0 deletions pkg/secrethub/fakeclient/idp_link.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package fakeclient

import (
"github.com/secrethub/secrethub-go/internals/api"
"github.com/secrethub/secrethub-go/internals/oauthorizer"
"github.com/secrethub/secrethub-go/pkg/secrethub"
"github.com/secrethub/secrethub-go/pkg/secrethub/iterator"
)

type IDPLinkService struct {
GCPService secrethub.IDPLinkGCPService
}

func (i IDPLinkService) GCP() secrethub.IDPLinkGCPService {
return i.GCPService
}

type IDPLinkGCPService struct {
CreateFunc func(namespace string, projectID string, authorizationCode string, redirectURI string) (*api.IdentityProviderLink, error)
ListFunc func(namespace string, params *secrethub.IdpLinkIteratorParams) secrethub.IdpLinkIterator
GetFunc func(namespace string, projectID string) (*api.IdentityProviderLink, error)
ExistsFunc func(namespace string, projectID string) (bool, error)
DeleteFunc func(namespace string, projectID string) error
AuthorizationCodeListenerFunc func(namespace string, projectID string) (oauthorizer.CallbackHandler, error)
}

func (i IDPLinkGCPService) Create(namespace string, projectID string, authorizationCode, redirectURI string) (*api.IdentityProviderLink, error) {
return i.CreateFunc(namespace, projectID, authorizationCode, redirectURI)
}

func (i IDPLinkGCPService) List(namespace string, params *secrethub.IdpLinkIteratorParams) secrethub.IdpLinkIterator {
return i.ListFunc(namespace, params)
}

func (i IDPLinkGCPService) Get(namespace string, projectID string) (*api.IdentityProviderLink, error) {
return i.GetFunc(namespace, projectID)
}

func (i IDPLinkGCPService) Exists(namespace string, projectID string) (bool, error) {
return i.ExistsFunc(namespace, projectID)
}

func (i IDPLinkGCPService) Delete(namespace string, projectID string) error {
return i.DeleteFunc(namespace, projectID)
}

func (i IDPLinkGCPService) AuthorizationCodeListener(namespace string, projectID string) (oauthorizer.CallbackHandler, error) {
return i.AuthorizationCodeListenerFunc(namespace, projectID)
}

type IDPLinkIterator struct {
IDPLinks []*api.IdentityProviderLink
CurrentIndex int
Err error
}

func (c *IDPLinkIterator) Next() (api.IdentityProviderLink, error) {
if c.Err != nil {
return api.IdentityProviderLink{}, c.Err
}

currentIndex := c.CurrentIndex
if currentIndex >= len(c.IDPLinks) {
return api.IdentityProviderLink{}, iterator.Done
}
c.CurrentIndex++
return *c.IDPLinks[currentIndex], nil
}
Loading

0 comments on commit f9c0186

Please sign in to comment.