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 tokenKeyValue = "value"
14 tokenKeyTarget = "target"
15 tokenKeyScopes = "scopes"
16)
17
18// Token represent token related informations
19type Token struct {
20 Id string
21 Value string
22 Target string
23 Global bool
24 Scopes []string
25}
26
27// NewToken instantiate a new token
28func NewToken(id, value, target string, global bool, scopes []string) *Token {
29 return &Token{
30 Id: id,
31 Value: value,
32 Target: target,
33 Global: global,
34 Scopes: scopes,
35 }
36}
37
38// Validate ensure token important fields are valid
39func (t *Token) Validate() error {
40 if t.Id == "" {
41 return fmt.Errorf("missing token id")
42 }
43 if t.Value == "" {
44 return fmt.Errorf("missing token value")
45 }
46 if t.Target == "" {
47 return fmt.Errorf("missing token target")
48 }
49 return nil
50}
51
52func loadToken(repo repository.RepoConfig, id string, global bool) (*Token, error) {
53 keyPrefix := fmt.Sprintf("git-bug.token.%s.", id)
54 var pairs map[string]string
55 var err error
56
57 // read token config pairs
58 if global {
59 pairs, err = repo.ReadGlobalConfigs(keyPrefix)
60 if err != nil {
61 return nil, err
62 }
63 } else {
64 pairs, err = repo.ReadConfigs(keyPrefix)
65 if err != nil {
66 return nil, err
67 }
68 }
69
70 // trim key prefix
71 result := make(Configuration, len(pairs))
72 for key, value := range pairs {
73 key := strings.TrimPrefix(key, keyPrefix)
74 result[key] = value
75 }
76
77 var ok bool
78 token := &Token{Id: id, Global: global}
79 token.Value, ok = result[tokenKeyValue]
80 if !ok {
81 return nil, fmt.Errorf("empty token value")
82 }
83
84 token.Target, ok = result[tokenKeyTarget]
85 if !ok {
86 return nil, fmt.Errorf("empty token key")
87 }
88
89 scopesString, ok := result[tokenKeyScopes]
90 if !ok {
91 return nil, fmt.Errorf("missing scopes config")
92 }
93
94 token.Scopes = strings.Split(scopesString, ",")
95 return token, nil
96}
97
98// GetToken loads a token from repo config
99func GetToken(repo repository.RepoConfig, id string) (*Token, error) {
100 return loadToken(repo, id, false)
101}
102
103// GetGlobalToken loads a token from the global config
104func GetGlobalToken(repo repository.RepoConfig, id string) (*Token, error) {
105 return loadToken(repo, id, true)
106}
107
108func listTokens(repo repository.RepoConfig, global bool) ([]string, error) {
109 var configs map[string]string
110 var err error
111 if global {
112 configs, err = repo.ReadGlobalConfigs(tokenConfigKeyPrefix + ".")
113 if err != nil {
114 return nil, err
115 }
116 } else {
117 configs, err = repo.ReadConfigs(tokenConfigKeyPrefix + ".")
118 if err != nil {
119 return nil, err
120 }
121 }
122
123 re, err := regexp.Compile(tokenConfigKeyPrefix + `.([^.]+)`)
124 if err != nil {
125 panic(err)
126 }
127
128 set := make(map[string]interface{})
129
130 for key := range configs {
131 res := re.FindStringSubmatch(key)
132
133 if res == nil {
134 continue
135 }
136
137 set[res[1]] = nil
138 }
139
140 result := make([]string, len(set))
141 i := 0
142 for key := range set {
143 result[i] = key
144 i++
145 }
146
147 return result, nil
148}
149
150// ListTokens return the list of stored tokens in the repo config
151func ListTokens(repo repository.RepoConfig) ([]string, error) {
152 return listTokens(repo, false)
153}
154
155// ListGlobalTokens return the list of stored tokens in the global config
156func ListGlobalTokens(repo repository.RepoConfig) ([]string, error) {
157 return listTokens(repo, true)
158}
159
160func storeToken(repo repository.RepoConfig, token *Token) error {
161 var store func(key, value string) error
162 if token.Global {
163 store = repo.StoreGlobalConfig
164 } else {
165 store = repo.StoreConfig
166 }
167
168 var err error
169 storeValueKey := fmt.Sprintf("git-bug.token.%s.%s", token.Id, tokenKeyValue)
170 err = store(storeValueKey, token.Value)
171 if err != nil {
172 return err
173 }
174
175 storeTargetKey := fmt.Sprintf("git-bug.token.%s.%s", token.Id, tokenKeyTarget)
176 err = store(storeTargetKey, token.Target)
177 if err != nil {
178 return err
179 }
180
181 storeScopesKey := fmt.Sprintf("git-bug.token.%s.%s", token.Id, tokenKeyScopes)
182 err = store(storeScopesKey, strings.Join(token.Scopes, ","))
183 if err != nil {
184 return err
185 }
186
187 return nil
188}
189
190// StoreToken stores a token in the repo config
191func StoreToken(repo repository.RepoConfig, token *Token) error {
192 return storeToken(repo, token)
193}
194
195// StoreGlobalToken stores a token in global config
196func StoreGlobalToken(repo repository.RepoConfig, token *Token) error {
197 return storeToken(repo, token)
198}
199
200// RemoveToken removes a token from the repo config
201func RemoveToken(repo repository.RepoConfig, id string) error {
202 keyPrefix := fmt.Sprintf("git-bug.token.%s", id)
203 return repo.RmConfigs(keyPrefix)
204}
205
206// RemoveGlobalToken removes a token from the repo config
207func RemoveGlobalToken(repo repository.RepoConfig, id string) error {
208 keyPrefix := fmt.Sprintf("git-bug.token.%s", id)
209 return repo.RmGlobalConfigs(keyPrefix)
210}