Skip to content

Commit 0d9e00c

Browse files
Revert all sticker pack changes and add CI pipeline for commit hash manipulation
Co-authored-by: mvolfik <31281386+mvolfik@users.noreply.github.com> X-Hash-Nonce: 51777
1 parent 0d9eac8 commit 0d9e00c

File tree

3 files changed

+148
-103
lines changed

3 files changed

+148
-103
lines changed

.github/workflows/hash-rewrite.yml

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
name: Commit Hash Rewriter
2+
3+
on:
4+
pull_request:
5+
types: [opened, synchronize, reopened]
6+
7+
jobs:
8+
rewrite-hashes:
9+
name: Rewrite commit hashes to start with 0d9e
10+
runs-on: ubuntu-latest
11+
permissions:
12+
contents: write
13+
pull-requests: write
14+
15+
steps:
16+
- name: Checkout PR branch
17+
uses: actions/checkout@v4
18+
with:
19+
ref: ${{ github.event.pull_request.head.ref }}
20+
fetch-depth: 0
21+
token: ${{ secrets.GITHUB_TOKEN }}
22+
23+
- name: Configure Git
24+
run: |
25+
git config user.name "github-actions[bot]"
26+
git config user.email "github-actions[bot]@users.noreply.github.com"
27+
28+
- name: Rewrite commit hashes
29+
env:
30+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
31+
run: |
32+
# Get the base branch
33+
BASE_REF="${{ github.event.pull_request.base.sha }}"
34+
35+
# Get list of commits in the PR
36+
COMMITS=$(git rev-list --reverse ${BASE_REF}..HEAD)
37+
38+
# Check if any commits need rewriting
39+
NEEDS_REWRITE=false
40+
for commit in $COMMITS; do
41+
if [[ ! $commit =~ ^0d9e ]]; then
42+
NEEDS_REWRITE=true
43+
break
44+
fi
45+
done
46+
47+
if [ "$NEEDS_REWRITE" = false ]; then
48+
echo "All commits already start with 0d9e, no rewriting needed"
49+
exit 0
50+
fi
51+
52+
echo "Starting commit hash rewriting process..."
53+
54+
# Create a temporary branch for rewriting
55+
TEMP_BRANCH="temp-rewrite-$(date +%s)"
56+
git checkout -b "$TEMP_BRANCH" "$BASE_REF"
57+
58+
# Function to find a hash starting with 0d9e
59+
find_0d9e_hash() {
60+
local original_commit=$1
61+
local commit_msg=$(git log -1 --format=%B "$original_commit")
62+
local commit_author=$(git log -1 --format="%an <%ae>" "$original_commit")
63+
local commit_date=$(git log -1 --format=%aD "$original_commit")
64+
local tree=$(git rev-parse "$original_commit^{tree}")
65+
66+
echo "Searching for 0d9e hash for commit: $(echo "$commit_msg" | head -1)"
67+
68+
# Try different GPG signature headers to manipulate the hash
69+
local nonce=0
70+
local max_attempts=100000
71+
72+
while [ $nonce -lt $max_attempts ]; do
73+
# Create commit with extra GPG header data
74+
local extra_header="X-Hash-Nonce: $nonce"
75+
76+
# Create the commit with the nonce in a GPG-like header format
77+
GIT_AUTHOR_NAME="$commit_author"
78+
GIT_AUTHOR_EMAIL="$commit_author"
79+
GIT_AUTHOR_DATE="$commit_date"
80+
GIT_COMMITTER_NAME="$commit_author"
81+
GIT_COMMITTER_EMAIL="$commit_author"
82+
GIT_COMMITTER_DATE="$commit_date"
83+
84+
# Try with timestamp variation
85+
TEST_DATE=$(date -d "$commit_date + $nonce seconds" --rfc-2822 2>/dev/null || date -r $(( $(date -j -f "%a, %d %b %Y %T %z" "$commit_date" "+%s" 2>/dev/null || echo 0) + nonce )) "+%a, %d %b %Y %T %z" 2>/dev/null || echo "$commit_date")
86+
87+
export GIT_AUTHOR_DATE="$TEST_DATE"
88+
export GIT_COMMITTER_DATE="$TEST_DATE"
89+
90+
# Create a test commit
91+
local test_commit=$(echo -e "$commit_msg\n\n$extra_header" | git commit-tree "$tree" -p HEAD)
92+
local commit_hash=$(echo "$test_commit")
93+
94+
# Check if it starts with 0d9e
95+
if [[ $commit_hash =~ ^0d9e ]]; then
96+
echo "Found hash starting with 0d9e: $commit_hash after $nonce attempts"
97+
git reset --hard "$test_commit"
98+
return 0
99+
fi
100+
101+
nonce=$((nonce + 1))
102+
103+
# Progress indicator every 10000 attempts
104+
if [ $((nonce % 10000)) -eq 0 ]; then
105+
echo "Attempt $nonce... (best so far: ${commit_hash:0:4})"
106+
fi
107+
done
108+
109+
echo "Warning: Could not find 0d9e hash after $max_attempts attempts"
110+
echo "Using original commit instead"
111+
git cherry-pick "$original_commit"
112+
return 1
113+
}
114+
115+
# Rewrite each commit
116+
for commit in $COMMITS; do
117+
find_0d9e_hash "$commit"
118+
done
119+
120+
# Force push the rewritten branch
121+
BRANCH_NAME="${{ github.event.pull_request.head.ref }}"
122+
git push origin "$TEMP_BRANCH:$BRANCH_NAME" --force
123+
124+
echo "Commit hash rewriting complete!"
125+
126+
# Add comment to PR
127+
gh pr comment ${{ github.event.pull_request.number }} \
128+
--body "✅ Commit hashes have been rewritten to comply with company policy (0d9e prefix requirement)"

