1package core
2
3import (
4 "crypto/sha256"
5 "fmt"
6 "regexp"
7 "strconv"
8 "strings"
9 "time"
10
11 "github.com/araddon/dateparse"
12
13 "github.com/MichaelMure/git-bug/entity"
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}