2020-02-12 20:32:01 +03:00
|
|
|
package auth
|
|
|
|
|
|
|
|
import (
|
2020-07-28 13:56:46 +03:00
|
|
|
"crypto/rand"
|
|
|
|
"encoding/base64"
|
2020-02-12 20:32:01 +03:00
|
|
|
"fmt"
|
2020-07-28 13:56:46 +03:00
|
|
|
"strings"
|
2020-02-12 20:32:01 +03:00
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/MichaelMure/git-bug/bridge/core"
|
|
|
|
"github.com/MichaelMure/git-bug/repository"
|
|
|
|
)
|
|
|
|
|
|
|
|
type credentialBase struct {
|
|
|
|
target string
|
|
|
|
createTime time.Time
|
|
|
|
salt []byte
|
|
|
|
meta map[string]string
|
|
|
|
}
|
|
|
|
|
|
|
|
func newCredentialBase(target string) *credentialBase {
|
|
|
|
return &credentialBase{
|
|
|
|
target: target,
|
|
|
|
createTime: time.Now(),
|
|
|
|
salt: makeSalt(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-28 13:56:46 +03:00
|
|
|
func makeSalt() []byte {
|
|
|
|
result := make([]byte, 16)
|
|
|
|
_, err := rand.Read(result)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
|
|
|
func newCredentialBaseFromData(data map[string]string) (*credentialBase, error) {
|
2020-02-12 20:32:01 +03:00
|
|
|
base := &credentialBase{
|
2020-07-28 13:56:46 +03:00
|
|
|
target: data[keyringKeyTarget],
|
|
|
|
meta: metaFromData(data),
|
2020-02-12 20:32:01 +03:00
|
|
|
}
|
|
|
|
|
2020-07-28 13:56:46 +03:00
|
|
|
if createTime, ok := data[keyringKeyCreateTime]; ok {
|
2020-02-12 20:32:01 +03:00
|
|
|
t, err := repository.ParseTimestamp(createTime)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
base.createTime = t
|
|
|
|
} else {
|
|
|
|
return nil, fmt.Errorf("missing create time")
|
|
|
|
}
|
|
|
|
|
2020-07-28 13:56:46 +03:00
|
|
|
salt, err := saltFromData(data)
|
2020-02-12 20:32:01 +03:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
base.salt = salt
|
|
|
|
|
|
|
|
return base, nil
|
|
|
|
}
|
|
|
|
|
2020-07-28 13:56:46 +03:00
|
|
|
func metaFromData(data map[string]string) map[string]string {
|
|
|
|
result := make(map[string]string)
|
|
|
|
for key, val := range data {
|
|
|
|
if strings.HasPrefix(key, keyringKeyPrefixMeta) {
|
|
|
|
key = strings.TrimPrefix(key, keyringKeyPrefixMeta)
|
|
|
|
result[key] = val
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if len(result) == 0 {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
|
|
|
func saltFromData(data map[string]string) ([]byte, error) {
|
|
|
|
val, ok := data[keyringKeySalt]
|
|
|
|
if !ok {
|
|
|
|
return nil, fmt.Errorf("no credential salt found")
|
|
|
|
}
|
|
|
|
return base64.StdEncoding.DecodeString(val)
|
|
|
|
}
|
|
|
|
|
2020-02-12 20:32:01 +03:00
|
|
|
func (cb *credentialBase) Target() string {
|
|
|
|
return cb.target
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cb *credentialBase) CreateTime() time.Time {
|
|
|
|
return cb.createTime
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cb *credentialBase) Salt() []byte {
|
|
|
|
return cb.salt
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cb *credentialBase) validate() error {
|
|
|
|
if cb.target == "" {
|
|
|
|
return fmt.Errorf("missing target")
|
|
|
|
}
|
|
|
|
if cb.createTime.IsZero() || cb.createTime.Equal(time.Time{}) {
|
|
|
|
return fmt.Errorf("missing creation time")
|
|
|
|
}
|
|
|
|
if !core.TargetExist(cb.target) {
|
|
|
|
return fmt.Errorf("unknown target")
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cb *credentialBase) Metadata() map[string]string {
|
|
|
|
return cb.meta
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cb *credentialBase) GetMetadata(key string) (string, bool) {
|
|
|
|
val, ok := cb.meta[key]
|
|
|
|
return val, ok
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cb *credentialBase) SetMetadata(key string, value string) {
|
|
|
|
if cb.meta == nil {
|
|
|
|
cb.meta = make(map[string]string)
|
|
|
|
}
|
|
|
|
cb.meta[key] = value
|
|
|
|
}
|