@sekyuriti/attest 0.2.1 → 0.2.2
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/bin/attest.js +110 -126
- package/package.json +1 -1
package/bin/attest.js
CHANGED
|
@@ -139,7 +139,109 @@ function printHeader() {
|
|
|
139
139
|
logBold(" █▀▀ █▀▀ █▄▀ █▄█ █ █ █▀█ █ ▀█▀ █");
|
|
140
140
|
logBold(" ▄▄█ ██▄ █ █ █ █▄█ █▀▄ █ █ █");
|
|
141
141
|
log("");
|
|
142
|
-
logDim(" ATTEST CLI v0.2.
|
|
142
|
+
logDim(" ATTEST CLI v0.2.1");
|
|
143
|
+
log("");
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
147
|
+
// INIT HELPER (used by both login and init commands)
|
|
148
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
149
|
+
|
|
150
|
+
async function runInit(publicKey, apiKey) {
|
|
151
|
+
let steps = [];
|
|
152
|
+
|
|
153
|
+
// Step 1: Add .env variables
|
|
154
|
+
const envPath = path.join(process.cwd(), ".env");
|
|
155
|
+
const envLocalPath = path.join(process.cwd(), ".env.local");
|
|
156
|
+
let targetEnvPath = envLocalPath;
|
|
157
|
+
|
|
158
|
+
if (fs.existsSync(envLocalPath)) {
|
|
159
|
+
targetEnvPath = envLocalPath;
|
|
160
|
+
} else if (fs.existsSync(envPath)) {
|
|
161
|
+
targetEnvPath = envPath;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const envVars = `
|
|
165
|
+
# ATTEST Configuration
|
|
166
|
+
NEXT_PUBLIC_ATTEST_KEY=${publicKey}
|
|
167
|
+
ATTEST_SECRET_KEY=${apiKey}
|
|
168
|
+
`.trim();
|
|
169
|
+
|
|
170
|
+
if (fs.existsSync(targetEnvPath)) {
|
|
171
|
+
let content = fs.readFileSync(targetEnvPath, "utf-8");
|
|
172
|
+
if (!content.includes("ATTEST_KEY")) {
|
|
173
|
+
content += "\n\n" + envVars + "\n";
|
|
174
|
+
fs.writeFileSync(targetEnvPath, content);
|
|
175
|
+
steps.push(`Added ATTEST config to ${path.basename(targetEnvPath)}`);
|
|
176
|
+
} else {
|
|
177
|
+
steps.push(`ATTEST config already in ${path.basename(targetEnvPath)}`);
|
|
178
|
+
}
|
|
179
|
+
} else {
|
|
180
|
+
fs.writeFileSync(envLocalPath, envVars + "\n");
|
|
181
|
+
steps.push("Created .env.local with ATTEST config");
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// Step 2: Find and update layout.tsx
|
|
185
|
+
const layoutPaths = [
|
|
186
|
+
path.join(process.cwd(), "src/app/layout.tsx"),
|
|
187
|
+
path.join(process.cwd(), "app/layout.tsx"),
|
|
188
|
+
path.join(process.cwd(), "src/app/layout.js"),
|
|
189
|
+
path.join(process.cwd(), "app/layout.js"),
|
|
190
|
+
];
|
|
191
|
+
|
|
192
|
+
let layoutPath = null;
|
|
193
|
+
for (const p of layoutPaths) {
|
|
194
|
+
if (fs.existsSync(p)) {
|
|
195
|
+
layoutPath = p;
|
|
196
|
+
break;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
const scriptTag = `<Script
|
|
201
|
+
src="https://sekyuriti.build/api/v2/attest/script/${publicKey}"
|
|
202
|
+
strategy="beforeInteractive"
|
|
203
|
+
/>`;
|
|
204
|
+
|
|
205
|
+
if (layoutPath) {
|
|
206
|
+
let layoutContent = fs.readFileSync(layoutPath, "utf-8");
|
|
207
|
+
|
|
208
|
+
if (layoutContent.includes("sekyuriti.build/api/v2/attest/script")) {
|
|
209
|
+
steps.push("ATTEST script already in layout");
|
|
210
|
+
} else {
|
|
211
|
+
// Check if Script is already imported
|
|
212
|
+
const hasScriptImport = layoutContent.includes("from 'next/script'") || layoutContent.includes('from "next/script"');
|
|
213
|
+
|
|
214
|
+
if (!hasScriptImport) {
|
|
215
|
+
// Add Script import after the first import line
|
|
216
|
+
layoutContent = layoutContent.replace(
|
|
217
|
+
/(import .+ from ['"][^'"]+['"];?\n)/,
|
|
218
|
+
`$1import Script from "next/script";\n`
|
|
219
|
+
);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// Add script tag after <body> or <body className=...>
|
|
223
|
+
if (layoutContent.includes("<body")) {
|
|
224
|
+
layoutContent = layoutContent.replace(
|
|
225
|
+
/(<body[^>]*>)/,
|
|
226
|
+
`$1\n ${scriptTag}`
|
|
227
|
+
);
|
|
228
|
+
fs.writeFileSync(layoutPath, layoutContent);
|
|
229
|
+
steps.push(`Added ATTEST script to ${path.basename(layoutPath)}`);
|
|
230
|
+
} else {
|
|
231
|
+
steps.push("Could not find <body> tag in layout");
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
} else {
|
|
235
|
+
steps.push("No layout.tsx found - add script manually");
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// Print results
|
|
239
|
+
for (const step of steps) {
|
|
240
|
+
log(` ${c.bold}✓${c.reset} ${step}`);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
log("");
|
|
244
|
+
log(" Documentation: https://sekyuriti.build/docs/attest");
|
|
143
245
|
log("");
|
|
144
246
|
}
|
|
145
247
|
|
|
@@ -211,6 +313,11 @@ async function cmdLogin() {
|
|
|
211
313
|
apiKey: data.apiKey,
|
|
212
314
|
});
|
|
213
315
|
|
|
316
|
+
// Auto-run init after successful login
|
|
317
|
+
log(" Setting up your project...");
|
|
318
|
+
log("");
|
|
319
|
+
await runInit(data.publicKey, data.apiKey);
|
|
320
|
+
|
|
214
321
|
return;
|
|
215
322
|
}
|
|
216
323
|
}
|
|
@@ -334,132 +441,9 @@ async function cmdInit() {
|
|
|
334
441
|
return;
|
|
335
442
|
}
|
|
336
443
|
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
// Step 1: Add .env variables
|
|
340
|
-
const envPath = path.join(process.cwd(), ".env");
|
|
341
|
-
const envLocalPath = path.join(process.cwd(), ".env.local");
|
|
342
|
-
let targetEnvPath = envLocalPath;
|
|
343
|
-
|
|
344
|
-
if (fs.existsSync(envLocalPath)) {
|
|
345
|
-
targetEnvPath = envLocalPath;
|
|
346
|
-
} else if (fs.existsSync(envPath)) {
|
|
347
|
-
targetEnvPath = envPath;
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
const envVars = `
|
|
351
|
-
# ATTEST Configuration
|
|
352
|
-
NEXT_PUBLIC_ATTEST_KEY=${config.publicKey}
|
|
353
|
-
ATTEST_SECRET_KEY=${config.apiKey}
|
|
354
|
-
`.trim();
|
|
355
|
-
|
|
356
|
-
if (fs.existsSync(targetEnvPath)) {
|
|
357
|
-
let content = fs.readFileSync(targetEnvPath, "utf-8");
|
|
358
|
-
if (!content.includes("ATTEST_KEY")) {
|
|
359
|
-
content += "\n\n" + envVars + "\n";
|
|
360
|
-
fs.writeFileSync(targetEnvPath, content);
|
|
361
|
-
steps.push(`Added ATTEST config to ${path.basename(targetEnvPath)}`);
|
|
362
|
-
} else {
|
|
363
|
-
steps.push(`ATTEST config already in ${path.basename(targetEnvPath)}`);
|
|
364
|
-
}
|
|
365
|
-
} else {
|
|
366
|
-
fs.writeFileSync(envLocalPath, envVars + "\n");
|
|
367
|
-
steps.push("Created .env.local with ATTEST config");
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
// Step 2: Find and update layout.tsx
|
|
371
|
-
const layoutPaths = [
|
|
372
|
-
path.join(process.cwd(), "src/app/layout.tsx"),
|
|
373
|
-
path.join(process.cwd(), "app/layout.tsx"),
|
|
374
|
-
path.join(process.cwd(), "src/app/layout.js"),
|
|
375
|
-
path.join(process.cwd(), "app/layout.js"),
|
|
376
|
-
];
|
|
377
|
-
|
|
378
|
-
let layoutPath = null;
|
|
379
|
-
for (const p of layoutPaths) {
|
|
380
|
-
if (fs.existsSync(p)) {
|
|
381
|
-
layoutPath = p;
|
|
382
|
-
break;
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
const scriptTag = `<Script
|
|
387
|
-
src="https://sekyuriti.build/api/v2/attest/script/${config.publicKey}"
|
|
388
|
-
strategy="beforeInteractive"
|
|
389
|
-
/>`;
|
|
390
|
-
|
|
391
|
-
if (layoutPath) {
|
|
392
|
-
let layoutContent = fs.readFileSync(layoutPath, "utf-8");
|
|
393
|
-
|
|
394
|
-
if (layoutContent.includes("sekyuriti.build/api/v2/attest/script")) {
|
|
395
|
-
steps.push("ATTEST script already in layout");
|
|
396
|
-
} else {
|
|
397
|
-
// Check if Script is already imported
|
|
398
|
-
const hasScriptImport = layoutContent.includes("from 'next/script'") || layoutContent.includes('from "next/script"');
|
|
399
|
-
|
|
400
|
-
if (!hasScriptImport) {
|
|
401
|
-
// Add Script import after the first import line
|
|
402
|
-
layoutContent = layoutContent.replace(
|
|
403
|
-
/(import .+ from ['"][^'"]+['"];?\n)/,
|
|
404
|
-
`$1import Script from "next/script";\n`
|
|
405
|
-
);
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
// Add script tag after <body> or <body className=...>
|
|
409
|
-
if (layoutContent.includes("<body")) {
|
|
410
|
-
layoutContent = layoutContent.replace(
|
|
411
|
-
/(<body[^>]*>)/,
|
|
412
|
-
`$1\n ${scriptTag}`
|
|
413
|
-
);
|
|
414
|
-
fs.writeFileSync(layoutPath, layoutContent);
|
|
415
|
-
steps.push(`Added ATTEST script to ${path.basename(layoutPath)}`);
|
|
416
|
-
} else {
|
|
417
|
-
steps.push("Could not find <body> tag in layout");
|
|
418
|
-
}
|
|
419
|
-
}
|
|
420
|
-
} else {
|
|
421
|
-
steps.push("No layout.tsx found - add script manually");
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
// Step 3: Check for middleware.ts and offer to add verification
|
|
425
|
-
const middlewarePaths = [
|
|
426
|
-
path.join(process.cwd(), "middleware.ts"),
|
|
427
|
-
path.join(process.cwd(), "src/middleware.ts"),
|
|
428
|
-
path.join(process.cwd(), "middleware.js"),
|
|
429
|
-
path.join(process.cwd(), "src/middleware.js"),
|
|
430
|
-
];
|
|
431
|
-
|
|
432
|
-
let hasMiddleware = false;
|
|
433
|
-
for (const p of middlewarePaths) {
|
|
434
|
-
if (fs.existsSync(p)) {
|
|
435
|
-
hasMiddleware = true;
|
|
436
|
-
break;
|
|
437
|
-
}
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
// Print results
|
|
441
|
-
log(" SETUP COMPLETE");
|
|
442
|
-
log("");
|
|
443
|
-
|
|
444
|
-
for (const step of steps) {
|
|
445
|
-
log(` ${c.bold}✓${c.reset} ${step}`);
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
log("");
|
|
449
|
-
|
|
450
|
-
if (!hasMiddleware) {
|
|
451
|
-
log(" Optional: Add middleware for server-side verification:");
|
|
452
|
-
log("");
|
|
453
|
-
log(` ${c.dim}// middleware.ts${c.reset}`);
|
|
454
|
-
log(` ${c.dim}import { createAttestMiddleware } from '@sekyuriti/attest/middleware';${c.reset}`);
|
|
455
|
-
log(` ${c.dim}export default createAttestMiddleware({${c.reset}`);
|
|
456
|
-
log(` ${c.dim} protectedPaths: ['/api/'],${c.reset}`);
|
|
457
|
-
log(` ${c.dim}});${c.reset}`);
|
|
458
|
-
log("");
|
|
459
|
-
}
|
|
460
|
-
|
|
461
|
-
log(" Documentation: https://sekyuriti.build/docs/attest");
|
|
444
|
+
log(" Setting up ATTEST...");
|
|
462
445
|
log("");
|
|
446
|
+
await runInit(config.publicKey, config.apiKey);
|
|
463
447
|
}
|
|
464
448
|
|
|
465
449
|
// ═══════════════════════════════════════════════════════════════════
|