forked from forgejo/forgejo
Abstract hash function usage (#28138)
Refactor Hash interfaces and centralize hash function. This will allow easier introduction of different hash function later on. This forms the "no-op" part of the SHA256 enablement patch.
This commit is contained in:
parent
064f05204c
commit
cbf923e87b
122 changed files with 947 additions and 594 deletions
143
modules/git/object_id.go
Normal file
143
modules/git/object_id.go
Normal file
|
@ -0,0 +1,143 @@
|
|||
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package git
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"hash"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type ObjectID interface {
|
||||
String() string
|
||||
IsZero() bool
|
||||
RawValue() []byte
|
||||
Type() ObjectFormat
|
||||
}
|
||||
|
||||
/* SHA1 */
|
||||
type Sha1Hash [20]byte
|
||||
|
||||
func (h *Sha1Hash) String() string {
|
||||
return hex.EncodeToString(h[:])
|
||||
}
|
||||
|
||||
func (h *Sha1Hash) IsZero() bool {
|
||||
empty := Sha1Hash{}
|
||||
return bytes.Equal(empty[:], h[:])
|
||||
}
|
||||
func (h *Sha1Hash) RawValue() []byte { return h[:] }
|
||||
func (*Sha1Hash) Type() ObjectFormat { return &Sha1ObjectFormat{} }
|
||||
|
||||
func NewSha1() *Sha1Hash {
|
||||
return &Sha1Hash{}
|
||||
}
|
||||
|
||||
// generic implementations
|
||||
func NewHash(hash string) (ObjectID, error) {
|
||||
hash = strings.ToLower(hash)
|
||||
switch hash {
|
||||
case "sha1":
|
||||
return &Sha1Hash{}, nil
|
||||
}
|
||||
|
||||
return nil, errors.New("unsupported hash type")
|
||||
}
|
||||
|
||||
func IDFromRaw(h ObjectFormat, b []byte) (ObjectID, error) {
|
||||
if len(b) != h.FullLength()/2 {
|
||||
return h.Empty(), fmt.Errorf("length must be %d: %v", h.FullLength(), b)
|
||||
}
|
||||
return h.MustID(b), nil
|
||||
}
|
||||
|
||||
func MustIDFromString(h ObjectFormat, s string) ObjectID {
|
||||
b, _ := hex.DecodeString(s)
|
||||
return h.MustID(b)
|
||||
}
|
||||
|
||||
func genericIDFromString(h ObjectFormat, s string) (ObjectID, error) {
|
||||
s = strings.TrimSpace(s)
|
||||
if len(s) != h.FullLength() {
|
||||
return h.Empty(), fmt.Errorf("length must be %d: %s", h.FullLength(), s)
|
||||
}
|
||||
b, err := hex.DecodeString(s)
|
||||
if err != nil {
|
||||
return h.Empty(), err
|
||||
}
|
||||
return h.NewID(b)
|
||||
}
|
||||
|
||||
// utils
|
||||
func IDFromString(hexHash string) (ObjectID, error) {
|
||||
switch len(hexHash) {
|
||||
case 40:
|
||||
hashType := Sha1ObjectFormat{}
|
||||
h, err := hashType.NewIDFromString(hexHash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return h, nil
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("invalid hash hex string: '%s' len: %d", hexHash, len(hexHash))
|
||||
}
|
||||
|
||||
func IsEmptyCommitID(commitID string) bool {
|
||||
if commitID == "" {
|
||||
return true
|
||||
}
|
||||
|
||||
id, err := IDFromString(commitID)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return id.IsZero()
|
||||
}
|
||||
|
||||
// HashInterface is a struct that will generate a Hash
|
||||
type HasherInterface interface {
|
||||
hash.Hash
|
||||
|
||||
HashSum() ObjectID
|
||||
}
|
||||
|
||||
type Sha1Hasher struct {
|
||||
hash.Hash
|
||||
}
|
||||
|
||||
// ComputeBlobHash compute the hash for a given blob content
|
||||
func ComputeBlobHash(hashType ObjectFormat, content []byte) ObjectID {
|
||||
return ComputeHash(hashType, ObjectBlob, content)
|
||||
}
|
||||
|
||||
// ComputeHash compute the hash for a given ObjectType and content
|
||||
func ComputeHash(hashType ObjectFormat, t ObjectType, content []byte) ObjectID {
|
||||
h := hashType.NewHasher()
|
||||
_, _ = h.Write(t.Bytes())
|
||||
_, _ = h.Write([]byte(" "))
|
||||
_, _ = h.Write([]byte(strconv.FormatInt(int64(len(content)), 10)))
|
||||
_, _ = h.Write([]byte{0})
|
||||
return h.HashSum()
|
||||
}
|
||||
|
||||
// Sum generates a SHA1 for the provided hash
|
||||
func (h *Sha1Hasher) HashSum() ObjectID {
|
||||
var sha1 Sha1Hash
|
||||
copy(sha1[:], h.Hash.Sum(nil))
|
||||
return &sha1
|
||||
}
|
||||
|
||||
type ErrInvalidSHA struct {
|
||||
SHA string
|
||||
}
|
||||
|
||||
func (err ErrInvalidSHA) Error() string {
|
||||
return fmt.Sprintf("invalid sha: %s", err.SHA)
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue