@kinosec/cli 0.4.0 → 0.6.0
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/dist/cli.js +592 -475
- package/dist/cli.js.map +1 -1
- package/package.json +2 -1
package/dist/cli.js
CHANGED
|
@@ -9283,6 +9283,320 @@ Examples:
|
|
|
9283
9283
|
});
|
|
9284
9284
|
}
|
|
9285
9285
|
|
|
9286
|
+
// src/commands/pentest.ts
|
|
9287
|
+
var import_picocolors6 = __toESM(require_picocolors(), 1);
|
|
9288
|
+
|
|
9289
|
+
// src/lib/confirm.ts
|
|
9290
|
+
var import_picocolors3 = __toESM(require_picocolors(), 1);
|
|
9291
|
+
import { createInterface } from "readline";
|
|
9292
|
+
async function confirmDestructive(message, yes) {
|
|
9293
|
+
if (yes) return;
|
|
9294
|
+
if (!isTTY()) {
|
|
9295
|
+
console.error("Use --yes to confirm destructive operations in non-interactive mode.");
|
|
9296
|
+
process.exit(2);
|
|
9297
|
+
}
|
|
9298
|
+
const rl = createInterface({ input: process.stdin, output: process.stderr });
|
|
9299
|
+
const answer = await new Promise((resolve) => {
|
|
9300
|
+
rl.question(`${message} (y/N) `, resolve);
|
|
9301
|
+
});
|
|
9302
|
+
rl.close();
|
|
9303
|
+
if (answer.toLowerCase() !== "y") {
|
|
9304
|
+
console.log("Cancelled.");
|
|
9305
|
+
process.exit(0);
|
|
9306
|
+
}
|
|
9307
|
+
}
|
|
9308
|
+
async function confirmAuthorization(target, yes) {
|
|
9309
|
+
if (yes) return;
|
|
9310
|
+
if (!isTTY()) {
|
|
9311
|
+
console.error("Use --yes to accept authorization terms in non-interactive mode.");
|
|
9312
|
+
process.exit(2);
|
|
9313
|
+
}
|
|
9314
|
+
const warning = import_picocolors3.default.yellow("\u26A0");
|
|
9315
|
+
console.error(`
|
|
9316
|
+
${warning} ${import_picocolors3.default.bold("Authorization Required")}
|
|
9317
|
+
|
|
9318
|
+
Penetration testing without proper authorization is illegal
|
|
9319
|
+
and may result in criminal prosecution.
|
|
9320
|
+
|
|
9321
|
+
${import_picocolors3.default.bold("Target:")} ${target}
|
|
9322
|
+
|
|
9323
|
+
By proceeding, you confirm that:
|
|
9324
|
+
${import_picocolors3.default.dim("\u2022")} You own or have explicit written authorization to test this target
|
|
9325
|
+
${import_picocolors3.default.dim("\u2022")} You will comply with all applicable laws and regulations
|
|
9326
|
+
${import_picocolors3.default.dim("\u2022")} You will not use the results for illegal or malicious purposes
|
|
9327
|
+
${import_picocolors3.default.dim("\u2022")} You accept full legal responsibility for this pentest
|
|
9328
|
+
|
|
9329
|
+
${import_picocolors3.default.dim("Unauthorized access to computer systems is a criminal offense under")}
|
|
9330
|
+
${import_picocolors3.default.dim("laws such as the CFAA (US), Computer Misuse Act (UK), and similar")}
|
|
9331
|
+
${import_picocolors3.default.dim("legislation worldwide. KinoSec bears no liability for unauthorized")}
|
|
9332
|
+
${import_picocolors3.default.dim("use of its services.")}
|
|
9333
|
+
`);
|
|
9334
|
+
const rl = createInterface({ input: process.stdin, output: process.stderr });
|
|
9335
|
+
const answer = await new Promise((resolve) => {
|
|
9336
|
+
rl.question("Agree and continue? (y/N) ", resolve);
|
|
9337
|
+
});
|
|
9338
|
+
rl.close();
|
|
9339
|
+
if (answer.toLowerCase() !== "y") {
|
|
9340
|
+
console.log("Cancelled.");
|
|
9341
|
+
process.exit(0);
|
|
9342
|
+
}
|
|
9343
|
+
}
|
|
9344
|
+
|
|
9345
|
+
// src/commands/schedule.ts
|
|
9346
|
+
var import_picocolors4 = __toESM(require_picocolors(), 1);
|
|
9347
|
+
var VALID_PATTERNS = ["once", "daily", "weekly", "biweekly", "monthly"];
|
|
9348
|
+
var VALID_MODES = ["quick", "full"];
|
|
9349
|
+
var DAY_NAMES = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
|
|
9350
|
+
function extractTime(scheduledAt) {
|
|
9351
|
+
if (!scheduledAt) return "\u2014";
|
|
9352
|
+
const d = new Date(scheduledAt);
|
|
9353
|
+
return d.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit", hour12: false });
|
|
9354
|
+
}
|
|
9355
|
+
function formatPattern(s) {
|
|
9356
|
+
const time = extractTime(s.scheduled_at);
|
|
9357
|
+
switch (s.recurrence_pattern) {
|
|
9358
|
+
case "once":
|
|
9359
|
+
return `Once at ${time}`;
|
|
9360
|
+
case "daily":
|
|
9361
|
+
return `Daily at ${time}`;
|
|
9362
|
+
case "weekly":
|
|
9363
|
+
return `Weekly ${s.day_of_week !== null ? DAY_NAMES[s.day_of_week] : ""} at ${time}`;
|
|
9364
|
+
case "biweekly":
|
|
9365
|
+
return `Every 2 weeks ${s.day_of_week !== null ? DAY_NAMES[s.day_of_week] : ""} at ${time}`;
|
|
9366
|
+
case "monthly":
|
|
9367
|
+
return `Monthly day ${s.day_of_month ?? "?"} at ${time}`;
|
|
9368
|
+
default:
|
|
9369
|
+
return s.recurrence_pattern;
|
|
9370
|
+
}
|
|
9371
|
+
}
|
|
9372
|
+
function registerScheduleCommand(pentestCmd) {
|
|
9373
|
+
const schedule = pentestCmd.command("schedule").description("Manage scheduled pentests");
|
|
9374
|
+
schedule.command("list").description("List scheduled pentests").option("--limit <n>", "Max results per page", "20").option("--cursor <cursor>", "Pagination cursor").option("--status <status>", "Filter: active, paused, or all", "all").addHelpText("after", `
|
|
9375
|
+
Examples:
|
|
9376
|
+
$ kinosec pentest schedule list
|
|
9377
|
+
$ kinosec pentest schedule list --status active --json`).action(async (options) => {
|
|
9378
|
+
try {
|
|
9379
|
+
const opts = schedule.parent.parent.opts();
|
|
9380
|
+
const { token, apiUrl } = resolveToken(opts);
|
|
9381
|
+
const client = new KinoSecClient({ apiUrl, token });
|
|
9382
|
+
const result = await client.schedules.list({
|
|
9383
|
+
limit: parseInt(options.limit, 10),
|
|
9384
|
+
cursor: options.cursor,
|
|
9385
|
+
status: options.status
|
|
9386
|
+
});
|
|
9387
|
+
if (opts.json || opts.output === "json") {
|
|
9388
|
+
printJson(result);
|
|
9389
|
+
return;
|
|
9390
|
+
}
|
|
9391
|
+
if (result.items.length === 0) {
|
|
9392
|
+
console.log("No scheduled pentests found.");
|
|
9393
|
+
return;
|
|
9394
|
+
}
|
|
9395
|
+
printTable(
|
|
9396
|
+
["ID", "Target", "Mode", "Schedule", "Status", "Next Run"],
|
|
9397
|
+
result.items.map((s) => [
|
|
9398
|
+
s.id,
|
|
9399
|
+
truncate(s.domain_or_ip, 25),
|
|
9400
|
+
s.scan_mode,
|
|
9401
|
+
formatPattern(s),
|
|
9402
|
+
s.is_active ? import_picocolors4.default.green("active") : import_picocolors4.default.yellow("paused"),
|
|
9403
|
+
s.next_scheduled_run ? new Date(s.next_scheduled_run).toLocaleString() : "\u2014"
|
|
9404
|
+
])
|
|
9405
|
+
);
|
|
9406
|
+
if (result.next_cursor) {
|
|
9407
|
+
console.log(import_picocolors4.default.dim(`
|
|
9408
|
+
More results available. Use --cursor ${result.next_cursor}`));
|
|
9409
|
+
}
|
|
9410
|
+
} catch (error) {
|
|
9411
|
+
handleError(error);
|
|
9412
|
+
}
|
|
9413
|
+
});
|
|
9414
|
+
schedule.command("get").description("Get schedule details").argument("<id>", "Schedule ID").addHelpText("after", `
|
|
9415
|
+
Examples:
|
|
9416
|
+
$ kinosec pentest schedule get abc123
|
|
9417
|
+
$ kinosec pentest schedule get abc123 --json`).action(async (id) => {
|
|
9418
|
+
try {
|
|
9419
|
+
const opts = schedule.parent.parent.opts();
|
|
9420
|
+
const { token, apiUrl } = resolveToken(opts);
|
|
9421
|
+
const client = new KinoSecClient({ apiUrl, token });
|
|
9422
|
+
const s = await client.schedules.get(id);
|
|
9423
|
+
if (opts.json || opts.output === "json") {
|
|
9424
|
+
printJson(s);
|
|
9425
|
+
return;
|
|
9426
|
+
}
|
|
9427
|
+
printTable(
|
|
9428
|
+
["Field", "Value"],
|
|
9429
|
+
[
|
|
9430
|
+
["ID", s.id],
|
|
9431
|
+
["Target", s.domain_or_ip],
|
|
9432
|
+
["Name", s.name],
|
|
9433
|
+
["Mode", s.scan_mode],
|
|
9434
|
+
["Schedule", formatPattern(s)],
|
|
9435
|
+
["Timezone", s.timezone],
|
|
9436
|
+
["Status", s.is_active ? "Active" : "Paused"],
|
|
9437
|
+
["Next Run", s.next_scheduled_run ?? "\u2014"],
|
|
9438
|
+
["Last Run", s.last_scheduled_run ?? "Never"],
|
|
9439
|
+
["Created", s.created_at]
|
|
9440
|
+
]
|
|
9441
|
+
);
|
|
9442
|
+
} catch (error) {
|
|
9443
|
+
handleError(error);
|
|
9444
|
+
}
|
|
9445
|
+
});
|
|
9446
|
+
schedule.command("create").description("Create a scheduled pentest").requiredOption("--asset <id>", "Asset ID to scan").requiredOption("--pattern <pattern>", "Recurrence: once, daily, weekly, biweekly, monthly").option("--name <name>", "Schedule name").option("--mode <mode>", "Scan mode: quick or full", "full").option("--time <HH:MM>", "Time of day (24h format)", "09:00").option("--day-of-week <0-6>", "Day of week (0=Sun..6=Sat) for weekly/biweekly").option("--day-of-month <1-31>", "Day of month for monthly").option("--timezone <tz>", "Timezone (e.g. America/New_York)", Intl.DateTimeFormat().resolvedOptions().timeZone).addHelpText("after", `
|
|
9447
|
+
Examples:
|
|
9448
|
+
$ kinosec pentest schedule create --asset abc123 --pattern weekly --day-of-week 1 --time 09:00
|
|
9449
|
+
$ kinosec pentest schedule create --asset abc123 --pattern daily --mode quick --time 14:00
|
|
9450
|
+
$ kinosec pentest schedule create --asset abc123 --pattern monthly --day-of-month 15 --time 03:00 --timezone UTC`).action(async (options) => {
|
|
9451
|
+
if (!VALID_PATTERNS.includes(options.pattern)) {
|
|
9452
|
+
console.error(`Invalid pattern "${options.pattern}". Must be: ${VALID_PATTERNS.join(", ")}`);
|
|
9453
|
+
process.exit(2);
|
|
9454
|
+
}
|
|
9455
|
+
if (!VALID_MODES.includes(options.mode)) {
|
|
9456
|
+
console.error(`Invalid mode "${options.mode}". Must be: ${VALID_MODES.join(", ")}`);
|
|
9457
|
+
process.exit(2);
|
|
9458
|
+
}
|
|
9459
|
+
if ((options.pattern === "weekly" || options.pattern === "biweekly") && options.dayOfWeek === void 0) {
|
|
9460
|
+
console.error(`--day-of-week is required for ${options.pattern} schedules.`);
|
|
9461
|
+
process.exit(2);
|
|
9462
|
+
}
|
|
9463
|
+
if (options.pattern === "monthly" && options.dayOfMonth === void 0) {
|
|
9464
|
+
console.error("--day-of-month is required for monthly schedules.");
|
|
9465
|
+
process.exit(2);
|
|
9466
|
+
}
|
|
9467
|
+
try {
|
|
9468
|
+
const opts = schedule.parent.parent.opts();
|
|
9469
|
+
const { token, apiUrl } = resolveToken(opts);
|
|
9470
|
+
const client = new KinoSecClient({ apiUrl, token });
|
|
9471
|
+
const params = {
|
|
9472
|
+
asset_id: options.domain_or_ip,
|
|
9473
|
+
name: options.name ?? `${options.pattern} ${options.mode} pentest`,
|
|
9474
|
+
scan_mode: options.mode,
|
|
9475
|
+
recurrence_pattern: options.pattern,
|
|
9476
|
+
time_of_day: options.time,
|
|
9477
|
+
timezone: options.timezone
|
|
9478
|
+
};
|
|
9479
|
+
if (options.dayOfWeek !== void 0) params.day_of_week = parseInt(options.dayOfWeek, 10);
|
|
9480
|
+
if (options.dayOfMonth !== void 0) params.day_of_month = parseInt(options.dayOfMonth, 10);
|
|
9481
|
+
const s = await client.schedules.create(params);
|
|
9482
|
+
if (opts.json || opts.output === "json") {
|
|
9483
|
+
printJson(s);
|
|
9484
|
+
return;
|
|
9485
|
+
}
|
|
9486
|
+
printSuccess(`Schedule created: ${s.domain_or_ip}`);
|
|
9487
|
+
console.log(` ID: ${s.id}`);
|
|
9488
|
+
console.log(` Schedule: ${formatPattern(s)}`);
|
|
9489
|
+
console.log(` Next run: ${s.next_scheduled_run ?? "pending"}`);
|
|
9490
|
+
console.log(`
|
|
9491
|
+
Manage: kinosec pentest schedule get ${s.id}`);
|
|
9492
|
+
} catch (error) {
|
|
9493
|
+
handleError(error);
|
|
9494
|
+
}
|
|
9495
|
+
});
|
|
9496
|
+
schedule.command("update").description("Update a schedule").argument("<id>", "Schedule ID").option("--pattern <pattern>", "Recurrence: once, daily, weekly, biweekly, monthly").option("--name <name>", "Schedule name").option("--mode <mode>", "Scan mode: quick or full").option("--time <HH:MM>", "Time of day (24h format)").option("--day-of-week <0-6>", "Day of week (0=Sun..6=Sat)").option("--day-of-month <1-31>", "Day of month").option("--timezone <tz>", "Timezone").addHelpText("after", `
|
|
9497
|
+
Examples:
|
|
9498
|
+
$ kinosec pentest schedule update abc123 --pattern daily --time 14:00
|
|
9499
|
+
$ kinosec pentest schedule update abc123 --mode quick`).action(async (id, options) => {
|
|
9500
|
+
const params = {};
|
|
9501
|
+
if (options.pattern) params.recurrence_pattern = options.pattern;
|
|
9502
|
+
if (options.name) params.name = options.name;
|
|
9503
|
+
if (options.mode) params.scan_mode = options.mode;
|
|
9504
|
+
if (options.time) params.time_of_day = options.time;
|
|
9505
|
+
if (options.dayOfWeek !== void 0) params.day_of_week = parseInt(options.dayOfWeek, 10);
|
|
9506
|
+
if (options.dayOfMonth !== void 0) params.day_of_month = parseInt(options.dayOfMonth, 10);
|
|
9507
|
+
if (options.timezone) params.timezone = options.timezone;
|
|
9508
|
+
if (Object.keys(params).length === 0) {
|
|
9509
|
+
console.error("Provide at least one field to update.");
|
|
9510
|
+
process.exit(2);
|
|
9511
|
+
}
|
|
9512
|
+
try {
|
|
9513
|
+
const opts = schedule.parent.parent.opts();
|
|
9514
|
+
const { token, apiUrl } = resolveToken(opts);
|
|
9515
|
+
const client = new KinoSecClient({ apiUrl, token });
|
|
9516
|
+
const s = await client.schedules.update(id, params);
|
|
9517
|
+
if (opts.json || opts.output === "json") {
|
|
9518
|
+
printJson(s);
|
|
9519
|
+
return;
|
|
9520
|
+
}
|
|
9521
|
+
printSuccess(`Schedule updated: ${s.domain_or_ip}`);
|
|
9522
|
+
console.log(` Schedule: ${formatPattern(s)}`);
|
|
9523
|
+
console.log(` Next run: ${s.next_scheduled_run ?? "pending"}`);
|
|
9524
|
+
} catch (error) {
|
|
9525
|
+
handleError(error);
|
|
9526
|
+
}
|
|
9527
|
+
});
|
|
9528
|
+
schedule.command("delete").description("Delete a schedule").argument("<id>", "Schedule ID").option("-y, --yes", "Skip confirmation prompt").addHelpText("after", `
|
|
9529
|
+
Examples:
|
|
9530
|
+
$ kinosec pentest schedule delete abc123
|
|
9531
|
+
$ kinosec pentest schedule delete abc123 --yes`).action(async (id, options) => {
|
|
9532
|
+
try {
|
|
9533
|
+
await confirmDestructive(`Delete schedule ${id}?`, Boolean(options.yes));
|
|
9534
|
+
const opts = schedule.parent.parent.opts();
|
|
9535
|
+
const { token, apiUrl } = resolveToken(opts);
|
|
9536
|
+
const client = new KinoSecClient({ apiUrl, token });
|
|
9537
|
+
await client.schedules.delete(id);
|
|
9538
|
+
if (opts.json || opts.output === "json") {
|
|
9539
|
+
printJson({ deleted: true, id });
|
|
9540
|
+
return;
|
|
9541
|
+
}
|
|
9542
|
+
printSuccess(`Schedule ${id} deleted.`);
|
|
9543
|
+
} catch (error) {
|
|
9544
|
+
handleError(error);
|
|
9545
|
+
}
|
|
9546
|
+
});
|
|
9547
|
+
schedule.command("pause").description("Pause a scheduled pentest").argument("<id>", "Schedule ID").addHelpText("after", `
|
|
9548
|
+
Examples:
|
|
9549
|
+
$ kinosec pentest schedule pause abc123`).action(async (id) => {
|
|
9550
|
+
try {
|
|
9551
|
+
const opts = schedule.parent.parent.opts();
|
|
9552
|
+
const { token, apiUrl } = resolveToken(opts);
|
|
9553
|
+
const client = new KinoSecClient({ apiUrl, token });
|
|
9554
|
+
const result = await client.schedules.pause(id);
|
|
9555
|
+
if (opts.json || opts.output === "json") {
|
|
9556
|
+
printJson(result);
|
|
9557
|
+
return;
|
|
9558
|
+
}
|
|
9559
|
+
printSuccess("Schedule paused.");
|
|
9560
|
+
} catch (error) {
|
|
9561
|
+
handleError(error);
|
|
9562
|
+
}
|
|
9563
|
+
});
|
|
9564
|
+
schedule.command("resume").description("Resume a paused schedule").argument("<id>", "Schedule ID").addHelpText("after", `
|
|
9565
|
+
Examples:
|
|
9566
|
+
$ kinosec pentest schedule resume abc123`).action(async (id) => {
|
|
9567
|
+
try {
|
|
9568
|
+
const opts = schedule.parent.parent.opts();
|
|
9569
|
+
const { token, apiUrl } = resolveToken(opts);
|
|
9570
|
+
const client = new KinoSecClient({ apiUrl, token });
|
|
9571
|
+
const result = await client.schedules.resume(id);
|
|
9572
|
+
if (opts.json || opts.output === "json") {
|
|
9573
|
+
printJson(result);
|
|
9574
|
+
return;
|
|
9575
|
+
}
|
|
9576
|
+
printSuccess("Schedule resumed.");
|
|
9577
|
+
if (result.next_scheduled_run) {
|
|
9578
|
+
console.log(` Next run: ${new Date(result.next_scheduled_run).toLocaleString()}`);
|
|
9579
|
+
}
|
|
9580
|
+
} catch (error) {
|
|
9581
|
+
handleError(error);
|
|
9582
|
+
}
|
|
9583
|
+
});
|
|
9584
|
+
}
|
|
9585
|
+
|
|
9586
|
+
// src/lib/watch.ts
|
|
9587
|
+
var import_picocolors5 = __toESM(require_picocolors(), 1);
|
|
9588
|
+
|
|
9589
|
+
// ../../node_modules/.pnpm/is-unicode-supported@2.1.0/node_modules/is-unicode-supported/index.js
|
|
9590
|
+
import process2 from "process";
|
|
9591
|
+
function isUnicodeSupported() {
|
|
9592
|
+
const { env: env2 } = process2;
|
|
9593
|
+
const { TERM, TERM_PROGRAM } = env2;
|
|
9594
|
+
if (process2.platform !== "win32") {
|
|
9595
|
+
return TERM !== "linux";
|
|
9596
|
+
}
|
|
9597
|
+
return Boolean(env2.WT_SESSION) || Boolean(env2.TERMINUS_SUBLIME) || env2.ConEmuTask === "{cmd::Cmder}" || TERM_PROGRAM === "Terminus-Sublime" || TERM_PROGRAM === "vscode" || TERM === "xterm-256color" || TERM === "alacritty" || TERM === "rxvt-unicode" || TERM === "rxvt-unicode-256color" || env2.TERMINAL_EMULATOR === "JetBrains-JediTerm";
|
|
9598
|
+
}
|
|
9599
|
+
|
|
9286
9600
|
// ../../node_modules/.pnpm/ora@8.2.0/node_modules/ora/index.js
|
|
9287
9601
|
import process9 from "process";
|
|
9288
9602
|
|
|
@@ -9473,16 +9787,16 @@ var ansiStyles2 = assembleStyles2();
|
|
|
9473
9787
|
var ansi_styles_default2 = ansiStyles2;
|
|
9474
9788
|
|
|
9475
9789
|
// ../../node_modules/.pnpm/chalk@5.6.2/node_modules/chalk/source/vendor/supports-color/index.js
|
|
9476
|
-
import
|
|
9790
|
+
import process3 from "process";
|
|
9477
9791
|
import os from "os";
|
|
9478
9792
|
import tty from "tty";
|
|
9479
|
-
function hasFlag(flag, argv = globalThis.Deno ? globalThis.Deno.args :
|
|
9793
|
+
function hasFlag(flag, argv = globalThis.Deno ? globalThis.Deno.args : process3.argv) {
|
|
9480
9794
|
const prefix = flag.startsWith("-") ? "" : flag.length === 1 ? "-" : "--";
|
|
9481
9795
|
const position = argv.indexOf(prefix + flag);
|
|
9482
9796
|
const terminatorPosition = argv.indexOf("--");
|
|
9483
9797
|
return position !== -1 && (terminatorPosition === -1 || position < terminatorPosition);
|
|
9484
9798
|
}
|
|
9485
|
-
var { env } =
|
|
9799
|
+
var { env } = process3;
|
|
9486
9800
|
var flagForceColor;
|
|
9487
9801
|
if (hasFlag("no-color") || hasFlag("no-colors") || hasFlag("color=false") || hasFlag("color=never")) {
|
|
9488
9802
|
flagForceColor = 0;
|
|
@@ -9538,7 +9852,7 @@ function _supportsColor(haveStream, { streamIsTTY, sniffFlags = true } = {}) {
|
|
|
9538
9852
|
if (env.TERM === "dumb") {
|
|
9539
9853
|
return min;
|
|
9540
9854
|
}
|
|
9541
|
-
if (
|
|
9855
|
+
if (process3.platform === "win32") {
|
|
9542
9856
|
const osRelease = os.release().split(".");
|
|
9543
9857
|
if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) {
|
|
9544
9858
|
return Number(osRelease[2]) >= 14931 ? 3 : 2;
|
|
@@ -9782,10 +10096,10 @@ var chalkStderr = createChalk({ level: stderrColor ? stderrColor.level : 0 });
|
|
|
9782
10096
|
var source_default = chalk;
|
|
9783
10097
|
|
|
9784
10098
|
// ../../node_modules/.pnpm/cli-cursor@5.0.0/node_modules/cli-cursor/index.js
|
|
9785
|
-
import
|
|
10099
|
+
import process6 from "process";
|
|
9786
10100
|
|
|
9787
10101
|
// ../../node_modules/.pnpm/restore-cursor@5.1.0/node_modules/restore-cursor/index.js
|
|
9788
|
-
import
|
|
10102
|
+
import process5 from "process";
|
|
9789
10103
|
|
|
9790
10104
|
// ../../node_modules/.pnpm/mimic-function@5.0.1/node_modules/mimic-function/index.js
|
|
9791
10105
|
var copyProperty = (to, from, property, ignoreNonConfigurable) => {
|
|
@@ -9974,7 +10288,7 @@ var SignalExit = class extends SignalExitBase {
|
|
|
9974
10288
|
// "SIGHUP" throws an `ENOSYS` error on Windows,
|
|
9975
10289
|
// so use a supported signal instead
|
|
9976
10290
|
/* c8 ignore start */
|
|
9977
|
-
#hupSig =
|
|
10291
|
+
#hupSig = process4.platform === "win32" ? "SIGINT" : "SIGHUP";
|
|
9978
10292
|
/* c8 ignore stop */
|
|
9979
10293
|
#emitter = new Emitter();
|
|
9980
10294
|
#process;
|
|
@@ -10085,7 +10399,7 @@ var SignalExit = class extends SignalExitBase {
|
|
|
10085
10399
|
}
|
|
10086
10400
|
}
|
|
10087
10401
|
};
|
|
10088
|
-
var
|
|
10402
|
+
var process4 = globalThis.process;
|
|
10089
10403
|
var {
|
|
10090
10404
|
/**
|
|
10091
10405
|
* Called when the process is exiting, whether via signal, explicit
|
|
@@ -10113,10 +10427,10 @@ var {
|
|
|
10113
10427
|
* @internal
|
|
10114
10428
|
*/
|
|
10115
10429
|
unload
|
|
10116
|
-
} = signalExitWrap(processOk(
|
|
10430
|
+
} = signalExitWrap(processOk(process4) ? new SignalExit(process4) : new SignalExitFallback());
|
|
10117
10431
|
|
|
10118
10432
|
// ../../node_modules/.pnpm/restore-cursor@5.1.0/node_modules/restore-cursor/index.js
|
|
10119
|
-
var terminal =
|
|
10433
|
+
var terminal = process5.stderr.isTTY ? process5.stderr : process5.stdout.isTTY ? process5.stdout : void 0;
|
|
10120
10434
|
var restoreCursor = terminal ? onetime_default(() => {
|
|
10121
10435
|
onExit(() => {
|
|
10122
10436
|
terminal.write("\x1B[?25h");
|
|
@@ -10128,14 +10442,14 @@ var restore_cursor_default = restoreCursor;
|
|
|
10128
10442
|
// ../../node_modules/.pnpm/cli-cursor@5.0.0/node_modules/cli-cursor/index.js
|
|
10129
10443
|
var isHidden = false;
|
|
10130
10444
|
var cliCursor = {};
|
|
10131
|
-
cliCursor.show = (writableStream =
|
|
10445
|
+
cliCursor.show = (writableStream = process6.stderr) => {
|
|
10132
10446
|
if (!writableStream.isTTY) {
|
|
10133
10447
|
return;
|
|
10134
10448
|
}
|
|
10135
10449
|
isHidden = false;
|
|
10136
10450
|
writableStream.write("\x1B[?25h");
|
|
10137
10451
|
};
|
|
10138
|
-
cliCursor.hide = (writableStream =
|
|
10452
|
+
cliCursor.hide = (writableStream = process6.stderr) => {
|
|
10139
10453
|
if (!writableStream.isTTY) {
|
|
10140
10454
|
return;
|
|
10141
10455
|
}
|
|
@@ -10159,12 +10473,12 @@ var cli_cursor_default = cliCursor;
|
|
|
10159
10473
|
var import_cli_spinners = __toESM(require_cli_spinners(), 1);
|
|
10160
10474
|
|
|
10161
10475
|
// ../../node_modules/.pnpm/is-unicode-supported@1.3.0/node_modules/is-unicode-supported/index.js
|
|
10162
|
-
import
|
|
10163
|
-
function
|
|
10164
|
-
if (
|
|
10165
|
-
return
|
|
10476
|
+
import process7 from "process";
|
|
10477
|
+
function isUnicodeSupported2() {
|
|
10478
|
+
if (process7.platform !== "win32") {
|
|
10479
|
+
return process7.env.TERM !== "linux";
|
|
10166
10480
|
}
|
|
10167
|
-
return Boolean(
|
|
10481
|
+
return Boolean(process7.env.CI) || Boolean(process7.env.WT_SESSION) || Boolean(process7.env.TERMINUS_SUBLIME) || process7.env.ConEmuTask === "{cmd::Cmder}" || process7.env.TERM_PROGRAM === "Terminus-Sublime" || process7.env.TERM_PROGRAM === "vscode" || process7.env.TERM === "xterm-256color" || process7.env.TERM === "alacritty" || process7.env.TERMINAL_EMULATOR === "JetBrains-JediTerm";
|
|
10168
10482
|
}
|
|
10169
10483
|
|
|
10170
10484
|
// ../../node_modules/.pnpm/log-symbols@6.0.0/node_modules/log-symbols/index.js
|
|
@@ -10180,7 +10494,7 @@ var fallback = {
|
|
|
10180
10494
|
warning: source_default.yellow("\u203C"),
|
|
10181
10495
|
error: source_default.red("\xD7")
|
|
10182
10496
|
};
|
|
10183
|
-
var logSymbols =
|
|
10497
|
+
var logSymbols = isUnicodeSupported2() ? main : fallback;
|
|
10184
10498
|
var log_symbols_default = logSymbols;
|
|
10185
10499
|
|
|
10186
10500
|
// ../../node_modules/.pnpm/emoji-regex@10.6.0/node_modules/emoji-regex/index.mjs
|
|
@@ -10243,17 +10557,6 @@ function isInteractive({ stream = process.stdout } = {}) {
|
|
|
10243
10557
|
);
|
|
10244
10558
|
}
|
|
10245
10559
|
|
|
10246
|
-
// ../../node_modules/.pnpm/is-unicode-supported@2.1.0/node_modules/is-unicode-supported/index.js
|
|
10247
|
-
import process7 from "process";
|
|
10248
|
-
function isUnicodeSupported2() {
|
|
10249
|
-
const { env: env2 } = process7;
|
|
10250
|
-
const { TERM, TERM_PROGRAM } = env2;
|
|
10251
|
-
if (process7.platform !== "win32") {
|
|
10252
|
-
return TERM !== "linux";
|
|
10253
|
-
}
|
|
10254
|
-
return Boolean(env2.WT_SESSION) || Boolean(env2.TERMINUS_SUBLIME) || env2.ConEmuTask === "{cmd::Cmder}" || TERM_PROGRAM === "Terminus-Sublime" || TERM_PROGRAM === "vscode" || TERM === "xterm-256color" || TERM === "alacritty" || TERM === "rxvt-unicode" || TERM === "rxvt-unicode-256color" || env2.TERMINAL_EMULATOR === "JetBrains-JediTerm";
|
|
10255
|
-
}
|
|
10256
|
-
|
|
10257
10560
|
// ../../node_modules/.pnpm/stdin-discarder@0.2.2/node_modules/stdin-discarder/index.js
|
|
10258
10561
|
import process8 from "process";
|
|
10259
10562
|
var ASCII_ETX_CODE = 3;
|
|
@@ -10389,7 +10692,7 @@ var Ora = class {
|
|
|
10389
10692
|
throw new Error("The given spinner must have a `frames` property");
|
|
10390
10693
|
}
|
|
10391
10694
|
this.#spinner = spinner;
|
|
10392
|
-
} else if (!
|
|
10695
|
+
} else if (!isUnicodeSupported()) {
|
|
10393
10696
|
this.#spinner = import_cli_spinners.default.line;
|
|
10394
10697
|
} else if (spinner === void 0) {
|
|
10395
10698
|
this.#spinner = import_cli_spinners.default.dots;
|
|
@@ -10509,386 +10812,242 @@ var Ora = class {
|
|
|
10509
10812
|
}
|
|
10510
10813
|
this.clear();
|
|
10511
10814
|
this.#stream.write(this.frame());
|
|
10512
|
-
this.#linesToClear = this.#lineCount;
|
|
10513
|
-
return this;
|
|
10514
|
-
}
|
|
10515
|
-
start(text) {
|
|
10516
|
-
if (text) {
|
|
10517
|
-
this.text = text;
|
|
10518
|
-
}
|
|
10519
|
-
if (this.#isSilent) {
|
|
10520
|
-
return this;
|
|
10521
|
-
}
|
|
10522
|
-
if (!this.#isEnabled) {
|
|
10523
|
-
if (this.text) {
|
|
10524
|
-
this.#stream.write(`- ${this.text}
|
|
10525
|
-
`);
|
|
10526
|
-
}
|
|
10527
|
-
return this;
|
|
10528
|
-
}
|
|
10529
|
-
if (this.isSpinning) {
|
|
10530
|
-
return this;
|
|
10531
|
-
}
|
|
10532
|
-
if (this.#options.hideCursor) {
|
|
10533
|
-
cli_cursor_default.hide(this.#stream);
|
|
10534
|
-
}
|
|
10535
|
-
if (this.#options.discardStdin && process9.stdin.isTTY) {
|
|
10536
|
-
this.#isDiscardingStdin = true;
|
|
10537
|
-
stdin_discarder_default.start();
|
|
10538
|
-
}
|
|
10539
|
-
this.render();
|
|
10540
|
-
this.#id = setInterval(this.render.bind(this), this.interval);
|
|
10541
|
-
return this;
|
|
10542
|
-
}
|
|
10543
|
-
stop() {
|
|
10544
|
-
if (!this.#isEnabled) {
|
|
10545
|
-
return this;
|
|
10546
|
-
}
|
|
10547
|
-
clearInterval(this.#id);
|
|
10548
|
-
this.#id = void 0;
|
|
10549
|
-
this.#frameIndex = 0;
|
|
10550
|
-
this.clear();
|
|
10551
|
-
if (this.#options.hideCursor) {
|
|
10552
|
-
cli_cursor_default.show(this.#stream);
|
|
10553
|
-
}
|
|
10554
|
-
if (this.#options.discardStdin && process9.stdin.isTTY && this.#isDiscardingStdin) {
|
|
10555
|
-
stdin_discarder_default.stop();
|
|
10556
|
-
this.#isDiscardingStdin = false;
|
|
10557
|
-
}
|
|
10558
|
-
return this;
|
|
10559
|
-
}
|
|
10560
|
-
succeed(text) {
|
|
10561
|
-
return this.stopAndPersist({ symbol: log_symbols_default.success, text });
|
|
10562
|
-
}
|
|
10563
|
-
fail(text) {
|
|
10564
|
-
return this.stopAndPersist({ symbol: log_symbols_default.error, text });
|
|
10565
|
-
}
|
|
10566
|
-
warn(text) {
|
|
10567
|
-
return this.stopAndPersist({ symbol: log_symbols_default.warning, text });
|
|
10568
|
-
}
|
|
10569
|
-
info(text) {
|
|
10570
|
-
return this.stopAndPersist({ symbol: log_symbols_default.info, text });
|
|
10571
|
-
}
|
|
10572
|
-
stopAndPersist(options = {}) {
|
|
10573
|
-
if (this.#isSilent) {
|
|
10574
|
-
return this;
|
|
10575
|
-
}
|
|
10576
|
-
const prefixText = options.prefixText ?? this.#prefixText;
|
|
10577
|
-
const fullPrefixText = this.#getFullPrefixText(prefixText, " ");
|
|
10578
|
-
const symbolText = options.symbol ?? " ";
|
|
10579
|
-
const text = options.text ?? this.text;
|
|
10580
|
-
const separatorText = symbolText ? " " : "";
|
|
10581
|
-
const fullText = typeof text === "string" ? separatorText + text : "";
|
|
10582
|
-
const suffixText = options.suffixText ?? this.#suffixText;
|
|
10583
|
-
const fullSuffixText = this.#getFullSuffixText(suffixText, " ");
|
|
10584
|
-
const textToWrite = fullPrefixText + symbolText + fullText + fullSuffixText + "\n";
|
|
10585
|
-
this.stop();
|
|
10586
|
-
this.#stream.write(textToWrite);
|
|
10587
|
-
return this;
|
|
10588
|
-
}
|
|
10589
|
-
};
|
|
10590
|
-
function ora(options) {
|
|
10591
|
-
return new Ora(options);
|
|
10592
|
-
}
|
|
10593
|
-
|
|
10594
|
-
// src/commands/pentest.ts
|
|
10595
|
-
var import_picocolors5 = __toESM(require_picocolors(), 1);
|
|
10596
|
-
|
|
10597
|
-
// src/lib/confirm.ts
|
|
10598
|
-
var import_picocolors3 = __toESM(require_picocolors(), 1);
|
|
10599
|
-
import { createInterface } from "readline";
|
|
10600
|
-
async function confirmDestructive(message, yes) {
|
|
10601
|
-
if (yes) return;
|
|
10602
|
-
if (!isTTY()) {
|
|
10603
|
-
console.error("Use --yes to confirm destructive operations in non-interactive mode.");
|
|
10604
|
-
process.exit(2);
|
|
10605
|
-
}
|
|
10606
|
-
const rl = createInterface({ input: process.stdin, output: process.stderr });
|
|
10607
|
-
const answer = await new Promise((resolve) => {
|
|
10608
|
-
rl.question(`${message} (y/N) `, resolve);
|
|
10609
|
-
});
|
|
10610
|
-
rl.close();
|
|
10611
|
-
if (answer.toLowerCase() !== "y") {
|
|
10612
|
-
console.log("Cancelled.");
|
|
10613
|
-
process.exit(0);
|
|
10614
|
-
}
|
|
10615
|
-
}
|
|
10616
|
-
async function confirmAuthorization(target, yes) {
|
|
10617
|
-
if (yes) return;
|
|
10618
|
-
if (!isTTY()) {
|
|
10619
|
-
console.error("Use --yes to accept authorization terms in non-interactive mode.");
|
|
10620
|
-
process.exit(2);
|
|
10621
|
-
}
|
|
10622
|
-
const warning = import_picocolors3.default.yellow("\u26A0");
|
|
10623
|
-
console.error(`
|
|
10624
|
-
${warning} ${import_picocolors3.default.bold("Authorization Required")}
|
|
10625
|
-
|
|
10626
|
-
Penetration testing without proper authorization is illegal
|
|
10627
|
-
and may result in criminal prosecution.
|
|
10628
|
-
|
|
10629
|
-
${import_picocolors3.default.bold("Target:")} ${target}
|
|
10630
|
-
|
|
10631
|
-
By proceeding, you confirm that:
|
|
10632
|
-
${import_picocolors3.default.dim("\u2022")} You own or have explicit written authorization to test this target
|
|
10633
|
-
${import_picocolors3.default.dim("\u2022")} You will comply with all applicable laws and regulations
|
|
10634
|
-
${import_picocolors3.default.dim("\u2022")} You will not use the results for illegal or malicious purposes
|
|
10635
|
-
${import_picocolors3.default.dim("\u2022")} You accept full legal responsibility for this pentest
|
|
10636
|
-
|
|
10637
|
-
${import_picocolors3.default.dim("Unauthorized access to computer systems is a criminal offense under")}
|
|
10638
|
-
${import_picocolors3.default.dim("laws such as the CFAA (US), Computer Misuse Act (UK), and similar")}
|
|
10639
|
-
${import_picocolors3.default.dim("legislation worldwide. KinoSec bears no liability for unauthorized")}
|
|
10640
|
-
${import_picocolors3.default.dim("use of its services.")}
|
|
10641
|
-
`);
|
|
10642
|
-
const rl = createInterface({ input: process.stdin, output: process.stderr });
|
|
10643
|
-
const answer = await new Promise((resolve) => {
|
|
10644
|
-
rl.question("Agree and continue? (y/N) ", resolve);
|
|
10645
|
-
});
|
|
10646
|
-
rl.close();
|
|
10647
|
-
if (answer.toLowerCase() !== "y") {
|
|
10648
|
-
console.log("Cancelled.");
|
|
10649
|
-
process.exit(0);
|
|
10650
|
-
}
|
|
10651
|
-
}
|
|
10652
|
-
|
|
10653
|
-
// src/commands/schedule.ts
|
|
10654
|
-
var import_picocolors4 = __toESM(require_picocolors(), 1);
|
|
10655
|
-
var VALID_PATTERNS = ["once", "daily", "weekly", "biweekly", "monthly"];
|
|
10656
|
-
var VALID_MODES = ["quick", "full"];
|
|
10657
|
-
var DAY_NAMES = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
|
|
10658
|
-
function extractTime(scheduledAt) {
|
|
10659
|
-
if (!scheduledAt) return "\u2014";
|
|
10660
|
-
const d = new Date(scheduledAt);
|
|
10661
|
-
return d.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit", hour12: false });
|
|
10662
|
-
}
|
|
10663
|
-
function formatPattern(s) {
|
|
10664
|
-
const time = extractTime(s.scheduled_at);
|
|
10665
|
-
switch (s.recurrence_pattern) {
|
|
10666
|
-
case "once":
|
|
10667
|
-
return `Once at ${time}`;
|
|
10668
|
-
case "daily":
|
|
10669
|
-
return `Daily at ${time}`;
|
|
10670
|
-
case "weekly":
|
|
10671
|
-
return `Weekly ${s.day_of_week !== null ? DAY_NAMES[s.day_of_week] : ""} at ${time}`;
|
|
10672
|
-
case "biweekly":
|
|
10673
|
-
return `Every 2 weeks ${s.day_of_week !== null ? DAY_NAMES[s.day_of_week] : ""} at ${time}`;
|
|
10674
|
-
case "monthly":
|
|
10675
|
-
return `Monthly day ${s.day_of_month ?? "?"} at ${time}`;
|
|
10676
|
-
default:
|
|
10677
|
-
return s.recurrence_pattern;
|
|
10678
|
-
}
|
|
10679
|
-
}
|
|
10680
|
-
function registerScheduleCommand(pentestCmd) {
|
|
10681
|
-
const schedule = pentestCmd.command("schedule").description("Manage scheduled pentests");
|
|
10682
|
-
schedule.command("list").description("List scheduled pentests").option("--limit <n>", "Max results per page", "20").option("--cursor <cursor>", "Pagination cursor").option("--status <status>", "Filter: active, paused, or all", "all").addHelpText("after", `
|
|
10683
|
-
Examples:
|
|
10684
|
-
$ kinosec pentest schedule list
|
|
10685
|
-
$ kinosec pentest schedule list --status active --json`).action(async (options) => {
|
|
10686
|
-
try {
|
|
10687
|
-
const opts = schedule.parent.parent.opts();
|
|
10688
|
-
const { token, apiUrl } = resolveToken(opts);
|
|
10689
|
-
const client = new KinoSecClient({ apiUrl, token });
|
|
10690
|
-
const result = await client.schedules.list({
|
|
10691
|
-
limit: parseInt(options.limit, 10),
|
|
10692
|
-
cursor: options.cursor,
|
|
10693
|
-
status: options.status
|
|
10694
|
-
});
|
|
10695
|
-
if (opts.json || opts.output === "json") {
|
|
10696
|
-
printJson(result);
|
|
10697
|
-
return;
|
|
10698
|
-
}
|
|
10699
|
-
if (result.items.length === 0) {
|
|
10700
|
-
console.log("No scheduled pentests found.");
|
|
10701
|
-
return;
|
|
10702
|
-
}
|
|
10703
|
-
printTable(
|
|
10704
|
-
["ID", "Target", "Mode", "Schedule", "Status", "Next Run"],
|
|
10705
|
-
result.items.map((s) => [
|
|
10706
|
-
s.id,
|
|
10707
|
-
truncate(s.domain_or_ip, 25),
|
|
10708
|
-
s.scan_mode,
|
|
10709
|
-
formatPattern(s),
|
|
10710
|
-
s.is_active ? import_picocolors4.default.green("active") : import_picocolors4.default.yellow("paused"),
|
|
10711
|
-
s.next_scheduled_run ? new Date(s.next_scheduled_run).toLocaleString() : "\u2014"
|
|
10712
|
-
])
|
|
10713
|
-
);
|
|
10714
|
-
if (result.next_cursor) {
|
|
10715
|
-
console.log(import_picocolors4.default.dim(`
|
|
10716
|
-
More results available. Use --cursor ${result.next_cursor}`));
|
|
10717
|
-
}
|
|
10718
|
-
} catch (error) {
|
|
10719
|
-
handleError(error);
|
|
10720
|
-
}
|
|
10721
|
-
});
|
|
10722
|
-
schedule.command("get").description("Get schedule details").argument("<id>", "Schedule ID").addHelpText("after", `
|
|
10723
|
-
Examples:
|
|
10724
|
-
$ kinosec pentest schedule get abc123
|
|
10725
|
-
$ kinosec pentest schedule get abc123 --json`).action(async (id) => {
|
|
10726
|
-
try {
|
|
10727
|
-
const opts = schedule.parent.parent.opts();
|
|
10728
|
-
const { token, apiUrl } = resolveToken(opts);
|
|
10729
|
-
const client = new KinoSecClient({ apiUrl, token });
|
|
10730
|
-
const s = await client.schedules.get(id);
|
|
10731
|
-
if (opts.json || opts.output === "json") {
|
|
10732
|
-
printJson(s);
|
|
10733
|
-
return;
|
|
10734
|
-
}
|
|
10735
|
-
printTable(
|
|
10736
|
-
["Field", "Value"],
|
|
10737
|
-
[
|
|
10738
|
-
["ID", s.id],
|
|
10739
|
-
["Target", s.domain_or_ip],
|
|
10740
|
-
["Name", s.name],
|
|
10741
|
-
["Mode", s.scan_mode],
|
|
10742
|
-
["Schedule", formatPattern(s)],
|
|
10743
|
-
["Timezone", s.timezone],
|
|
10744
|
-
["Status", s.is_active ? "Active" : "Paused"],
|
|
10745
|
-
["Next Run", s.next_scheduled_run ?? "\u2014"],
|
|
10746
|
-
["Last Run", s.last_scheduled_run ?? "Never"],
|
|
10747
|
-
["Created", s.created_at]
|
|
10748
|
-
]
|
|
10749
|
-
);
|
|
10750
|
-
} catch (error) {
|
|
10751
|
-
handleError(error);
|
|
10815
|
+
this.#linesToClear = this.#lineCount;
|
|
10816
|
+
return this;
|
|
10817
|
+
}
|
|
10818
|
+
start(text) {
|
|
10819
|
+
if (text) {
|
|
10820
|
+
this.text = text;
|
|
10752
10821
|
}
|
|
10753
|
-
|
|
10754
|
-
|
|
10755
|
-
Examples:
|
|
10756
|
-
$ kinosec pentest schedule create --asset abc123 --pattern weekly --day-of-week 1 --time 09:00
|
|
10757
|
-
$ kinosec pentest schedule create --asset abc123 --pattern daily --mode quick --time 14:00
|
|
10758
|
-
$ kinosec pentest schedule create --asset abc123 --pattern monthly --day-of-month 15 --time 03:00 --timezone UTC`).action(async (options) => {
|
|
10759
|
-
if (!VALID_PATTERNS.includes(options.pattern)) {
|
|
10760
|
-
console.error(`Invalid pattern "${options.pattern}". Must be: ${VALID_PATTERNS.join(", ")}`);
|
|
10761
|
-
process.exit(2);
|
|
10822
|
+
if (this.#isSilent) {
|
|
10823
|
+
return this;
|
|
10762
10824
|
}
|
|
10763
|
-
if (!
|
|
10764
|
-
|
|
10765
|
-
|
|
10825
|
+
if (!this.#isEnabled) {
|
|
10826
|
+
if (this.text) {
|
|
10827
|
+
this.#stream.write(`- ${this.text}
|
|
10828
|
+
`);
|
|
10829
|
+
}
|
|
10830
|
+
return this;
|
|
10766
10831
|
}
|
|
10767
|
-
if (
|
|
10768
|
-
|
|
10769
|
-
process.exit(2);
|
|
10832
|
+
if (this.isSpinning) {
|
|
10833
|
+
return this;
|
|
10770
10834
|
}
|
|
10771
|
-
if (options.
|
|
10772
|
-
|
|
10773
|
-
process.exit(2);
|
|
10835
|
+
if (this.#options.hideCursor) {
|
|
10836
|
+
cli_cursor_default.hide(this.#stream);
|
|
10774
10837
|
}
|
|
10775
|
-
|
|
10776
|
-
|
|
10777
|
-
|
|
10778
|
-
const client = new KinoSecClient({ apiUrl, token });
|
|
10779
|
-
const params = {
|
|
10780
|
-
asset_id: options.domain_or_ip,
|
|
10781
|
-
name: options.name ?? `${options.pattern} ${options.mode} pentest`,
|
|
10782
|
-
scan_mode: options.mode,
|
|
10783
|
-
recurrence_pattern: options.pattern,
|
|
10784
|
-
time_of_day: options.time,
|
|
10785
|
-
timezone: options.timezone
|
|
10786
|
-
};
|
|
10787
|
-
if (options.dayOfWeek !== void 0) params.day_of_week = parseInt(options.dayOfWeek, 10);
|
|
10788
|
-
if (options.dayOfMonth !== void 0) params.day_of_month = parseInt(options.dayOfMonth, 10);
|
|
10789
|
-
const s = await client.schedules.create(params);
|
|
10790
|
-
if (opts.json || opts.output === "json") {
|
|
10791
|
-
printJson(s);
|
|
10792
|
-
return;
|
|
10793
|
-
}
|
|
10794
|
-
printSuccess(`Schedule created: ${s.domain_or_ip}`);
|
|
10795
|
-
console.log(` ID: ${s.id}`);
|
|
10796
|
-
console.log(` Schedule: ${formatPattern(s)}`);
|
|
10797
|
-
console.log(` Next run: ${s.next_scheduled_run ?? "pending"}`);
|
|
10798
|
-
console.log(`
|
|
10799
|
-
Manage: kinosec pentest schedule get ${s.id}`);
|
|
10800
|
-
} catch (error) {
|
|
10801
|
-
handleError(error);
|
|
10838
|
+
if (this.#options.discardStdin && process9.stdin.isTTY) {
|
|
10839
|
+
this.#isDiscardingStdin = true;
|
|
10840
|
+
stdin_discarder_default.start();
|
|
10802
10841
|
}
|
|
10803
|
-
|
|
10804
|
-
|
|
10805
|
-
|
|
10806
|
-
|
|
10807
|
-
|
|
10808
|
-
|
|
10809
|
-
|
|
10810
|
-
if (options.name) params.name = options.name;
|
|
10811
|
-
if (options.mode) params.scan_mode = options.mode;
|
|
10812
|
-
if (options.time) params.time_of_day = options.time;
|
|
10813
|
-
if (options.dayOfWeek !== void 0) params.day_of_week = parseInt(options.dayOfWeek, 10);
|
|
10814
|
-
if (options.dayOfMonth !== void 0) params.day_of_month = parseInt(options.dayOfMonth, 10);
|
|
10815
|
-
if (options.timezone) params.timezone = options.timezone;
|
|
10816
|
-
if (Object.keys(params).length === 0) {
|
|
10817
|
-
console.error("Provide at least one field to update.");
|
|
10818
|
-
process.exit(2);
|
|
10842
|
+
this.render();
|
|
10843
|
+
this.#id = setInterval(this.render.bind(this), this.interval);
|
|
10844
|
+
return this;
|
|
10845
|
+
}
|
|
10846
|
+
stop() {
|
|
10847
|
+
if (!this.#isEnabled) {
|
|
10848
|
+
return this;
|
|
10819
10849
|
}
|
|
10820
|
-
|
|
10821
|
-
|
|
10822
|
-
|
|
10823
|
-
|
|
10824
|
-
|
|
10825
|
-
|
|
10826
|
-
printJson(s);
|
|
10827
|
-
return;
|
|
10828
|
-
}
|
|
10829
|
-
printSuccess(`Schedule updated: ${s.domain_or_ip}`);
|
|
10830
|
-
console.log(` Schedule: ${formatPattern(s)}`);
|
|
10831
|
-
console.log(` Next run: ${s.next_scheduled_run ?? "pending"}`);
|
|
10832
|
-
} catch (error) {
|
|
10833
|
-
handleError(error);
|
|
10850
|
+
clearInterval(this.#id);
|
|
10851
|
+
this.#id = void 0;
|
|
10852
|
+
this.#frameIndex = 0;
|
|
10853
|
+
this.clear();
|
|
10854
|
+
if (this.#options.hideCursor) {
|
|
10855
|
+
cli_cursor_default.show(this.#stream);
|
|
10834
10856
|
}
|
|
10835
|
-
|
|
10836
|
-
|
|
10837
|
-
|
|
10838
|
-
$ kinosec pentest schedule delete abc123
|
|
10839
|
-
$ kinosec pentest schedule delete abc123 --yes`).action(async (id, options) => {
|
|
10840
|
-
try {
|
|
10841
|
-
await confirmDestructive(`Delete schedule ${id}?`, Boolean(options.yes));
|
|
10842
|
-
const opts = schedule.parent.parent.opts();
|
|
10843
|
-
const { token, apiUrl } = resolveToken(opts);
|
|
10844
|
-
const client = new KinoSecClient({ apiUrl, token });
|
|
10845
|
-
await client.schedules.delete(id);
|
|
10846
|
-
if (opts.json || opts.output === "json") {
|
|
10847
|
-
printJson({ deleted: true, id });
|
|
10848
|
-
return;
|
|
10849
|
-
}
|
|
10850
|
-
printSuccess(`Schedule ${id} deleted.`);
|
|
10851
|
-
} catch (error) {
|
|
10852
|
-
handleError(error);
|
|
10857
|
+
if (this.#options.discardStdin && process9.stdin.isTTY && this.#isDiscardingStdin) {
|
|
10858
|
+
stdin_discarder_default.stop();
|
|
10859
|
+
this.#isDiscardingStdin = false;
|
|
10853
10860
|
}
|
|
10854
|
-
|
|
10855
|
-
|
|
10856
|
-
|
|
10857
|
-
|
|
10858
|
-
|
|
10859
|
-
|
|
10860
|
-
|
|
10861
|
-
|
|
10862
|
-
|
|
10863
|
-
|
|
10864
|
-
|
|
10865
|
-
|
|
10866
|
-
|
|
10867
|
-
|
|
10868
|
-
|
|
10869
|
-
|
|
10861
|
+
return this;
|
|
10862
|
+
}
|
|
10863
|
+
succeed(text) {
|
|
10864
|
+
return this.stopAndPersist({ symbol: log_symbols_default.success, text });
|
|
10865
|
+
}
|
|
10866
|
+
fail(text) {
|
|
10867
|
+
return this.stopAndPersist({ symbol: log_symbols_default.error, text });
|
|
10868
|
+
}
|
|
10869
|
+
warn(text) {
|
|
10870
|
+
return this.stopAndPersist({ symbol: log_symbols_default.warning, text });
|
|
10871
|
+
}
|
|
10872
|
+
info(text) {
|
|
10873
|
+
return this.stopAndPersist({ symbol: log_symbols_default.info, text });
|
|
10874
|
+
}
|
|
10875
|
+
stopAndPersist(options = {}) {
|
|
10876
|
+
if (this.#isSilent) {
|
|
10877
|
+
return this;
|
|
10870
10878
|
}
|
|
10879
|
+
const prefixText = options.prefixText ?? this.#prefixText;
|
|
10880
|
+
const fullPrefixText = this.#getFullPrefixText(prefixText, " ");
|
|
10881
|
+
const symbolText = options.symbol ?? " ";
|
|
10882
|
+
const text = options.text ?? this.text;
|
|
10883
|
+
const separatorText = symbolText ? " " : "";
|
|
10884
|
+
const fullText = typeof text === "string" ? separatorText + text : "";
|
|
10885
|
+
const suffixText = options.suffixText ?? this.#suffixText;
|
|
10886
|
+
const fullSuffixText = this.#getFullSuffixText(suffixText, " ");
|
|
10887
|
+
const textToWrite = fullPrefixText + symbolText + fullText + fullSuffixText + "\n";
|
|
10888
|
+
this.stop();
|
|
10889
|
+
this.#stream.write(textToWrite);
|
|
10890
|
+
return this;
|
|
10891
|
+
}
|
|
10892
|
+
};
|
|
10893
|
+
function ora(options) {
|
|
10894
|
+
return new Ora(options);
|
|
10895
|
+
}
|
|
10896
|
+
|
|
10897
|
+
// src/lib/watch.ts
|
|
10898
|
+
var UNICODE = isUnicodeSupported();
|
|
10899
|
+
var sym = {
|
|
10900
|
+
success: UNICODE ? "\u2713" : "v",
|
|
10901
|
+
fail: UNICODE ? "\u2717" : "x",
|
|
10902
|
+
warn: UNICODE ? "\u26A0" : "!",
|
|
10903
|
+
rule: UNICODE ? "\u2500" : "-"
|
|
10904
|
+
};
|
|
10905
|
+
var LABEL_WIDTH = 40;
|
|
10906
|
+
var TIMING_WIDTH = 8;
|
|
10907
|
+
function formatDuration(ms) {
|
|
10908
|
+
if (ms < 1e4) return `${(ms / 1e3).toFixed(1)}s`;
|
|
10909
|
+
if (ms < 6e4) return `${Math.round(ms / 1e3)}s`;
|
|
10910
|
+
const totalSec = Math.round(ms / 1e3);
|
|
10911
|
+
const m = Math.floor(totalSec / 60);
|
|
10912
|
+
const r = totalSec % 60;
|
|
10913
|
+
return `${m}m ${r.toString().padStart(2, "0")}s`;
|
|
10914
|
+
}
|
|
10915
|
+
function completedStepLine(label, phaseMs, totalMs) {
|
|
10916
|
+
const lbl = label.padEnd(LABEL_WIDTH);
|
|
10917
|
+
const dur = formatDuration(phaseMs).padStart(TIMING_WIDTH);
|
|
10918
|
+
const tty2 = isTTY();
|
|
10919
|
+
const total = tty2 ? import_picocolors5.default.dim(`(total ${formatDuration(totalMs)})`) : `(total ${formatDuration(totalMs)})`;
|
|
10920
|
+
const icon = tty2 ? import_picocolors5.default.green(sym.success) : sym.success;
|
|
10921
|
+
return `${icon} ${lbl}${dur} ${total}`;
|
|
10922
|
+
}
|
|
10923
|
+
function renderFindingsSummary(counts) {
|
|
10924
|
+
const levels = [
|
|
10925
|
+
{ key: "critical", label: "critical", color: import_picocolors5.default.red },
|
|
10926
|
+
{ key: "high", label: "high", color: import_picocolors5.default.yellow },
|
|
10927
|
+
{ key: "medium", label: "medium", color: (s) => import_picocolors5.default.dim(import_picocolors5.default.yellow(s)) },
|
|
10928
|
+
{ key: "low", label: "low", color: import_picocolors5.default.green },
|
|
10929
|
+
{ key: "info", label: "info", color: import_picocolors5.default.cyan }
|
|
10930
|
+
];
|
|
10931
|
+
const tty2 = isTTY();
|
|
10932
|
+
const parts = levels.map(({ key, label, color }) => {
|
|
10933
|
+
const count = findCount(counts, key);
|
|
10934
|
+
const text = `${count} ${label}`;
|
|
10935
|
+
if (!tty2) return text;
|
|
10936
|
+
return count === 0 ? import_picocolors5.default.dim(text) : color(text);
|
|
10871
10937
|
});
|
|
10872
|
-
|
|
10873
|
-
|
|
10874
|
-
|
|
10875
|
-
|
|
10876
|
-
|
|
10877
|
-
|
|
10878
|
-
|
|
10879
|
-
|
|
10880
|
-
|
|
10881
|
-
|
|
10882
|
-
|
|
10938
|
+
return parts.join(" ");
|
|
10939
|
+
}
|
|
10940
|
+
function findCount(counts, level) {
|
|
10941
|
+
const key = Object.keys(counts).find((k) => k.toLowerCase() === level);
|
|
10942
|
+
return key ? counts[key] : 0;
|
|
10943
|
+
}
|
|
10944
|
+
async function watchPentest(client, profileId, options) {
|
|
10945
|
+
const { timeoutMs, intervalMs, useJson, showFindingsSummary } = options;
|
|
10946
|
+
const tty2 = isTTY();
|
|
10947
|
+
const loopStart = Date.now();
|
|
10948
|
+
let spinner = null;
|
|
10949
|
+
let lastActivity = "";
|
|
10950
|
+
let phaseStart = Date.now();
|
|
10951
|
+
if (!useJson && tty2) {
|
|
10952
|
+
spinner = ora({ text: "Fetching pentest status...", isEnabled: true }).start();
|
|
10953
|
+
}
|
|
10954
|
+
const cleanup = () => {
|
|
10955
|
+
if (spinner) spinner.stop();
|
|
10956
|
+
};
|
|
10957
|
+
process.once("SIGINT", () => {
|
|
10958
|
+
cleanup();
|
|
10959
|
+
console.log("\nWatch cancelled. Pentest is still running.");
|
|
10960
|
+
process.exit(0);
|
|
10961
|
+
});
|
|
10962
|
+
while (true) {
|
|
10963
|
+
const scanDetail = await client.scans.get(profileId);
|
|
10964
|
+
const activity = scanDetail.current_activity || "";
|
|
10965
|
+
const totalMs = Date.now() - loopStart;
|
|
10966
|
+
const currentPhaseMs = Date.now() - phaseStart;
|
|
10967
|
+
if (useJson) {
|
|
10968
|
+
const elapsed = Math.round(totalMs / 1e3);
|
|
10969
|
+
process.stdout.write(
|
|
10970
|
+
JSON.stringify({ ...scanDetail, elapsed_seconds: elapsed }) + "\n"
|
|
10971
|
+
);
|
|
10972
|
+
} else if (spinner) {
|
|
10973
|
+
if (activity && activity !== lastActivity && lastActivity) {
|
|
10974
|
+
const phaseDuration = Date.now() - phaseStart;
|
|
10975
|
+
const line = completedStepLine(lastActivity, phaseDuration, totalMs);
|
|
10976
|
+
spinner.stopAndPersist({ symbol: "", text: line });
|
|
10977
|
+
spinner = ora({ isEnabled: true }).start();
|
|
10978
|
+
phaseStart = Date.now();
|
|
10979
|
+
}
|
|
10980
|
+
lastActivity = activity || lastActivity;
|
|
10981
|
+
const dur = formatDuration(currentPhaseMs);
|
|
10982
|
+
spinner.text = `${activity || lastActivity} ${import_picocolors5.default.dim(dur)}`;
|
|
10983
|
+
} else if (!useJson) {
|
|
10984
|
+
if (activity && activity !== lastActivity && lastActivity) {
|
|
10985
|
+
const phaseDuration = Date.now() - phaseStart;
|
|
10986
|
+
console.log(`${sym.success} ${lastActivity} ${formatDuration(phaseDuration)}`);
|
|
10987
|
+
phaseStart = Date.now();
|
|
10988
|
+
}
|
|
10989
|
+
if (activity && activity !== lastActivity) {
|
|
10990
|
+
console.log(`\u2022 ${activity}`);
|
|
10991
|
+
}
|
|
10992
|
+
lastActivity = activity || lastActivity;
|
|
10993
|
+
}
|
|
10994
|
+
const terminalStatuses = ["Completed", "Failed", "Stopped"];
|
|
10995
|
+
if (terminalStatuses.some((s) => scanDetail.scan_status.includes(s))) {
|
|
10996
|
+
cleanup();
|
|
10997
|
+
if (useJson) break;
|
|
10998
|
+
if (scanDetail.scan_status.includes("Failed")) {
|
|
10999
|
+
const icon2 = tty2 ? import_picocolors5.default.red(sym.fail) : sym.fail;
|
|
11000
|
+
const reason = scanDetail.failure_reason || "unknown reason";
|
|
11001
|
+
console.log(`
|
|
11002
|
+
${icon2} Pentest failed: ${reason}`);
|
|
11003
|
+
process.exit(1);
|
|
11004
|
+
}
|
|
11005
|
+
if (scanDetail.scan_status.includes("Stopped")) {
|
|
11006
|
+
const icon2 = tty2 ? import_picocolors5.default.yellow(sym.warn) : sym.warn;
|
|
11007
|
+
console.log(`
|
|
11008
|
+
${icon2} Pentest was cancelled.`);
|
|
11009
|
+
break;
|
|
10883
11010
|
}
|
|
10884
|
-
|
|
10885
|
-
|
|
10886
|
-
|
|
11011
|
+
const totalDur = formatDuration(Date.now() - loopStart);
|
|
11012
|
+
const domain = tty2 ? import_picocolors5.default.bold(scanDetail.domain_or_ip) : scanDetail.domain_or_ip;
|
|
11013
|
+
const icon = tty2 ? import_picocolors5.default.green(sym.success) : sym.success;
|
|
11014
|
+
const dur = tty2 ? import_picocolors5.default.dim(totalDur) : totalDur;
|
|
11015
|
+
console.log(`
|
|
11016
|
+
${icon} Pentest completed: ${domain} ${dur}`);
|
|
11017
|
+
if (showFindingsSummary) {
|
|
11018
|
+
await printFindingsSummary(client, profileId, tty2);
|
|
10887
11019
|
}
|
|
10888
|
-
|
|
10889
|
-
|
|
11020
|
+
const cmd = `kinosec finding list ${profileId}`;
|
|
11021
|
+
const viewLabel = tty2 ? import_picocolors5.default.dim("View details:") : "View details:";
|
|
11022
|
+
const viewCmd = tty2 ? import_picocolors5.default.cyan(cmd) : cmd;
|
|
11023
|
+
console.log(`
|
|
11024
|
+
${viewLabel} ${viewCmd}`);
|
|
11025
|
+
console.log();
|
|
11026
|
+
break;
|
|
10890
11027
|
}
|
|
10891
|
-
|
|
11028
|
+
if (Date.now() - loopStart > timeoutMs) {
|
|
11029
|
+
cleanup();
|
|
11030
|
+
const secs = Math.round(timeoutMs / 1e3);
|
|
11031
|
+
console.error(`
|
|
11032
|
+
Timeout: pentest still running after ${secs}s.`);
|
|
11033
|
+
console.error(`Check status: kinosec pentest get ${profileId}`);
|
|
11034
|
+
process.exit(3);
|
|
11035
|
+
}
|
|
11036
|
+
await new Promise((resolve) => setTimeout(resolve, intervalMs));
|
|
11037
|
+
}
|
|
11038
|
+
}
|
|
11039
|
+
async function printFindingsSummary(client, profileId, tty2) {
|
|
11040
|
+
try {
|
|
11041
|
+
const reports = await client.reports.list({ limit: 20 });
|
|
11042
|
+
const report = reports.items.find((r) => r.scan_profile_id === profileId);
|
|
11043
|
+
if (report?.severity_counts) {
|
|
11044
|
+
const label = tty2 ? import_picocolors5.default.dim("Findings:") : "Findings:";
|
|
11045
|
+
const summary = renderFindingsSummary(report.severity_counts);
|
|
11046
|
+
console.log(`
|
|
11047
|
+
${label} ${summary}`);
|
|
11048
|
+
}
|
|
11049
|
+
} catch {
|
|
11050
|
+
}
|
|
10892
11051
|
}
|
|
10893
11052
|
|
|
10894
11053
|
// src/commands/pentest.ts
|
|
@@ -10901,7 +11060,7 @@ function isValidDomain(value) {
|
|
|
10901
11060
|
return value.includes(".") && !/\s/.test(value);
|
|
10902
11061
|
}
|
|
10903
11062
|
function registerPentestCommand(program3) {
|
|
10904
|
-
const pentest = program3.command("pentest").description("Run and manage pentests").option("-t, --target <domain>", "Target domain to pentest").option("--profile <id>", "Pentest profile ID (alternative to --target)").option("--mode <mode>", "Pentest mode: quick or full", "full").option("-y, --yes", "Accept authorization terms without prompting").addHelpText("after", `
|
|
11063
|
+
const pentest = program3.command("pentest").description("Run and manage pentests").option("-t, --target <domain>", "Target domain to pentest").option("--profile <id>", "Pentest profile ID (alternative to --target)").option("--mode <mode>", "Pentest mode: quick or full", "full").option("-y, --yes", "Accept authorization terms without prompting").option("--no-watch", "Skip auto-watch after starting the pentest").addHelpText("after", `
|
|
10905
11064
|
Examples:
|
|
10906
11065
|
$ kinosec pentest -t delikado.org
|
|
10907
11066
|
$ kinosec pentest --target delikado.org --mode quick
|
|
@@ -10957,9 +11116,22 @@ Examples:
|
|
|
10957
11116
|
printSuccess(`Pentest started: ${result.domain_or_ip}`);
|
|
10958
11117
|
console.log(` Profile ID: ${result.scan_profile_id}`);
|
|
10959
11118
|
console.log(` Mode: ${result.scan_mode}`);
|
|
10960
|
-
|
|
10961
|
-
|
|
11119
|
+
if (!options.watch || !isTTY()) {
|
|
11120
|
+
console.log(` Status: ${result.scan_status}`);
|
|
11121
|
+
console.log(`
|
|
10962
11122
|
Watch progress: kinosec pentest watch ${result.scan_profile_id}`);
|
|
11123
|
+
return;
|
|
11124
|
+
}
|
|
11125
|
+
const divider = isTTY() ? import_picocolors6.default.dim("\u2500".repeat(37)) : "-".repeat(37);
|
|
11126
|
+
console.log(`
|
|
11127
|
+
${divider}
|
|
11128
|
+
`);
|
|
11129
|
+
await watchPentest(client, result.scan_profile_id, {
|
|
11130
|
+
timeoutMs: 1800 * 1e3,
|
|
11131
|
+
intervalMs: 5 * 1e3,
|
|
11132
|
+
useJson: false,
|
|
11133
|
+
showFindingsSummary: true
|
|
11134
|
+
});
|
|
10963
11135
|
} catch (error) {
|
|
10964
11136
|
handleError(error);
|
|
10965
11137
|
}
|
|
@@ -10996,7 +11168,7 @@ Examples:
|
|
|
10996
11168
|
])
|
|
10997
11169
|
);
|
|
10998
11170
|
if (result.next_cursor) {
|
|
10999
|
-
console.log(
|
|
11171
|
+
console.log(import_picocolors6.default.dim(`
|
|
11000
11172
|
More results available. Use --cursor ${result.next_cursor}`));
|
|
11001
11173
|
}
|
|
11002
11174
|
} catch (error) {
|
|
@@ -11059,67 +11231,12 @@ Examples:
|
|
|
11059
11231
|
const opts = program3.opts();
|
|
11060
11232
|
const { token, apiUrl } = resolveToken(opts);
|
|
11061
11233
|
const client = new KinoSecClient({ apiUrl, token });
|
|
11062
|
-
|
|
11063
|
-
|
|
11064
|
-
|
|
11065
|
-
|
|
11066
|
-
|
|
11067
|
-
let lastActivity = "";
|
|
11068
|
-
if (!useJson && isTTY()) {
|
|
11069
|
-
spinner = ora("Fetching pentest status...").start();
|
|
11070
|
-
}
|
|
11071
|
-
const cleanup = () => {
|
|
11072
|
-
if (spinner) spinner.stop();
|
|
11073
|
-
};
|
|
11074
|
-
process.once("SIGINT", () => {
|
|
11075
|
-
cleanup();
|
|
11076
|
-
console.log("\nWatch cancelled. Pentest is still running.");
|
|
11077
|
-
process.exit(0);
|
|
11234
|
+
await watchPentest(client, id, {
|
|
11235
|
+
timeoutMs: parseInt(options.timeout, 10) * 1e3,
|
|
11236
|
+
intervalMs: parseInt(options.interval, 10) * 1e3,
|
|
11237
|
+
useJson: Boolean(opts.json || opts.output === "json"),
|
|
11238
|
+
showFindingsSummary: true
|
|
11078
11239
|
});
|
|
11079
|
-
while (true) {
|
|
11080
|
-
const scanDetail = await client.scans.get(id);
|
|
11081
|
-
const elapsed = Math.round((Date.now() - startTime) / 1e3);
|
|
11082
|
-
const activity = scanDetail.current_activity || "";
|
|
11083
|
-
if (useJson) {
|
|
11084
|
-
process.stdout.write(JSON.stringify({ ...scanDetail, elapsed_seconds: elapsed }) + "\n");
|
|
11085
|
-
} else if (spinner) {
|
|
11086
|
-
if (activity && activity !== lastActivity && lastActivity) {
|
|
11087
|
-
spinner.stopAndPersist({ symbol: import_picocolors5.default.green("\u2713"), text: lastActivity });
|
|
11088
|
-
spinner = ora().start();
|
|
11089
|
-
}
|
|
11090
|
-
lastActivity = activity || lastActivity;
|
|
11091
|
-
const activitySuffix = activity ? ` \u2014 ${activity}` : "";
|
|
11092
|
-
spinner.text = `${scanDetail.domain_or_ip}${activitySuffix} \u2014 ${elapsed}s elapsed`;
|
|
11093
|
-
}
|
|
11094
|
-
const terminalStatuses = ["Completed", "Failed", "Stopped"];
|
|
11095
|
-
if (terminalStatuses.some((s) => scanDetail.scan_status.includes(s))) {
|
|
11096
|
-
cleanup();
|
|
11097
|
-
if (useJson) {
|
|
11098
|
-
break;
|
|
11099
|
-
}
|
|
11100
|
-
if (scanDetail.scan_status.includes("Failed")) {
|
|
11101
|
-
console.log(import_picocolors5.default.red(`
|
|
11102
|
-
Pentest failed: ${scanDetail.failure_reason || "unknown reason"}`));
|
|
11103
|
-
process.exit(1);
|
|
11104
|
-
}
|
|
11105
|
-
if (scanDetail.scan_status.includes("Stopped")) {
|
|
11106
|
-
console.log(import_picocolors5.default.yellow("\nPentest was cancelled."));
|
|
11107
|
-
break;
|
|
11108
|
-
}
|
|
11109
|
-
console.log(import_picocolors5.default.green(`
|
|
11110
|
-
Pentest completed: ${scanDetail.domain_or_ip}`));
|
|
11111
|
-
console.log(` View findings: kinosec finding list ${id}`);
|
|
11112
|
-
break;
|
|
11113
|
-
}
|
|
11114
|
-
if (Date.now() - startTime > timeoutMs) {
|
|
11115
|
-
cleanup();
|
|
11116
|
-
console.error(`
|
|
11117
|
-
Timeout: pentest still running after ${options.timeout}s.`);
|
|
11118
|
-
console.error(`Check status: kinosec pentest get ${id}`);
|
|
11119
|
-
process.exit(3);
|
|
11120
|
-
}
|
|
11121
|
-
await new Promise((resolve) => setTimeout(resolve, intervalMs));
|
|
11122
|
-
}
|
|
11123
11240
|
} catch (error) {
|
|
11124
11241
|
handleError(error);
|
|
11125
11242
|
}
|
|
@@ -11127,10 +11244,10 @@ Timeout: pentest still running after ${options.timeout}s.`);
|
|
|
11127
11244
|
}
|
|
11128
11245
|
|
|
11129
11246
|
// src/commands/asset.ts
|
|
11130
|
-
var
|
|
11247
|
+
var import_picocolors8 = __toESM(require_picocolors(), 1);
|
|
11131
11248
|
|
|
11132
11249
|
// src/commands/asset-auth.ts
|
|
11133
|
-
var
|
|
11250
|
+
var import_picocolors7 = __toESM(require_picocolors(), 1);
|
|
11134
11251
|
|
|
11135
11252
|
// src/lib/resolve-asset.ts
|
|
11136
11253
|
var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-/i;
|
|
@@ -11387,7 +11504,7 @@ Examples:
|
|
|
11387
11504
|
}
|
|
11388
11505
|
if (!creds.has_credentials) {
|
|
11389
11506
|
console.log(`Asset: ${asset.asset_value}`);
|
|
11390
|
-
console.log(`Auth Type: ${
|
|
11507
|
+
console.log(`Auth Type: ${import_picocolors7.default.dim("(none)")}`);
|
|
11391
11508
|
console.log(`Has Credentials: no`);
|
|
11392
11509
|
return;
|
|
11393
11510
|
}
|
|
@@ -11408,9 +11525,9 @@ Examples:
|
|
|
11408
11525
|
const hasAny = ta.has_username || ta.has_cookie || ta.has_bearer_token || ta.has_apikey;
|
|
11409
11526
|
if (hasAny) {
|
|
11410
11527
|
const detail = ta.has_username ? "username" : ta.has_bearer_token ? "bearer token" : ta.has_cookie ? "cookie" : "API key";
|
|
11411
|
-
console.log(`Target Account: ${
|
|
11528
|
+
console.log(`Target Account: ${import_picocolors7.default.green("configured")} (${detail})`);
|
|
11412
11529
|
} else {
|
|
11413
|
-
console.log(`Target Account: ${
|
|
11530
|
+
console.log(`Target Account: ${import_picocolors7.default.dim("not configured")}`);
|
|
11414
11531
|
}
|
|
11415
11532
|
}
|
|
11416
11533
|
} catch (error) {
|
|
@@ -11561,7 +11678,7 @@ Examples:
|
|
|
11561
11678
|
])
|
|
11562
11679
|
);
|
|
11563
11680
|
if (result.next_cursor) {
|
|
11564
|
-
console.log(
|
|
11681
|
+
console.log(import_picocolors8.default.dim(`
|
|
11565
11682
|
More results available. Use --cursor ${result.next_cursor}`));
|
|
11566
11683
|
}
|
|
11567
11684
|
} catch (error) {
|
|
@@ -11673,7 +11790,7 @@ Examples:
|
|
|
11673
11790
|
}
|
|
11674
11791
|
|
|
11675
11792
|
// src/commands/finding.ts
|
|
11676
|
-
var
|
|
11793
|
+
var import_picocolors9 = __toESM(require_picocolors(), 1);
|
|
11677
11794
|
function formatPoc(poc) {
|
|
11678
11795
|
if (poc == null) return null;
|
|
11679
11796
|
if (typeof poc === "string") return poc.trim() || null;
|
|
@@ -11714,7 +11831,7 @@ Examples:
|
|
|
11714
11831
|
])
|
|
11715
11832
|
);
|
|
11716
11833
|
if (result.next_cursor) {
|
|
11717
|
-
console.log(
|
|
11834
|
+
console.log(import_picocolors9.default.dim(`
|
|
11718
11835
|
More results available. Use --cursor ${result.next_cursor}`));
|
|
11719
11836
|
}
|
|
11720
11837
|
} catch (error) {
|
|
@@ -11802,7 +11919,7 @@ Examples:
|
|
|
11802
11919
|
}
|
|
11803
11920
|
|
|
11804
11921
|
// src/commands/report.ts
|
|
11805
|
-
var
|
|
11922
|
+
var import_picocolors10 = __toESM(require_picocolors(), 1);
|
|
11806
11923
|
function renderMarkdown(data) {
|
|
11807
11924
|
const { scan, findings } = data;
|
|
11808
11925
|
const lines = [];
|
|
@@ -11879,7 +11996,7 @@ Examples:
|
|
|
11879
11996
|
])
|
|
11880
11997
|
);
|
|
11881
11998
|
if (result.next_cursor) {
|
|
11882
|
-
console.log(
|
|
11999
|
+
console.log(import_picocolors10.default.dim(`
|
|
11883
12000
|
More results available. Use --cursor ${result.next_cursor}`));
|
|
11884
12001
|
}
|
|
11885
12002
|
} catch (error) {
|
|
@@ -11950,7 +12067,7 @@ Examples:
|
|
|
11950
12067
|
}
|
|
11951
12068
|
|
|
11952
12069
|
// src/commands/token.ts
|
|
11953
|
-
var
|
|
12070
|
+
var import_picocolors11 = __toESM(require_picocolors(), 1);
|
|
11954
12071
|
function registerTokenCommand(program3) {
|
|
11955
12072
|
const token = program3.command("token").description("Manage API tokens");
|
|
11956
12073
|
token.command("list").description("List API tokens").option("--limit <n>", "Max results per page", "20").option("--cursor <cursor>", "Pagination cursor").addHelpText("after", `
|
|
@@ -11985,7 +12102,7 @@ Examples:
|
|
|
11985
12102
|
])
|
|
11986
12103
|
);
|
|
11987
12104
|
if (result.next_cursor) {
|
|
11988
|
-
console.log(
|
|
12105
|
+
console.log(import_picocolors11.default.dim(`
|
|
11989
12106
|
More results available. Use --cursor ${result.next_cursor}`));
|
|
11990
12107
|
}
|
|
11991
12108
|
} catch (error) {
|
|
@@ -12012,7 +12129,7 @@ Examples:
|
|
|
12012
12129
|
}
|
|
12013
12130
|
printSuccess(`Token created: ${result.name}`);
|
|
12014
12131
|
console.log("");
|
|
12015
|
-
console.log(
|
|
12132
|
+
console.log(import_picocolors11.default.bold(" Token: ") + result.token);
|
|
12016
12133
|
console.log("");
|
|
12017
12134
|
printWarning("Save this token \u2014 it will not be shown again.");
|
|
12018
12135
|
console.log(` ID: ${result.id}`);
|
|
@@ -12045,7 +12162,7 @@ Examples:
|
|
|
12045
12162
|
|
|
12046
12163
|
// src/cli.ts
|
|
12047
12164
|
var program2 = new Command();
|
|
12048
|
-
program2.name("kinosec").description("KinoSec CLI \u2014 run pentests from your terminal").version("0.
|
|
12165
|
+
program2.name("kinosec").description("KinoSec CLI \u2014 run pentests from your terminal").version("0.6.0", "-v, --version").option("--token <pat>", "API token (overrides KINOSEC_TOKEN and config)").option("--api-url <url>", "API base URL (overrides config)").option("--output <format>", "Output format: text or json", "text").option("--json", "Shorthand for --output json").option("--no-color", "Disable colors");
|
|
12049
12166
|
registerAuthCommand(program2);
|
|
12050
12167
|
registerConfigCommand(program2);
|
|
12051
12168
|
registerMeCommand(program2);
|
|
@@ -12054,7 +12171,7 @@ registerAssetCommand(program2);
|
|
|
12054
12171
|
registerFindingCommand(program2);
|
|
12055
12172
|
registerReportCommand(program2);
|
|
12056
12173
|
registerTokenCommand(program2);
|
|
12057
|
-
program2.parseAsync(process.argv).then(() => checkForUpdate("0.
|
|
12174
|
+
program2.parseAsync(process.argv).then(() => checkForUpdate("0.6.0")).catch(handleError);
|
|
12058
12175
|
/*! Bundled license information:
|
|
12059
12176
|
|
|
12060
12177
|
ky/distribution/index.js:
|