Skip to content

Commit 3ad5466

Browse files
vakovalskiiclaude
andcommitted
feat: sync integrity check + anti-cheat caps on leaderboard
Client: sends version + SHA-256 integrity fingerprint with sync Server: caps totals (200k msgs, 50k hours), week (20k msgs), logs version/integrity Prevents inflated stats from modified clients or sub-agent counting Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 7ffc782 commit 3ad5466

File tree

2 files changed

+12
-1
lines changed

2 files changed

+12
-1
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "codedash-app",
3-
"version": "6.15.9",
3+
"version": "6.15.10",
44
"description": "Dashboard + CLI for Claude Code, Codex & OpenCode sessions. View, search, resume, convert, handoff between agents.",
55
"bin": {
66
"codedash": "./bin/cli.js"

src/server.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -880,12 +880,23 @@ async function syncLeaderboard() {
880880

881881
const stats = getLeaderboardStats();
882882
const anon = stats.anon || {};
883+
// Build integrity fingerprint: SHA-256(version + data.js header)
884+
const pkg = require('../package.json');
885+
let integrity = '';
886+
try {
887+
const dataJsPath = require('path').join(__dirname, 'data.js');
888+
const header = require('fs').readFileSync(dataJsPath, 'utf8').slice(0, 200);
889+
integrity = require('crypto').createHash('sha256').update(pkg.version + header).digest('hex').slice(0, 16);
890+
} catch {}
891+
883892
const payload = {
884893
username: profile.username,
885894
avatar: profile.avatar,
886895
name: profile.name,
887896
deviceId: anon.id || require('crypto').randomUUID(),
888897
token: profile.token, // for server-side GitHub verification
898+
version: pkg.version,
899+
integrity: integrity,
889900
stats: {
890901
today: { ...stats.today, hours: Math.min(stats.today.hours || 0, 24) },
891902
week: stats.daily ? stats.daily.slice(0, 7).reduce((acc, d) => ({ messages: acc.messages + d.messages, hours: acc.hours + d.hours, cost: acc.cost + d.cost }), { messages: 0, hours: 0, cost: 0 }) : { messages: 0, hours: 0, cost: 0 },

0 commit comments

Comments
 (0)