ai-warden 0.9.2 → 0.9.4

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.
Files changed (3) hide show
  1. package/package.json +1 -1
  2. package/src/cli.js +116 -4
  3. package/src/config.js +98 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-warden",
3
- "version": "0.9.2",
3
+ "version": "0.9.4",
4
4
  "description": "AI security scanner - Detect prompt injection attacks and PII with user settings",
5
5
  "main": "src/index.js",
6
6
  "bin": {
package/src/cli.js CHANGED
@@ -7,11 +7,14 @@
7
7
 
8
8
  const fs = require('fs');
9
9
  const path = require('path');
10
+ const { execSync } = require('child_process');
11
+ const readline = require('readline');
10
12
  const scanner = require('./scanner');
11
13
  const fileClassifier = require('./fileClassifier');
12
14
  const IgnoreParser = require('./ignoreParser');
13
15
  const InteractivePrompt = require('./interactivePrompt');
14
16
  const AIWarden = require('./index');
17
+ const config = require('./config');
15
18
 
16
19
  const args = process.argv.slice(2);
17
20
  const command = args[0];
@@ -30,6 +33,9 @@ Usage: aiwarden <command> [options]
30
33
  Commands:
31
34
  scan <path> Scan file or directory (offline mode)
32
35
  validate <text> Validate text via API (requires API key)
36
+ login Sign up or log in and save API key
37
+ logout Remove saved API key
38
+ whoami Show current API key status
33
39
  version Show version
34
40
  help Show this help
35
41
 
@@ -271,17 +277,23 @@ async function validateCommand(textOrPath, options = {}) {
271
277
  }
272
278
  }
273
279
 
274
- // Get API key from --api-key flag or environment variable
275
- const apiKey = options.apiKey || process.env.AI_WARDEN_API_KEY;
280
+ // Get API key from:
281
+ // 1. --api-key flag
282
+ // 2. Environment variable
283
+ // 3. Saved config file
284
+ const apiKey = options.apiKey || process.env.AI_WARDEN_API_KEY || config.getApiKey();
276
285
 
