2019-09-16 23:16:33 +03:00
|
|
|
package core
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"regexp"
|
|
|
|
"strings"
|
|
|
|
|
2019-09-17 14:59:40 +03:00
|
|
|
"github.com/MichaelMure/git-bug/repository"
|
2019-09-16 23:16:33 +03:00
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
tokenConfigKeyPrefix = "git-bug.token"
|
|
|
|
tokenKeyTarget = "target"
|
|
|
|
tokenKeyScopes = "scopes"
|
|
|
|
)
|
|
|
|
|
2019-10-12 12:10:44 +03:00
|
|
|
// Token holds an API access token data
|
2019-09-16 23:16:33 +03:00
|
|
|
type Token struct {
|
|
|
|
Value string
|
|
|
|
Target string
|
|
|
|
Global bool
|
|
|
|
Scopes []string
|
|
|
|
}
|
|
|
|
|
2019-09-17 14:59:40 +03:00
|
|
|
// NewToken instantiate a new token
|
2019-09-22 12:48:48 +03:00
|
|
|
func NewToken(value, target string, global bool, scopes []string) *Token {
|
2019-09-16 23:16:33 +03:00
|
|
|
return &Token{
|
|
|
|
Value: value,
|
|
|
|
Target: target,
|
|
|
|
Global: global,
|
|
|
|
Scopes: scopes,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-17 14:59:40 +03:00
|
|
|
// Validate ensure token important fields are valid
|
|
|
|
func (t *Token) Validate() error {
|
2019-09-16 23:16:33 +03:00
|
|
|
if t.Value == "" {
|
2019-10-12 12:10:44 +03:00
|
|
|
return fmt.Errorf("missing value")
|
2019-09-16 23:16:33 +03:00
|
|
|
}
|
|
|
|
if t.Target == "" {
|
2019-10-12 12:10:44 +03:00
|
|
|
return fmt.Errorf("missing target")
|
|
|
|
}
|
|
|
|
if _, ok := bridgeImpl[t.Target]; !ok {
|
|
|
|
return fmt.Errorf("unknown target")
|
2019-09-16 23:16:33 +03:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2019-09-22 12:48:48 +03:00
|
|
|
func loadToken(repo repository.RepoConfig, value string, global bool) (*Token, error) {
|
|
|
|
keyPrefix := fmt.Sprintf("git-bug.token.%s.", value)
|
2019-09-17 14:59:40 +03:00
|
|
|
|
2019-10-12 12:10:44 +03:00
|
|
|
readerFn := repo.ReadConfigs
|
2019-09-16 23:16:33 +03:00
|
|
|
if global {
|
2019-10-12 12:10:44 +03:00
|
|
|
readerFn = repo.ReadGlobalConfigs
|
|
|
|
}
|
|
|
|
|
|
|
|
// read token config pairs
|
|
|
|
configs, err := readerFn(keyPrefix)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
2019-09-16 23:16:33 +03:00
|
|
|
}
|
|
|
|
|
2019-09-17 14:59:40 +03:00
|
|
|
// trim key prefix
|
2019-10-12 12:10:44 +03:00
|
|
|
for key, value := range configs {
|
|
|
|
newKey := strings.TrimPrefix(key, keyPrefix)
|
|
|
|
configs[newKey] = value
|
|
|
|
delete(configs, key)
|
2019-09-16 23:16:33 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
var ok bool
|
2019-09-22 12:48:48 +03:00
|
|
|
token := &Token{Value: value, Global: global}
|
2019-10-12 12:10:44 +03:00
|
|
|
token.Target, ok = configs[tokenKeyTarget]
|
2019-09-16 23:16:33 +03:00
|
|
|
if !ok {
|
2019-09-17 14:59:40 +03:00
|
|
|
return nil, fmt.Errorf("empty token key")
|
2019-09-16 23:16:33 +03:00
|
|
|
}
|
|
|
|
|
2019-10-12 12:10:44 +03:00
|
|
|
scopesString, ok := configs[tokenKeyScopes]
|
2019-09-16 23:16:33 +03:00
|
|
|
if !ok {
|
|
|
|
return nil, fmt.Errorf("missing scopes config")
|
|
|
|
}
|
|
|
|
|
|
|
|
token.Scopes = strings.Split(scopesString, ",")
|
|
|
|
return token, nil
|
|
|
|
}
|
|
|
|
|
2019-09-17 14:59:40 +03:00
|
|
|
// GetToken loads a token from repo config
|
2019-09-22 12:48:48 +03:00
|
|
|
func GetToken(repo repository.RepoConfig, value string) (*Token, error) {
|
|
|
|
return loadToken(repo, value, false)
|
2019-09-16 23:16:33 +03:00
|
|
|
}
|
|
|
|
|
2019-09-17 14:59:40 +03:00
|
|
|
// GetGlobalToken loads a token from the global config
|
2019-09-22 12:48:48 +03:00
|
|
|
func GetGlobalToken(repo repository.RepoConfig, value string) (*Token, error) {
|
|
|
|
return loadToken(repo, value, true)
|
2019-09-16 23:16:33 +03:00
|
|
|
}
|
|
|
|
|
2019-09-17 14:59:40 +03:00
|
|
|
func listTokens(repo repository.RepoConfig, global bool) ([]string, error) {
|
2019-10-12 12:10:44 +03:00
|
|
|
readerFn := repo.ReadConfigs
|
2019-09-16 23:16:33 +03:00
|
|
|
if global {
|
2019-10-12 12:10:44 +03:00
|
|
|
readerFn = repo.ReadGlobalConfigs
|
|
|
|
}
|
|
|
|
|
|
|
|
configs, err := readerFn(tokenConfigKeyPrefix + ".")
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
2019-09-16 23:16:33 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
re, err := regexp.Compile(tokenConfigKeyPrefix + `.([^.]+)`)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
set := make(map[string]interface{})
|
|
|
|
|
|
|
|
for key := range configs {
|
|
|
|
res := re.FindStringSubmatch(key)
|
|
|
|
|
|
|
|
if res == nil {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
set[res[1]] = nil
|
|
|
|
}
|
|
|
|
|
|
|
|
result := make([]string, len(set))
|
|
|
|
i := 0
|
|
|
|
for key := range set {
|
|
|
|
result[i] = key
|
|
|
|
i++
|
|
|
|
}
|
|
|
|
|
|
|
|
return result, nil
|
|
|
|
}
|
|
|
|
|
2019-09-17 14:59:40 +03:00
|
|
|
// ListTokens return the list of stored tokens in the repo config
|
|
|
|
func ListTokens(repo repository.RepoConfig) ([]string, error) {
|
2019-09-16 23:16:33 +03:00
|
|
|
return listTokens(repo, false)
|
|
|
|
}
|
|
|
|
|
2019-09-17 14:59:40 +03:00
|
|
|
// ListGlobalTokens return the list of stored tokens in the global config
|
|
|
|
func ListGlobalTokens(repo repository.RepoConfig) ([]string, error) {
|
2019-09-16 23:16:33 +03:00
|
|
|
return listTokens(repo, true)
|
|
|
|
}
|
|
|
|
|
2019-09-17 14:59:40 +03:00
|
|
|
func storeToken(repo repository.RepoConfig, token *Token) error {
|
2019-10-12 12:10:44 +03:00
|
|
|
storeFn := repo.StoreConfig
|
2019-09-16 23:16:33 +03:00
|
|
|
if token.Global {
|
2019-10-12 12:10:44 +03:00
|
|
|
storeFn = repo.StoreGlobalConfig
|
2019-09-16 23:16:33 +03:00
|
|
|
}
|
|
|
|
|
2019-09-22 12:48:48 +03:00
|
|
|
storeTargetKey := fmt.Sprintf("git-bug.token.%s.%s", token.Value, tokenKeyTarget)
|
2019-10-12 12:10:44 +03:00
|
|
|
err := storeFn(storeTargetKey, token.Target)
|
2019-09-16 23:16:33 +03:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2019-09-22 12:48:48 +03:00
|
|
|
storeScopesKey := fmt.Sprintf("git-bug.token.%s.%s", token.Value, tokenKeyScopes)
|
2019-10-12 12:10:44 +03:00
|
|
|
return storeFn(storeScopesKey, strings.Join(token.Scopes, ","))
|
2019-09-16 23:16:33 +03:00
|
|
|
}
|
|
|
|
|
2019-09-17 14:59:40 +03:00
|
|
|
// StoreToken stores a token in the repo config
|
2019-09-18 22:00:07 +03:00
|
|
|
func StoreToken(repo repository.RepoConfig, token *Token) error {
|
|
|
|
return storeToken(repo, token)
|
2019-09-16 23:16:33 +03:00
|
|
|
}
|
|
|
|
|
2019-09-17 14:59:40 +03:00
|
|
|
// StoreGlobalToken stores a token in global config
|
2019-09-18 22:00:07 +03:00
|
|
|
func StoreGlobalToken(repo repository.RepoConfig, token *Token) error {
|
|
|
|
return storeToken(repo, token)
|
2019-09-16 23:16:33 +03:00
|
|
|
}
|
|
|
|
|
2019-09-17 14:59:40 +03:00
|
|
|
// RemoveToken removes a token from the repo config
|
2019-09-22 12:48:48 +03:00
|
|
|
func RemoveToken(repo repository.RepoConfig, value string) error {
|
|
|
|
keyPrefix := fmt.Sprintf("git-bug.token.%s", value)
|
2019-09-16 23:16:33 +03:00
|
|
|
return repo.RmConfigs(keyPrefix)
|
|
|
|
}
|
|
|
|
|
2019-09-17 14:59:40 +03:00
|
|
|
// RemoveGlobalToken removes a token from the repo config
|
2019-09-22 12:48:48 +03:00
|
|
|
func RemoveGlobalToken(repo repository.RepoConfig, value string) error {
|
|
|
|
keyPrefix := fmt.Sprintf("git-bug.token.%s", value)
|
2019-09-16 23:16:33 +03:00
|
|
|
return repo.RmGlobalConfigs(keyPrefix)
|
|
|
|
}
|