1package auth
2
3import (
4 "crypto/rand"
5 "encoding/base64"
6 "fmt"
7 "strings"
8 "time"
9
10 "github.com/MichaelMure/git-bug/bridge/core"
11 "github.com/MichaelMure/git-bug/repository"
12)
13
14type credentialBase struct {
15 target string
16 createTime time.Time
17 salt []byte
18 meta map[string]string
19}
20
21func newCredentialBase(target string) *credentialBase {
22 return &credentialBase{
23 target: target,
24 createTime: time.Now(),
25 salt: makeSalt(),
26 }
27}
28
29func makeSalt() []byte {
30 result := make([]byte, 16)
31 _, err := rand.Read(result)
32 if err != nil {
33 panic(err)
34 }
35 return result
36}
37
38func newCredentialBaseFromData(data map[string]string) (*credentialBase, error) {
39 base := &credentialBase{
40 target: data[keyringKeyTarget],
41 meta: metaFromData(data),
42 }
43
44 if createTime, ok := data[keyringKeyCreateTime]; ok {
45 t, err := repository.ParseTimestamp(createTime)
46 if err != nil {
47 return nil, err
48 }
49 base.createTime = t
50 } else {
51 return nil, fmt.Errorf("missing create time")
52 }
53
54 salt, err := saltFromData(data)
55 if err != nil {
56 return nil, err
57 }
58 base.salt = salt
59
60 return base, nil
61}
62
63func metaFromData(data map[string]string) map[string]string {
64 result := make(map[string]string)
65 for key, val := range data {
66 if strings.HasPrefix(key, keyringKeyPrefixMeta) {
67 key = strings.TrimPrefix(key, keyringKeyPrefixMeta)
68 result[key] = val
69 }
70 }
71 if len(result) == 0 {
72 return nil
73 }
74 return result
75}
76
77func saltFromData(data map[string]string) ([]byte, error) {
78 val, ok := data[keyringKeySalt]
79 if !ok {
80 return nil, fmt.Errorf("no credential salt found")
81 }
82 return base64.StdEncoding.DecodeString(val)
83}
84
85func (cb *credentialBase) Target() string {
86 return cb.target
87}
88
89func (cb *credentialBase) CreateTime() time.Time {
90 return cb.createTime
91}
92
93func (cb *credentialBase) Salt() []byte {
94 return cb.salt
95}
96
97func (cb *credentialBase) validate() error {
98 if cb.target == "" {
99 return fmt.Errorf("missing target")
100 }
101 if cb.createTime.IsZero() || cb.createTime.Equal(time.Time{}) {
102 return fmt.Errorf("missing creation time")
103 }
104 if !core.TargetExist(cb.target) {
105 return fmt.Errorf("unknown target")
106 }
107 return nil
108}
109
110func (cb *credentialBase) Metadata() map[string]string {
111 return cb.meta
112}
113
114func (cb *credentialBase) GetMetadata(key string) (string, bool) {
115 val, ok := cb.meta[key]
116 return val, ok
117}
118
119func (cb *credentialBase) SetMetadata(key string, value string) {
120 if cb.meta == nil {
121 cb.meta = make(map[string]string)
122 }
123 cb.meta[key] = value
124}