@rozoai/checkout 0.1.5 → 0.1.7
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/package.json +1 -1
- package/scripts/dist/cli.js +293 -239
- package/scripts/dist/send-evm.js +129 -110
- package/scripts/dist/send-sol.js +132 -113
- package/docs/review-history.md +0 -77
package/scripts/dist/send-evm.js
CHANGED
|
@@ -10310,9 +10310,9 @@ function assertNoTrackedDotEnv(cwd = process.cwd()) {
|
|
|
10310
10310
|
}
|
|
10311
10311
|
|
|
10312
10312
|
// scripts/src/lib/key-source.mjs
|
|
10313
|
-
import
|
|
10314
|
-
import
|
|
10315
|
-
import
|
|
10313
|
+
import fs3 from "node:fs";
|
|
10314
|
+
import path3 from "node:path";
|
|
10315
|
+
import os2 from "node:os";
|
|
10316
10316
|
import crypto3 from "node:crypto";
|
|
10317
10317
|
|
|
10318
10318
|
// node_modules/viem/_esm/utils/getAction.js
|
|
@@ -21278,18 +21278,121 @@ function http(url, config = {}) {
|
|
|
21278
21278
|
init_encodeFunctionData();
|
|
21279
21279
|
init_keccak256();
|
|
21280
21280
|
|
|
21281
|
+
// scripts/src/lib/dotenv.mjs
|
|
21282
|
+
import fs2 from "node:fs";
|
|
21283
|
+
import os from "node:os";
|
|
21284
|
+
import path2 from "node:path";
|
|
21285
|
+
var ALLOWED_KEYS = [
|
|
21286
|
+
"ROZO_CHECKOUT_EVM_KEY",
|
|
21287
|
+
"ROZO_CHECKOUT_SOL_KEY",
|
|
21288
|
+
"ROZO_CHECKOUT_EVM_KEYSTORE",
|
|
21289
|
+
"ROZO_CHECKOUT_KEYSTORE_PASSPHRASE"
|
|
21290
|
+
];
|
|
21291
|
+
var ALLOWED_PATTERN = /^ROZO_CHECKOUT_RPC_[A-Za-z0-9_]+$/;
|
|
21292
|
+
function isAllowedKey(key) {
|
|
21293
|
+
return ALLOWED_KEYS.includes(key) || ALLOWED_PATTERN.test(key);
|
|
21294
|
+
}
|
|
21295
|
+
function parseDotenv(text) {
|
|
21296
|
+
const vars = {};
|
|
21297
|
+
const lines = String(text).split(/\r?\n/);
|
|
21298
|
+
lines.forEach((rawLine, i) => {
|
|
21299
|
+
const lineNo = i + 1;
|
|
21300
|
+
const line = rawLine.trim();
|
|
21301
|
+
if (!line || line.startsWith("#")) return;
|
|
21302
|
+
const withoutExport = line.startsWith("export ") ? line.slice(7).trim() : line;
|
|
21303
|
+
const eq = withoutExport.indexOf("=");
|
|
21304
|
+
if (eq === -1) {
|
|
21305
|
+
throw new SkillError(
|
|
21306
|
+
"BAD_ENV_FILE",
|
|
21307
|
+
`Malformed .env: line ${lineNo} is not KEY=VALUE. (Content withheld \u2014 it may be a secret.)`
|
|
21308
|
+
);
|
|
21309
|
+
}
|
|
21310
|
+
const key = withoutExport.slice(0, eq).trim();
|
|
21311
|
+
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(key)) {
|
|
21312
|
+
throw new SkillError(
|
|
21313
|
+
"BAD_ENV_FILE",
|
|
21314
|
+
`Malformed .env: line ${lineNo} has an invalid key name. (Content withheld.)`
|
|
21315
|
+
);
|
|
21316
|
+
}
|
|
21317
|
+
let value = withoutExport.slice(eq + 1).trim();
|
|
21318
|
+
if (value.length >= 2 && (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'"))) {
|
|
21319
|
+
value = value.slice(1, -1);
|
|
21320
|
+
}
|
|
21321
|
+
vars[key] = value;
|
|
21322
|
+
});
|
|
21323
|
+
return vars;
|
|
21324
|
+
}
|
|
21325
|
+
function filterAllowed(vars) {
|
|
21326
|
+
const out = {};
|
|
21327
|
+
for (const [k, v] of Object.entries(vars)) if (isAllowedKey(k)) out[k] = v;
|
|
21328
|
+
return out;
|
|
21329
|
+
}
|
|
21330
|
+
function envFileCandidates({ cwd = process.cwd(), home = os.homedir() } = {}) {
|
|
21331
|
+
const candidates = [path2.join(cwd, ".env")];
|
|
21332
|
+
const owned = path2.join(home, ".rozo-checkout", ".env");
|
|
21333
|
+
if (owned !== candidates[0]) candidates.push(owned);
|
|
21334
|
+
return candidates;
|
|
21335
|
+
}
|
|
21336
|
+
function resolveEnvFile({ file, cwd = process.cwd(), home = os.homedir() } = {}) {
|
|
21337
|
+
if (file) {
|
|
21338
|
+
const p = path2.resolve(file);
|
|
21339
|
+
if (!fs2.existsSync(p)) {
|
|
21340
|
+
throw new SkillError("ENV_FILE_MISSING", `No such env file: ${file}`);
|
|
21341
|
+
}
|
|
21342
|
+
return p;
|
|
21343
|
+
}
|
|
21344
|
+
return envFileCandidates({ cwd, home }).find((p) => fs2.existsSync(p)) ?? null;
|
|
21345
|
+
}
|
|
21346
|
+
function applyDotenv({
|
|
21347
|
+
file,
|
|
21348
|
+
cwd = process.cwd(),
|
|
21349
|
+
home = os.homedir(),
|
|
21350
|
+
env = process.env
|
|
21351
|
+
} = {}) {
|
|
21352
|
+
const target = resolveEnvFile({ file, cwd, home });
|
|
21353
|
+
if (!target) return null;
|
|
21354
|
+
let stat;
|
|
21355
|
+
try {
|
|
21356
|
+
stat = fs2.statSync(target);
|
|
21357
|
+
} catch (err) {
|
|
21358
|
+
throw new SkillError("ENV_FILE_MISSING", `Cannot read env file (${err.code || "error"}).`);
|
|
21359
|
+
}
|
|
21360
|
+
if (process.platform !== "win32" && stat.mode & 63) {
|
|
21361
|
+
const mode = (stat.mode & 511).toString(8).padStart(3, "0");
|
|
21362
|
+
throw new SkillError(
|
|
21363
|
+
"ENV_FILE_PERMISSIONS",
|
|
21364
|
+
`That .env is readable by other users (mode ${mode}). Run: chmod 600 ${target}`
|
|
21365
|
+
);
|
|
21366
|
+
}
|
|
21367
|
+
assertNotTrackedByGit(target);
|
|
21368
|
+
const parsed = parseDotenv(fs2.readFileSync(target, "utf8"));
|
|
21369
|
+
const allowed = filterAllowed(parsed);
|
|
21370
|
+
const applied = [];
|
|
21371
|
+
for (const [k, v] of Object.entries(allowed)) {
|
|
21372
|
+
const existing = env[k];
|
|
21373
|
+
if (existing !== void 0 && String(existing).trim() !== "") continue;
|
|
21374
|
+
env[k] = v;
|
|
21375
|
+
applied.push(k);
|
|
21376
|
+
}
|
|
21377
|
+
return {
|
|
21378
|
+
path: target,
|
|
21379
|
+
applied,
|
|
21380
|
+
ignored: Object.keys(parsed).length - Object.keys(allowed).length
|
|
21381
|
+
};
|
|
21382
|
+
}
|
|
21383
|
+
|
|
21281
21384
|
// scripts/src/lib/key-source.mjs
|
|
21282
21385
|
var EVM_KEY_ENV = "ROZO_CHECKOUT_EVM_KEY";
|
|
21283
21386
|
var SOL_KEY_ENV = "ROZO_CHECKOUT_SOL_KEY";
|
|
21284
21387
|
var EVM_KEYSTORE_ENV = "ROZO_CHECKOUT_EVM_KEYSTORE";
|
|
21285
21388
|
var KEYSTORE_PASSPHRASE_ENV = "ROZO_CHECKOUT_KEYSTORE_PASSPHRASE";
|
|
21286
21389
|
function defaultSolanaKeypairPath() {
|
|
21287
|
-
return
|
|
21390
|
+
return path3.join(os2.homedir(), ".config", "solana", "id.json");
|
|
21288
21391
|
}
|
|
21289
21392
|
function assertKeyfileSafe(file) {
|
|
21290
21393
|
let stat;
|
|
21291
21394
|
try {
|
|
21292
|
-
stat =
|
|
21395
|
+
stat = fs3.statSync(file);
|
|
21293
21396
|
} catch (err) {
|
|
21294
21397
|
throw new SkillError(
|
|
21295
21398
|
"KEYFILE_UNREADABLE",
|
|
@@ -21466,12 +21569,16 @@ function looksLikeKeystore(text) {
|
|
|
21466
21569
|
return false;
|
|
21467
21570
|
}
|
|
21468
21571
|
}
|
|
21469
|
-
function
|
|
21572
|
+
function searchedSuffix(searched) {
|
|
21573
|
+
if (!searched || !searched.length) return "";
|
|
21574
|
+
return ` Looked for a .env in: ${searched.map(displayPath).join(", ")}.`;
|
|
21575
|
+
}
|
|
21576
|
+
function planKeySource({ family, keyfile, env = process.env, searched }) {
|
|
21470
21577
|
if (keyfile) {
|
|
21471
21578
|
const resolved = expandHome(keyfile);
|
|
21472
21579
|
let text;
|
|
21473
21580
|
try {
|
|
21474
|
-
text =
|
|
21581
|
+
text = fs3.readFileSync(resolved, "utf8");
|
|
21475
21582
|
} catch (err) {
|
|
21476
21583
|
throw new SkillError(
|
|
21477
21584
|
"KEYFILE_UNREADABLE",
|
|
@@ -21495,13 +21602,13 @@ function planKeySource({ family, keyfile, env = process.env }) {
|
|
|
21495
21602
|
}
|
|
21496
21603
|
if (family === "solana") {
|
|
21497
21604
|
const standard = defaultSolanaKeypairPath();
|
|
21498
|
-
if (
|
|
21605
|
+
if (fs3.existsSync(standard)) {
|
|
21499
21606
|
return { kind: "keypair-file", path: standard, label: displayPath(standard) };
|
|
21500
21607
|
}
|
|
21501
21608
|
if (env[SOL_KEY_ENV]) return { kind: "env", label: SOL_KEY_ENV };
|
|
21502
21609
|
throw new SkillError(
|
|
21503
21610
|
"NO_KEY_SOURCE",
|
|
21504
|
-
`No signing key found. Either create one with solana-keygen (writes ${displayPath(standard)}), pass --keyfile <path>, or set ${SOL_KEY_ENV}.`
|
|
21611
|
+
`No signing key found. Either create one with solana-keygen (writes ${displayPath(standard)}), pass --keyfile <path>, or set ${SOL_KEY_ENV}.` + searchedSuffix(searched)
|
|
21505
21612
|
);
|
|
21506
21613
|
}
|
|
21507
21614
|
if (family === "evm") {
|
|
@@ -21513,7 +21620,7 @@ function planKeySource({ family, keyfile, env = process.env }) {
|
|
|
21513
21620
|
if (env[EVM_KEY_ENV]) return { kind: "env", label: EVM_KEY_ENV };
|
|
21514
21621
|
throw new SkillError(
|
|
21515
21622
|
"NO_KEY_SOURCE",
|
|
21516
|
-
`No signing key found. Either point ${EVM_KEYSTORE_ENV} at an encrypted JSON keystore, pass --keyfile <path>, or set ${EVM_KEY_ENV}
|
|
21623
|
+
`No signing key found. Either point ${EVM_KEYSTORE_ENV} at an encrypted JSON keystore, pass --keyfile <path>, or set ${EVM_KEY_ENV}.${searchedSuffix(searched)}`
|
|
21517
21624
|
);
|
|
21518
21625
|
}
|
|
21519
21626
|
throw new SkillError("NO_KEY_SOURCE", `No key source for family "${family}".`);
|
|
@@ -21531,7 +21638,7 @@ async function loadKeySource(plan, { family, env = process.env, askPassphrase }
|
|
|
21531
21638
|
return { secretKey: decodeSolanaEnvKey(raw), label: plan.label, kind: plan.kind };
|
|
21532
21639
|
}
|
|
21533
21640
|
assertKeyfileSafe(plan.path);
|
|
21534
|
-
const text =
|
|
21641
|
+
const text = fs3.readFileSync(plan.path, "utf8");
|
|
21535
21642
|
if (plan.kind === "keypair-file") {
|
|
21536
21643
|
return { secretKey: parseSolanaKeypairJson(text), label: plan.label, kind: plan.kind };
|
|
21537
21644
|
}
|
|
@@ -21550,106 +21657,14 @@ async function loadKeySource(plan, { family, env = process.env, askPassphrase }
|
|
|
21550
21657
|
}
|
|
21551
21658
|
function expandHome(p) {
|
|
21552
21659
|
const s = String(p);
|
|
21553
|
-
if (s === "~") return
|
|
21554
|
-
if (s.startsWith("~/")) return
|
|
21660
|
+
if (s === "~") return os2.homedir();
|
|
21661
|
+
if (s.startsWith("~/")) return path3.join(os2.homedir(), s.slice(2));
|
|
21555
21662
|
return s;
|
|
21556
21663
|
}
|
|
21557
21664
|
function displayPath(p) {
|
|
21558
|
-
const home =
|
|
21665
|
+
const home = os2.homedir();
|
|
21559
21666
|
const s = String(p);
|
|
21560
|
-
return s.startsWith(home +
|
|
21561
|
-
}
|
|
21562
|
-
|
|
21563
|
-
// scripts/src/lib/dotenv.mjs
|
|
21564
|
-
import fs3 from "node:fs";
|
|
21565
|
-
import path3 from "node:path";
|
|
21566
|
-
var ALLOWED_KEYS = [
|
|
21567
|
-
"ROZO_CHECKOUT_EVM_KEY",
|
|
21568
|
-
"ROZO_CHECKOUT_SOL_KEY",
|
|
21569
|
-
"ROZO_CHECKOUT_EVM_KEYSTORE",
|
|
21570
|
-
"ROZO_CHECKOUT_KEYSTORE_PASSPHRASE"
|
|
21571
|
-
];
|
|
21572
|
-
var ALLOWED_PATTERN = /^ROZO_CHECKOUT_RPC_[A-Za-z0-9_]+$/;
|
|
21573
|
-
function isAllowedKey(key) {
|
|
21574
|
-
return ALLOWED_KEYS.includes(key) || ALLOWED_PATTERN.test(key);
|
|
21575
|
-
}
|
|
21576
|
-
function parseDotenv(text) {
|
|
21577
|
-
const vars = {};
|
|
21578
|
-
const lines = String(text).split(/\r?\n/);
|
|
21579
|
-
lines.forEach((rawLine, i) => {
|
|
21580
|
-
const lineNo = i + 1;
|
|
21581
|
-
const line = rawLine.trim();
|
|
21582
|
-
if (!line || line.startsWith("#")) return;
|
|
21583
|
-
const withoutExport = line.startsWith("export ") ? line.slice(7).trim() : line;
|
|
21584
|
-
const eq = withoutExport.indexOf("=");
|
|
21585
|
-
if (eq === -1) {
|
|
21586
|
-
throw new SkillError(
|
|
21587
|
-
"BAD_ENV_FILE",
|
|
21588
|
-
`Malformed .env: line ${lineNo} is not KEY=VALUE. (Content withheld \u2014 it may be a secret.)`
|
|
21589
|
-
);
|
|
21590
|
-
}
|
|
21591
|
-
const key = withoutExport.slice(0, eq).trim();
|
|
21592
|
-
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(key)) {
|
|
21593
|
-
throw new SkillError(
|
|
21594
|
-
"BAD_ENV_FILE",
|
|
21595
|
-
`Malformed .env: line ${lineNo} has an invalid key name. (Content withheld.)`
|
|
21596
|
-
);
|
|
21597
|
-
}
|
|
21598
|
-
let value = withoutExport.slice(eq + 1).trim();
|
|
21599
|
-
if (value.length >= 2 && (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'"))) {
|
|
21600
|
-
value = value.slice(1, -1);
|
|
21601
|
-
}
|
|
21602
|
-
vars[key] = value;
|
|
21603
|
-
});
|
|
21604
|
-
return vars;
|
|
21605
|
-
}
|
|
21606
|
-
function filterAllowed(vars) {
|
|
21607
|
-
const out = {};
|
|
21608
|
-
for (const [k, v] of Object.entries(vars)) if (isAllowedKey(k)) out[k] = v;
|
|
21609
|
-
return out;
|
|
21610
|
-
}
|
|
21611
|
-
function resolveEnvFile({ file, cwd = process.cwd() } = {}) {
|
|
21612
|
-
if (file) {
|
|
21613
|
-
const p = path3.resolve(file);
|
|
21614
|
-
if (!fs3.existsSync(p)) {
|
|
21615
|
-
throw new SkillError("ENV_FILE_MISSING", `No such env file: ${file}`);
|
|
21616
|
-
}
|
|
21617
|
-
return p;
|
|
21618
|
-
}
|
|
21619
|
-
const fallback = path3.join(cwd, ".env");
|
|
21620
|
-
return fs3.existsSync(fallback) ? fallback : null;
|
|
21621
|
-
}
|
|
21622
|
-
function applyDotenv({ file, cwd = process.cwd(), env = process.env } = {}) {
|
|
21623
|
-
const target = resolveEnvFile({ file, cwd });
|
|
21624
|
-
if (!target) return null;
|
|
21625
|
-
let stat;
|
|
21626
|
-
try {
|
|
21627
|
-
stat = fs3.statSync(target);
|
|
21628
|
-
} catch (err) {
|
|
21629
|
-
throw new SkillError("ENV_FILE_MISSING", `Cannot read env file (${err.code || "error"}).`);
|
|
21630
|
-
}
|
|
21631
|
-
if (process.platform !== "win32" && stat.mode & 63) {
|
|
21632
|
-
const mode = (stat.mode & 511).toString(8).padStart(3, "0");
|
|
21633
|
-
throw new SkillError(
|
|
21634
|
-
"ENV_FILE_PERMISSIONS",
|
|
21635
|
-
`That .env is readable by other users (mode ${mode}). Run: chmod 600 ${target}`
|
|
21636
|
-
);
|
|
21637
|
-
}
|
|
21638
|
-
assertNotTrackedByGit(target);
|
|
21639
|
-
const parsed = parseDotenv(fs3.readFileSync(target, "utf8"));
|
|
21640
|
-
const allowed = filterAllowed(parsed);
|
|
21641
|
-
const applied = [];
|
|
21642
|
-
for (const [k, v] of Object.entries(allowed)) {
|
|
21643
|
-
const existing = env[k];
|
|
21644
|
-
if (existing !== void 0 && String(existing).trim() !== "") continue;
|
|
21645
|
-
env[k] = v;
|
|
21646
|
-
applied.push(k);
|
|
21647
|
-
}
|
|
21648
|
-
return {
|
|
21649
|
-
path: target,
|
|
21650
|
-
applied,
|
|
21651
|
-
ignored: Object.keys(parsed).length - Object.keys(allowed).length
|
|
21652
|
-
};
|
|
21667
|
+
return s.startsWith(home + path3.sep) ? `~${s.slice(home.length)}` : s;
|
|
21653
21668
|
}
|
|
21654
21669
|
|
|
21655
21670
|
// scripts/src/lib/passphrase.mjs
|
|
@@ -22215,7 +22230,7 @@ function assertNotBlacklisted(targets, blacklist) {
|
|
|
22215
22230
|
// scripts/src/lib/state.mjs
|
|
22216
22231
|
import fs5 from "node:fs";
|
|
22217
22232
|
import path5 from "node:path";
|
|
22218
|
-
import
|
|
22233
|
+
import os3 from "node:os";
|
|
22219
22234
|
import crypto5 from "node:crypto";
|
|
22220
22235
|
var LOCK_STALE_MS = 6e4;
|
|
22221
22236
|
var LOCK_WAIT_MS = 1e4;
|
|
@@ -22276,7 +22291,7 @@ function withLock(fn) {
|
|
|
22276
22291
|
}
|
|
22277
22292
|
}
|
|
22278
22293
|
function stateRoot() {
|
|
22279
|
-
return process.env.ROZO_CHECKOUT_STATE_DIR || path5.join(
|
|
22294
|
+
return process.env.ROZO_CHECKOUT_STATE_DIR || path5.join(os3.homedir(), ".rozo-checkout", "state");
|
|
22280
22295
|
}
|
|
22281
22296
|
function statePath(rozoPaymentId) {
|
|
22282
22297
|
if (!/^[A-Za-z0-9-]{8,64}$/.test(String(rozoPaymentId || ""))) {
|
|
@@ -22770,7 +22785,11 @@ async function main(argv) {
|
|
|
22770
22785
|
const rozoPaymentId = assertRozoPaymentId(args["rozo-payment-id"] || args._[0]);
|
|
22771
22786
|
assertNoTrackedDotEnv();
|
|
22772
22787
|
const dotenv = applyDotenv({ file: args["env-file"] });
|
|
22773
|
-
const plan = planKeySource({
|
|
22788
|
+
const plan = planKeySource({
|
|
22789
|
+
family: "evm",
|
|
22790
|
+
keyfile: args.keyfile,
|
|
22791
|
+
searched: args["env-file"] ? null : envFileCandidates()
|
|
22792
|
+
});
|
|
22774
22793
|
const loaded = await loadKeySource(plan, { family: "evm", askPassphrase: promptPassphrase });
|
|
22775
22794
|
const account = privateKeyToAccount(loaded.privateKey);
|
|
22776
22795
|
const sender = account.address;
|
package/scripts/dist/send-sol.js
CHANGED
|
@@ -15507,14 +15507,14 @@ var require_node_gyp_build = __commonJS({
|
|
|
15507
15507
|
"node_modules/node-gyp-build/node-gyp-build.js"(exports, module) {
|
|
15508
15508
|
var fs6 = __require("fs");
|
|
15509
15509
|
var path6 = __require("path");
|
|
15510
|
-
var
|
|
15510
|
+
var os4 = __require("os");
|
|
15511
15511
|
var runtimeRequire = typeof __webpack_require__ === "function" ? __non_webpack_require__ : __require;
|
|
15512
15512
|
var vars = process.config && process.config.variables || {};
|
|
15513
15513
|
var prebuildsOnly = !!process.env.PREBUILDS_ONLY;
|
|
15514
15514
|
var abi = process.versions.modules;
|
|
15515
15515
|
var runtime = isElectron() ? "electron" : isNwjs() ? "node-webkit" : "node";
|
|
15516
|
-
var arch = process.env.npm_config_arch ||
|
|
15517
|
-
var platform = process.env.npm_config_platform ||
|
|
15516
|
+
var arch = process.env.npm_config_arch || os4.arch();
|
|
15517
|
+
var platform = process.env.npm_config_platform || os4.platform();
|
|
15518
15518
|
var libc = process.env.LIBC || (isAlpine(platform) ? "musl" : "glibc");
|
|
15519
15519
|
var armv = process.env.ARM_VERSION || (arch === "arm64" ? "8" : vars.arm_version) || "";
|
|
15520
15520
|
var uv = (process.versions.uv || "").split(".")[0];
|
|
@@ -32455,26 +32455,129 @@ function assertNoTrackedDotEnv(cwd = process.cwd()) {
|
|
|
32455
32455
|
}
|
|
32456
32456
|
|
|
32457
32457
|
// scripts/src/lib/key-source.mjs
|
|
32458
|
-
import
|
|
32459
|
-
import
|
|
32460
|
-
import
|
|
32458
|
+
import fs3 from "node:fs";
|
|
32459
|
+
import path3 from "node:path";
|
|
32460
|
+
import os2 from "node:os";
|
|
32461
32461
|
import crypto2 from "node:crypto";
|
|
32462
32462
|
|
|
32463
32463
|
// node_modules/viem/_esm/index.js
|
|
32464
32464
|
init_keccak256();
|
|
32465
32465
|
|
|
32466
|
+
// scripts/src/lib/dotenv.mjs
|
|
32467
|
+
import fs2 from "node:fs";
|
|
32468
|
+
import os from "node:os";
|
|
32469
|
+
import path2 from "node:path";
|
|
32470
|
+
var ALLOWED_KEYS = [
|
|
32471
|
+
"ROZO_CHECKOUT_EVM_KEY",
|
|
32472
|
+
"ROZO_CHECKOUT_SOL_KEY",
|
|
32473
|
+
"ROZO_CHECKOUT_EVM_KEYSTORE",
|
|
32474
|
+
"ROZO_CHECKOUT_KEYSTORE_PASSPHRASE"
|
|
32475
|
+
];
|
|
32476
|
+
var ALLOWED_PATTERN = /^ROZO_CHECKOUT_RPC_[A-Za-z0-9_]+$/;
|
|
32477
|
+
function isAllowedKey(key) {
|
|
32478
|
+
return ALLOWED_KEYS.includes(key) || ALLOWED_PATTERN.test(key);
|
|
32479
|
+
}
|
|
32480
|
+
function parseDotenv(text) {
|
|
32481
|
+
const vars = {};
|
|
32482
|
+
const lines = String(text).split(/\r?\n/);
|
|
32483
|
+
lines.forEach((rawLine, i) => {
|
|
32484
|
+
const lineNo = i + 1;
|
|
32485
|
+
const line = rawLine.trim();
|
|
32486
|
+
if (!line || line.startsWith("#")) return;
|
|
32487
|
+
const withoutExport = line.startsWith("export ") ? line.slice(7).trim() : line;
|
|
32488
|
+
const eq = withoutExport.indexOf("=");
|
|
32489
|
+
if (eq === -1) {
|
|
32490
|
+
throw new SkillError(
|
|
32491
|
+
"BAD_ENV_FILE",
|
|
32492
|
+
`Malformed .env: line ${lineNo} is not KEY=VALUE. (Content withheld \u2014 it may be a secret.)`
|
|
32493
|
+
);
|
|
32494
|
+
}
|
|
32495
|
+
const key = withoutExport.slice(0, eq).trim();
|
|
32496
|
+
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(key)) {
|
|
32497
|
+
throw new SkillError(
|
|
32498
|
+
"BAD_ENV_FILE",
|
|
32499
|
+
`Malformed .env: line ${lineNo} has an invalid key name. (Content withheld.)`
|
|
32500
|
+
);
|
|
32501
|
+
}
|
|
32502
|
+
let value = withoutExport.slice(eq + 1).trim();
|
|
32503
|
+
if (value.length >= 2 && (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'"))) {
|
|
32504
|
+
value = value.slice(1, -1);
|
|
32505
|
+
}
|
|
32506
|
+
vars[key] = value;
|
|
32507
|
+
});
|
|
32508
|
+
return vars;
|
|
32509
|
+
}
|
|
32510
|
+
function filterAllowed(vars) {
|
|
32511
|
+
const out = {};
|
|
32512
|
+
for (const [k, v] of Object.entries(vars)) if (isAllowedKey(k)) out[k] = v;
|
|
32513
|
+
return out;
|
|
32514
|
+
}
|
|
32515
|
+
function envFileCandidates({ cwd = process.cwd(), home = os.homedir() } = {}) {
|
|
32516
|
+
const candidates = [path2.join(cwd, ".env")];
|
|
32517
|
+
const owned = path2.join(home, ".rozo-checkout", ".env");
|
|
32518
|
+
if (owned !== candidates[0]) candidates.push(owned);
|
|
32519
|
+
return candidates;
|
|
32520
|
+
}
|
|
32521
|
+
function resolveEnvFile({ file, cwd = process.cwd(), home = os.homedir() } = {}) {
|
|
32522
|
+
if (file) {
|
|
32523
|
+
const p = path2.resolve(file);
|
|
32524
|
+
if (!fs2.existsSync(p)) {
|
|
32525
|
+
throw new SkillError("ENV_FILE_MISSING", `No such env file: ${file}`);
|
|
32526
|
+
}
|
|
32527
|
+
return p;
|
|
32528
|
+
}
|
|
32529
|
+
return envFileCandidates({ cwd, home }).find((p) => fs2.existsSync(p)) ?? null;
|
|
32530
|
+
}
|
|
32531
|
+
function applyDotenv({
|
|
32532
|
+
file,
|
|
32533
|
+
cwd = process.cwd(),
|
|
32534
|
+
home = os.homedir(),
|
|
32535
|
+
env = process.env
|
|
32536
|
+
} = {}) {
|
|
32537
|
+
const target = resolveEnvFile({ file, cwd, home });
|
|
32538
|
+
if (!target) return null;
|
|
32539
|
+
let stat;
|
|
32540
|
+
try {
|
|
32541
|
+
stat = fs2.statSync(target);
|
|
32542
|
+
} catch (err) {
|
|
32543
|
+
throw new SkillError("ENV_FILE_MISSING", `Cannot read env file (${err.code || "error"}).`);
|
|
32544
|
+
}
|
|
32545
|
+
if (process.platform !== "win32" && stat.mode & 63) {
|
|
32546
|
+
const mode = (stat.mode & 511).toString(8).padStart(3, "0");
|
|
32547
|
+
throw new SkillError(
|
|
32548
|
+
"ENV_FILE_PERMISSIONS",
|
|
32549
|
+
`That .env is readable by other users (mode ${mode}). Run: chmod 600 ${target}`
|
|
32550
|
+
);
|
|
32551
|
+
}
|
|
32552
|
+
assertNotTrackedByGit(target);
|
|
32553
|
+
const parsed = parseDotenv(fs2.readFileSync(target, "utf8"));
|
|
32554
|
+
const allowed = filterAllowed(parsed);
|
|
32555
|
+
const applied = [];
|
|
32556
|
+
for (const [k, v] of Object.entries(allowed)) {
|
|
32557
|
+
const existing = env[k];
|
|
32558
|
+
if (existing !== void 0 && String(existing).trim() !== "") continue;
|
|
32559
|
+
env[k] = v;
|
|
32560
|
+
applied.push(k);
|
|
32561
|
+
}
|
|
32562
|
+
return {
|
|
32563
|
+
path: target,
|
|
32564
|
+
applied,
|
|
32565
|
+
ignored: Object.keys(parsed).length - Object.keys(allowed).length
|
|
32566
|
+
};
|
|
32567
|
+
}
|
|
32568
|
+
|
|
32466
32569
|
// scripts/src/lib/key-source.mjs
|
|
32467
32570
|
var EVM_KEY_ENV = "ROZO_CHECKOUT_EVM_KEY";
|
|
32468
32571
|
var SOL_KEY_ENV = "ROZO_CHECKOUT_SOL_KEY";
|
|
32469
32572
|
var EVM_KEYSTORE_ENV = "ROZO_CHECKOUT_EVM_KEYSTORE";
|
|
32470
32573
|
var KEYSTORE_PASSPHRASE_ENV = "ROZO_CHECKOUT_KEYSTORE_PASSPHRASE";
|
|
32471
32574
|
function defaultSolanaKeypairPath() {
|
|
32472
|
-
return
|
|
32575
|
+
return path3.join(os2.homedir(), ".config", "solana", "id.json");
|
|
32473
32576
|
}
|
|
32474
32577
|
function assertKeyfileSafe(file) {
|
|
32475
32578
|
let stat;
|
|
32476
32579
|
try {
|
|
32477
|
-
stat =
|
|
32580
|
+
stat = fs3.statSync(file);
|
|
32478
32581
|
} catch (err) {
|
|
32479
32582
|
throw new SkillError(
|
|
32480
32583
|
"KEYFILE_UNREADABLE",
|
|
@@ -32651,12 +32754,16 @@ function looksLikeKeystore(text) {
|
|
|
32651
32754
|
return false;
|
|
32652
32755
|
}
|
|
32653
32756
|
}
|
|
32654
|
-
function
|
|
32757
|
+
function searchedSuffix(searched) {
|
|
32758
|
+
if (!searched || !searched.length) return "";
|
|
32759
|
+
return ` Looked for a .env in: ${searched.map(displayPath).join(", ")}.`;
|
|
32760
|
+
}
|
|
32761
|
+
function planKeySource({ family, keyfile, env = process.env, searched }) {
|
|
32655
32762
|
if (keyfile) {
|
|
32656
32763
|
const resolved = expandHome(keyfile);
|
|
32657
32764
|
let text;
|
|
32658
32765
|
try {
|
|
32659
|
-
text =
|
|
32766
|
+
text = fs3.readFileSync(resolved, "utf8");
|
|
32660
32767
|
} catch (err) {
|
|
32661
32768
|
throw new SkillError(
|
|
32662
32769
|
"KEYFILE_UNREADABLE",
|
|
@@ -32680,13 +32787,13 @@ function planKeySource({ family, keyfile, env = process.env }) {
|
|
|
32680
32787
|
}
|
|
32681
32788
|
if (family === "solana") {
|
|
32682
32789
|
const standard = defaultSolanaKeypairPath();
|
|
32683
|
-
if (
|
|
32790
|
+
if (fs3.existsSync(standard)) {
|
|
32684
32791
|
return { kind: "keypair-file", path: standard, label: displayPath(standard) };
|
|
32685
32792
|
}
|
|
32686
32793
|
if (env[SOL_KEY_ENV]) return { kind: "env", label: SOL_KEY_ENV };
|
|
32687
32794
|
throw new SkillError(
|
|
32688
32795
|
"NO_KEY_SOURCE",
|
|
32689
|
-
`No signing key found. Either create one with solana-keygen (writes ${displayPath(standard)}), pass --keyfile <path>, or set ${SOL_KEY_ENV}.`
|
|
32796
|
+
`No signing key found. Either create one with solana-keygen (writes ${displayPath(standard)}), pass --keyfile <path>, or set ${SOL_KEY_ENV}.` + searchedSuffix(searched)
|
|
32690
32797
|
);
|
|
32691
32798
|
}
|
|
32692
32799
|
if (family === "evm") {
|
|
@@ -32698,7 +32805,7 @@ function planKeySource({ family, keyfile, env = process.env }) {
|
|
|
32698
32805
|
if (env[EVM_KEY_ENV]) return { kind: "env", label: EVM_KEY_ENV };
|
|
32699
32806
|
throw new SkillError(
|
|
32700
32807
|
"NO_KEY_SOURCE",
|
|
32701
|
-
`No signing key found. Either point ${EVM_KEYSTORE_ENV} at an encrypted JSON keystore, pass --keyfile <path>, or set ${EVM_KEY_ENV}
|
|
32808
|
+
`No signing key found. Either point ${EVM_KEYSTORE_ENV} at an encrypted JSON keystore, pass --keyfile <path>, or set ${EVM_KEY_ENV}.${searchedSuffix(searched)}`
|
|
32702
32809
|
);
|
|
32703
32810
|
}
|
|
32704
32811
|
throw new SkillError("NO_KEY_SOURCE", `No key source for family "${family}".`);
|
|
@@ -32716,7 +32823,7 @@ async function loadKeySource(plan, { family, env = process.env, askPassphrase }
|
|
|
32716
32823
|
return { secretKey: decodeSolanaEnvKey(raw), label: plan.label, kind: plan.kind };
|
|
32717
32824
|
}
|
|
32718
32825
|
assertKeyfileSafe(plan.path);
|
|
32719
|
-
const text =
|
|
32826
|
+
const text = fs3.readFileSync(plan.path, "utf8");
|
|
32720
32827
|
if (plan.kind === "keypair-file") {
|
|
32721
32828
|
return { secretKey: parseSolanaKeypairJson(text), label: plan.label, kind: plan.kind };
|
|
32722
32829
|
}
|
|
@@ -32735,106 +32842,14 @@ async function loadKeySource(plan, { family, env = process.env, askPassphrase }
|
|
|
32735
32842
|
}
|
|
32736
32843
|
function expandHome(p) {
|
|
32737
32844
|
const s = String(p);
|
|
32738
|
-
if (s === "~") return
|
|
32739
|
-
if (s.startsWith("~/")) return
|
|
32845
|
+
if (s === "~") return os2.homedir();
|
|
32846
|
+
if (s.startsWith("~/")) return path3.join(os2.homedir(), s.slice(2));
|
|
32740
32847
|
return s;
|
|
32741
32848
|
}
|
|
32742
32849
|
function displayPath(p) {
|
|
32743
|
-
const home =
|
|
32850
|
+
const home = os2.homedir();
|
|
32744
32851
|
const s = String(p);
|
|
32745
|
-
return s.startsWith(home +
|
|
32746
|
-
}
|
|
32747
|
-
|
|
32748
|
-
// scripts/src/lib/dotenv.mjs
|
|
32749
|
-
import fs3 from "node:fs";
|
|
32750
|
-
import path3 from "node:path";
|
|
32751
|
-
var ALLOWED_KEYS = [
|
|
32752
|
-
"ROZO_CHECKOUT_EVM_KEY",
|
|
32753
|
-
"ROZO_CHECKOUT_SOL_KEY",
|
|
32754
|
-
"ROZO_CHECKOUT_EVM_KEYSTORE",
|
|
32755
|
-
"ROZO_CHECKOUT_KEYSTORE_PASSPHRASE"
|
|
32756
|
-
];
|
|
32757
|
-
var ALLOWED_PATTERN = /^ROZO_CHECKOUT_RPC_[A-Za-z0-9_]+$/;
|
|
32758
|
-
function isAllowedKey(key) {
|
|
32759
|
-
return ALLOWED_KEYS.includes(key) || ALLOWED_PATTERN.test(key);
|
|
32760
|
-
}
|
|
32761
|
-
function parseDotenv(text) {
|
|
32762
|
-
const vars = {};
|
|
32763
|
-
const lines = String(text).split(/\r?\n/);
|
|
32764
|
-
lines.forEach((rawLine, i) => {
|
|
32765
|
-
const lineNo = i + 1;
|
|
32766
|
-
const line = rawLine.trim();
|
|
32767
|
-
if (!line || line.startsWith("#")) return;
|
|
32768
|
-
const withoutExport = line.startsWith("export ") ? line.slice(7).trim() : line;
|
|
32769
|
-
const eq = withoutExport.indexOf("=");
|
|
32770
|
-
if (eq === -1) {
|
|
32771
|
-
throw new SkillError(
|
|
32772
|
-
"BAD_ENV_FILE",
|
|
32773
|
-
`Malformed .env: line ${lineNo} is not KEY=VALUE. (Content withheld \u2014 it may be a secret.)`
|
|
32774
|
-
);
|
|
32775
|
-
}
|
|
32776
|
-
const key = withoutExport.slice(0, eq).trim();
|
|
32777
|
-
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(key)) {
|
|
32778
|
-
throw new SkillError(
|
|
32779
|
-
"BAD_ENV_FILE",
|
|
32780
|
-
`Malformed .env: line ${lineNo} has an invalid key name. (Content withheld.)`
|
|
32781
|
-
);
|
|
32782
|
-
}
|
|
32783
|
-
let value = withoutExport.slice(eq + 1).trim();
|
|
32784
|
-
if (value.length >= 2 && (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'"))) {
|
|
32785
|
-
value = value.slice(1, -1);
|
|
32786
|
-
}
|
|
32787
|
-
vars[key] = value;
|
|
32788
|
-
});
|
|
32789
|
-
return vars;
|
|
32790
|
-
}
|
|
32791
|
-
function filterAllowed(vars) {
|
|
32792
|
-
const out = {};
|
|
32793
|
-
for (const [k, v] of Object.entries(vars)) if (isAllowedKey(k)) out[k] = v;
|
|
32794
|
-
return out;
|
|
32795
|
-
}
|
|
32796
|
-
function resolveEnvFile({ file, cwd = process.cwd() } = {}) {
|
|
32797
|
-
if (file) {
|
|
32798
|
-
const p = path3.resolve(file);
|
|
32799
|
-
if (!fs3.existsSync(p)) {
|
|
32800
|
-
throw new SkillError("ENV_FILE_MISSING", `No such env file: ${file}`);
|
|
32801
|
-
}
|
|
32802
|
-
return p;
|
|
32803
|
-
}
|
|
32804
|
-
const fallback = path3.join(cwd, ".env");
|
|
32805
|
-
return fs3.existsSync(fallback) ? fallback : null;
|
|
32806
|
-
}
|
|
32807
|
-
function applyDotenv({ file, cwd = process.cwd(), env = process.env } = {}) {
|
|
32808
|
-
const target = resolveEnvFile({ file, cwd });
|
|
32809
|
-
if (!target) return null;
|
|
32810
|
-
let stat;
|
|
32811
|
-
try {
|
|
32812
|
-
stat = fs3.statSync(target);
|
|
32813
|
-
} catch (err) {
|
|
32814
|
-
throw new SkillError("ENV_FILE_MISSING", `Cannot read env file (${err.code || "error"}).`);
|
|
32815
|
-
}
|
|
32816
|
-
if (process.platform !== "win32" && stat.mode & 63) {
|
|
32817
|
-
const mode = (stat.mode & 511).toString(8).padStart(3, "0");
|
|
32818
|
-
throw new SkillError(
|
|
32819
|
-
"ENV_FILE_PERMISSIONS",
|
|
32820
|
-
`That .env is readable by other users (mode ${mode}). Run: chmod 600 ${target}`
|
|
32821
|
-
);
|
|
32822
|
-
}
|
|
32823
|
-
assertNotTrackedByGit(target);
|
|
32824
|
-
const parsed = parseDotenv(fs3.readFileSync(target, "utf8"));
|
|
32825
|
-
const allowed = filterAllowed(parsed);
|
|
32826
|
-
const applied = [];
|
|
32827
|
-
for (const [k, v] of Object.entries(allowed)) {
|
|
32828
|
-
const existing = env[k];
|
|
32829
|
-
if (existing !== void 0 && String(existing).trim() !== "") continue;
|
|
32830
|
-
env[k] = v;
|
|
32831
|
-
applied.push(k);
|
|
32832
|
-
}
|
|
32833
|
-
return {
|
|
32834
|
-
path: target,
|
|
32835
|
-
applied,
|
|
32836
|
-
ignored: Object.keys(parsed).length - Object.keys(allowed).length
|
|
32837
|
-
};
|
|
32852
|
+
return s.startsWith(home + path3.sep) ? `~${s.slice(home.length)}` : s;
|
|
32838
32853
|
}
|
|
32839
32854
|
|
|
32840
32855
|
// scripts/src/lib/passphrase.mjs
|
|
@@ -33400,7 +33415,7 @@ function assertNotBlacklisted(targets, blacklist) {
|
|
|
33400
33415
|
// scripts/src/lib/state.mjs
|
|
33401
33416
|
import fs5 from "node:fs";
|
|
33402
33417
|
import path5 from "node:path";
|
|
33403
|
-
import
|
|
33418
|
+
import os3 from "node:os";
|
|
33404
33419
|
import crypto4 from "node:crypto";
|
|
33405
33420
|
var LOCK_STALE_MS = 6e4;
|
|
33406
33421
|
var LOCK_WAIT_MS = 1e4;
|
|
@@ -33461,7 +33476,7 @@ function withLock(fn) {
|
|
|
33461
33476
|
}
|
|
33462
33477
|
}
|
|
33463
33478
|
function stateRoot() {
|
|
33464
|
-
return process.env.ROZO_CHECKOUT_STATE_DIR || path5.join(
|
|
33479
|
+
return process.env.ROZO_CHECKOUT_STATE_DIR || path5.join(os3.homedir(), ".rozo-checkout", "state");
|
|
33465
33480
|
}
|
|
33466
33481
|
function statePath(rozoPaymentId) {
|
|
33467
33482
|
if (!/^[A-Za-z0-9-]{8,64}$/.test(String(rozoPaymentId || ""))) {
|
|
@@ -35480,7 +35495,11 @@ async function main(argv) {
|
|
|
35480
35495
|
const rozoPaymentId = assertRozoPaymentId(args["rozo-payment-id"] || args._[0]);
|
|
35481
35496
|
assertNoTrackedDotEnv();
|
|
35482
35497
|
const dotenv = applyDotenv({ file: args["env-file"] });
|
|
35483
|
-
const plan = planKeySource({
|
|
35498
|
+
const plan = planKeySource({
|
|
35499
|
+
family: "solana",
|
|
35500
|
+
keyfile: args.keyfile,
|
|
35501
|
+
searched: args["env-file"] ? null : envFileCandidates()
|
|
35502
|
+
});
|
|
35484
35503
|
const loaded = await loadKeySource(plan, { family: "solana", askPassphrase: promptPassphrase });
|
|
35485
35504
|
const secret = loaded.secretKey;
|
|
35486
35505
|
const keypair = secret.length === 64 ? import_web36.Keypair.fromSecretKey(secret) : import_web36.Keypair.fromSeed(secret);
|