antigravity-claude-proxy 2.7.1 → 2.7.3
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/README.md +0 -1
- package/package.json +1 -1
- package/public/css/style.css +1 -1
- package/public/index.html +0 -2
- package/public/js/components/account-manager.js +9 -121
- package/public/js/components/server-config.js +32 -0
- package/public/js/config/constants.js +4 -0
- package/public/views/accounts.html +0 -149
- package/public/views/settings.html +58 -0
- package/src/account-manager/credentials.js +2 -2
- package/src/account-manager/index.js +25 -87
- package/src/account-manager/onboarding.js +2 -2
- package/src/account-manager/rate-limits.js +27 -1
- package/src/account-manager/storage.js +9 -16
- package/src/auth/oauth.js +5 -4
- package/src/cli/accounts.js +2 -4
- package/src/cloudcode/message-handler.js +37 -4
- package/src/cloudcode/model-api.js +3 -2
- package/src/cloudcode/rate-limit-state.js +41 -0
- package/src/cloudcode/request-builder.js +2 -7
- package/src/cloudcode/streaming-handler.js +41 -8
- package/src/config.js +2 -0
- package/src/constants.js +1 -4
- package/src/errors.js +33 -0
- package/src/server.js +0 -2
- package/src/utils/helpers.js +18 -0
- package/src/webui/index.js +16 -73
- package/src/utils/fingerprint.js +0 -133
package/src/webui/index.js
CHANGED
|
@@ -292,6 +292,15 @@ export function mountWebUI(app, dirname, accountManager) {
|
|
|
292
292
|
const { email } = req.params;
|
|
293
293
|
accountManager.clearTokenCache(email);
|
|
294
294
|
accountManager.clearProjectCache(email);
|
|
295
|
+
|
|
296
|
+
// For verification errors (403 VALIDATION_REQUIRED), clear isInvalid on refresh.
|
|
297
|
+
// The user has completed verification on Google's site and clicks Refresh to re-enable.
|
|
298
|
+
// Auth errors (no verifyUrl) still require OAuth re-auth via FIX button.
|
|
299
|
+
const account = accountManager.getAllAccounts().find(a => a.email === email);
|
|
300
|
+
if (account && account.isInvalid && account.verifyUrl) {
|
|
301
|
+
accountManager.clearInvalid(email);
|
|
302
|
+
}
|
|
303
|
+
|
|
295
304
|
res.json({
|
|
296
305
|
status: 'ok',
|
|
297
306
|
message: `Token cache cleared for ${email}`
|
|
@@ -347,78 +356,6 @@ export function mountWebUI(app, dirname, accountManager) {
|
|
|
347
356
|
}
|
|
348
357
|
});
|
|
349
358
|
|
|
350
|
-
/**
|
|
351
|
-
* POST /api/accounts/:email/fingerprint/regenerate - Regenerate fingerprint
|
|
352
|
-
*/
|
|
353
|
-
app.post('/api/accounts/:email/fingerprint/regenerate', async (req, res) => {
|
|
354
|
-
try {
|
|
355
|
-
const { email } = req.params;
|
|
356
|
-
const fingerprint = accountManager.regenerateFingerprint(email);
|
|
357
|
-
|
|
358
|
-
if (!fingerprint) {
|
|
359
|
-
return res.status(404).json({ status: 'error', error: 'Account not found' });
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
res.json({
|
|
363
|
-
status: 'ok',
|
|
364
|
-
message: 'Fingerprint regenerated',
|
|
365
|
-
fingerprint
|
|
366
|
-
});
|
|
367
|
-
} catch (error) {
|
|
368
|
-
res.status(500).json({ status: 'error', error: error.message });
|
|
369
|
-
}
|
|
370
|
-
});
|
|
371
|
-
|
|
372
|
-
/**
|
|
373
|
-
* GET /api/accounts/:email/fingerprint - Get fingerprint details and history
|
|
374
|
-
*/
|
|
375
|
-
app.get('/api/accounts/:email/fingerprint', async (req, res) => {
|
|
376
|
-
try {
|
|
377
|
-
const { email } = req.params;
|
|
378
|
-
const account = accountManager.getAllAccounts().find(a => a.email === email);
|
|
379
|
-
|
|
380
|
-
if (!account) {
|
|
381
|
-
return res.status(404).json({ status: 'error', error: 'Account not found' });
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
res.json({
|
|
385
|
-
status: 'ok',
|
|
386
|
-
fingerprint: account.fingerprint,
|
|
387
|
-
history: account.fingerprintHistory || []
|
|
388
|
-
});
|
|
389
|
-
} catch (error) {
|
|
390
|
-
res.status(500).json({ status: 'error', error: error.message });
|
|
391
|
-
}
|
|
392
|
-
});
|
|
393
|
-
|
|
394
|
-
/**
|
|
395
|
-
* POST /api/accounts/:email/fingerprint/restore - Restore fingerprint from history
|
|
396
|
-
*/
|
|
397
|
-
app.post('/api/accounts/:email/fingerprint/restore', async (req, res) => {
|
|
398
|
-
try {
|
|
399
|
-
const { email } = req.params;
|
|
400
|
-
const { index } = req.body;
|
|
401
|
-
|
|
402
|
-
if (typeof index !== 'number') {
|
|
403
|
-
return res.status(400).json({ status: 'error', error: 'History index required' });
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
const fingerprint = accountManager.restoreFingerprint(email, index);
|
|
407
|
-
|
|
408
|
-
if (!fingerprint) {
|
|
409
|
-
return res.status(404).json({ status: 'error', error: 'Account or history entry not found' });
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
res.json({
|
|
413
|
-
status: 'ok',
|
|
414
|
-
message: 'Fingerprint restored',
|
|
415
|
-
fingerprint
|
|
416
|
-
});
|
|
417
|
-
} catch (error) {
|
|
418
|
-
res.status(500).json({ status: 'error', error: error.message });
|
|
419
|
-
}
|
|
420
|
-
});
|
|
421
|
-
|
|
422
359
|
/**
|
|
423
360
|
* PATCH /api/accounts/:email - Update account settings (thresholds)
|
|
424
361
|
*/
|
|
@@ -644,7 +581,7 @@ export function mountWebUI(app, dirname, accountManager) {
|
|
|
644
581
|
*/
|
|
645
582
|
app.post('/api/config', async (req, res) => {
|
|
646
583
|
try {
|
|
647
|
-
const { debug, devMode, logLevel, persistTokenCache } = req.body;
|
|
584
|
+
const { debug, devMode, logLevel, persistTokenCache, requestThrottlingEnabled, requestDelayMs } = req.body;
|
|
648
585
|
|
|
649
586
|
// Validate tunable config fields via shared helper
|
|
650
587
|
const updates = validateConfigFields(req.body);
|
|
@@ -665,6 +602,12 @@ export function mountWebUI(app, dirname, accountManager) {
|
|
|
665
602
|
if (typeof persistTokenCache === 'boolean') {
|
|
666
603
|
updates.persistTokenCache = persistTokenCache;
|
|
667
604
|
}
|
|
605
|
+
if (typeof requestThrottlingEnabled === 'boolean') {
|
|
606
|
+
updates.requestThrottlingEnabled = requestThrottlingEnabled;
|
|
607
|
+
}
|
|
608
|
+
if (typeof requestDelayMs === 'number' && requestDelayMs >= 100 && requestDelayMs <= 5000) {
|
|
609
|
+
updates.requestDelayMs = requestDelayMs;
|
|
610
|
+
}
|
|
668
611
|
|
|
669
612
|
if (Object.keys(updates).length === 0) {
|
|
670
613
|
return res.status(400).json({
|
package/src/utils/fingerprint.js
DELETED
|
@@ -1,133 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Device Fingerprint Generator for Rate Limit Mitigation
|
|
3
|
-
*
|
|
4
|
-
* Generates randomized device fingerprints to help distribute API usage
|
|
5
|
-
* across different apparent device identities.
|
|
6
|
-
*
|
|
7
|
-
* Based on: https://github.com/NoeFabris/opencode-antigravity-auth
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import crypto from 'crypto';
|
|
11
|
-
import { IDE_TYPE, PLATFORM, PLUGIN_TYPE, ANTIGRAVITY_VERSION } from '../constants.js';
|
|
12
|
-
|
|
13
|
-
const OS_VERSIONS = {
|
|
14
|
-
darwin: ['10.15.7', '11.6.8', '12.6.3', '13.5.2', '14.2.1', '14.5'],
|
|
15
|
-
win32: ['10.0.19041', '10.0.19042', '10.0.19043', '10.0.22000', '10.0.22621', '10.0.22631'],
|
|
16
|
-
linux: ['5.15.0', '5.19.0', '6.1.0', '6.2.0', '6.5.0', '6.6.0']
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
const ARCHITECTURES = ['x64', 'arm64'];
|
|
20
|
-
|
|
21
|
-
const IDE_TYPES = [
|
|
22
|
-
'IDE_UNSPECIFIED',
|
|
23
|
-
'VSCODE',
|
|
24
|
-
'INTELLIJ',
|
|
25
|
-
'ANDROID_STUDIO',
|
|
26
|
-
'CLOUD_SHELL_EDITOR'
|
|
27
|
-
];
|
|
28
|
-
|
|
29
|
-
const SDK_CLIENTS = [
|
|
30
|
-
'google-cloud-sdk vscode_cloudshelleditor/0.1',
|
|
31
|
-
'google-cloud-sdk vscode/1.86.0',
|
|
32
|
-
'google-cloud-sdk vscode/1.87.0',
|
|
33
|
-
'google-cloud-sdk intellij/2024.1',
|
|
34
|
-
'google-cloud-sdk android-studio/2024.1',
|
|
35
|
-
'gcloud-python/1.2.0 grpc-google-iam-v1/0.12.6'
|
|
36
|
-
];
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Maximum number of fingerprint versions to keep in history
|
|
40
|
-
*/
|
|
41
|
-
export const MAX_FINGERPRINT_HISTORY = 5;
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Pick a random item from an array
|
|
45
|
-
* @template T
|
|
46
|
-
* @param {T[]} arr
|
|
47
|
-
* @returns {T}
|
|
48
|
-
*/
|
|
49
|
-
function randomFrom(arr) {
|
|
50
|
-
return arr[Math.floor(Math.random() * arr.length)];
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
function generateDeviceId() {
|
|
54
|
-
return crypto.randomUUID();
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
function generateSessionToken() {
|
|
58
|
-
return crypto.randomBytes(16).toString('hex');
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Generate a randomized device fingerprint.
|
|
63
|
-
* Each fingerprint represents a unique "device" identity.
|
|
64
|
-
* @returns {Object} Fingerprint object
|
|
65
|
-
*/
|
|
66
|
-
export function generateFingerprint() {
|
|
67
|
-
const platform = randomFrom(['darwin', 'win32', 'linux']);
|
|
68
|
-
const arch = randomFrom(ARCHITECTURES);
|
|
69
|
-
const osVersion = randomFrom(OS_VERSIONS[platform] || OS_VERSIONS.linux);
|
|
70
|
-
|
|
71
|
-
let matchingPlatform;
|
|
72
|
-
if (platform === 'darwin') matchingPlatform = PLATFORM.MACOS;
|
|
73
|
-
else if (platform === 'win32') matchingPlatform = PLATFORM.WINDOWS;
|
|
74
|
-
else if (platform === 'linux') matchingPlatform = PLATFORM.LINUX;
|
|
75
|
-
else matchingPlatform = PLATFORM.UNSPECIFIED;
|
|
76
|
-
|
|
77
|
-
return {
|
|
78
|
-
deviceId: generateDeviceId(),
|
|
79
|
-
sessionToken: generateSessionToken(),
|
|
80
|
-
userAgent: `antigravity/${ANTIGRAVITY_VERSION} ${platform}/${arch}`,
|
|
81
|
-
apiClient: randomFrom(SDK_CLIENTS),
|
|
82
|
-
clientMetadata: {
|
|
83
|
-
ideType: randomFrom(IDE_TYPES),
|
|
84
|
-
platform: matchingPlatform,
|
|
85
|
-
pluginType: PLUGIN_TYPE.GEMINI,
|
|
86
|
-
osVersion: osVersion,
|
|
87
|
-
arch: arch,
|
|
88
|
-
sqmId: `{${crypto.randomUUID().toUpperCase()}}`
|
|
89
|
-
},
|
|
90
|
-
quotaUser: `device-${crypto.randomBytes(8).toString('hex')}`,
|
|
91
|
-
createdAt: Date.now()
|
|
92
|
-
};
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* Build HTTP headers from a fingerprint object.
|
|
97
|
-
* These headers are used to identify the "device" making API requests.
|
|
98
|
-
* @param {Object} fingerprint - The fingerprint object
|
|
99
|
-
* @returns {Object} Headers object
|
|
100
|
-
*/
|
|
101
|
-
export function buildFingerprintHeaders(fingerprint) {
|
|
102
|
-
if (!fingerprint) {
|
|
103
|
-
return {};
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
return {
|
|
107
|
-
'User-Agent': fingerprint.userAgent,
|
|
108
|
-
'X-Goog-Api-Client': fingerprint.apiClient,
|
|
109
|
-
'Client-Metadata': JSON.stringify(fingerprint.clientMetadata),
|
|
110
|
-
'X-Goog-QuotaUser': fingerprint.quotaUser,
|
|
111
|
-
'X-Client-Device-Id': fingerprint.deviceId
|
|
112
|
-
};
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
/**
|
|
116
|
-
* Update fingerprint userAgent to current version if outdated.
|
|
117
|
-
* Extracts platform/arch from existing userAgent and rebuilds with current version.
|
|
118
|
-
* @param {Object} fingerprint
|
|
119
|
-
* @returns {Object} Updated fingerprint
|
|
120
|
-
*/
|
|
121
|
-
export function updateFingerprintVersion(fingerprint) {
|
|
122
|
-
if (!fingerprint || !fingerprint.userAgent) return fingerprint;
|
|
123
|
-
|
|
124
|
-
const match = fingerprint.userAgent.match(/^antigravity\/\S+ (.+)$/);
|
|
125
|
-
if (match) {
|
|
126
|
-
const platformArch = match[1];
|
|
127
|
-
const expectedUserAgent = `antigravity/${ANTIGRAVITY_VERSION} ${platformArch}`;
|
|
128
|
-
if (fingerprint.userAgent !== expectedUserAgent) {
|
|
129
|
-
return { ...fingerprint, userAgent: expectedUserAgent };
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
return fingerprint;
|
|
133
|
-
}
|