design-lazyyy-cli 0.2.1 → 0.3.1

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 (2) hide show
  1. package/package.json +1 -1
  2. package/src/index.js +105 -5
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "design-lazyyy-cli",
3
- "version": "0.2.1",
3
+ "version": "0.3.1",
4
4
  "description": "CLI for managing Figma design systems. Create variables, components, and more. No API key required.",
5
5
  "author": "plugin87",
6
6
  "license": "MIT",
package/src/index.js CHANGED
@@ -11,6 +11,13 @@ import { createInterface } from 'readline';
11
11
  import { homedir, platform } from 'os';
12
12
  import { FigJamClient } from './figjam-client.js';
13
13
 
14
+ // Auth — offline hash-based verification
15
+ import { createHash } from 'crypto';
16
+ const VALID_TOKEN_HASHES = [
17
+ // SHA-256 hashes of valid tokens (add more with: echo -n "token" | shasum -a 256)
18
+ '065ea2d80d8e1e61025f115d01d08518b00615047a3ec14bd4e6f7d4f8813929',
19
+ ];
20
+
14
21
  // Platform detection
15
22
  const IS_WINDOWS = platform() === 'win32';
16
23
  const IS_MAC = platform() === 'darwin';
@@ -95,10 +102,56 @@ function saveConfig(config) {
95
102
  writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));
96
103
  }
97
104
 
98
- // Resolve engine binary path (local node_modules)
105
+ // Helper: Hash token with SHA-256
106
+ function hashToken(token) {
107
+ return createHash('sha256').update(token).digest('hex');
108
+ }
109
+
110
+ // Helper: Verify token offline against known hashes
111
+ function verifyToken(token) {
112
+ return VALID_TOKEN_HASHES.includes(hashToken(token));
113
+ }
114
+
115
+ // Helper: Check API key (gate all commands)
116
+ function checkApiKey() {
117
+ const config = loadConfig();
118
+ if (!config.token) {
119
+ console.log(chalk.red('\n✗ Token required.\n'));
120
+ console.log(chalk.white(' Get a token from plugin87, then run:\n'));
121
+ console.log(chalk.cyan(' design-lazyyy-cli login <token>\n'));
122
+ process.exit(1);
123
+ }
124
+ if (!verifyToken(config.token)) {
125
+ console.log(chalk.red('\n✗ Token invalid or revoked.\n'));
126
+ console.log(chalk.white(' Get a new token from plugin87, then run:\n'));
127
+ console.log(chalk.cyan(' design-lazyyy-cli login <token>\n'));
128
+ delete config.token;
129
+ saveConfig(config);
130
+ process.exit(1);
131
+ }
132
+ return true;
133
+ }
134
+
135
+ // Resolve engine binary path (check local then walk up for hoisted deps)
99
136
  const __filename2 = fileURLToPath(import.meta.url);
100
137
  const __pkgRoot = dirname(dirname(__filename2));
101
- const ENGINE_BIN = resolve(__pkgRoot, 'node_modules', '.bin', 'figma-use');
138
+
139
+ function findEngineBin() {
140
+ // Check local node_modules first
141
+ const local = resolve(__pkgRoot, 'node_modules', '.bin', 'figma-use');
142
+ if (existsSync(local)) return local;
143
+ // Walk up directories to find hoisted binary
144
+ let dir = __pkgRoot;
145
+ while (true) {
146
+ const parent = dirname(dir);
147
+ const candidate = resolve(parent, 'node_modules', '.bin', 'figma-use');
148
+ if (existsSync(candidate)) return candidate;
149
+ if (parent === dir) break;
150
+ dir = parent;
151
+ }
152
+ return local; // fallback
153
+ }
154
+ const ENGINE_BIN = findEngineBin();
102
155
 
103
156
  // Helper: Run engine command
