diff options
Diffstat (limited to 'identity')
-rw-r--r-- | identity/bare.go | 55 | ||||
-rw-r--r-- | identity/bare_test.go | 13 | ||||
-rw-r--r-- | identity/common.go | 53 | ||||
-rw-r--r-- | identity/identity.go | 16 | ||||
-rw-r--r-- | identity/interface.go | 5 |
5 files changed, 117 insertions, 25 deletions
diff --git a/identity/bare.go b/identity/bare.go index 24f30f9f..729dc2e0 100644 --- a/identity/bare.go +++ b/identity/bare.go @@ -1,20 +1,25 @@ package identity import ( + "crypto/sha256" "encoding/json" "fmt" "strings" + "github.com/MichaelMure/git-bug/repository" "github.com/MichaelMure/git-bug/util/lamport" "github.com/MichaelMure/git-bug/util/text" ) +var _ Interface = &Bare{} + // 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. type Bare struct { + id string name string email string login string @@ -36,7 +41,7 @@ type bareIdentityJson struct { AvatarUrl string `json:"avatar_url,omitempty"` } -func (i Bare) MarshalJSON() ([]byte, error) { +func (i *Bare) MarshalJSON() ([]byte, error) { return json.Marshal(bareIdentityJson{ Name: i.name, Email: i.email, @@ -45,7 +50,7 @@ func (i Bare) MarshalJSON() ([]byte, error) { }) } -func (i Bare) UnmarshalJSON(data []byte) error { +func (i *Bare) UnmarshalJSON(data []byte) error { aux := bareIdentityJson{} if err := json.Unmarshal(data, &aux); err != nil { @@ -60,35 +65,54 @@ func (i Bare) UnmarshalJSON(data []byte) error { return nil } -func (i Bare) Name() string { +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 { return i.name } -func (i Bare) Email() string { +func (i *Bare) Email() string { return i.email } -func (i Bare) Login() string { +func (i *Bare) Login() string { return i.login } -func (i Bare) AvatarUrl() string { +func (i *Bare) AvatarUrl() string { return i.avatarUrl } // Keys return the last version of the valid keys -func (i Bare) Keys() []Key { +func (i *Bare) Keys() []Key { return []Key{} } // ValidKeysAtTime return the set of keys valid at a given lamport time -func (i Bare) ValidKeysAtTime(time lamport.Time) []Key { +func (i *Bare) ValidKeysAtTime(time lamport.Time) []Key { return []Key{} } // DisplayName return a non-empty string to display, representing the // identity, based on the non-empty values. -func (i Bare) DisplayName() string { +func (i *Bare) DisplayName() string { switch { case i.name == "" && i.login != "": return i.login @@ -102,7 +126,7 @@ func (i Bare) DisplayName() string { } // Match tell is the Person match the given query string -func (i Bare) Match(query string) bool { +func (i *Bare) Match(query string) bool { query = strings.ToLower(query) return strings.Contains(strings.ToLower(i.name), query) || @@ -110,7 +134,7 @@ func (i Bare) Match(query string) bool { } // Validate check if the Identity data is valid -func (i Bare) Validate() error { +func (i *Bare) Validate() error { if text.Empty(i.name) && text.Empty(i.login) { return fmt.Errorf("either name or login should be set") } @@ -146,8 +170,15 @@ func (i Bare) Validate() error { return nil } +// 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 +} + // 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. -func (i Bare) IsProtected() bool { +func (i *Bare) IsProtected() bool { return false } diff --git a/identity/bare_test.go b/identity/bare_test.go new file mode 100644 index 00000000..1458107a --- /dev/null +++ b/identity/bare_test.go @@ -0,0 +1,13 @@ +package identity + +import ( + "testing" + + "github.com/magiconair/properties/assert" +) + +func TestBare_Id(t *testing.T) { + i := NewBare("name", "email") + id := i.Id() + assert.Equal(t, "7b226e616d65223a226e616d65222c22", id) +} diff --git a/identity/common.go b/identity/common.go new file mode 100644 index 00000000..32dd3d9e --- /dev/null +++ b/identity/common.go @@ -0,0 +1,53 @@ +package identity + +import ( + "encoding/json" + "errors" + "fmt" + "strings" +) + +var ErrIdentityNotExist = errors.New("identity doesn't exist") + +type ErrMultipleMatch struct { + Matching []string +} + +func (e ErrMultipleMatch) Error() string { + return fmt.Sprintf("Multiple matching identities found:\n%s", strings.Join(e.Matching, "\n")) +} + +// Custom unmarshaling function to allow package user to delegate +// the decoding of an Identity and distinguish between an Identity +// and a Bare. +// +// If the given message has a "id" field, it's considered being a proper Identity. +func UnmarshalJSON(raw json.RawMessage) (Interface, error) { + // First try to decode as a normal Identity + var i Identity + + err := json.Unmarshal(raw, &i) + if err == nil && i.id != "" { + return &i, nil + } + + // abort if we have an error other than the wrong type + if _, ok := err.(*json.UnmarshalTypeError); err != nil && !ok { + return nil, err + } + + // Fallback on a legacy Bare identity + var b Bare + + err = json.Unmarshal(raw, &b) + if err == nil && (b.name != "" || b.login != "") { + return &b, nil + } + + // abort if we have an error other than the wrong type + if _, ok := err.(*json.UnmarshalTypeError); err != nil && !ok { + return nil, err + } + + return nil, fmt.Errorf("unknown identity type") +} diff --git a/identity/identity.go b/identity/identity.go index 313e3fd7..38729e37 100644 --- a/identity/identity.go +++ b/identity/identity.go @@ -16,16 +16,6 @@ const identityRefPattern = "refs/identities/" const versionEntryName = "version" const identityConfigKey = "git-bug.identity" -var ErrIdentityNotExist = errors.New("identity doesn't exist") - -type ErrMultipleMatch struct { - Matching []string -} - -func (e ErrMultipleMatch) Error() string { - return fmt.Sprintf("Multiple matching identities found:\n%s", strings.Join(e.Matching, "\n")) -} - var _ Interface = &Identity{} type Identity struct { @@ -85,8 +75,6 @@ func (i *Identity) UnmarshalJSON(data []byte) error { return nil } -// TODO: load/write from OpBase - // Read load an Identity from the identities data available in git func Read(repo repository.Repo, id string) (*Identity, error) { i := &Identity{ @@ -230,7 +218,9 @@ func (i *Identity) AddVersion(version *Version) { i.Versions = append(i.Versions, version) } -func (i *Identity) Commit(repo repository.ClockedRepo) error { +// Write the identity into the Repository. In particular, this ensure that +// the Id is properly set. +func (i *Identity) Commit(repo repository.Repo) error { // Todo: check for mismatch between memory and commited data var lastCommit git.Hash = "" diff --git a/identity/interface.go b/identity/interface.go index 6489efbe..c784a7a6 100644 --- a/identity/interface.go +++ b/identity/interface.go @@ -1,6 +1,7 @@ package identity import ( + "github.com/MichaelMure/git-bug/repository" "github.com/MichaelMure/git-bug/util/lamport" ) @@ -28,6 +29,10 @@ type Interface interface { // Validate check if the Identity data is valid Validate() error + // Write the identity into the Repository. In particular, this ensure that + // the Id is properly set. + Commit(repo repository.Repo) error + // 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. IsProtected() bool |