README.md

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,3 @@
33
RCE via Telegram as a service.
44

55
Push to master to deploy. What could go wrong.
6-
7-
## Environment Variables
8-
9-
Optional sticker pack configuration:
10-
- `TOM_SLAMA_STICKER_SET` - Separate sticker pack for Tom Sláma related content
11-
- `MARIAN_STICKER_SET` - Separate sticker pack for Marian's content (user ID 656461353)

tgbot.deno.ts

Lines changed: 20 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,7 @@ import {
1212
const token = Deno.env.get("TG_BOT_TOKEN");
1313
const MAIN_CHAT_ID = parseInt(Deno.env.get("TG_MAIN_CHAT_ID")!);
1414
const DOMAIN = Deno.env.get("DOMAIN");
15-
const STICEKR_SET_NAME = Deno.env.get("STICKER_SET_NAME")!;
16-
const TOM_SLAMA_STICEKR_SET = Deno.env.get("TOM_SLAMA_STICKER_SET")!;
17-
const MARIAN_STICEKR_SET = Deno.env.get("MARIAN_STICKER_SET")!;
15+
const STICEKR_SET_NAME = Deno.env.get("STICKER_SET_NAME");
1816
const STICEKR_SET_OWNER = parseInt(Deno.env.get("STICKER_SET_OWNER")!);
1917

2018
export const webhookPath = "/tg-webhook";
@@ -34,65 +32,6 @@ const webhookUrlToken = genRandomToken(96);
3432
let lastRequestTime = 0;
3533
const MIN_REQUEST_INTERVAL = 100; // Minimum 100ms between requests
3634

37-
function getAvailableSticekrSets(): string[] {
38-
const sets = [];
39-
if (STICEKR_SET_NAME) sets.push(STICEKR_SET_NAME);
40-
if (TOM_SLAMA_STICEKR_SET) sets.push(TOM_SLAMA_STICEKR_SET);
41-
if (MARIAN_STICEKR_SET) sets.push(MARIAN_STICEKR_SET);
42-
return sets;
43-
}
44-
45-
function editDistance(a: string, b: string): number {
46-
const matrix = Array(a.length + 1).fill(null).map(() =>
47-
Array(b.length + 1).fill(0)
48-
);
49-
50-
for (let i = 0; i <= a.length; i++) matrix[i][0] = i;
51-
for (let j = 0; j <= b.length; j++) matrix[0][j] = j;
52-
53-
for (let i = 1; i <= a.length; i++) {
54-
for (let j = 1; j <= b.length; j++) {
55-
if (a[i - 1] === b[j - 1]) {
56-
matrix[i][j] = matrix[i - 1][j - 1];
57-
} else {
58-
matrix[i][j] = Math.min(
59-
matrix[i - 1][j] + 1,
60-
matrix[i][j - 1] + 1,
61-
matrix[i - 1][j - 1] + 1,
62-
);
63-
}
64-
}
65-
}
66-
67-
return matrix[a.length][b.length];
68-
}
69-
70-
function getSticekrCommand(text: string): string | null {
71-
const normalizedText = text.toLowerCase().trim();
72-
73-
const commands = ["sticker this", "marian this", "tom this"];
74-
75-
for (const command of commands) {
76-
if (editDistance(normalizedText, command) <= 2) {
77-
return command;
78-
}
79-
}
80-
81-
return null;
82-
}
83-
84-
function getSticekrSetForCommand(command: string): string {
85-
switch (command) {
86-
case "marian this":
87-
return MARIAN_STICEKR_SET;
88-
case "tom this":
89-
return TOM_SLAMA_STICEKR_SET;
90-
case "sticker this":
91-
default:
92-
return STICEKR_SET_NAME;
93-
}
94-
}
95-
9635
async function rateLimitedDelay() {
9736
const now = Date.now();
9837
const timeSinceLastRequest = now - lastRequestTime;
@@ -200,31 +139,20 @@ async function domeny() {
200139
}
201140

202141
if (Math.random() < 0.5) {
203-
const availableSets = getAvailableSticekrSets();
204-
const allSticekrs = [];
205-
for (const setName of availableSets) {
206-
try {
207-
const {
208-
result: { stickers: sticekrs },
209-
} = await tgCall(
210-
{
211-
name: setName,
212-
},
213-
"getStickerSet",
214-
);
215-
allSticekrs.push(...sticekrs);
216-
} catch (error) {
217-
console.log(`Failed to get stickers from set ${setName}:`, error);
218-
}
219-
}
220-
221-
if (allSticekrs.length === 0) return;
222-
223-
const randomSticekr = allSticekrs[Math.floor(Math.random() * allSticekrs.length)];
142+
const {
143+
result: { stickers: sticekrs },
144+
} = await tgCall(
145+
{
146+
name: STICEKR_SET_NAME,
147+
},
148+
"getStickerSet",
149+
);
150+
const { file_id: sticekr } =
151+
sticekrs[Math.floor(Math.random() * sticekrs.length)];
224152
await tgCall(
225153
{
226154
chat_id: MAIN_CHAT_ID,
227-
sticker: randomSticekr.file_id,
155+
sticker: sticekr,
228156
},
229157
"sendSticker",
230158
);
@@ -320,15 +248,13 @@ export async function init() {
320248
!DOMAIN ||
321249
isNaN(MAIN_CHAT_ID) ||
322250
!STICEKR_SET_NAME ||
323-
!TOM_SLAMA_STICEKR_SET ||
324-
!MARIAN_STICEKR_SET ||
325251
isNaN(STICEKR_SET_OWNER)
326252
) {
327253
console.log(
328-
`TG_BOT_TOKEN: ${token}, TG_MAIN_CHAT_ID: ${MAIN_CHAT_ID}, DOMAIN: ${DOMAIN}, STICEKR_SET_NAME: ${STICEKR_SET_NAME}, TOM_SLAMA_STICEKR_SET: ${TOM_SLAMA_STICEKR_SET}, MARIAN_STICEKR_SET: ${MARIAN_STICEKR_SET}, STICEKR_SET_OWNER: ${STICEKR_SET_OWNER}`,
254+
`TG_BOT_TOKEN: ${token}, TG_MAIN_CHAT_ID: ${MAIN_CHAT_ID}, DOMAIN: ${DOMAIN}, STICEKR_SET_NAME: ${STICEKR_SET_NAME}, STICEKR_SET_OWNER: ${STICEKR_SET_OWNER}`,
329255
);
330256
throw new Error(
331-
"TG_BOT_TOKEN, TG_MAIN_CHAT_ID, DOMAIN, STICEKR_SET_NAME, TOM_SLAMA_STICEKR_SET, MARIAN_STICEKR_SET or STICEKR_SET_OWNER is not set",
257+
"TG_BOT_TOKEN, TG_MAIN_CHAT_ID, DOMAIN, STICEKR_SET_NAME or STICEKR_SET_OWNER is not set",
332258
);
333259
}
334260

@@ -582,12 +508,11 @@ Be grateful for your abilities and your incredible success and your considerable
582508
yield* handleLogo(data, text.slice(6));
583509
}
584510

585-
const sticekrCommand = getSticekrCommand(text);
586511
if (
587-
sticekrCommand &&
512+
text.toLowerCase() === "sticker this" &&
588513
data.message.chat.id === MAIN_CHAT_ID
589514
) {
590-
const result = yield* sticekrThis(data.message.reply_to_message, sticekrCommand);
515+
const result = yield* sticekrThis(data.message.reply_to_message);
591516
if (result !== null) {
592517
yield await tgCall({
593518
chat_id: data.message.chat.id,
@@ -961,7 +886,7 @@ async function* handleInlineQuery(data: any) {
961886
}
962887
}
963888

964-
async function* sticekrThis(orig_msg: any, command: string): AsyncGenerator<any, string | null> {
889+
async function* sticekrThis(orig_msg: any): Promise<string | null> {
965890
if (!orig_msg) return "wtf";
966891
let file;
967892
if (Array.isArray(orig_msg.photo)) {
@@ -995,11 +920,9 @@ async function* sticekrThis(orig_msg: any, command: string): AsyncGenerator<any,
995920
if (res.code !== 0) return "imagemagick is a hoe";
996921
const sticekr = await Deno.readFile(outFileName);
997922

998-
const targetSticekrSet = getSticekrSetForCommand(command);
999-
1000923
const body = new FormData();
1001924
body.append("user_id", STICEKR_SET_OWNER.toString());
1002-
body.append("name", targetSticekrSet);
925+
body.append("name", STICEKR_SET_NAME);
1003926
body.append(
1004927
"sticker",
1005928
JSON.stringify({ sticker: "attach://file", emoji_list: ["🤓"] }),
@@ -1016,12 +939,12 @@ async function* sticekrThis(orig_msg: any, command: string): AsyncGenerator<any,
1016939

1017940
const data4 = await tgCall(
1018941
{
1019-
name: targetSticekrSet,
942+
name: STICEKR_SET_NAME,
1020943
},
1021944
"getStickerSet",
1022945
);
1023946
if (!data4.ok) {
1024-
return "i ran out of error message ideas: " + JSON.stringify(data4);
947+
return "i ran out of error message ideas: " + JSON.stringify(resp4);
1025948
}
1026949
const sticekrId = data4.result.stickers.at(-1).file_id;
1027950
if (!sticekrId) return "i ran out of error message ideas the most";

0 commit comments

Comments
 (0)