104
157
  function figmaUse(args, options = {}) {
@@ -115,8 +168,9 @@ function figmaUse(args, options = {}) {
115
168
  }
116
169
  }
117
170
 
118
- // Helper: Check connection
171
+ // Helper: Check connection (also gates on API key)
119
172
  function checkConnection() {
173
+ checkApiKey();
120
174
  const result = figmaUse('status', { silent: true });
121
175
  if (!result || result.includes('Not connected')) {
122
176
  console.log(chalk.red('\n✗ Not connected to Figma\n'));
@@ -178,11 +232,13 @@ program
178
232
  program.action(async () => {
179
233
  const config = loadConfig();
180
234
 
235
+ // Auth gate
236
+ checkApiKey();
237
+
181
238
  // First time? Run init
182
239
  if (!config.patched || !checkDependencies(true)) {
183
240
  showBanner();
184
241
  console.log(chalk.white(' Welcome! Let\'s get you set up.\n'));
185
- console.log(chalk.gray(' This takes about 30 seconds. No API key needed.\n'));
186
242
 
187
243
  // Step 1: Check Node version
188
244
  console.log(chalk.blue('Step 1/4: ') + 'Checking Node.js...');
@@ -338,10 +394,10 @@ program
338
394
  .command('init')
339
395
  .description('Interactive setup wizard')
340
396
  .action(async () => {
397
+ checkApiKey();
341
398
  showBanner();
342
399
 
343
400
  console.log(chalk.white(' Welcome! Let\'s get you set up.\n'));
344
- console.log(chalk.gray(' This takes about 30 seconds. No API key needed.\n'));
345
401
 
346
402
  // Step 1: Check Node version
347
403
  console.log(chalk.blue('Step 1/4: ') + 'Checking Node.js...');
@@ -447,12 +503,55 @@ program
447
503
  execSync('design-lazyyy-cli init', { stdio: 'inherit' });
448
504
  });
449
505
 
506
+ // ============ LOGIN ============
507
+
508
+ program
509
+ .command('login [token]')
510
+ .description('Authenticate with a token from plugin87')
511
+ .action(async (token) => {
512
+ if (!token) {
513
+ token = await prompt(chalk.white('Enter token: '));
514
+ }
515
+ token = token.trim();
516
+ if (!token) {
517
+ console.log(chalk.red('\n✗ Token cannot be empty.\n'));
518
+ process.exit(1);
519
+ }
520
+
521
+ if (!verifyToken(token)) {
522
+ console.log(chalk.red('\n✗ Invalid token.\n'));
523
+ process.exit(1);
524
+ }
525
+
526
+ const config = loadConfig();
527
+ config.token = token;
528
+ saveConfig(config);
529
+ console.log(chalk.green('\n✓ Token verified! Welcome.\n'));
530
+ });
531
+
532
+ // ============ LOGOUT ============
533
+
534
+ program
535
+ .command('logout')
536
+ .description('Remove saved token')
537
+ .action(() => {
538
+ const config = loadConfig();
539
+ if (!config.token) {
540
+ console.log(chalk.yellow('\nNo token saved.\n'));
541
+ return;
542
+ }
543
+ delete config.token;
544
+ saveConfig(config);
545
+ console.log(chalk.green('\n✓ Token removed. You are logged out.\n'));
546
+ });
547
+
450
548
  // ============ STATUS ============
451
549
 
452
550
  program
453
551
  .command('status')
454
552
  .description('Check connection to Figma')
455
553
  .action(() => {
554
+ checkApiKey();
456
555
  // Check if first run
457
556
  const config = loadConfig();
458
557
  if (!config.patched && !checkDependencies(true)) {
@@ -469,6 +568,7 @@ program
469
568
  .command('connect')
470
569
  .description('Start Figma with remote debugging enabled')
471
570
  .action(async () => {
571
+ checkApiKey();
472
572
  // Check if first run
473
573
  const config = loadConfig();
474
574
  if (!config.patched) {