Skip to content

Commit

Permalink
credential,endpoint: Split from pkg (#843)
Browse files Browse the repository at this point in the history
* credential,endpoint: Split from pkg

Signed-off-by: Xuanwo <github@xuanwo.io>

* Update Makefile

Signed-off-by: Xuanwo <github@xuanwo.io>

* Fix filename

Signed-off-by: Xuanwo <github@xuanwo.io>
  • Loading branch information
Xuanwo authored Oct 14, 2021
1 parent 1e32aa0 commit 4976396
Show file tree
Hide file tree
Showing 28 changed files with 1,053 additions and 605 deletions.
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

0 comments on commit 4976396

Please sign in to comment.