Skip to content

Commit 9aaed95

Browse files
committed
Add versions of Decrypt and DecryptInt64 that return an error instead of panicking.
1 parent 3bd0a92 commit 9aaed95

File tree

2 files changed

+53
-7
lines changed

2 files changed

+53
-7
lines changed

hashids.go

+36-7
Original file line numberDiff line numberDiff line change
@@ -201,18 +201,43 @@ func (h *HashID) EncodeInt64(numbers []int64) (string, error) {
201201
// It is symmetric with Encode if the Alphabet and Salt are the same ones which were used to hash.
202202
// MinLength has no effect on Decode.
203203
func (h *HashID) Decode(hash string) []int {
204-
result64 := h.DecodeInt64(hash)
204+
result, err := h.DecodeWithError(hash)
205+
if err != nil {
206+
panic(err)
207+
}
208+
return result
209+
}
210+
211+
// Decode unhashes the string passed to an array of int.
212+
// It is symmetric with Encode if the Alphabet and Salt are the same ones which were used to hash.
213+
// MinLength has no effect on Decode.
214+
func (h *HashID) DecodeWithError(hash string) ([]int, error) {
215+
result64, err := h.DecodeInt64WithError(hash)
216+
if err != nil {
217+
return nil, err
218+
}
205219
result := make([]int, 0, len(result64))
206220
for _, id := range result64 {
207221
result = append(result, int(id))
208222
}
209-
return result
223+
return result, nil
210224
}
211225

212226
// DecodeInt64 unhashes the string passed to an array of int64.
213227
// It is symmetric with EncodeInt64 if the Alphabet and Salt are the same ones which were used to hash.
214228
// MinLength has no effect on DecodeInt64.
215229
func (h *HashID) DecodeInt64(hash string) []int64 {
230+
result, err := h.DecodeInt64WithError(hash)
231+
if err != nil {
232+
panic(err)
233+
}
234+
return result
235+
}
236+
237+
// DecodeInt64 unhashes the string passed to an array of int64.
238+
// It is symmetric with EncodeInt64 if the Alphabet and Salt are the same ones which were used to hash.
239+
// MinLength has no effect on DecodeInt64.
240+
func (h *HashID) DecodeInt64WithError(hash string) ([]int64, error) {
216241
hashes := splitRunes([]rune(hash), h.guards)
217242
hashIndex := 0
218243
if len(hashes) == 2 || len(hashes) == 3 {
@@ -230,11 +255,15 @@ func (h *HashID) DecodeInt64(hash string) []int64 {
230255
for _, subHash := range hashes {
231256
buffer := append([]rune{lottery}, append(h.salt, alphabet...)...)
232257
alphabet = consistentShuffle(alphabet, buffer[:len(alphabet)])
233-
result = append(result, unhash(subHash, alphabet))
258+
number, err := unhash(subHash, alphabet)
259+
if err != nil {
260+
return nil, err
261+
}
262+
result = append(result, number)
234263
}
235264
}
236265

237-
return result
266+
return result, nil
238267
}
239268

240269
func splitRunes(input, seps []rune) [][]rune {
@@ -278,7 +307,7 @@ func hash(input int64, alphabet []rune) []rune {
278307
return reversed
279308
}
280309

281-
func unhash(input, alphabet []rune) int64 {
310+
func unhash(input, alphabet []rune) (int64, error) {
282311
result := int64(0)
283312
for i, inputRune := range input {
284313
alphabetPos := -1
@@ -289,12 +318,12 @@ func unhash(input, alphabet []rune) int64 {
289318
}
290319
}
291320
if alphabetPos == -1 {
292-
panic("should not happen, alphabet used for hash was different")
321+
return 0, errors.New("alphabet used for hash was different")
293322
}
294323

295324
result += int64(alphabetPos) * int64(math.Pow(float64(len(alphabet)), float64(len(input)-i-1)))
296325
}
297-
return result
326+
return result, nil
298327
}
299328

300329
func consistentShuffle(alphabet, salt []rune) []rune {

hashids_test.go

+17
Original file line numberDiff line numberDiff line change
@@ -159,3 +159,20 @@ func TestCustomAlphabet(t *testing.T) {
159159
}
160160
}
161161
}
162+
163+
func TestDecryptWithError(t *testing.T) {
164+
hdata := NewData()
165+
hdata.Alphabet = "PleasAkMEFoThStx"
166+
hdata.Salt = "this is my salt"
167+
168+
hid := NewWithData(hdata)
169+
// hash now contains a letter not in the alphabet
170+
dec, err := hid.DecodeWithError("MAkhkloFAxAoskaZ")
171+
172+
if dec != nil {
173+
t.Error("DecryptWithError should have returned nil result")
174+
}
175+
if err == nil {
176+
t.Error("DecryptWithError should have returned error")
177+
}
178+
}

0 commit comments

Comments
 (0)