EnhancedSettingsForm.cs 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513
  1. using static qdr.app.tools.claudecodebalancewidget.MainForm;
  2. namespace qdr.app.tools.claudecodebalancewidget
  3. {
  4. public partial class EnhancedSettingsForm : Form
  5. {
  6. private TabControl tabControl;
  7. private TabPage sessionTabPage;
  8. private TabPage apiTabPage;
  9. private TabPage helpTabPage;
  10. // Session Cookie Tab Controls
  11. private TextBox sessionTokenTextBox;
  12. private Button sessionShowHideButton;
  13. private Button sessionTestButton;
  14. private Label sessionStatusLabel;
  15. private Label sessionInstructionsLabel;
  16. private bool isSessionTokenVisible = false;
  17. // API Key Tab Controls
  18. private TextBox apiKeyTextBox;
  19. private Button apiShowHideButton;
  20. private Button apiTestButton;
  21. private Label apiStatusLabel;
  22. private Label apiInstructionsLabel;
  23. private bool isApiKeyVisible = false;
  24. // Common Controls
  25. private RadioButton sessionRadioButton;
  26. private RadioButton apiRadioButton;
  27. private Button okButton;
  28. private Button cancelButton;
  29. public string SessionToken { get; private set; }
  30. public string ApiKey { get; private set; }
  31. public AuthenticationMethod AuthMethod { get; private set; }
  32. public EnhancedSettingsForm(string currentSessionToken, string currentApiKey, AuthenticationMethod currentAuthMethod)
  33. {
  34. SessionToken = currentSessionToken;
  35. ApiKey = currentApiKey;
  36. AuthMethod = currentAuthMethod;
  37. InitializeComponent();
  38. sessionTokenTextBox.Text = currentSessionToken;
  39. apiKeyTextBox.Text = currentApiKey;
  40. if (currentAuthMethod == AuthenticationMethod.ApiKey)
  41. {
  42. apiRadioButton.Checked = true;
  43. tabControl.SelectedTab = apiTabPage;
  44. }
  45. else
  46. {
  47. sessionRadioButton.Checked = true;
  48. tabControl.SelectedTab = sessionTabPage;
  49. }
  50. }
  51. //private void InitializeComponent()
  52. //{
  53. // this.SuspendLayout();
  54. // // Form
  55. // this.ClientSize = new Size(600, 500);
  56. // this.Text = "Settings - Claude Balance Monitor";
  57. // this.StartPosition = FormStartPosition.CenterParent;
  58. // this.FormBorderStyle = FormBorderStyle.FixedDialog;
  59. // this.MaximizeBox = false;
  60. // this.MinimizeBox = false;
  61. // // Authentication Method Selection
  62. // var authMethodLabel = new Label();
  63. // authMethodLabel.Text = "Authentication Method:";
  64. // authMethodLabel.Location = new Point(10, 10);
  65. // authMethodLabel.Size = new Size(150, 20);
  66. // authMethodLabel.Font = new Font("Segoe UI", 9, FontStyle.Bold);
  67. // this.Controls.Add(authMethodLabel);
  68. // sessionRadioButton = new RadioButton();
  69. // sessionRadioButton.Text = "Session Cookie (Legacy)";
  70. // sessionRadioButton.Location = new Point(10, 35);
  71. // sessionRadioButton.Size = new Size(200, 20);
  72. // sessionRadioButton.Checked = true;
  73. // sessionRadioButton.CheckedChanged += AuthMethod_CheckedChanged;
  74. // this.Controls.Add(sessionRadioButton);
  75. // apiRadioButton = new RadioButton();
  76. // apiRadioButton.Text = "API Key (Recommended)";
  77. // apiRadioButton.Location = new Point(220, 35);
  78. // apiRadioButton.Size = new Size(200, 20);
  79. // apiRadioButton.CheckedChanged += AuthMethod_CheckedChanged;
  80. // this.Controls.Add(apiRadioButton);
  81. // // Tab Control
  82. // tabControl = new TabControl();
  83. // tabControl.Location = new Point(10, 65);
  84. // tabControl.Size = new Size(570, 350);
  85. // this.Controls.Add(tabControl);
  86. // // Session Cookie Tab
  87. // sessionTabPage = new TabPage("Session Cookie");
  88. // CreateSessionTab();
  89. // tabControl.TabPages.Add(sessionTabPage);
  90. // // API Key Tab
  91. // apiTabPage = new TabPage("API Key");
  92. // CreateApiTab();
  93. // tabControl.TabPages.Add(apiTabPage);
  94. // // Help Tab
  95. // helpTabPage = new TabPage("Help");
  96. // CreateHelpTab();
  97. // tabControl.TabPages.Add(helpTabPage);
  98. // // OK Button
  99. // okButton = new Button();
  100. // okButton.Text = "OK";
  101. // okButton.Location = new Point(405, 430);
  102. // okButton.Size = new Size(90, 30);
  103. // okButton.Click += OkButton_Click;
  104. // this.Controls.Add(okButton);
  105. // // Cancel Button
  106. // cancelButton = new Button();
  107. // cancelButton.Text = "Cancel";
  108. // cancelButton.Location = new Point(505, 430);
  109. // cancelButton.Size = new Size(90, 30);
  110. // cancelButton.Click += CancelButton_Click;
  111. // this.Controls.Add(cancelButton);
  112. // this.ResumeLayout(false);
  113. //}
  114. private void CreateSessionTab()
  115. {
  116. // Instructions
  117. sessionInstructionsLabel = new Label();
  118. sessionInstructionsLabel.Text =
  119. "⚠️ WARNING: Session cookie method may no longer work due to enhanced security.\n\n" +
  120. "To get your session token (if still working):\n" +
  121. "1. Go to https://console.anthropic.com/settings/billing\n" +
  122. "2. Open Developer Tools (F12)\n" +
  123. "3. Go to Application → Cookies\n" +
  124. "4. Find and copy the 'sessionKey' cookie value\n\n" +
  125. "Note: This method is deprecated. Use API Key instead.";
  126. sessionInstructionsLabel.Location = new Point(10, 10);
  127. sessionInstructionsLabel.Size = new Size(540, 120);
  128. sessionInstructionsLabel.Font = new Font("Segoe UI", 9);
  129. sessionInstructionsLabel.ForeColor = Color.DarkOrange;
  130. sessionTabPage.Controls.Add(sessionInstructionsLabel);
  131. // Session Token Label
  132. var sessionTokenLabel = new Label();
  133. sessionTokenLabel.Text = "Session Token:";
  134. sessionTokenLabel.Location = new Point(10, 140);
  135. sessionTokenLabel.Size = new Size(100, 20);
  136. sessionTokenLabel.Font = new Font("Segoe UI", 9, FontStyle.Bold);
  137. sessionTabPage.Controls.Add(sessionTokenLabel);
  138. // Session Token TextBox
  139. sessionTokenTextBox = new TextBox();
  140. sessionTokenTextBox.Location = new Point(10, 165);
  141. sessionTokenTextBox.Size = new Size(420, 23);
  142. sessionTokenTextBox.UseSystemPasswordChar = true;
  143. sessionTokenTextBox.Font = new Font("Consolas", 9);
  144. sessionTabPage.Controls.Add(sessionTokenTextBox);
  145. // Session Show/Hide Button
  146. sessionShowHideButton = new Button();
  147. sessionShowHideButton.Text = "Show";
  148. sessionShowHideButton.Location = new Point(440, 165);
  149. sessionShowHideButton.Size = new Size(60, 23);
  150. sessionShowHideButton.Click += SessionShowHideButton_Click;
  151. sessionTabPage.Controls.Add(sessionShowHideButton);
  152. // Session Test Button
  153. sessionTestButton = new Button();
  154. sessionTestButton.Text = "Test Connection";
  155. sessionTestButton.Location = new Point(10, 200);
  156. sessionTestButton.Size = new Size(120, 30);
  157. sessionTestButton.Click += SessionTestButton_Click;
  158. sessionTabPage.Controls.Add(sessionTestButton);
  159. // Session Status Label
  160. sessionStatusLabel = new Label();
  161. sessionStatusLabel.Name = "sessionStatusLabel";
  162. sessionStatusLabel.Text = "Enter your session token and click 'Test Connection'";
  163. sessionStatusLabel.Location = new Point(140, 205);
  164. sessionStatusLabel.Size = new Size(360, 20);
  165. sessionStatusLabel.ForeColor = Color.Gray;
  166. sessionTabPage.Controls.Add(sessionStatusLabel);
  167. }
  168. private void CreateApiTab()
  169. {
  170. // Instructions
  171. apiInstructionsLabel = new Label();
  172. apiInstructionsLabel.Text =
  173. "✅ RECOMMENDED: Use API Key for reliable access.\n\n" +
  174. "To get your API key:\n" +
  175. "1. Go to https://console.anthropic.com/\n" +
  176. "2. Sign up or log in to your account\n" +
  177. "3. Go to Settings → API Keys\n" +
  178. "4. Click 'Create Key' and copy the generated key\n" +
  179. "5. Make sure you have billing set up and credits available\n\n" +
  180. "Note: API keys provide more reliable access than session cookies.";
  181. apiInstructionsLabel.Location = new Point(10, 10);
  182. apiInstructionsLabel.Size = new Size(540, 120);
  183. apiInstructionsLabel.Font = new Font("Segoe UI", 9);
  184. apiInstructionsLabel.ForeColor = Color.DarkGreen;
  185. apiTabPage.Controls.Add(apiInstructionsLabel);
  186. // API Key Label
  187. var apiKeyLabel = new Label();
  188. apiKeyLabel.Text = "API Key:";
  189. apiKeyLabel.Location = new Point(10, 140);
  190. apiKeyLabel.Size = new Size(100, 20);
  191. apiKeyLabel.Font = new Font("Segoe UI", 9, FontStyle.Bold);
  192. apiTabPage.Controls.Add(apiKeyLabel);
  193. // API Key TextBox
  194. apiKeyTextBox = new TextBox();
  195. apiKeyTextBox.Location = new Point(10, 165);
  196. apiKeyTextBox.Size = new Size(420, 23);
  197. apiKeyTextBox.UseSystemPasswordChar = true;
  198. apiKeyTextBox.Font = new Font("Consolas", 9);
  199. apiTabPage.Controls.Add(apiKeyTextBox);
  200. // API Show/Hide Button
  201. apiShowHideButton = new Button();
  202. apiShowHideButton.Text = "Show";
  203. apiShowHideButton.Location = new Point(440, 165);
  204. apiShowHideButton.Size = new Size(60, 23);
  205. apiShowHideButton.Click += ApiShowHideButton_Click;
  206. apiTabPage.Controls.Add(apiShowHideButton);
  207. // API Test Button
  208. apiTestButton = new Button();
  209. apiTestButton.Text = "Test API Key";
  210. apiTestButton.Location = new Point(10, 200);
  211. apiTestButton.Size = new Size(120, 30);
  212. apiTestButton.Click += ApiTestButton_Click;
  213. apiTabPage.Controls.Add(apiTestButton);
  214. // API Status Label
  215. apiStatusLabel = new Label();
  216. apiStatusLabel.Name = "apiStatusLabel";
  217. apiStatusLabel.Text = "Enter your API key and click 'Test API Key'";
  218. apiStatusLabel.Location = new Point(140, 205);
  219. apiStatusLabel.Size = new Size(360, 20);
  220. apiStatusLabel.ForeColor = Color.Gray;
  221. apiTabPage.Controls.Add(apiStatusLabel);
  222. // Additional API Information
  223. var apiInfoLabel = new Label();
  224. apiInfoLabel.Text =
  225. "💡 Tips:\n" +
  226. "• API keys start with 'sk-ant-api03-'\n" +
  227. "• Keep your API key secure and don't share it\n" +
  228. "• You can monitor usage in the Anthropic Console\n" +
  229. "• API access requires a paid plan with credits";
  230. apiInfoLabel.Location = new Point(10, 240);
  231. apiInfoLabel.Size = new Size(540, 80);
  232. apiInfoLabel.Font = new Font("Segoe UI", 8.5f);
  233. apiInfoLabel.ForeColor = Color.DarkBlue;
  234. apiTabPage.Controls.Add(apiInfoLabel);
  235. }
  236. private void CreateHelpTab()
  237. {
  238. var helpText = new RichTextBox();
  239. helpText.Text =
  240. "CLAUDE BALANCE MONITOR HELP\n\n" +
  241. "AUTHENTICATION METHODS:\n\n" +
  242. "1. API Key (Recommended)\n" +
  243. " ✅ Most reliable method\n" +
  244. " ✅ Official Anthropic authentication\n" +
  245. " ✅ Works with current security measures\n" +
  246. " ❌ Requires paid Anthropic Console account\n\n" +
  247. "2. Session Cookie (Legacy)\n" +
  248. " ❌ May not work due to enhanced security\n" +
  249. " ❌ Prone to expiration\n" +
  250. " ❌ May trigger Forbidden errors\n" +
  251. " ✅ No additional setup if it works\n\n" +
  252. "TROUBLESHOOTING:\n\n" +
  253. "Forbidden Error:\n" +
  254. "• Anthropic has enhanced security measures\n" +
  255. "• Session cookies may no longer work\n" +
  256. "• Switch to API Key authentication\n" +
  257. "• Ensure you have a valid Anthropic Console account\n\n" +
  258. "API Key Issues:\n" +
  259. "• Verify the key starts with 'sk-ant-api03-'\n" +
  260. "• Check that billing is set up in Console\n" +
  261. "• Ensure you have available credits\n" +
  262. "• Make sure the key has proper permissions\n\n" +
  263. "No Balance Found:\n" +
  264. "• Check your Anthropic Console billing page manually\n" +
  265. "• Verify your account has API access\n" +
  266. "• Try refreshing the widget manually\n\n" +
  267. "GETTING HELP:\n" +
  268. "• Check Anthropic's official documentation\n" +
  269. "• Visit https://support.anthropic.com/\n" +
  270. "• Ensure your account is properly set up\n\n" +
  271. "Note: This tool is unofficial and may break if Anthropic changes their systems.";
  272. helpText.Location = new Point(10, 10);
  273. helpText.Size = new Size(540, 300);
  274. helpText.Font = new Font("Segoe UI", 9);
  275. helpText.ReadOnly = true;
  276. helpText.BackColor = SystemColors.Control;
  277. helpTabPage.Controls.Add(helpText);
  278. }
  279. private void AuthMethod_CheckedChanged(object sender, EventArgs e)
  280. {
  281. if (sessionRadioButton.Checked)
  282. {
  283. tabControl.SelectedTab = sessionTabPage;
  284. }
  285. else if (apiRadioButton.Checked)
  286. {
  287. tabControl.SelectedTab = apiTabPage;
  288. }
  289. }
  290. private void SessionShowHideButton_Click(object sender, EventArgs e)
  291. {
  292. isSessionTokenVisible = !isSessionTokenVisible;
  293. sessionTokenTextBox.UseSystemPasswordChar = !isSessionTokenVisible;
  294. sessionShowHideButton.Text = isSessionTokenVisible ? "Hide" : "Show";
  295. }
  296. private void ApiShowHideButton_Click(object sender, EventArgs e)
  297. {
  298. isApiKeyVisible = !isApiKeyVisible;
  299. apiKeyTextBox.UseSystemPasswordChar = !isApiKeyVisible;
  300. apiShowHideButton.Text = isApiKeyVisible ? "Hide" : "Show";
  301. }
  302. private async void SessionTestButton_Click(object sender, EventArgs e)
  303. {
  304. var testToken = sessionTokenTextBox.Text.Trim();
  305. if (string.IsNullOrEmpty(testToken))
  306. {
  307. sessionStatusLabel.Text = "Please enter a session token";
  308. sessionStatusLabel.ForeColor = Color.Red;
  309. return;
  310. }
  311. sessionStatusLabel.Text = "Testing connection...";
  312. sessionStatusLabel.ForeColor = Color.Blue;
  313. sessionTestButton.Enabled = false;
  314. try
  315. {
  316. using (var testClient = new HttpClient())
  317. {
  318. testClient.Timeout = TimeSpan.FromSeconds(10);
  319. testClient.DefaultRequestHeaders.Add("User-Agent",
  320. "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36");
  321. testClient.DefaultRequestHeaders.Add("Cookie", $"sessionKey={testToken}");
  322. testClient.DefaultRequestHeaders.Add("X-Requested-With", "XMLHttpRequest");
  323. testClient.DefaultRequestHeaders.Add("Referer", "https://console.anthropic.com/");
  324. var response = await testClient.GetAsync("https://console.anthropic.com/settings/billing");
  325. if (response.IsSuccessStatusCode)
  326. {
  327. sessionStatusLabel.Text = "✓ Connection successful!";
  328. sessionStatusLabel.ForeColor = Color.Green;
  329. }
  330. else if (response.StatusCode == System.Net.HttpStatusCode.Forbidden)
  331. {
  332. sessionStatusLabel.Text = "✗ Forbidden - Session cookies may no longer work. Try API Key.";
  333. sessionStatusLabel.ForeColor = Color.Red;
  334. }
  335. else
  336. {
  337. sessionStatusLabel.Text = $"✗ Connection failed (Status: {response.StatusCode})";
  338. sessionStatusLabel.ForeColor = Color.Red;
  339. }
  340. }
  341. }
  342. catch (Exception ex)
  343. {
  344. sessionStatusLabel.Text = $"✗ Connection error: {ex.Message}";
  345. sessionStatusLabel.ForeColor = Color.Red;
  346. }
  347. finally
  348. {
  349. sessionTestButton.Enabled = true;
  350. }
  351. }
  352. private async void ApiTestButton_Click(object sender, EventArgs e)
  353. {
  354. var testApiKey = apiKeyTextBox.Text.Trim();
  355. if (string.IsNullOrEmpty(testApiKey))
  356. {
  357. apiStatusLabel.Text = "Please enter an API key";
  358. apiStatusLabel.ForeColor = Color.Red;
  359. return;
  360. }
  361. if (!testApiKey.StartsWith("sk-ant-api03-"))
  362. {
  363. apiStatusLabel.Text = "API key should start with 'sk-ant-api03-'";
  364. apiStatusLabel.ForeColor = Color.Orange;
  365. return;
  366. }
  367. apiStatusLabel.Text = "Testing API key...";
  368. apiStatusLabel.ForeColor = Color.Blue;
  369. apiTestButton.Enabled = false;
  370. try
  371. {
  372. using (var testClient = new HttpClient())
  373. {
  374. testClient.Timeout = TimeSpan.FromSeconds(10);
  375. // Test with a simple API call
  376. var request = new HttpRequestMessage(HttpMethod.Post, "https://api.anthropic.com/v1/messages");
  377. request.Headers.Add("x-api-key", testApiKey);
  378. request.Headers.Add("anthropic-version", "2023-06-01");
  379. // Simple test message
  380. var testContent = @"{
  381. ""model"": ""claude-3-5-haiku-20241022"",
  382. ""max_tokens"": 10,
  383. ""messages"": [{
  384. ""role"": ""user"",
  385. ""content"": ""Hello""
  386. }]
  387. }";
  388. request.Content = new StringContent(testContent, System.Text.Encoding.UTF8, "application/json");
  389. var response = await testClient.SendAsync(request);
  390. if (response.IsSuccessStatusCode)
  391. {
  392. apiStatusLabel.Text = "✓ API key is valid and working!";
  393. apiStatusLabel.ForeColor = Color.Green;
  394. }
  395. else if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized)
  396. {
  397. apiStatusLabel.Text = "✗ Invalid API key";
  398. apiStatusLabel.ForeColor = Color.Red;
  399. }
  400. else if (response.StatusCode == System.Net.HttpStatusCode.PaymentRequired)
  401. {
  402. apiStatusLabel.Text = "✗ No credits available. Add funds to your account.";
  403. apiStatusLabel.ForeColor = Color.Orange;
  404. }
  405. else
  406. {
  407. apiStatusLabel.Text = $"✗ API error (Status: {response.StatusCode})";
  408. apiStatusLabel.ForeColor = Color.Red;
  409. }
  410. }
  411. }
  412. catch (Exception ex)
  413. {
  414. apiStatusLabel.Text = $"✗ Connection error: {ex.Message}";
  415. apiStatusLabel.ForeColor = Color.Red;
  416. }
  417. finally
  418. {
  419. apiTestButton.Enabled = true;
  420. }
  421. }
  422. private void OkButton_Click(object sender, EventArgs e)
  423. {
  424. SessionToken = sessionTokenTextBox.Text.Trim();
  425. ApiKey = apiKeyTextBox.Text.Trim();
  426. if (apiRadioButton.Checked)
  427. {
  428. AuthMethod = AuthenticationMethod.ApiKey;
  429. if (string.IsNullOrEmpty(ApiKey))
  430. {
  431. MessageBox.Show("Please enter an API key or switch to session cookie method.",
  432. "Missing API Key", MessageBoxButtons.OK, MessageBoxIcon.Warning);
  433. return;
  434. }
  435. }
  436. else
  437. {
  438. AuthMethod = AuthenticationMethod.SessionCookie;
  439. if (string.IsNullOrEmpty(SessionToken))
  440. {
  441. MessageBox.Show("Please enter a session token or switch to API key method.",
  442. "Missing Session Token", MessageBoxButtons.OK, MessageBoxIcon.Warning);
  443. return;
  444. }
  445. }
  446. DialogResult = DialogResult.OK;
  447. Close();
  448. }
  449. private void CancelButton_Click(object sender, EventArgs e)
  450. {
  451. DialogResult = DialogResult.Cancel;
  452. Close();
  453. }
  454. }
  455. }