git-slot-machine 2.1.5 → 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.
@@ -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,36 @@ 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
+
33
+ ## [2.1.6] - 2025-10-17
34
+
35
+ ### Added
36
+ - Web app: Update notification banner
37
+
8
38
  ## [2.1.5] - 2025-10-17
9
39
 
10
40
  ### Fixed
@@ -1 +1 @@
1
- {"version":3,"file":"play.d.ts","sourceRoot":"","sources":["../../src/commands/play.ts"],"names":[],"mappings":"AAOA,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,CAyInF"}
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"}
@@ -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":"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"}
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('1.3.1', '-v, --version', 'Output the current 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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "git-slot-machine",
3
- "version": "2.1.5",
3
+ "version": "2.2.0",
4
4
  "description": "Turn your git commits into a slot machine game! CLI tool with global leaderboards and win streaks.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -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('1.3.1', '-v, --version', 'Output the current 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
+ }