Skip to content

Commit 3bdfd60

Browse files
committed
update: Leet flag generator
1 parent 4a3cd66 commit 3bdfd60

File tree

4 files changed

+141
-0
lines changed

4 files changed

+141
-0
lines changed

internal/util/flag.go

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
// Copyright 2025 Rina
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// https://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package util
16+
17+
import (
18+
"regexp"
19+
"strings"
20+
"unicode"
21+
22+
"golang.org/x/exp/rand"
23+
)
24+
25+
var leetMap = map[rune][]rune{
26+
'A': {'4', 'A', 'a'},
27+
'B': {'8', 'B', 'b'},
28+
'C': {'C', 'c'},
29+
'D': {'D', 'd'},
30+
'E': {'3', 'E', 'e'},
31+
'F': {'F', 'f'},
32+
'G': {'6', 'G', 'g'},
33+
'H': {'H', 'h'},
34+
'I': {'I', 'i', '1'},
35+
'J': {'J', 'j'},
36+
'K': {'K', 'k'},
37+
'L': {'L', 'l', '1'},
38+
'M': {'M', 'm'},
39+
'N': {'N', 'n'},
40+
'O': {'O', 'o', '0'},
41+
'P': {'P', 'p'},
42+
'Q': {'Q', 'q'},
43+
'R': {'R', 'r'},
44+
'S': {'S', 's', '5', '$'},
45+
'T': {'T', 't', '7'},
46+
'U': {'U', 'u'},
47+
'V': {'V', 'v'},
48+
'W': {'W', 'w'},
49+
'X': {'X', 'x'},
50+
'Y': {'Y', 'y'},
51+
'Z': {'Z', 'z', '2'},
52+
}
53+
54+
func Leetify(input string, seed uint64) string {
55+
rand.Seed(seed)
56+
57+
var result strings.Builder
58+
for _, char := range input {
59+
if leetChars, ok := leetMap[unicode.ToUpper(char)]; ok {
60+
result.WriteRune(leetChars[rand.Intn(len(leetChars))])
61+
} else {
62+
result.WriteRune(char)
63+
}
64+
}
65+
66+
return result.String()
67+
}
68+
69+
func GenerateFlagContent(format string, seed string) string {
70+
// Use [] to wrap the string to be leetified
71+
// Use {hash} to insert the sha256ed seed
72+
// Use {uuid} to insert a random uuid
73+
74+
leetRe := regexp.MustCompile(`\[([^\[\]]+)\]`)
75+
76+
result := format
77+
result = strings.ReplaceAll(result, "{hash}", SHA256(seed)[:8])
78+
result = strings.ReplaceAll(result, "{uuid}", UUID())
79+
80+
leet := leetRe.FindAllString(result, -1)
81+
for _, l := range leet {
82+
result = strings.ReplaceAll(result, l, Leetify(l[1:len(l)-1], SHA256Uint64(seed)))
83+
}
84+
85+
return result
86+
}

internal/util/flag_test.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// Copyright 2025 Rina
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// https://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package util
16+
17+
import (
18+
"testing"
19+
20+
"github.com/stretchr/testify/assert"
21+
)
22+
23+
func TestFlag(t *testing.T) {
24+
flag1 := GenerateFlagContent("takanashi_hoshino_is_super_kawaii", "random_seed")
25+
assert.Equal(t, "takanashi_hoshino_is_super_kawaii", flag1, "they should be equal")
26+
27+
flag2 := GenerateFlagContent("[takanashi_hoshino_is_super_kawaii]_[leet2]", "random_seed")
28+
println(flag2)
29+
assert.NotEqual(t, "takanashi_hoshino_is_super_kawaii_leet2", flag2, "they should not be equal")
30+
31+
flag3 := GenerateFlagContent("[takanashi_hoshino_is_super_kawaii]_[leet2]", "random_seed")
32+
flag6 := GenerateFlagContent("[takanashi_hoshino_is_super_kawaii]_[leet2]", "random_seeeeeeed")
33+
println(flag3, flag6)
34+
assert.Equal(t, flag2, flag3, "they should be equal")
35+
assert.NotEqual(t, flag3, flag6, "they should not be equal")
36+
37+
flag4 := GenerateFlagContent("[takanashi_hoshino_is_super_kawaii]_{seed}", "random_seed")
38+
flag5 := GenerateFlagContent("[takanashi_hoshino_is_super_kawaii_{seed}]", "random_seed")
39+
println(flag4, flag5)
40+
assert.NotEqual(t, flag4, flag5, "they should not be equal")
41+
42+
}

internal/util/hash.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ package util
1717
import (
1818
"crypto/sha256"
1919
"fmt"
20+
"strconv"
2021
"time"
2122

2223
"github.com/google/uuid"
@@ -34,6 +35,11 @@ func SHA256(secret string) string {
3435
return fmt.Sprintf("%x", h.Sum(nil))
3536
}
3637

38+
func SHA256Uint64(secret string) uint64 {
39+
res, _ := strconv.ParseUint(SHA256(secret)[:16], 16, 64)
40+
return res
41+
}
42+
3743
func SHA256WithSalt(secret string, salt string) string {
3844
return SHA256(secret + salt)
3945
}

internal/util/hash_test.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,10 @@ func TestGenerateRandomText(t *testing.T) {
4040
randomText := GenerateRandomText(length)
4141
assert.Equal(t, length, int32(len(randomText)), "length should be equal to the specified length")
4242
}
43+
44+
func TestSHA256Uint64(t *testing.T) {
45+
seedToInt := SHA256Uint64("takanashi_hoshino_is_super_kawaii")
46+
assert.Equal(t, uint64(0xa649edaea14f0f0), seedToInt, "they should be equal")
47+
seedToInt2 := SHA256Uint64("takanashi_hoshino_is_super_kawaii222")
48+
assert.NotEqual(t, seedToInt, seedToInt2, "they should not be equal")
49+
}

0 commit comments

Comments
 (0)