277
286
  if (!apiKey) {
278
287
  console.error('āŒ Error: API key required for validate command');
279
288
  console.log('');
280
289
  console.log('Options:');
281
- console.log(' 1. Pass --api-key flag:');
290
+ console.log(' 1. Log in (saves key for future use):');
291
+ console.log(' aiwarden login');
292
+ console.log('');
293
+ console.log(' 2. Pass --api-key flag:');
282
294
  console.log(' aiwarden validate "text" --api-key sk_live_xxx');
283
295
  console.log('');
284
- console.log(' 2. Set environment variable:');
296
+ console.log(' 3. Set environment variable:');
285
297
  console.log(' export AI_WARDEN_API_KEY=sk_live_xxx');
286
298
  console.log(' aiwarden validate "text"');
287
299
  console.log('');
@@ -383,6 +395,100 @@ function parseArgs() {
383
395
  return options;
384
396
  }
385
397
 
398
+ // Login command
399
+ async function loginCommand() {
400
+ console.log('šŸ” AI-Warden Login\n');
401
+
402
+ console.log('Opening browser to get your API key...');
403
+ console.log('→ https://prompt-shield.se/signup\n');
404
+
405
+ // Open browser
406
+ const url = 'https://prompt-shield.se/signup';
407
+ try {
408
+ const platform = process.platform;
409
+ if (platform === 'darwin') {
410
+ execSync(`open "${url}"`);
411
+ } else if (platform === 'win32') {
412
+ // Windows: start "" "URL" (first empty string is window title)
413
+ execSync(`start "" "${url}"`, { shell: true });
414
+ } else {
415
+ execSync(`xdg-open "${url}"`);
416
+ }
417
+ } catch (error) {
418
+ console.log('āš ļø Could not open browser automatically.');
419
+ console.log(`Please visit: ${url}\n`);
420
+ }
421
+
422
+ console.log('After signing up:');
423
+ console.log('1. Copy your API key from the dashboard');
424
+ console.log('2. Paste it below\n');
425
+
426
+ // Read API key from stdin
427
+ const rl = readline.createInterface({
428
+ input: process.stdin,
429
+ output: process.stdout
430
+ });
431
+
432
+ rl.question('API Key: ', (apiKey) => {
433
+ rl.close();
434
+
435
+ apiKey = apiKey.trim();
436
+
437
+ if (!apiKey) {
438
+ console.error('āŒ No API key provided');
439
+ process.exit(1);
440
+ }
441
+
442
+ // Validate format (sk_live_... or sk_test_...)
443
+ if (!apiKey.startsWith('sk_live_') && !apiKey.startsWith('sk_test_')) {
444
+ console.error('āŒ Invalid API key format');
445
+ console.error('Expected format: sk_live_... or sk_test_...');
446
+ process.exit(1);
447
+ }
448
+
449
+ // Save to config
450
+ config.setApiKey(apiKey);
451
+
452
+ const keyType = apiKey.startsWith('sk_live_') ? 'Live' : 'Test';
453
+ console.log(`\nāœ… ${keyType} API key saved successfully!`);
454
+ console.log(`Config: ${config.getConfigPath()}`);
455
+ console.log('\nYou can now use: aiwarden validate "text"');
456
+ });
457
+ }
458
+
459
+ // Logout command
460
+ function logoutCommand() {
461
+ const currentKey = config.getApiKey();
462
+
463
+ if (!currentKey) {
464
+ console.log('ā„¹ļø No API key configured');
465
+ return;
466
+ }
467
+
468
+ config.removeApiKey();
469
+ console.log('āœ… API key removed');
470
+ console.log(`Config file: ${config.getConfigPath()}`);
471
+ }
472
+
473
+ // Whoami command
474
+ function whoamiCommand() {
475
+ const apiKey = config.getApiKey();
476
+
477
+ if (!apiKey) {
478
+ console.log('āŒ Not logged in');
479
+ console.log('Run: aiwarden login');
480
+ process.exit(1);
481
+ }
482
+
483
+ const keyType = apiKey.startsWith('sk_live_') ? 'Live' : 'Test';
484
+ const masked = apiKey.substring(0, 12) + '...' + apiKey.substring(apiKey.length - 4);
485
+
486
+ console.log('āœ… Logged in');
487
+ console.log(`Type: ${keyType}`);
488
+ console.log(`Key: ${masked}`);
489
+ console.log(`Config: ${config.getConfigPath()}`);
490
+ }
491
+
386
492
  // Main
387
493
  (async () => {
388
494
  if (!command || command === 'help' || command === '--help' || command === '-h') {
@@ -403,6 +509,12 @@ function parseArgs() {
403
509
  const text = args[1];
404
510
  const options = parseArgs();
405
511
  await validateCommand(text, options);
512
+ } else if (command === 'login') {
513
+ await loginCommand();
514
+ } else if (command === 'logout') {
515
+ logoutCommand();
516
+ } else if (command === 'whoami') {
517
+ whoamiCommand();
406
518
  } else {
407
519
  console.error(`āŒ Unknown command: ${command}`);
408
520
  console.log('Run "aiwarden help" for usage information');
package/src/config.js ADDED
@@ -0,0 +1,98 @@
1
+ /**
2
+ * AI-Warden Config Manager
3
+ * Handles API key storage in ~/.config/aiwarden/config.json
4
+ */
5
+
6
+ const fs = require('fs');
7
+ const path = require('path');
8
+ const os = require('os');
9
+
10
+ const CONFIG_DIR = path.join(os.homedir(), '.config', 'aiwarden');
11
+ const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');
12
+
13
+ /**
14
+ * Ensure config directory exists
15
+ */
16
+ function ensureConfigDir() {
17
+ if (!fs.existsSync(CONFIG_DIR)) {
18
+ fs.mkdirSync(CONFIG_DIR, { recursive: true });
19
+ }
20
+ }
21
+
22
+ /**
23
+ * Load config from file
24
+ * @returns {object} Config object (empty if file doesn't exist)
25
+ */
26
+ function loadConfig() {
27
+ if (!fs.existsSync(CONFIG_FILE)) {
28
+ return {};
29
+ }
30
+
31
+ try {
32
+ const data = fs.readFileSync(CONFIG_FILE, 'utf8');
33
+ return JSON.parse(data);
34
+ } catch (error) {
35
+ console.error('āš ļø Warning: Could not read config file:', error.message);
36
+ return {};
37
+ }
38
+ }
39
+
40
+ /**
41
+ * Save config to file
42
+ * @param {object} config - Config object to save
43
+ */
44
+ function saveConfig(config) {
45
+ ensureConfigDir();
46
+
47
+ try {
48
+ fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2), 'utf8');
49
+ } catch (error) {
50
+ console.error('āŒ Error: Could not save config:', error.message);
51
+ process.exit(1);
52
+ }
53
+ }
54
+
55
+ /**
56
+ * Get stored API key
57
+ * @returns {string|null} API key or null if not set
58
+ */
59
+ function getApiKey() {
60
+ const config = loadConfig();
61
+ return config.apiKey || null;
62
+ }
63
+
64
+ /**
65
+ * Set API key
66
+ * @param {string} apiKey - API key to store
67
+ */
68
+ function setApiKey(apiKey) {
69
+ const config = loadConfig();
70
+ config.apiKey = apiKey;
71
+ saveConfig(config);
72
+ }
73
+
74
+ /**
75
+ * Remove API key
76
+ */
77
+ function removeApiKey() {
78
+ const config = loadConfig();
79
+ delete config.apiKey;
80
+ saveConfig(config);
81
+ }
82
+
83
+ /**
84
+ * Get config file path
85
+ * @returns {string} Path to config file
86
+ */
87
+ function getConfigPath() {
88
+ return CONFIG_FILE;
89
+ }
90
+
91
+ module.exports = {
92
+ getApiKey,
93
+ setApiKey,
94
+ removeApiKey,
95
+ getConfigPath,
96
+ loadConfig,
97
+ saveConfig
98
+ };