2018-11-21 20:56:12 +03:00
|
|
|
package identity
|
|
|
|
|
|
|
|
import (
|
2019-01-19 21:23:31 +03:00
|
|
|
"crypto/sha256"
|
2018-11-21 20:56:12 +03:00
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
|
|
|
"strings"
|
|
|
|
|
2019-01-19 21:23:31 +03:00
|
|
|
"github.com/MichaelMure/git-bug/repository"
|
2018-11-21 20:56:12 +03:00
|
|
|
"github.com/MichaelMure/git-bug/util/lamport"
|
|
|
|
"github.com/MichaelMure/git-bug/util/text"
|
|
|
|
)
|
|
|
|
|
2019-01-19 21:23:31 +03:00
|
|
|
var _ Interface = &Bare{}
|
|
|
|
|
2019-01-16 23:23:49 +03:00
|
|
|
// Bare is a very minimal identity, designed to be fully embedded directly along
|
|
|
|
// other data.
|
|
|
|
//
|
|
|
|
// in particular, this identity is designed to be compatible with the handling of
|
|
|
|
// identities in the early version of git-bug.
|
2018-11-21 20:56:12 +03:00
|
|
|
type Bare struct {
|
2019-01-19 21:23:31 +03:00
|
|
|
id string
|
2018-11-21 20:56:12 +03:00
|
|
|
name string
|
|
|
|
email string
|
|
|
|
login string
|
|
|
|
avatarUrl string
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewBare(name string, email string) *Bare {
|
|
|
|
return &Bare{name: name, email: email}
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewBareFull(name string, email string, login string, avatarUrl string) *Bare {
|
|
|
|
return &Bare{name: name, email: email, login: login, avatarUrl: avatarUrl}
|
|
|
|
}
|
|
|
|
|
2019-01-20 17:41:27 +03:00
|
|
|
type bareIdentityJSON struct {
|
2018-11-21 20:56:12 +03:00
|
|
|
Name string `json:"name,omitempty"`
|
|
|
|
Email string `json:"email,omitempty"`
|
|
|
|
Login string `json:"login,omitempty"`
|
|
|
|
AvatarUrl string `json:"avatar_url,omitempty"`
|
|
|
|
}
|
|
|
|
|
2019-01-19 21:23:31 +03:00
|
|
|
func (i *Bare) MarshalJSON() ([]byte, error) {
|
2019-01-20 17:41:27 +03:00
|
|
|
return json.Marshal(bareIdentityJSON{
|
2018-11-21 20:56:12 +03:00
|
|
|
Name: i.name,
|
|
|
|
Email: i.email,
|
|
|
|
Login: i.login,
|
|
|
|
AvatarUrl: i.avatarUrl,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2019-01-19 21:23:31 +03:00
|
|
|
func (i *Bare) UnmarshalJSON(data []byte) error {
|
2019-01-20 17:41:27 +03:00
|
|
|
aux := bareIdentityJSON{}
|
2018-11-21 20:56:12 +03:00
|
|
|
|
|
|
|
if err := json.Unmarshal(data, &aux); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
i.name = aux.Name
|
|
|
|
i.email = aux.Email
|
|
|
|
i.login = aux.Login
|
|
|
|
i.avatarUrl = aux.AvatarUrl
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2019-01-19 21:23:31 +03:00
|
|
|
func (i *Bare) Id() string {
|
|
|
|
// We don't have a proper ID at hand, so let's hash all the data to get one.
|
|
|
|
// Hopefully the
|
|
|
|
|
|
|
|
if i.id != "" {
|
|
|
|
return i.id
|
|
|
|
}
|
|
|
|
|
|
|
|
data, err := json.Marshal(i)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
h := fmt.Sprintf("%x", sha256.New().Sum(data)[:16])
|
|
|
|
i.id = string(h)
|
|
|
|
|
|
|
|
return i.id
|
|
|
|
}
|
|
|
|
|
|
|
|
func (i *Bare) Name() string {
|
2018-11-21 20:56:12 +03:00
|
|
|
return i.name
|
|
|
|
}
|
|
|
|
|
2019-01-19 21:23:31 +03:00
|
|
|
func (i *Bare) Email() string {
|
2018-11-21 20:56:12 +03:00
|
|
|
return i.email
|
|
|
|
}
|
|
|
|
|
2019-01-19 21:23:31 +03:00
|
|
|
func (i *Bare) Login() string {
|
2018-11-21 20:56:12 +03:00
|
|
|
return i.login
|
|
|
|
}
|
|
|
|
|
2019-01-19 21:23:31 +03:00
|
|
|
func (i *Bare) AvatarUrl() string {
|
2018-11-21 20:56:12 +03:00
|
|
|
return i.avatarUrl
|
|
|
|
}
|
|
|
|
|
2019-01-16 23:23:49 +03:00
|
|
|
// Keys return the last version of the valid keys
|
2019-01-19 21:23:31 +03:00
|
|
|
func (i *Bare) Keys() []Key {
|
2018-11-21 20:56:12 +03:00
|
|
|
return []Key{}
|
|
|
|
}
|
|
|
|
|
2019-01-16 23:23:49 +03:00
|
|
|
// ValidKeysAtTime return the set of keys valid at a given lamport time
|
2019-01-19 21:23:31 +03:00
|
|
|
func (i *Bare) ValidKeysAtTime(time lamport.Time) []Key {
|
2018-11-21 20:56:12 +03:00
|
|
|
return []Key{}
|
|
|
|
}
|
|
|
|
|
|
|
|
// DisplayName return a non-empty string to display, representing the
|
|
|
|
// identity, based on the non-empty values.
|
2019-01-19 21:23:31 +03:00
|
|
|
func (i *Bare) DisplayName() string {
|
2018-11-21 20:56:12 +03:00
|
|
|
switch {
|
|
|
|
case i.name == "" && i.login != "":
|
|
|
|
return i.login
|
|
|
|
case i.name != "" && i.login == "":
|
|
|
|
return i.name
|
|
|
|
case i.name != "" && i.login != "":
|
|
|
|
return fmt.Sprintf("%s (%s)", i.name, i.login)
|
|
|
|
}
|
|
|
|
|
|
|
|
panic("invalid person data")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Validate check if the Identity data is valid
|
2019-01-19 21:23:31 +03:00
|
|
|
func (i *Bare) Validate() error {
|
2018-11-21 20:56:12 +03:00
|
|
|
if text.Empty(i.name) && text.Empty(i.login) {
|
|
|
|
return fmt.Errorf("either name or login should be set")
|
|
|
|
}
|
|
|
|
|
|
|
|
if strings.Contains(i.name, "\n") {
|
|
|
|
return fmt.Errorf("name should be a single line")
|
|
|
|
}
|
|
|
|
|
|
|
|
if !text.Safe(i.name) {
|
|
|
|
return fmt.Errorf("name is not fully printable")
|
|
|
|
}
|
|
|
|
|
|
|
|
if strings.Contains(i.login, "\n") {
|
|
|
|
return fmt.Errorf("login should be a single line")
|
|
|
|
}
|
|
|
|
|
|
|
|
if !text.Safe(i.login) {
|
|
|
|
return fmt.Errorf("login is not fully printable")
|
|
|
|
}
|
|
|
|
|
|
|
|
if strings.Contains(i.email, "\n") {
|
|
|
|
return fmt.Errorf("email should be a single line")
|
|
|
|
}
|
|
|
|
|
|
|
|
if !text.Safe(i.email) {
|
|
|
|
return fmt.Errorf("email is not fully printable")
|
|
|
|
}
|
|
|
|
|
|
|
|
if i.avatarUrl != "" && !text.ValidUrl(i.avatarUrl) {
|
|
|
|
return fmt.Errorf("avatarUrl is not a valid URL")
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2019-01-19 21:23:31 +03:00
|
|
|
// Write the identity into the Repository. In particular, this ensure that
|
|
|
|
// the Id is properly set.
|
|
|
|
func (i *Bare) Commit(repo repository.Repo) error {
|
|
|
|
// Nothing to do, everything is directly embedded
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2019-01-16 23:23:49 +03:00
|
|
|
// IsProtected return true if the chain of git commits started to be signed.
|
|
|
|
// If that's the case, only signed commit with a valid key for this identity can be added.
|
2019-01-19 21:23:31 +03:00
|
|
|
func (i *Bare) IsProtected() bool {
|
2018-11-21 20:56:12 +03:00
|
|
|
return false
|
|
|
|
}
|