aboutsummaryrefslogtreecommitdiffstats
path: root/bridge/core/token.go
diff options
context:
space:
mode:
Diffstat (limited to 'bridge/core/token.go')
-rw-r--r--bridge/core/token.go182
1 files changed, 182 insertions, 0 deletions
diff --git a/bridge/core/token.go b/bridge/core/token.go
new file mode 100644
index 00000000..2ceabca2
--- /dev/null
+++ b/bridge/core/token.go
@@ -0,0 +1,182 @@
+package core
+
+import (
+ "crypto/sha256"
+ "errors"
+ "fmt"
+ "regexp"
+ "sort"
+ "strings"
+ "time"
+
+ "github.com/MichaelMure/git-bug/entity"
+ "github.com/MichaelMure/git-bug/repository"
+)
+
+const (
+ tokenConfigKeyPrefix = "git-bug.token"
+ tokenValueKey = "value"
+ tokenTargetKey = "target"
+ tokenCreateTimeKey = "createtime"
+)
+
+var ErrTokenNotExist = errors.New("token doesn't exist")
+
+func NewErrMultipleMatchToken(matching []entity.Id) *entity.ErrMultipleMatch {
+ return entity.NewErrMultipleMatch("token", matching)
+}
+
+// Token holds an API access token data
+type Token struct {
+ Value string
+ Target string
+ CreateTime time.Time
+}
+
+// NewToken instantiate a new token
+func NewToken(value, target string) *Token {
+ return &Token{
+ Value: value,
+ Target: target,
+ CreateTime: time.Now(),
+ }
+}
+
+func (t *Token) ID() entity.Id {
+ sum := sha256.Sum256([]byte(t.Value))
+ return entity.Id(fmt.Sprintf("%x", sum))
+}
+
+// Validate ensure token important fields are valid
+func (t *Token) Validate() error {
+ if t.Value == "" {
+ return fmt.Errorf("missing value")
+ }
+ if t.Target == "" {
+ return fmt.Errorf("missing target")
+ }
+ if t.CreateTime.IsZero() || t.CreateTime.Equal(time.Time{}) {
+ return fmt.Errorf("missing creation time")
+ }
+ if !TargetExist(t.Target) {
+ return fmt.Errorf("unknown target")
+ }
+ return nil
+}
+
+// LoadToken loads a token from the repo config
+func LoadToken(repo repository.RepoCommon, id entity.Id) (*Token, error) {
+ keyPrefix := fmt.Sprintf("git-bug.token.%s.", id)
+
+ // read token config pairs
+ rawconfigs, err := repo.GlobalConfig().ReadAll(keyPrefix)
+ if err != nil {
+ // Not exactly right due to the limitation of ReadAll()
+ return nil, ErrTokenNotExist
+ }
+
+ // trim key prefix
+ configs := make(map[string]string)
+ for key, value := range rawconfigs {
+ newKey := strings.TrimPrefix(key, keyPrefix)
+ configs[newKey] = value
+ }
+
+ token := &Token{}
+
+ token.Value = configs[tokenValueKey]
+ token.Target = configs[tokenTargetKey]
+ if createTime, ok := configs[tokenCreateTimeKey]; ok {
+ if t, err := repository.ParseTimestamp(createTime); err == nil {
+ token.CreateTime = t
+ }
+ }
+
+ return token, nil
+}
+
+// LoadTokenPrefix load a token from the repo config with a prefix
+func LoadTokenPrefix(repo repository.RepoCommon, prefix string) (*Token, error) {
+ tokens, err := ListTokens(repo)
+ if err != nil {
+ return nil, err
+ }
+
+ // preallocate but empty
+ matching := make([]entity.Id, 0, 5)
+
+ for _, id := range tokens {
+ if id.HasPrefix(prefix) {
+ matching = append(matching, id)
+ }
+ }
+
+ if len(matching) > 1 {
+ return nil, NewErrMultipleMatchToken(matching)
+ }
+
+ if len(matching) == 0 {
+ return nil, ErrTokenNotExist
+ }
+
+ return LoadToken(repo, matching[0])
+}
+
+// ListTokens return a map representing the stored tokens in the repo config and global config
+// along with their type (global: true, local:false)
+func ListTokens(repo repository.RepoCommon) ([]entity.Id, error) {
+ configs, err := repo.GlobalConfig().ReadAll(tokenConfigKeyPrefix + ".")
+ if err != nil {
+ return nil, err
+ }
+
+ 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([]entity.Id, 0, len(set))
+ for key := range set {
+ result = append(result, entity.Id(key))
+ }
+
+ sort.Sort(entity.Alphabetical(result))
+
+ return result, nil
+}
+
+// StoreToken stores a token in the repo config
+func StoreToken(repo repository.RepoCommon, token *Token) error {
+ storeValueKey := fmt.Sprintf("git-bug.token.%s.%s", token.ID().String(), tokenValueKey)
+ err := repo.GlobalConfig().StoreString(storeValueKey, token.Value)
+ if err != nil {
+ return err
+ }
+
+ storeTargetKey := fmt.Sprintf("git-bug.token.%s.%s", token.ID().String(), tokenTargetKey)
+ err = repo.GlobalConfig().StoreString(storeTargetKey, token.Target)
+ if err != nil {
+ return err
+ }
+
+ createTimeKey := fmt.Sprintf("git-bug.token.%s.%s", token.ID().String(), tokenCreateTimeKey)
+ return repo.GlobalConfig().StoreTimestamp(createTimeKey, token.CreateTime)
+}
+
+// RemoveToken removes a token from the repo config
+func RemoveToken(repo repository.RepoCommon, id entity.Id) error {
+ keyPrefix := fmt.Sprintf("git-bug.token.%s", id)
+ return repo.GlobalConfig().RemoveAll(keyPrefix)
+}