token.go

  1package core
  2
  3import (
  4	"crypto/sha256"
  5	"fmt"
  6	"regexp"
  7	"strconv"
  8	"strings"
  9	"time"
 10
 11	"github.com/MichaelMure/git-bug/entity"
 12	"github.com/araddon/dateparse"
 13
 14	"github.com/MichaelMure/git-bug/repository"
 15)
 16
 17const (
 18	tokenConfigKeyPrefix = "git-bug.token"
 19	tokenValueKey        = "value"
 20	tokenTargetKey       = "target"
 21	tokenCreateTimeKey   = "createtime"
 22)
 23
 24// Token holds an API access token data
 25type Token struct {
 26	ID         entity.Id
 27	Value      string
 28	Target     string
 29	CreateTime time.Time
 30}
 31
 32// NewToken instantiate a new token
 33func NewToken(value, target string) *Token {
 34	token := &Token{
 35		Value:      value,
 36		Target:     target,
 37		CreateTime: time.Now(),
 38	}
 39
 40	token.ID = entity.Id(hashToken(token))
 41	return token
 42}
 43
 44func hashToken(token *Token) string {
 45	sum := sha256.Sum256([]byte(token.Value))
 46	return fmt.Sprintf("%x", sum)
 47}
 48
 49// Validate ensure token important fields are valid
 50func (t *Token) Validate() error {
 51	if t.ID == "" {
 52		return fmt.Errorf("missing id")
 53	}
 54	if t.Value == "" {
 55		return fmt.Errorf("missing value")
 56	}
 57	if t.Target == "" {
 58		return fmt.Errorf("missing target")
 59	}
 60	if t.CreateTime.Equal(time.Time{}) {
 61		return fmt.Errorf("missing creation time")
 62	}
 63	if _, ok := bridgeImpl[t.Target]; !ok {
 64		return fmt.Errorf("unknown target")
 65	}
 66	return nil
 67}
 68
 69// LoadToken loads a token from repo config
 70func LoadToken(repo repository.RepoCommon, id string) (*Token, error) {
 71	keyPrefix := fmt.Sprintf("git-bug.token.%s.", id)
 72
 73	// read token config pairs
 74	configs, err := repo.GlobalConfig().ReadAll(keyPrefix)
 75	if err != nil {
 76		return nil, err
 77	}
 78
 79	// trim key prefix
 80	for key, value := range configs {
 81		delete(configs, key)
 82		newKey := strings.TrimPrefix(key, keyPrefix)
 83		configs[newKey] = value
 84	}
 85
 86	token := &Token{ID: entity.Id(id)}
 87
 88	var ok bool
 89	token.Value, ok = configs[tokenValueKey]
 90	if !ok {
 91		return nil, fmt.Errorf("empty token value")
 92	}
 93
 94	token.Target, ok = configs[tokenTargetKey]
 95	if !ok {
 96		return nil, fmt.Errorf("empty token key")
 97	}
 98
 99	createTime, ok := configs[tokenCreateTimeKey]
100	if !ok {
101		return nil, fmt.Errorf("missing createtime key")
102	}
103
104	token.CreateTime, err = dateparse.ParseLocal(createTime)
105	if err != nil {
106		return nil, err
107	}
108	return token, nil
109}
110
111// ListTokens return a map representing the stored tokens in the repo config and global config
112// along with their type (global: true, local:false)
113func ListTokens(repo repository.RepoCommon) ([]string, error) {
114	configs, err := repo.GlobalConfig().ReadAll(tokenConfigKeyPrefix + ".")
115	if err != nil {
116		return nil, err
117	}
118
119	re, err := regexp.Compile(tokenConfigKeyPrefix + `.([^.]+)`)
120	if err != nil {
121		panic(err)
122	}
123
124	set := make(map[string]interface{})
125
126	for key := range configs {
127		res := re.FindStringSubmatch(key)
128
129		if res == nil {
130			continue
131		}
132
133		set[res[1]] = nil
134	}
135
136	result := make([]string, len(set))
137	i := 0
138	for key := range set {
139		result[i] = key
140		i++
141	}
142
143	return result, nil
144}
145
146// StoreToken stores a token in the repo config
147func StoreToken(repo repository.RepoCommon, token *Token) error {
148	storeValueKey := fmt.Sprintf("git-bug.token.%s.%s", token.ID.String(), tokenValueKey)
149	err := repo.GlobalConfig().StoreString(storeValueKey, token.Value)
150	if err != nil {
151		return err
152	}
153
154	storeTargetKey := fmt.Sprintf("git-bug.token.%s.%s", token.ID.String(), tokenTargetKey)
155	err = repo.GlobalConfig().StoreString(storeTargetKey, token.Target)
156	if err != nil {
157		return err
158	}
159
160	createTimeKey := fmt.Sprintf("git-bug.token.%s.%s", token.ID.String(), tokenCreateTimeKey)
161	return repo.GlobalConfig().StoreString(createTimeKey, strconv.Itoa(int(token.CreateTime.Unix())))
162}
163
164// RemoveToken removes a token from the repo config
165func RemoveToken(repo repository.RepoCommon, id string) error {
166	keyPrefix := fmt.Sprintf("git-bug.token.%s", id)
167	return repo.GlobalConfig().RemoveAll(keyPrefix)
168}