token.go

  1package core
  2
  3import (
  4	"fmt"
  5	"regexp"
  6	"strings"
  7
  8	"github.com/MichaelMure/git-bug/repository"
  9)
 10
 11const (
 12	tokenConfigKeyPrefix = "git-bug.token"
 13	tokenKeyTarget       = "target"
 14	tokenKeyScopes       = "scopes"
 15)
 16
 17// Token holds an API access token data
 18type Token struct {
 19	Value  string
 20	Target string
 21	Global bool
 22	Scopes []string
 23}
 24
 25// NewToken instantiate a new token
 26func NewToken(value, target string, global bool, scopes []string) *Token {
 27	return &Token{
 28		Value:  value,
 29		Target: target,
 30		Global: global,
 31		Scopes: scopes,
 32	}
 33}
 34
 35// Validate ensure token important fields are valid
 36func (t *Token) Validate() error {
 37	if t.Value == "" {
 38		return fmt.Errorf("missing value")
 39	}
 40	if t.Target == "" {
 41		return fmt.Errorf("missing target")
 42	}
 43	if _, ok := bridgeImpl[t.Target]; !ok {
 44		return fmt.Errorf("unknown target")
 45	}
 46	return nil
 47}
 48
 49func loadToken(repo repository.RepoConfig, value string, global bool) (*Token, error) {
 50	keyPrefix := fmt.Sprintf("git-bug.token.%s.", value)
 51
 52	readerFn := repo.ReadConfigs
 53	if global {
 54		readerFn = repo.ReadGlobalConfigs
 55	}
 56
 57	// read token config pairs
 58	configs, err := readerFn(keyPrefix)
 59	if err != nil {
 60		return nil, err
 61	}
 62
 63	// trim key prefix
 64	for key, value := range configs {
 65		newKey := strings.TrimPrefix(key, keyPrefix)
 66		configs[newKey] = value
 67		delete(configs, key)
 68	}
 69
 70	var ok bool
 71	token := &Token{Value: value, Global: global}
 72	token.Target, ok = configs[tokenKeyTarget]
 73	if !ok {
 74		return nil, fmt.Errorf("empty token key")
 75	}
 76
 77	scopesString, ok := configs[tokenKeyScopes]
 78	if !ok {
 79		return nil, fmt.Errorf("missing scopes config")
 80	}
 81
 82	token.Scopes = strings.Split(scopesString, ",")
 83	return token, nil
 84}
 85
 86// GetToken loads a token from repo config
 87func GetToken(repo repository.RepoConfig, value string) (*Token, error) {
 88	return loadToken(repo, value, false)
 89}
 90
 91// GetGlobalToken loads a token from the global config
 92func GetGlobalToken(repo repository.RepoConfig, value string) (*Token, error) {
 93	return loadToken(repo, value, true)
 94}
 95
 96func listTokens(repo repository.RepoConfig, global bool) ([]string, error) {
 97	readerFn := repo.ReadConfigs
 98	if global {
 99		readerFn = repo.ReadGlobalConfigs
100	}
101
102	configs, err := readerFn(tokenConfigKeyPrefix + ".")
103	if err != nil {
104		return nil, err
105	}
106
107	re, err := regexp.Compile(tokenConfigKeyPrefix + `.([^.]+)`)
108	if err != nil {
109		panic(err)
110	}
111
112	set := make(map[string]interface{})
113
114	for key := range configs {
115		res := re.FindStringSubmatch(key)
116
117		if res == nil {
118			continue
119		}
120
121		set[res[1]] = nil
122	}
123
124	result := make([]string, len(set))
125	i := 0
126	for key := range set {
127		result[i] = key
128		i++
129	}
130
131	return result, nil
132}
133
134// ListTokens return the list of stored tokens in the repo config
135func ListTokens(repo repository.RepoConfig) ([]string, error) {
136	return listTokens(repo, false)
137}
138
139// ListGlobalTokens return the list of stored tokens in the global config
140func ListGlobalTokens(repo repository.RepoConfig) ([]string, error) {
141	return listTokens(repo, true)
142}
143
144func storeToken(repo repository.RepoConfig, token *Token) error {
145	storeFn := repo.StoreConfig
146	if token.Global {
147		storeFn = repo.StoreGlobalConfig
148	}
149
150	storeTargetKey := fmt.Sprintf("git-bug.token.%s.%s", token.Value, tokenKeyTarget)
151	err := storeFn(storeTargetKey, token.Target)
152	if err != nil {
153		return err
154	}
155
156	storeScopesKey := fmt.Sprintf("git-bug.token.%s.%s", token.Value, tokenKeyScopes)
157	return storeFn(storeScopesKey, strings.Join(token.Scopes, ","))
158}
159
160// StoreToken stores a token in the repo config
161func StoreToken(repo repository.RepoConfig, token *Token) error {
162	return storeToken(repo, token)
163}
164
165// StoreGlobalToken stores a token in global config
166func StoreGlobalToken(repo repository.RepoConfig, token *Token) error {
167	return storeToken(repo, token)
168}
169
170// RemoveToken removes a token from the repo config
171func RemoveToken(repo repository.RepoConfig, value string) error {
172	keyPrefix := fmt.Sprintf("git-bug.token.%s", value)
173	return repo.RmConfigs(keyPrefix)
174}
175
176// RemoveGlobalToken removes a token from the repo config
177func RemoveGlobalToken(repo repository.RepoConfig, value string) error {
178	keyPrefix := fmt.Sprintf("git-bug.token.%s", value)
179	return repo.RmGlobalConfigs(keyPrefix)
180}