1package identity
2
3import (
4 "crypto/sha256"
5 "encoding/json"
6 "fmt"
7 "strings"
8
9 "github.com/MichaelMure/git-bug/repository"
10 "github.com/MichaelMure/git-bug/util/lamport"
11 "github.com/MichaelMure/git-bug/util/text"
12)
13
14var _ Interface = &Bare{}
15
16// Bare is a very minimal identity, designed to be fully embedded directly along
17// other data.
18//
19// in particular, this identity is designed to be compatible with the handling of
20// identities in the early version of git-bug.
21type Bare struct {
22 id string
23 name string
24 email string
25 login string
26 avatarUrl string
27}
28
29func NewBare(name string, email string) *Bare {
30 return &Bare{name: name, email: email}
31}
32
33func NewBareFull(name string, email string, login string, avatarUrl string) *Bare {
34 return &Bare{name: name, email: email, login: login, avatarUrl: avatarUrl}
35}
36
37type bareIdentityJSON struct {
38 Name string `json:"name,omitempty"`
39 Email string `json:"email,omitempty"`
40 Login string `json:"login,omitempty"`
41 AvatarUrl string `json:"avatar_url,omitempty"`
42}
43
44func (i *Bare) MarshalJSON() ([]byte, error) {
45 return json.Marshal(bareIdentityJSON{
46 Name: i.name,
47 Email: i.email,
48 Login: i.login,
49 AvatarUrl: i.avatarUrl,
50 })
51}
52
53func (i *Bare) UnmarshalJSON(data []byte) error {
54 aux := bareIdentityJSON{}
55
56 if err := json.Unmarshal(data, &aux); err != nil {
57 return err
58 }
59
60 i.name = aux.Name
61 i.email = aux.Email
62 i.login = aux.Login
63 i.avatarUrl = aux.AvatarUrl
64
65 return nil
66}
67
68func (i *Bare) Id() string {
69 // We don't have a proper ID at hand, so let's hash all the data to get one.
70 // Hopefully the
71
72 if i.id != "" {
73 return i.id
74 }
75
76 data, err := json.Marshal(i)
77 if err != nil {
78 panic(err)
79 }
80
81 h := fmt.Sprintf("%x", sha256.New().Sum(data)[:16])
82 i.id = string(h)
83
84 return i.id
85}
86
87func (i *Bare) Name() string {
88 return i.name
89}
90
91func (i *Bare) Email() string {
92 return i.email
93}
94
95func (i *Bare) Login() string {
96 return i.login
97}
98
99func (i *Bare) AvatarUrl() string {
100 return i.avatarUrl
101}
102
103// Keys return the last version of the valid keys
104func (i *Bare) Keys() []Key {
105 return []Key{}
106}
107
108// ValidKeysAtTime return the set of keys valid at a given lamport time
109func (i *Bare) ValidKeysAtTime(time lamport.Time) []Key {
110 return []Key{}
111}
112
113// DisplayName return a non-empty string to display, representing the
114// identity, based on the non-empty values.
115func (i *Bare) DisplayName() string {
116 switch {
117 case i.name == "" && i.login != "":
118 return i.login
119 case i.name != "" && i.login == "":
120 return i.name
121 case i.name != "" && i.login != "":
122 return fmt.Sprintf("%s (%s)", i.name, i.login)
123 }
124
125 panic("invalid person data")
126}
127
128// Validate check if the Identity data is valid
129func (i *Bare) Validate() error {
130 if text.Empty(i.name) && text.Empty(i.login) {
131 return fmt.Errorf("either name or login should be set")
132 }
133
134 if strings.Contains(i.name, "\n") {
135 return fmt.Errorf("name should be a single line")
136 }
137
138 if !text.Safe(i.name) {
139 return fmt.Errorf("name is not fully printable")
140 }
141
142 if strings.Contains(i.login, "\n") {
143 return fmt.Errorf("login should be a single line")
144 }
145
146 if !text.Safe(i.login) {
147 return fmt.Errorf("login is not fully printable")
148 }
149
150 if strings.Contains(i.email, "\n") {
151 return fmt.Errorf("email should be a single line")
152 }
153
154 if !text.Safe(i.email) {
155 return fmt.Errorf("email is not fully printable")
156 }
157
158 if i.avatarUrl != "" && !text.ValidUrl(i.avatarUrl) {
159 return fmt.Errorf("avatarUrl is not a valid URL")
160 }
161
162 return nil
163}
164
165// Write the identity into the Repository. In particular, this ensure that
166// the Id is properly set.
167func (i *Bare) Commit(repo repository.Repo) error {
168 // Nothing to do, everything is directly embedded
169 return nil
170}
171
172// IsProtected return true if the chain of git commits started to be signed.
173// If that's the case, only signed commit with a valid key for this identity can be added.
174func (i *Bare) IsProtected() bool {
175 return false
176}