1// Copyright 2023 The Gitea Authors. All rights reserved.
2// SPDX-License-Identifier: MIT
3
4package git
5
6import (
7 "crypto/sha1"
8 "crypto/sha256"
9 "hash"
10 "regexp"
11 "strconv"
12)
13
14// sha1Pattern can be used to determine if a string is an valid sha
15var sha1Pattern = regexp.MustCompile(`^[0-9a-f]{4,40}$`)
16
17// sha256Pattern can be used to determine if a string is an valid sha
18var sha256Pattern = regexp.MustCompile(`^[0-9a-f]{4,64}$`)
19
20type ObjectFormat interface {
21 // Name returns the name of the object format
22 Name() string
23 // EmptyObjectID creates a new empty ObjectID from an object format hash name
24 EmptyObjectID() ObjectID
25 // EmptyTree is the hash of an empty tree
26 EmptyTree() ObjectID
27 // FullLength is the length of the hash's hex string
28 FullLength() int
29 // IsValid returns true if the input is a valid hash
30 IsValid(input string) bool
31 // MustID creates a new ObjectID from a byte slice
32 MustID(b []byte) ObjectID
33 // ComputeHash compute the hash for a given ObjectType and content
34 ComputeHash(t ObjectType, content []byte) ObjectID
35}
36
37func computeHash(dst []byte, hasher hash.Hash, t ObjectType, content []byte) {
38 _, _ = hasher.Write(t.Bytes())
39 _, _ = hasher.Write([]byte(" "))
40 _, _ = hasher.Write([]byte(strconv.Itoa(len(content))))
41 _, _ = hasher.Write([]byte{0})
42 _, _ = hasher.Write(content)
43 hasher.Sum(dst)
44}
45
46/* SHA1 Type */
47type Sha1ObjectFormatImpl struct{}
48
49var (
50 emptySha1ObjectID = &Sha1Hash{}
51 emptySha1Tree = &Sha1Hash{
52 0x4b, 0x82, 0x5d, 0xc6, 0x42, 0xcb, 0x6e, 0xb9, 0xa0, 0x60,
53 0xe5, 0x4b, 0xf8, 0xd6, 0x92, 0x88, 0xfb, 0xee, 0x49, 0x04,
54 }
55)
56
57func (Sha1ObjectFormatImpl) Name() string { return "sha1" }
58func (Sha1ObjectFormatImpl) EmptyObjectID() ObjectID {
59 return emptySha1ObjectID
60}
61
62func (Sha1ObjectFormatImpl) EmptyTree() ObjectID {
63 return emptySha1Tree
64}
65func (Sha1ObjectFormatImpl) FullLength() int { return 40 }
66func (Sha1ObjectFormatImpl) IsValid(input string) bool {
67 return sha1Pattern.MatchString(input)
68}
69
70func (Sha1ObjectFormatImpl) MustID(b []byte) ObjectID {
71 var id Sha1Hash
72 copy(id[0:20], b)
73 return &id
74}
75
76// ComputeHash compute the hash for a given ObjectType and content
77func (h Sha1ObjectFormatImpl) ComputeHash(t ObjectType, content []byte) ObjectID {
78 var obj Sha1Hash
79 computeHash(obj[:0], sha1.New(), t, content)
80 return &obj
81}
82
83/* SHA256 Type */
84type Sha256ObjectFormatImpl struct{}
85
86var (
87 emptySha256ObjectID = &Sha256Hash{}
88 emptySha256Tree = &Sha256Hash{
89 0x6e, 0xf1, 0x9b, 0x41, 0x22, 0x5c, 0x53, 0x69, 0xf1, 0xc1,
90 0x04, 0xd4, 0x5d, 0x8d, 0x85, 0xef, 0xa9, 0xb0, 0x57, 0xb5,
91 0x3b, 0x14, 0xb4, 0xb9, 0xb9, 0x39, 0xdd, 0x74, 0xde, 0xcc,
92 0x53, 0x21,
93 }
94)
95
96func (Sha256ObjectFormatImpl) Name() string { return "sha256" }
97func (Sha256ObjectFormatImpl) EmptyObjectID() ObjectID {
98 return emptySha256ObjectID
99}
100
101func (Sha256ObjectFormatImpl) EmptyTree() ObjectID {
102 return emptySha256Tree
103}
104func (Sha256ObjectFormatImpl) FullLength() int { return 64 }
105func (Sha256ObjectFormatImpl) IsValid(input string) bool {
106 return sha256Pattern.MatchString(input)
107}
108
109func (Sha256ObjectFormatImpl) MustID(b []byte) ObjectID {
110 var id Sha256Hash
111 copy(id[0:32], b)
112 return &id
113}
114
115// ComputeHash compute the hash for a given ObjectType and content
116func (h Sha256ObjectFormatImpl) ComputeHash(t ObjectType, content []byte) ObjectID {
117 var obj Sha256Hash
118 computeHash(obj[:0], sha256.New(), t, content)
119 return &obj
120}
121
122var (
123 Sha1ObjectFormat ObjectFormat = Sha1ObjectFormatImpl{}
124 Sha256ObjectFormat ObjectFormat = Sha256ObjectFormatImpl{}
125 // any addition must be reflected in IsEmptyCommitID
126)
127
128var SupportedObjectFormats = []ObjectFormat{
129 Sha1ObjectFormat,
130}
131
132func ObjectFormatFromName(name string) ObjectFormat {
133 for _, objectFormat := range SupportedObjectFormats {
134 if name == objectFormat.Name() {
135 return objectFormat
136 }
137 }
138 return nil
139}
140
141func IsValidObjectFormat(name string) bool {
142 return ObjectFormatFromName(name) != nil
143}