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}