// Copyright 2023 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT package git import ( "bytes" "encoding/hex" "fmt" "gitea.dev/modules/util" ) type ObjectID interface { String() string RefName() RefName IsZero() bool RawValue() []byte Type() ObjectFormat } type Sha1Hash [20]byte var _ ObjectID = (*Sha1Hash)(nil) func (h *Sha1Hash) String() string { return hex.EncodeToString(h[:]) } func (h *Sha1Hash) RefName() RefName { return RefName(h.String()) } 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 MustIDFromString(hexHash string) ObjectID { id, err := NewIDFromString(hexHash) if err != nil { panic(err) } return id } type Sha256Hash [32]byte var _ ObjectID = (*Sha256Hash)(nil) func (h *Sha256Hash) String() string { return hex.EncodeToString(h[:]) } func (h *Sha256Hash) RefName() RefName { return RefName(h.String()) } func (h *Sha256Hash) IsZero() bool { empty := Sha256Hash{} return bytes.Equal(empty[:], h[:]) } func (h *Sha256Hash) RawValue() []byte { return h[:] } func (*Sha256Hash) Type() ObjectFormat { return Sha256ObjectFormat } func NewIDFromString(hexHash string) (ObjectID, error) { var theObjectFormat ObjectFormat for _, objectFormat := range DefaultFeatures().SupportedObjectFormats { if len(hexHash) == objectFormat.FullLength() { theObjectFormat = objectFormat break } } if theObjectFormat == nil { return nil, fmt.Errorf("length %d has no matched object format: %s", len(hexHash), hexHash) } b, err := hex.DecodeString(hexHash) if err != nil { return nil, err } if len(b) != theObjectFormat.FullLength()/2 { return theObjectFormat.EmptyObjectID(), fmt.Errorf("length must be %d: %v", theObjectFormat.FullLength(), b) } return theObjectFormat.MustID(b), nil } func IsEmptyCommitID(commitID string) bool { if commitID == "" { return true } id, err := NewIDFromString(commitID) if err != nil { return false } return id.IsZero() } // ComputeBlobHash compute the hash for a given blob content func ComputeBlobHash(hashType ObjectFormat, content []byte) ObjectID { return hashType.ComputeHash(ObjectBlob, content) } func IsStringValidObjectID(objFmt ObjectFormat, s string, optMinLen ...int) bool { if objFmt == invalidObjectFormat { return false } var minLen, maxLen int if objFmt != nil { maxLen = objFmt.FullLength() minLen = util.OptionalArg(optMinLen, maxLen) } else { if len(optMinLen) == 0 { // if no "min length" is applied, then the length must exactly match one of the formats if len(s) != Sha1ObjectFormat.FullLength() && len(s) != Sha256ObjectFormat.FullLength() { return false } } maxLen = Sha256ObjectFormat.FullLength() minLen = util.OptionalArg(optMinLen, Sha1ObjectFormat.FullLength()) } if len(s) < minLen || len(s) > maxLen { return false } return isStringLowerHex(s) } func isStringLowerHex(s string) bool { for _, c := range s { isHex := (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') if !isHex { return false } } return len(s) > 0 // it accepts odd length because "shorten commit id" can be 7-chars }