Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

credential,endpoint: Split from pkg #843

Merged
merged 3 commits into from
Oct 14, 2021
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
SHELL := /bin/bash
PACKAGES = credential endpoint

.PHONY: all check format vet lint build test generate tidy integration_test
.PHONY: all check format vet lint build test generate tidy integration_test $(PACKAGES)

help:
@echo "Please use \`make <target>\` where <target> is one of"
Expand Down Expand Up @@ -33,6 +34,11 @@ build: tidy generate format check
@go build -tags tools ./...
@echo "ok"

build-all: $(PACKAGES)

$(PACKAGES):
pushd $@ && make build && popd

test:
@echo "run test"
@go test -race -coverprofile=coverage.txt -covermode=atomic -v ./...
Expand Down
13 changes: 13 additions & 0 deletions credential/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Change Log

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/)
and this project adheres to [Semantic Versioning](https://semver.org/).

## [Unreleased]

## v0.1.0 - 2021-09-27

- Migrate credential from go-storage to separate repo.
- Add basic support
36 changes: 36 additions & 0 deletions credential/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
SHELL := /bin/bash

.PHONY: all check format vet lint build test generate tidy integration_test

help:
@echo "Please use \`make <target>\` where <target> is one of"
@echo " check to do static check"
@echo " build to create bin directory and build"
@echo " test to run test"

check: vet

format:
@echo "go fmt"
@go fmt ./...
@echo "ok"

vet:
@echo "go vet"
@go vet ./...
@echo "ok"

build: tidy check
@echo "build go-credential"
@go build ./...
@echo "ok"

test:
@echo "run test"
@go test -race -coverprofile=coverage.txt -covermode=atomic -v ./...
@go tool cover -html="coverage.txt" -o "coverage.html"
@echo "ok"

tidy:
@go mod tidy
@go mod verify
49 changes: 49 additions & 0 deletions credential/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# credential

Both human and machine-readable credential format.

## Format

```
<protocol>:<value>+
```

For example:

- hmac: `hmac:access_key:secret_key`
- apikey: `apikey:apikey`
- file: `file:/path/to/config/file`
- basic: `basic:user:password`

## Quick Start

```go
cred, err := credential.Parse("hmac:access_key:secret_key)
if err != nil {
log.Fatal("parse: ", err)
}

switch cred.Protocol() {
case ProtocolHmac:
ak, sk := cred.Hmac()
log.Println("access_key: ", ak)
log.Println("secret_key: ", sk)
case ProtocolAPIKey:
apikey := cred.APIKey()
log.Println("apikey: ", apikey)
case ProtocolFile:
path := cred.File()
log.Println("path: ", path)
case ProtocolEnv:
log.Println("use env value")
case ProtocolBase64:
content := cred.Base64()
log.Println("base64: ", content)
case ProtocolBasic:
user, password := cred.Basic()
log.Println("user: ", user)
log.Println("password: ", password)
default:
panic("unsupported protocol")
}
```
67 changes: 45 additions & 22 deletions pkg/credential/credential.go → credential/credential.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,33 +30,37 @@ const (
// Storage service like gcs will take token files as input, we provide base64 protocol so that user
// can pass token binary data directly.
ProtocolBase64 = "base64"
// ProtocolBasic will hold user and password credential.
//
// value = [user, password]
ProtocolBasic = "basic"
)

// Provider will provide credential protocol and values.
type Provider struct {
// Credential will provide credential protocol and values.
type Credential struct {
protocol string
args []string
}

// Protocol provides current credential's protocol.
func (p Provider) Protocol() string {
func (p Credential) Protocol() string {
return p.protocol
}

// Value provides current credential's value in string array.
func (p Provider) Value() []string {
func (p Credential) Value() []string {
return p.args
}

// Value provides current credential's value in string array.
func (p Provider) String() string {
func (p Credential) String() string {
if len(p.args) == 0 {
return p.protocol
}
return p.protocol + ":" + strings.Join(p.args, ":")
}

func (p Provider) Hmac() (accessKey, secretKey string) {
func (p Credential) Hmac() (accessKey, secretKey string) {
if p.protocol != ProtocolHmac {
panic(Error{
Op: "hmac",
Expand All @@ -68,7 +72,7 @@ func (p Provider) Hmac() (accessKey, secretKey string) {
return p.args[0], p.args[1]
}

func (p Provider) APIKey() (apiKey string) {
func (p Credential) APIKey() (apiKey string) {
if p.protocol != ProtocolAPIKey {
panic(Error{
Op: "api_key",
Expand All @@ -80,7 +84,7 @@ func (p Provider) APIKey() (apiKey string) {
return p.args[0]
}

func (p Provider) File() (path string) {
func (p Credential) File() (path string) {
if p.protocol != ProtocolFile {
panic(Error{
Op: "file",
Expand All @@ -92,7 +96,7 @@ func (p Provider) File() (path string) {
return p.args[0]
}

func (p Provider) Base64() (value string) {
func (p Credential) Base64() (value string) {
if p.protocol != ProtocolBase64 {
panic(Error{
Op: "base64",
Expand All @@ -104,8 +108,20 @@ func (p Provider) Base64() (value string) {
return p.args[0]
}

// Parse will parse config string to create a credential Provider.
func Parse(cfg string) (Provider, error) {
func (p Credential) Basic() (user, password string) {
if p.protocol != ProtocolBasic {
panic(Error{
Op: "basic",
Err: ErrInvalidValue,
Protocol: p.protocol,
Values: p.args,
})
}
return p.args[0], p.args[1]
}

// Parse will parse config string to create a credential Credential.
func Parse(cfg string) (Credential, error) {
s := strings.Split(cfg, ":")

switch s[0] {
Expand All @@ -119,32 +135,39 @@ func Parse(cfg string) (Provider, error) {
return NewEnv(), nil
case ProtocolBase64:
return NewBase64(s[1]), nil
case ProtocolBasic:
return NewBasic(s[1], s[2]), nil
default:
return Provider{}, &Error{"parse", ErrUnsupportedProtocol, s[0], nil}
return Credential{}, &Error{"parse", ErrUnsupportedProtocol, s[0], nil}
}
}

// NewHmac create a hmac provider.
func NewHmac(accessKey, secretKey string) Provider {
return Provider{ProtocolHmac, []string{accessKey, secretKey}}
func NewHmac(accessKey, secretKey string) Credential {
return Credential{ProtocolHmac, []string{accessKey, secretKey}}
}

// NewAPIKey create a api key provider.
func NewAPIKey(apiKey string) Provider {
return Provider{ProtocolAPIKey, []string{apiKey}}
func NewAPIKey(apiKey string) Credential {
return Credential{ProtocolAPIKey, []string{apiKey}}
}

// NewFile create a file provider.
func NewFile(filePath string) Provider {
return Provider{ProtocolFile, []string{filePath}}
func NewFile(filePath string) Credential {
return Credential{ProtocolFile, []string{filePath}}
}

// NewEnv create a env provider.
func NewEnv() Provider {
return Provider{ProtocolEnv, nil}
func NewEnv() Credential {
return Credential{ProtocolEnv, nil}
}

// NewBase64 create a base64 provider.
func NewBase64(value string) Provider {
return Provider{ProtocolBase64, []string{value}}
func NewBase64(value string) Credential {
return Credential{ProtocolBase64, []string{value}}
}

// NewBasic create a basic provider.
func NewBasic(user, password string) Credential {
return Credential{ProtocolBasic, []string{user, password}}
}
115 changes: 115 additions & 0 deletions credential/credential_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
package credential

import (
"errors"
"log"
"testing"

"github.com/google/uuid"
"github.com/stretchr/testify/assert"
)

func TestProvider(t *testing.T) {
protocol := uuid.New().String()
args := []string{uuid.New().String(), uuid.New().String()}

p := Credential{protocol: protocol, args: args}

assert.Equal(t, protocol, p.Protocol())
assert.EqualValues(t, args, p.Value())
}

func TestParse(t *testing.T) {
cases := []struct {
name string
cfg string
value Credential
err error
}{
{
"hmac",
"hmac:ak:sk",
Credential{protocol: ProtocolHmac, args: []string{"ak", "sk"}},
nil,
},
{
"api key",
"apikey:key",
Credential{protocol: ProtocolAPIKey, args: []string{"key"}},
nil,
},
{
"file",
"file:/path/to/file",
Credential{protocol: ProtocolFile, args: []string{"/path/to/file"}},
nil,
},
{
"env",
"env",
Credential{protocol: ProtocolEnv},
nil,
},
{
"base64",
"base64:aGVsbG8sd29ybGQhCg==",
Credential{protocol: ProtocolBase64, args: []string{"aGVsbG8sd29ybGQhCg=="}},
nil,
},
{
"basic",
"basic:user:password",
Credential{protocol: ProtocolBasic, args: []string{"user", "password"}},
nil,
},
{
"not supported protocol",
"notsupported:ak:sk",
Credential{},
ErrUnsupportedProtocol,
},
}

for _, tt := range cases {
t.Run(tt.name, func(t *testing.T) {
p, err := Parse(tt.cfg)
if tt.err == nil {
assert.Nil(t, err)
} else {
assert.True(t, errors.Is(err, tt.err))
}
assert.EqualValues(t, tt.value, p)
})
}
}

func ExampleParse() {
cred, err := Parse("hmac:access_key:secret_key")
if err != nil {
log.Fatal("parse: ", err)
}

switch cred.Protocol() {
case ProtocolHmac:
ak, sk := cred.Hmac()
log.Println("access_key: ", ak)
log.Println("secret_key: ", sk)
case ProtocolAPIKey:
apikey := cred.APIKey()
log.Println("apikey: ", apikey)
case ProtocolFile:
path := cred.File()
log.Println("path: ", path)
case ProtocolEnv:
log.Println("use env value")
case ProtocolBase64:
content := cred.Base64()
log.Println("base64: ", content)
case ProtocolBasic:
user, password := cred.Basic()
log.Println("user: ", user)
log.Println("password: ", password)
default:
panic("unsupported protocol")
}
}
Loading