git-slot-machine 2.1.6 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/settings.local.json +7 -1
- package/CHANGELOG.md +25 -0
- package/dist/commands/play.d.ts.map +1 -1
- package/dist/commands/play.js +11 -0
- package/dist/commands/play.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/utils/amendDetector.d.ts +17 -0
- package/dist/utils/amendDetector.d.ts.map +1 -0
- package/dist/utils/amendDetector.js +58 -0
- package/dist/utils/amendDetector.js.map +1 -0
- package/package.json +1 -1
- package/src/commands/play.ts +13 -0
- package/src/index.ts +1 -1
- package/src/utils/amendDetector.ts +74 -0
|
@@ -8,7 +8,13 @@
|
|
|
8
8
|
"Bash(git push:*)",
|
|
9
9
|
"Bash(npm publish)",
|
|
10
10
|
"Bash(npm config set:*)",
|
|
11
|
-
"Read(//Users/than/Sites/gitslotmachine.com/**)"
|
|
11
|
+
"Read(//Users/than/Sites/gitslotmachine.com/**)",
|
|
12
|
+
"Read(//Users/than/Sites/**)",
|
|
13
|
+
"Bash(xargs:*)",
|
|
14
|
+
"Bash(php artisan play:remove:*)",
|
|
15
|
+
"Bash(php artisan tinker:*)",
|
|
16
|
+
"Bash(git reflog:*)",
|
|
17
|
+
"Bash(php artisan:*)"
|
|
12
18
|
],
|
|
13
19
|
"deny": [],
|
|
14
20
|
"ask": []
|
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,31 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [2.2.0] - 2025-10-23
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- **Hash grinding detection** - Detects and flags suspicious commit amending behavior
|
|
12
|
+
- Checks git reflog for commit amend patterns
|
|
13
|
+
- Flags commits with 5+ amends in a 5-minute window
|
|
14
|
+
- Sends suspicious activity flag and amend count to API
|
|
15
|
+
- Displays warning to users when suspicious activity is detected
|
|
16
|
+
- **API: Suspicious activity tracking** - Tracks hash grinding attempts
|
|
17
|
+
- New `suspicious` and `amend_count` columns in plays table
|
|
18
|
+
- Stores and tracks flagged commits for review
|
|
19
|
+
- **Artisan command: `play:remove`** - Safely remove plays and recalculate stats
|
|
20
|
+
- Removes specific plays by commit hash and username
|
|
21
|
+
- Recalculates all repository and user statistics
|
|
22
|
+
- Uses database transactions for safety
|
|
23
|
+
- **Artisan command: `plays:suspicious`** - View flagged commits
|
|
24
|
+
- Lists all plays flagged for hash grinding
|
|
25
|
+
- Shows statistics and top offenders
|
|
26
|
+
- Filter by user with `--user` option
|
|
27
|
+
- Limit results with `--limit` option
|
|
28
|
+
|
|
29
|
+
### Security
|
|
30
|
+
- Prevents hash grinding exploitation by detecting and flagging suspicious amend patterns
|
|
31
|
+
- All admin functions are terminal-based (secure for public repositories)
|
|
32
|
+
|
|
8
33
|
## [2.1.6] - 2025-10-17
|
|
9
34
|
|
|
10
35
|
### Added
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"play.d.ts","sourceRoot":"","sources":["../../src/commands/play.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"play.d.ts","sourceRoot":"","sources":["../../src/commands/play.ts"],"names":[],"mappings":"AAQA,UAAU,WAAW;IACnB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,wBAAsB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAqJnF"}
|
package/dist/commands/play.js
CHANGED
|
@@ -3,6 +3,7 @@ import { animateSlotMachine, animateSmallMode } from '../animation/slotMachine.j
|
|
|
3
3
|
import { getBalance, updateBalance, setBalance } from '../balance.js';
|
|
4
4
|
import { sendPlayToAPI } from '../api.js';
|
|
5
5
|
import { getRepoInfo, getGitHubUsername } from '../config.js';
|
|
6
|
+
import { detectAmendGrinding, getAmendWarningMessage } from '../utils/amendDetector.js';
|
|
6
7
|
import chalk from 'chalk';
|
|
7
8
|
export async function playCommand(hash, options) {
|
|
8
9
|
try {
|
|
@@ -61,6 +62,9 @@ export async function playCommand(hash, options) {
|
|
|
61
62
|
}
|
|
62
63
|
// Update balance locally
|
|
63
64
|
let newBalance = updateBalance(hash.toLowerCase(), result.payout);
|
|
65
|
+
// Detect potential hash grinding
|
|
66
|
+
const amendDetection = detectAmendGrinding();
|
|
67
|
+
const warningMessage = getAmendWarningMessage(amendDetection);
|
|
64
68
|
// Send to API and sync balance with server
|
|
65
69
|
let shareUrl;
|
|
66
70
|
if (repoInfo && githubUsername) {
|
|
@@ -76,6 +80,8 @@ export async function playCommand(hash, options) {
|
|
|
76
80
|
github_username: githubUsername,
|
|
77
81
|
repo_owner: repoInfo.owner,
|
|
78
82
|
repo_name: repoInfo.name,
|
|
83
|
+
suspicious: amendDetection.suspiciousActivity,
|
|
84
|
+
amend_count: amendDetection.recentAmendCount,
|
|
79
85
|
};
|
|
80
86
|
// Only send full hash if we have one (not in test mode)
|
|
81
87
|
if (options.fullHash && options.fullHash.length === 40) {
|
|
@@ -122,6 +128,11 @@ export async function playCommand(hash, options) {
|
|
|
122
128
|
const urlPadding = Math.floor((boxWidth - shareUrl.length) / 2);
|
|
123
129
|
console.log(' '.repeat(urlPadding) + chalk.green.underline(shareUrl));
|
|
124
130
|
}
|
|
131
|
+
// Show warning if suspicious activity detected
|
|
132
|
+
if (warningMessage && !options.small) {
|
|
133
|
+
console.log();
|
|
134
|
+
console.log(chalk.yellow(warningMessage));
|
|
135
|
+
}
|
|
125
136
|
}
|
|
126
137
|
catch (error) {
|
|
127
138
|
console.error(chalk.red(`Error: ${error.message}`));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"play.js","sourceRoot":"","sources":["../../src/commands/play.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AACnF,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AACtE,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAC9D,OAAO,KAAK,MAAM,OAAO,CAAC;AAO1B,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,IAAY,EAAE,OAAoB;IAClE,IAAI,CAAC;QACH,6BAA6B;QAC7B,MAAM,aAAa,GAAG,UAAU,EAAE,CAAC;QAEnC,iBAAiB;QACjB,MAAM,MAAM,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC;QAEnC,wBAAwB;QACxB,MAAM,MAAM,GAAG;YACb,SAAS,EAAE,IAAI,CAAC,WAAW,EAAE;YAC7B,KAAK,EAAE,OAAO,CAAC,KAAK,IAAI,KAAK;YAC7B,aAAa,EAAE,MAAM;SACtB,CAAC;QAEF,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;YAClB,MAAM,gBAAgB,CAAC,MAAM,CAAC,CAAC;QACjC,CAAC;aAAM,CAAC;YACN,MAAM,kBAAkB,CAAC,MAAM,CAAC,CAAC;QACnC,CAAC;QAED,cAAc;QACd,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;YACnB,OAAO,CAAC,GAAG,EAAE,CAAC;YAEd,wDAAwD;YACxD,MAAM,QAAQ,GAAG,EAAE,CAAC;YAEpB,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACtB,MAAM,UAAU,GAAG,GAAG,MAAM,CAAC,IAAI,GAAG,CAAC;gBACrC,MAAM,aAAa,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,QAAQ,GAAG,UAAU,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;gBACrE,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,aAAa,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;gBAErE,MAAM,UAAU,GAAG,IAAI,MAAM,CAAC,MAAM,SAAS,CAAC;gBAC9C,MAAM,aAAa,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,QAAQ,GAAG,UAAU,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;gBACrE,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,aAAa,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;YACxE,CAAC;iBAAM,CAAC;gBACN,MAAM,SAAS,GAAG,QAAQ,CAAC;gBAC3B,MAAM,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,QAAQ,GAAG,SAAS,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;gBACnE,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,YAAY,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC;gBAElE,MAAM,QAAQ,GAAG,YAAY,CAAC;gBAC9B,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;gBACjE,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;YACpE,CAAC;YAED,OAAO,CAAC,GAAG,EAAE,CAAC;YACd,MAAM,QAAQ,GAAG,MAAM,CAAC,WAAW,CAAC;YACpC,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;YACjE,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC;QAC7D,CAAC;QAED,sCAAsC;QACtC,MAAM,QAAQ,GAAG,WAAW,EAAE,CAAC;QAC/B,MAAM,cAAc,GAAG,iBAAiB,EAAE,CAAC;QAE3C,IAAI,CAAC,QAAQ,IAAI,cAAc,EAAE,CAAC;YAChC,OAAO,CAAC,GAAG,EAAE,CAAC;YACd,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,sCAAsC,CAAC,CAAC,CAAC;YACvE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,6CAA6C,CAAC,CAAC,CAAC;YACtE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,+BAA+B,CAAC,CAAC,CAAC;YACxD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,8DAA8D,CAAC,CAAC,CAAC;YACxF,OAAO,CAAC,GAAG,EAAE,CAAC;QAChB,CAAC;QAED,yBAAyB;QACzB,IAAI,UAAU,GAAG,aAAa,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;QAElE,2CAA2C;QAC3C,IAAI,QAA4B,CAAC;QAEjC,IAAI,QAAQ,IAAI,cAAc,EAAE,CAAC;YAC/B,MAAM,QAAQ,GAAQ;gBACpB,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE;gBAC/B,YAAY,EAAE,MAAM,CAAC,IAAI;gBACzB,YAAY,EAAE,MAAM,CAAC,IAAI;gBACzB,MAAM,EAAE,MAAM,CAAC,MAAM;gBACrB,KAAK,EAAE,EAAE;gBACT,cAAc,EAAE,aAAa;gBAC7B,aAAa,EAAE,UAAU;gBACzB,QAAQ,EAAE,QAAQ,CAAC,GAAG;gBACtB,eAAe,EAAE,cAAc;gBAC/B,UAAU,EAAE,QAAQ,CAAC,KAAK;gBAC1B,SAAS,EAAE,QAAQ,CAAC,IAAI;
|
|
1
|
+
{"version":3,"file":"play.js","sourceRoot":"","sources":["../../src/commands/play.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -13,7 +13,7 @@ const program = new Command();
|
|
|
13
13
|
program
|
|
14
14
|
.name('git-slot-machine')
|
|
15
15
|
.description('Git commit hash slot machine')
|
|
16
|
-
.version('
|
|
16
|
+
.version('2.2.0', '-v, --version', 'Output the current version');
|
|
17
17
|
program
|
|
18
18
|
.command('play')
|
|
19
19
|
.description('Play the slot machine with a git hash')
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
interface AmendDetectionResult {
|
|
2
|
+
isAmended: boolean;
|
|
3
|
+
recentAmendCount: number;
|
|
4
|
+
suspiciousActivity: boolean;
|
|
5
|
+
recentAmendHashes: string[];
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Detects if the current commit appears to be the result of hash grinding
|
|
9
|
+
* by checking git reflog for suspicious amend patterns
|
|
10
|
+
*/
|
|
11
|
+
export declare function detectAmendGrinding(timeWindowMinutes?: number, suspiciousThreshold?: number): AmendDetectionResult;
|
|
12
|
+
/**
|
|
13
|
+
* Get a warning message for suspicious amend activity
|
|
14
|
+
*/
|
|
15
|
+
export declare function getAmendWarningMessage(result: AmendDetectionResult): string | null;
|
|
16
|
+
export {};
|
|
17
|
+
//# sourceMappingURL=amendDetector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"amendDetector.d.ts","sourceRoot":"","sources":["../../src/utils/amendDetector.ts"],"names":[],"mappings":"AAEA,UAAU,oBAAoB;IAC5B,SAAS,EAAE,OAAO,CAAC;IACnB,gBAAgB,EAAE,MAAM,CAAC;IACzB,kBAAkB,EAAE,OAAO,CAAC;IAC5B,iBAAiB,EAAE,MAAM,EAAE,CAAC;CAC7B;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,iBAAiB,GAAE,MAAU,EAAE,mBAAmB,GAAE,MAAU,GAAG,oBAAoB,CA8CxH;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,oBAAoB,GAAG,MAAM,GAAG,IAAI,CASlF"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { execSync } from 'child_process';
|
|
2
|
+
/**
|
|
3
|
+
* Detects if the current commit appears to be the result of hash grinding
|
|
4
|
+
* by checking git reflog for suspicious amend patterns
|
|
5
|
+
*/
|
|
6
|
+
export function detectAmendGrinding(timeWindowMinutes = 5, suspiciousThreshold = 5) {
|
|
7
|
+
try {
|
|
8
|
+
// Get reflog entries from the last timeWindowMinutes
|
|
9
|
+
// Format: %gd = reflog selector, %gs = reflog subject, %H = commit hash, %ct = committer timestamp
|
|
10
|
+
const reflogOutput = execSync(`git reflog --since="${timeWindowMinutes} minutes ago" --format="%gs|%H|%ct"`, { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'ignore'] }).trim();
|
|
11
|
+
if (!reflogOutput) {
|
|
12
|
+
return {
|
|
13
|
+
isAmended: false,
|
|
14
|
+
recentAmendCount: 0,
|
|
15
|
+
suspiciousActivity: false,
|
|
16
|
+
recentAmendHashes: [],
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
const entries = reflogOutput.split('\n');
|
|
20
|
+
const amendEntries = entries.filter(entry => entry.includes('commit (amend)'));
|
|
21
|
+
const amendHashes = amendEntries.map(entry => {
|
|
22
|
+
const parts = entry.split('|');
|
|
23
|
+
return parts[1]?.substring(0, 7) || '';
|
|
24
|
+
}).filter(hash => hash.length === 7);
|
|
25
|
+
const recentAmendCount = amendEntries.length;
|
|
26
|
+
const suspiciousActivity = recentAmendCount >= suspiciousThreshold;
|
|
27
|
+
// Check if the most recent action was an amend
|
|
28
|
+
const isAmended = entries.length > 0 && entries[0].includes('commit (amend)');
|
|
29
|
+
return {
|
|
30
|
+
isAmended,
|
|
31
|
+
recentAmendCount,
|
|
32
|
+
suspiciousActivity,
|
|
33
|
+
recentAmendHashes: amendHashes,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
// If git reflog fails, assume no amending
|
|
38
|
+
return {
|
|
39
|
+
isAmended: false,
|
|
40
|
+
recentAmendCount: 0,
|
|
41
|
+
suspiciousActivity: false,
|
|
42
|
+
recentAmendHashes: [],
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Get a warning message for suspicious amend activity
|
|
48
|
+
*/
|
|
49
|
+
export function getAmendWarningMessage(result) {
|
|
50
|
+
if (!result.suspiciousActivity) {
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
return `⚠️ Suspicious Activity Detected\n` +
|
|
54
|
+
` ${result.recentAmendCount} commit amends in the last 5 minutes\n` +
|
|
55
|
+
` This pattern suggests hash grinding/gaming\n` +
|
|
56
|
+
` Your commit will be flagged for review`;
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=amendDetector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"amendDetector.js","sourceRoot":"","sources":["../../src/utils/amendDetector.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AASzC;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CAAC,oBAA4B,CAAC,EAAE,sBAA8B,CAAC;IAChG,IAAI,CAAC;QACH,qDAAqD;QACrD,mGAAmG;QACnG,MAAM,YAAY,GAAG,QAAQ,CAC3B,uBAAuB,iBAAiB,qCAAqC,EAC7E,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,CACzD,CAAC,IAAI,EAAE,CAAC;QAET,IAAI,CAAC,YAAY,EAAE,CAAC;YAClB,OAAO;gBACL,SAAS,EAAE,KAAK;gBAChB,gBAAgB,EAAE,CAAC;gBACnB,kBAAkB,EAAE,KAAK;gBACzB,iBAAiB,EAAE,EAAE;aACtB,CAAC;QACJ,CAAC;QAED,MAAM,OAAO,GAAG,YAAY,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACzC,MAAM,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAC,CAAC;QAC/E,MAAM,WAAW,GAAG,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE;YAC3C,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YAC/B,OAAO,KAAK,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;QACzC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC;QAErC,MAAM,gBAAgB,GAAG,YAAY,CAAC,MAAM,CAAC;QAC7C,MAAM,kBAAkB,GAAG,gBAAgB,IAAI,mBAAmB,CAAC;QAEnE,+CAA+C;QAC/C,MAAM,SAAS,GAAG,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAC;QAE9E,OAAO;YACL,SAAS;YACT,gBAAgB;YAChB,kBAAkB;YAClB,iBAAiB,EAAE,WAAW;SAC/B,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,0CAA0C;QAC1C,OAAO;YACL,SAAS,EAAE,KAAK;YAChB,gBAAgB,EAAE,CAAC;YACnB,kBAAkB,EAAE,KAAK;YACzB,iBAAiB,EAAE,EAAE;SACtB,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,sBAAsB,CAAC,MAA4B;IACjE,IAAI,CAAC,MAAM,CAAC,kBAAkB,EAAE,CAAC;QAC/B,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,oCAAoC;QACzC,MAAM,MAAM,CAAC,gBAAgB,wCAAwC;QACrE,iDAAiD;QACjD,2CAA2C,CAAC;AAChD,CAAC"}
|
package/package.json
CHANGED
package/src/commands/play.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { animateSlotMachine, animateSmallMode } from '../animation/slotMachine.j
|
|
|
3
3
|
import { getBalance, updateBalance, setBalance } from '../balance.js';
|
|
4
4
|
import { sendPlayToAPI } from '../api.js';
|
|
5
5
|
import { getRepoInfo, getGitHubUsername } from '../config.js';
|
|
6
|
+
import { detectAmendGrinding, getAmendWarningMessage } from '../utils/amendDetector.js';
|
|
6
7
|
import chalk from 'chalk';
|
|
7
8
|
|
|
8
9
|
interface PlayOptions {
|
|
@@ -78,6 +79,10 @@ export async function playCommand(hash: string, options: PlayOptions): Promise<v
|
|
|
78
79
|
// Update balance locally
|
|
79
80
|
let newBalance = updateBalance(hash.toLowerCase(), result.payout);
|
|
80
81
|
|
|
82
|
+
// Detect potential hash grinding
|
|
83
|
+
const amendDetection = detectAmendGrinding();
|
|
84
|
+
const warningMessage = getAmendWarningMessage(amendDetection);
|
|
85
|
+
|
|
81
86
|
// Send to API and sync balance with server
|
|
82
87
|
let shareUrl: string | undefined;
|
|
83
88
|
|
|
@@ -94,6 +99,8 @@ export async function playCommand(hash: string, options: PlayOptions): Promise<v
|
|
|
94
99
|
github_username: githubUsername,
|
|
95
100
|
repo_owner: repoInfo.owner,
|
|
96
101
|
repo_name: repoInfo.name,
|
|
102
|
+
suspicious: amendDetection.suspiciousActivity,
|
|
103
|
+
amend_count: amendDetection.recentAmendCount,
|
|
97
104
|
};
|
|
98
105
|
|
|
99
106
|
// Only send full hash if we have one (not in test mode)
|
|
@@ -143,6 +150,12 @@ export async function playCommand(hash: string, options: PlayOptions): Promise<v
|
|
|
143
150
|
console.log(' '.repeat(urlPadding) + chalk.green.underline(shareUrl));
|
|
144
151
|
}
|
|
145
152
|
|
|
153
|
+
// Show warning if suspicious activity detected
|
|
154
|
+
if (warningMessage && !options.small) {
|
|
155
|
+
console.log();
|
|
156
|
+
console.log(chalk.yellow(warningMessage));
|
|
157
|
+
}
|
|
158
|
+
|
|
146
159
|
} catch (error) {
|
|
147
160
|
console.error(chalk.red(`Error: ${(error as Error).message}`));
|
|
148
161
|
process.exit(1);
|
package/src/index.ts
CHANGED
|
@@ -16,7 +16,7 @@ const program = new Command();
|
|
|
16
16
|
program
|
|
17
17
|
.name('git-slot-machine')
|
|
18
18
|
.description('Git commit hash slot machine')
|
|
19
|
-
.version('
|
|
19
|
+
.version('2.2.0', '-v, --version', 'Output the current version');
|
|
20
20
|
|
|
21
21
|
program
|
|
22
22
|
.command('play')
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { execSync } from 'child_process';
|
|
2
|
+
|
|
3
|
+
interface AmendDetectionResult {
|
|
4
|
+
isAmended: boolean;
|
|
5
|
+
recentAmendCount: number;
|
|
6
|
+
suspiciousActivity: boolean;
|
|
7
|
+
recentAmendHashes: string[];
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Detects if the current commit appears to be the result of hash grinding
|
|
12
|
+
* by checking git reflog for suspicious amend patterns
|
|
13
|
+
*/
|
|
14
|
+
export function detectAmendGrinding(timeWindowMinutes: number = 5, suspiciousThreshold: number = 5): AmendDetectionResult {
|
|
15
|
+
try {
|
|
16
|
+
// Get reflog entries from the last timeWindowMinutes
|
|
17
|
+
// Format: %gd = reflog selector, %gs = reflog subject, %H = commit hash, %ct = committer timestamp
|
|
18
|
+
const reflogOutput = execSync(
|
|
19
|
+
`git reflog --since="${timeWindowMinutes} minutes ago" --format="%gs|%H|%ct"`,
|
|
20
|
+
{ encoding: 'utf-8', stdio: ['pipe', 'pipe', 'ignore'] }
|
|
21
|
+
).trim();
|
|
22
|
+
|
|
23
|
+
if (!reflogOutput) {
|
|
24
|
+
return {
|
|
25
|
+
isAmended: false,
|
|
26
|
+
recentAmendCount: 0,
|
|
27
|
+
suspiciousActivity: false,
|
|
28
|
+
recentAmendHashes: [],
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const entries = reflogOutput.split('\n');
|
|
33
|
+
const amendEntries = entries.filter(entry => entry.includes('commit (amend)'));
|
|
34
|
+
const amendHashes = amendEntries.map(entry => {
|
|
35
|
+
const parts = entry.split('|');
|
|
36
|
+
return parts[1]?.substring(0, 7) || '';
|
|
37
|
+
}).filter(hash => hash.length === 7);
|
|
38
|
+
|
|
39
|
+
const recentAmendCount = amendEntries.length;
|
|
40
|
+
const suspiciousActivity = recentAmendCount >= suspiciousThreshold;
|
|
41
|
+
|
|
42
|
+
// Check if the most recent action was an amend
|
|
43
|
+
const isAmended = entries.length > 0 && entries[0].includes('commit (amend)');
|
|
44
|
+
|
|
45
|
+
return {
|
|
46
|
+
isAmended,
|
|
47
|
+
recentAmendCount,
|
|
48
|
+
suspiciousActivity,
|
|
49
|
+
recentAmendHashes: amendHashes,
|
|
50
|
+
};
|
|
51
|
+
} catch (error) {
|
|
52
|
+
// If git reflog fails, assume no amending
|
|
53
|
+
return {
|
|
54
|
+
isAmended: false,
|
|
55
|
+
recentAmendCount: 0,
|
|
56
|
+
suspiciousActivity: false,
|
|
57
|
+
recentAmendHashes: [],
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Get a warning message for suspicious amend activity
|
|
64
|
+
*/
|
|
65
|
+
export function getAmendWarningMessage(result: AmendDetectionResult): string | null {
|
|
66
|
+
if (!result.suspiciousActivity) {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return `⚠️ Suspicious Activity Detected\n` +
|
|
71
|
+
` ${result.recentAmendCount} commit amends in the last 5 minutes\n` +
|
|
72
|
+
` This pattern suggests hash grinding/gaming\n` +
|
|
73
|
+
` Your commit will be flagged for review`;
|
|
74
|
+
}
|