rwn64 1.0.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.
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.copyToClipboard = copyToClipboard;
4
+ exports.clipAvailable = clipAvailable;
5
+ const child_process_1 = require("child_process");
6
+ const env_1 = require("./env");
7
+ function _cmd() {
8
+ if (env_1.env.isMacOS)
9
+ return "pbcopy";
10
+ if (env_1.env.isTermux) {
11
+ try {
12
+ (0, child_process_1.execSync)("which termux-clipboard-set", { stdio: "ignore" });
13
+ return "termux-clipboard-set";
14
+ }
15
+ catch { }
16
+ return null;
17
+ }
18
+ for (const [bin, cmd] of [["xclip", "xclip -selection clipboard"], ["xsel", "xsel --clipboard --input"], ["wl-copy", "wl-copy"]]) {
19
+ try {
20
+ (0, child_process_1.execSync)(`which ${bin}`, { stdio: "ignore" });
21
+ return cmd;
22
+ }
23
+ catch { }
24
+ }
25
+ return null;
26
+ }
27
+ function copyToClipboard(text) {
28
+ const cmd = _cmd();
29
+ if (!cmd)
30
+ return false;
31
+ try {
32
+ (0, child_process_1.execSync)(cmd, { input: text, stdio: ["pipe", "ignore", "ignore"] });
33
+ return true;
34
+ }
35
+ catch {
36
+ return false;
37
+ }
38
+ }
39
+ function clipAvailable() { return _cmd() !== null; }
@@ -0,0 +1,24 @@
1
+ export declare const TOKEN_PREFIX = "rwn64:v2:";
2
+ export declare const VERSION = "v2";
3
+ export interface EncryptOptions {
4
+ expiresMs?: number;
5
+ }
6
+ export declare function encrypt(plaintext: string, password: string, opts?: EncryptOptions): string;
7
+ export interface DecryptResult {
8
+ plaintext: string;
9
+ expiresAt?: Date;
10
+ tokenVersion: number;
11
+ }
12
+ export declare function decrypt(token: string, password: string): DecryptResult;
13
+ export declare function verify(token: string, password: string): boolean;
14
+ export declare function hmacFingerprint(input: string, secret: string): string;
15
+ export declare function inspectToken(token: string): {
16
+ version: string;
17
+ saltHex: string;
18
+ nonceHex: string;
19
+ payloadBytes: number;
20
+ prefix: string;
21
+ algo: string;
22
+ };
23
+ export declare function generatePassword(bytes?: number): string;
24
+ export declare function parseExpiry(raw: string): number;
@@ -0,0 +1,134 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.VERSION = exports.TOKEN_PREFIX = void 0;
4
+ exports.encrypt = encrypt;
5
+ exports.decrypt = decrypt;
6
+ exports.verify = verify;
7
+ exports.hmacFingerprint = hmacFingerprint;
8
+ exports.inspectToken = inspectToken;
9
+ exports.generatePassword = generatePassword;
10
+ exports.parseExpiry = parseExpiry;
11
+ const crypto_1 = require("crypto");
12
+ const _PFX_V1 = "rwn64:v1:";
13
+ const _PFX_V2 = "rwn64:v2:";
14
+ const _ALG_V1 = "aes-256-gcm";
15
+ const _ALG_V2 = "chacha20-poly1305";
16
+ const _SL = 16;
17
+ const _NL = 12;
18
+ const _TL = 16;
19
+ const _KL = 32;
20
+ const _SCRYPT = { N: 16384, r: 8, p: 1 };
21
+ exports.TOKEN_PREFIX = _PFX_V2;
22
+ exports.VERSION = "v2";
23
+ function _kdf(pass, salt) {
24
+ const buf = Buffer.from(pass, "utf8");
25
+ const key = (0, crypto_1.scryptSync)(buf, salt, _KL, _SCRYPT);
26
+ buf.fill(0);
27
+ return key;
28
+ }
29
+ function _encExp(ms) {
30
+ const b = Buffer.allocUnsafe(8);
31
+ b.writeUInt32BE(Math.floor(ms / 0x100000000), 0);
32
+ b.writeUInt32BE(ms >>> 0, 4);
33
+ return b;
34
+ }
35
+ function _decExp(b) {
36
+ return b.readUInt32BE(0) * 0x100000000 + b.readUInt32BE(4);
37
+ }
38
+ function encrypt(plaintext, password, opts = {}) {
39
+ const salt = (0, crypto_1.randomBytes)(_SL);
40
+ const nonce = (0, crypto_1.randomBytes)(_NL);
41
+ const key = _kdf(password, salt);
42
+ const hasx = opts.expiresMs !== undefined;
43
+ const meta = Buffer.alloc(1);
44
+ meta[0] = hasx ? 1 : 0;
45
+ const inner = Buffer.concat([meta, hasx ? _encExp(opts.expiresMs) : Buffer.alloc(0), Buffer.from(plaintext, "utf8")]);
46
+ const ciph = (0, crypto_1.createCipheriv)(_ALG_V2, key, nonce, { authTagLength: _TL });
47
+ const body = Buffer.concat([ciph.update(inner), ciph.final()]);
48
+ const tag = ciph.getAuthTag();
49
+ return _PFX_V2 + Buffer.concat([salt, nonce, tag, body]).toString("base64url");
50
+ }
51
+ function decrypt(token, password) {
52
+ let pfx;
53
+ let alg;
54
+ let ver;
55
+ if (token.startsWith(_PFX_V2)) {
56
+ pfx = _PFX_V2;
57
+ alg = _ALG_V2;
58
+ ver = 2;
59
+ }
60
+ else if (token.startsWith(_PFX_V1)) {
61
+ pfx = _PFX_V1;
62
+ alg = _ALG_V1;
63
+ ver = 1;
64
+ }
65
+ else
66
+ throw Object.assign(new Error("invalid token format"), { code: "ERR_FORMAT" });
67
+ const payload = Buffer.from(token.slice(pfx.length), "base64url");
68
+ if (payload.length < _SL + _NL + _TL + 2)
69
+ throw Object.assign(new Error("token is too short or malformed"), { code: "ERR_MALFORMED" });
70
+ const salt = payload.subarray(0, _SL);
71
+ const nonce = payload.subarray(_SL, _SL + _NL);
72
+ const tag = payload.subarray(_SL + _NL, _SL + _NL + _TL);
73
+ const body = payload.subarray(_SL + _NL + _TL);
74
+ const key = _kdf(password, salt);
75
+ const dc = (0, crypto_1.createDecipheriv)(alg, key, nonce, ver === 2 ? { authTagLength: _TL } : undefined);
76
+ dc.setAuthTag(tag);
77
+ let inner;
78
+ try {
79
+ inner = Buffer.concat([dc.update(body), dc.final()]);
80
+ }
81
+ catch {
82
+ throw Object.assign(new Error("wrong password or corrupted token"), { code: "ERR_AUTH" });
83
+ }
84
+ const hasx = inner[0] === 1;
85
+ if (hasx) {
86
+ const expMs = _decExp(inner.subarray(1, 9));
87
+ const expDate = new Date(expMs);
88
+ if (Date.now() > expMs)
89
+ throw Object.assign(new Error(`token expired at ${expDate.toISOString()}`), { code: "ERR_EXPIRED", expiredAt: expDate });
90
+ return { plaintext: inner.subarray(9).toString("utf8"), expiresAt: expDate, tokenVersion: ver };
91
+ }
92
+ return { plaintext: inner.subarray(1).toString("utf8"), tokenVersion: ver };
93
+ }
94
+ function verify(token, password) {
95
+ try {
96
+ decrypt(token, password);
97
+ return true;
98
+ }
99
+ catch {
100
+ return false;
101
+ }
102
+ }
103
+ function hmacFingerprint(input, secret) {
104
+ return (0, crypto_1.createHmac)("sha256", secret).update(input).digest("hex").slice(0, 16);
105
+ }
106
+ function inspectToken(token) {
107
+ let pfx;
108
+ let algo;
109
+ let ver;
110
+ if (token.startsWith(_PFX_V2)) {
111
+ pfx = _PFX_V2;
112
+ algo = "ChaCha20-Poly1305";
113
+ ver = 2;
114
+ }
115
+ else if (token.startsWith(_PFX_V1)) {
116
+ pfx = _PFX_V1;
117
+ algo = "AES-256-GCM";
118
+ ver = 1;
119
+ }
120
+ else
121
+ throw Object.assign(new Error("invalid token format"), { code: "ERR_FORMAT" });
122
+ const payload = Buffer.from(token.slice(pfx.length), "base64url");
123
+ if (payload.length < _SL + _NL + _TL + 2)
124
+ throw Object.assign(new Error("token is too short or malformed"), { code: "ERR_MALFORMED" });
125
+ return { version: `v${ver}`, prefix: pfx, algo, saltHex: payload.subarray(0, _SL).toString("hex"), nonceHex: payload.subarray(_SL, _SL + _NL).toString("hex"), payloadBytes: payload.length };
126
+ }
127
+ function generatePassword(bytes = 24) { return (0, crypto_1.randomBytes)(bytes).toString("base64url"); }
128
+ function parseExpiry(raw) {
129
+ const m = raw.match(/^(\d+)(s|m|h|d)$/);
130
+ if (!m)
131
+ throw new Error(`invalid expiry format: "${raw}" — use 30s, 5m, 2h, 7d`);
132
+ const u = { s: 1000, m: 60000, h: 3600000, d: 86400000 };
133
+ return Date.now() + parseInt(m[1], 10) * u[m[2]];
134
+ }
@@ -0,0 +1,13 @@
1
+ export type Env = "termux" | "linux" | "macos" | "unknown";
2
+ export interface EnvInfo {
3
+ type: Env;
4
+ isTermux: boolean;
5
+ isLinux: boolean;
6
+ isMacOS: boolean;
7
+ hasTTY: boolean;
8
+ hasRawMode: boolean;
9
+ hasColor: boolean;
10
+ cols: number;
11
+ rows: number;
12
+ }
13
+ export declare const env: EnvInfo;
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.env = void 0;
4
+ function _detect() {
5
+ if (process.env.TERMUX_VERSION !== undefined ||
6
+ (process.env.PREFIX ?? "").includes("com.termux") ||
7
+ (process.env.HOME ?? "").includes("com.termux"))
8
+ return "termux";
9
+ if (process.platform === "darwin")
10
+ return "macos";
11
+ if (process.platform === "linux")
12
+ return "linux";
13
+ return "unknown";
14
+ }
15
+ function _cols() {
16
+ try {
17
+ return process.stdout.columns || 80;
18
+ }
19
+ catch {
20
+ return 80;
21
+ }
22
+ }
23
+ function _rows() {
24
+ try {
25
+ return process.stdout.rows || 24;
26
+ }
27
+ catch {
28
+ return 24;
29
+ }
30
+ }
31
+ const _type = _detect();
32
+ exports.env = {
33
+ type: _type,
34
+ isTermux: _type === "termux",
35
+ isLinux: _type === "linux",
36
+ isMacOS: _type === "macos",
37
+ hasTTY: !!process.stdin.isTTY,
38
+ hasRawMode: typeof process.stdin.setRawMode === "function",
39
+ hasColor: process.env.NO_COLOR === undefined && !!process.stderr.isTTY,
40
+ cols: _cols(),
41
+ rows: _rows(),
42
+ };
@@ -0,0 +1 @@
1
+ export declare function installErrorHandler(): void;
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.installErrorHandler = installErrorHandler;
4
+ const _nc = !process.stderr.isTTY || process.env.NO_COLOR !== undefined;
5
+ const _e = _nc ? "" : "\x1b[31m";
6
+ const _c = _nc ? "" : "\x1b[36m";
7
+ const _d = _nc ? "" : "\x1b[2m";
8
+ const _r = _nc ? "" : "\x1b[0m";
9
+ const _DEFS = [
10
+ { match: (m) => m.includes("rwn64:") && (m.includes("$") || m.includes("expanded")),
11
+ message: "token contains unescaped shell characters",
12
+ fix: "use single quotes: rwn64 denc 'rwn64:v2:...' -sw password", exit: 2 },
13
+ { match: (m, c) => c === "EACCES" || m.includes("permission denied"),
14
+ message: "permission denied",
15
+ fix: "check file permissions", exit: 2 },
16
+ { match: (m, c) => c === "ENOMEM" || m.includes("out of memory") || m.includes("heap"),
17
+ message: "out of memory",
18
+ fix: "input may be too large. try: NODE_OPTIONS=--max-old-space-size=512 rwn64 ...", exit: 2 },
19
+ { match: (m) => m.includes("scrypt") || m.includes("memory limit exceeded"),
20
+ message: "scrypt memory limit exceeded",
21
+ fix: "device may have limited memory. try a shorter input or restart Termux", exit: 2 },
22
+ { match: (m, c) => c === "MODULE_NOT_FOUND" || m.includes("cannot find module"),
23
+ message: "internal module not found",
24
+ fix: "reinstall rwn64: npm install -g rwn64", exit: 1 },
25
+ { match: (m, c) => c === "ERR_INVALID_ARG_TYPE" || c === "ERR_INVALID_ARG_VALUE" || m.includes("invalid argument"),
26
+ message: "invalid argument",
27
+ fix: "run rwn64 -h to see correct usage", exit: 1 },
28
+ { match: (m, c) => c === "ENOENT" || m.includes("no such file"),
29
+ message: "file not found",
30
+ fix: "check that the file path is correct", exit: 2 },
31
+ ];
32
+ function _fmt(msg, fix) {
33
+ return `\n${_e}error${_r} ${msg}\n${_d}fix${_r} ${_c}${fix}${_r}\n`;
34
+ }
35
+ function _handle(err) {
36
+ const msg = (err.message ?? "").toLowerCase();
37
+ const code = err.code ?? "";
38
+ for (const d of _DEFS) {
39
+ if (d.match(msg, code)) {
40
+ process.stderr.write(_fmt(d.message, d.fix));
41
+ process.exit(d.exit);
42
+ }
43
+ }
44
+ return false;
45
+ }
46
+ function _unknown(msg) {
47
+ process.stderr.write(`\n${_e}error${_r} unexpected error\n${_d}fix${_r} ${_c}run rwn64 -h for usage${_r}\n${_d} ${msg}${_r}\n`);
48
+ process.exit(1);
49
+ }
50
+ function installErrorHandler() {
51
+ process.on("uncaughtException", (err) => { if (!_handle(err))
52
+ _unknown(err.message ?? String(err)); });
53
+ process.on("unhandledRejection", (reason) => {
54
+ const err = reason instanceof Error ? reason : new Error(String(reason));
55
+ if (!_handle(err))
56
+ _unknown(err.message);
57
+ });
58
+ process.on("warning", () => { });
59
+ const _orig = process.emit.bind(process);
60
+ process.emit = (ev, ...a) => ev === "warning" ? false : _orig(ev, ...a);
61
+ }
@@ -0,0 +1,9 @@
1
+ interface _Entry {
2
+ ts: number;
3
+ cmd: string;
4
+ fp: string;
5
+ }
6
+ export declare function recordHistory(cmd: string, token: string): void;
7
+ export declare function getHistory(): _Entry[];
8
+ export declare function clearHistory(): void;
9
+ export {};
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.recordHistory = recordHistory;
4
+ exports.getHistory = getHistory;
5
+ exports.clearHistory = clearHistory;
6
+ const fs_1 = require("fs");
7
+ const path_1 = require("path");
8
+ const os_1 = require("os");
9
+ const crypto_1 = require("crypto");
10
+ const _FILE = (0, path_1.join)((0, os_1.tmpdir)(), ".rwn64_history");
11
+ function _load() {
12
+ if (!(0, fs_1.existsSync)(_FILE))
13
+ return [];
14
+ try {
15
+ return JSON.parse((0, fs_1.readFileSync)(_FILE, "utf8"));
16
+ }
17
+ catch {
18
+ return [];
19
+ }
20
+ }
21
+ function _save(e) {
22
+ try {
23
+ (0, fs_1.writeFileSync)(_FILE, JSON.stringify(e), "utf8");
24
+ }
25
+ catch { }
26
+ }
27
+ function recordHistory(cmd, token) {
28
+ const e = _load();
29
+ e.push({ ts: Date.now(), cmd, fp: (0, crypto_1.createHash)("sha256").update(token).digest("hex").slice(0, 8) });
30
+ if (e.length > 50)
31
+ e.splice(0, e.length - 50);
32
+ _save(e);
33
+ }
34
+ function getHistory() { return _load(); }
35
+ function clearHistory() { _save([]); }
@@ -0,0 +1,2 @@
1
+ export declare function resolvePassword(raw: string): string;
2
+ export declare function describePasswordSource(raw: string): string;
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resolvePassword = resolvePassword;
4
+ exports.describePasswordSource = describePasswordSource;
5
+ const fs_1 = require("fs");
6
+ function resolvePassword(raw) {
7
+ if (raw.startsWith("@")) {
8
+ const path = raw.slice(1).trim();
9
+ try {
10
+ return (0, fs_1.readFileSync)(path, "utf8").trim();
11
+ }
12
+ catch {
13
+ throw Object.assign(new Error(`cannot read password file: ${path}`), { code: "ERR_PWFILE" });
14
+ }
15
+ }
16
+ if (raw.startsWith("env:")) {
17
+ const name = raw.slice(4).trim();
18
+ const val = process.env[name];
19
+ if (!val)
20
+ throw Object.assign(new Error(`env variable not set: ${name}`), { code: "ERR_PWENV" });
21
+ return val;
22
+ }
23
+ return raw;
24
+ }
25
+ function describePasswordSource(raw) {
26
+ if (raw.startsWith("@"))
27
+ return `file(${raw.slice(1)})`;
28
+ if (raw.startsWith("env:"))
29
+ return `env(${raw.slice(4)})`;
30
+ return "inline";
31
+ }
@@ -0,0 +1,7 @@
1
+ export interface XH32RC {
2
+ password?: string;
3
+ bytes?: number;
4
+ maxSize?: number;
5
+ clip?: boolean;
6
+ }
7
+ export declare function loadRC(): XH32RC;
package/dist/lib/rc.js ADDED
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.loadRC = loadRC;
4
+ const fs_1 = require("fs");
5
+ const path_1 = require("path");
6
+ const os_1 = require("os");
7
+ const _DEFAULTS = { bytes: 24, maxSize: 20, clip: false };
8
+ const _RC_FILE = ".rwn64rc";
9
+ function _parse(raw) {
10
+ const out = {};
11
+ for (const line of raw.split("\n")) {
12
+ const t = line.trim();
13
+ if (!t || t.startsWith("#"))
14
+ continue;
15
+ const eq = t.indexOf("=");
16
+ if (eq === -1)
17
+ continue;
18
+ const k = t.slice(0, eq).trim();
19
+ const v = t.slice(eq + 1).trim();
20
+ if (k === "password")
21
+ out.password = v;
22
+ if (k === "bytes")
23
+ out.bytes = parseInt(v, 10);
24
+ if (k === "maxSize")
25
+ out.maxSize = parseInt(v, 10);
26
+ if (k === "clip")
27
+ out.clip = v === "true";
28
+ }
29
+ return out;
30
+ }
31
+ function _load(path) {
32
+ if (!(0, fs_1.existsSync)(path))
33
+ return null;
34
+ try {
35
+ return _parse((0, fs_1.readFileSync)(path, "utf8"));
36
+ }
37
+ catch {
38
+ return null;
39
+ }
40
+ }
41
+ function loadRC() {
42
+ const local = _load((0, path_1.resolve)(process.cwd(), _RC_FILE));
43
+ const global = _load((0, path_1.join)((0, os_1.homedir)(), _RC_FILE));
44
+ return { ..._DEFAULTS, ...global, ...local };
45
+ }
@@ -0,0 +1,17 @@
1
+ export declare const VERSION = "1.0.0";
2
+ export declare const PKG = "rwn64";
3
+ export declare const BIN = "rwn64";
4
+ export declare function data(s: string): void;
5
+ export declare function err(msg: string, code?: number): never;
6
+ export declare function warn(msg: string): void;
7
+ export interface BoxRow {
8
+ label: string;
9
+ value: string;
10
+ valueColor?: string;
11
+ }
12
+ export declare function box(rows: BoxRow[]): void;
13
+ export declare function token(t: string): void;
14
+ export declare function ms(elapsed: number): void;
15
+ export declare function section(title: string): void;
16
+ export declare function usage(): void;
17
+ export declare function row(label: string, value: string, color?: string): void;
package/dist/lib/ui.js ADDED
@@ -0,0 +1,128 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.BIN = exports.PKG = exports.VERSION = void 0;
4
+ exports.data = data;
5
+ exports.err = err;
6
+ exports.warn = warn;
7
+ exports.box = box;
8
+ exports.token = token;
9
+ exports.ms = ms;
10
+ exports.section = section;
11
+ exports.usage = usage;
12
+ exports.row = row;
13
+ const env_1 = require("./env");
14
+ const _NC = !env_1.env.hasColor;
15
+ const _c = _NC ? {
16
+ r: "", d: "", b: "", g: "", y: "", c: "", e: "", w: "", dim: "", hi: ""
17
+ } : {
18
+ r: "\x1b[0m",
19
+ d: "\x1b[2m",
20
+ b: "\x1b[1m",
21
+ g: "\x1b[32m",
22
+ y: "\x1b[33m",
23
+ c: "\x1b[36m",
24
+ e: "\x1b[31m",
25
+ w: "\x1b[37m",
26
+ dim: "\x1b[38;5;245m",
27
+ hi: "\x1b[38;5;252m",
28
+ };
29
+ exports.VERSION = "1.0.0";
30
+ exports.PKG = "rwn64";
31
+ exports.BIN = "rwn64";
32
+ const _BOX = { tl: "┌", tr: "┐", bl: "└", br: "┘", h: "─", v: "│" };
33
+ function _ui(s) { process.stderr.write(s); }
34
+ function data(s) { process.stdout.write(s + "\n"); }
35
+ function err(msg, code = 1) {
36
+ _ui(`\n${_c.e}error${_c.r} ${msg}\n`);
37
+ process.exit(code);
38
+ }
39
+ function warn(msg) {
40
+ _ui(`${_c.y}warn${_c.r} ${msg}\n`);
41
+ }
42
+ function _visLen(s) {
43
+ return s.replace(/\x1b\[[0-9;]*m/g, "").length;
44
+ }
45
+ function _boxLine(inner, width) {
46
+ const pad = Math.max(0, width - _visLen(inner) - 2);
47
+ return `${_c.dim}${_BOX.v}${_c.r} ${inner}${" ".repeat(pad)} ${_c.dim}${_BOX.v}${_c.r}\n`;
48
+ }
49
+ function _hline(width, l, r) {
50
+ return `${_c.dim}${l}${_BOX.h.repeat(width - 2)}${r}${_c.r}\n`;
51
+ }
52
+ function box(rows) {
53
+ const lw = Math.max(...rows.map((r) => r.label.length));
54
+ const lines = rows.map((r) => {
55
+ const pad = " ".repeat(lw - r.label.length + 1);
56
+ const vc = r.valueColor ?? _c.hi;
57
+ return `${_c.dim}${r.label}${_c.r}${pad}${vc}${r.value}${_c.r}`;
58
+ });
59
+ const width = Math.max(...lines.map(_visLen)) + 4;
60
+ _ui(_hline(width, _BOX.tl, _BOX.tr));
61
+ for (const l of lines)
62
+ _ui(_boxLine(l, width));
63
+ _ui(_hline(width, _BOX.bl, _BOX.br));
64
+ }
65
+ function token(t) {
66
+ _ui(`\n${_c.hi}${t}${_c.r}\n\n`);
67
+ }
68
+ function ms(elapsed) {
69
+ _ui(`${_c.dim}done in ${elapsed}ms${_c.r}\n`);
70
+ }
71
+ function section(title) {
72
+ _ui(`\n${_c.w}${title}${_c.r}\n\n`);
73
+ }
74
+ function usage() {
75
+ _ui(`\n${_c.b}${_c.c}${exports.PKG}${_c.r} ${_c.dim}v${exports.VERSION}${_c.r} ChaCha20-Poly1305 / AES-256-GCM\n\n`);
76
+ const c = (s) => ` ${_c.c}${s}${_c.r}`;
77
+ const lines = [
78
+ `${_c.w}commands${_c.r}`,
79
+ ``,
80
+ c(`${exports.BIN} enc <text|@file> -sw <password>`) + " encrypt",
81
+ c(`${exports.BIN} denc <token> -sw <password>`) + " decrypt",
82
+ c(`${exports.BIN} verify <token> -sw <password>`) + " verify token integrity",
83
+ c(`${exports.BIN} fp <text> -sw <secret> `) + " HMAC fingerprint",
84
+ c(`${exports.BIN} gen [bytes] `) + " generate secure password",
85
+ c(`${exports.BIN} info <token> `) + " inspect token metadata",
86
+ c(`${exports.BIN} history `) + " show session history",
87
+ c(`${exports.BIN} upgrade (or -u) `) + " check for updates",
88
+ ``,
89
+ `${_c.w}flags${_c.r}`,
90
+ ``,
91
+ ` ${_c.c}-sw <password>${_c.r} password source`,
92
+ ` ${_c.c}--expires <time>${_c.r} token expiry (30s, 5m, 2h, 7d)`,
93
+ ` ${_c.c}--clip${_c.r} copy result to clipboard`,
94
+ ` ${_c.c}--out <file>${_c.r} (denc) save output to file`,
95
+ ` ${_c.c}--no-color${_c.r} disable ANSI colors`,
96
+ ` ${_c.c}-v, --version${_c.r} print version`,
97
+ ` ${_c.c}-h, --help${_c.r} show this help`,
98
+ ``,
99
+ `${_c.w}password sources${_c.r}`,
100
+ ``,
101
+ ` -sw mypassword inline`,
102
+ ` -sw @~/.rwn64key read from file (recommended)`,
103
+ ` -sw env:RWN64_KEY read from env variable`,
104
+ ``,
105
+ `${_c.w}.rwn64rc${_c.r}`,
106
+ ``,
107
+ ` password = env:RWN64_KEY`,
108
+ ` bytes = 32`,
109
+ ` maxSize = 20`,
110
+ ` clip = false`,
111
+ ``,
112
+ `${_c.w}examples${_c.r}`,
113
+ ``,
114
+ ` rwn64 enc 'my secret' -sw mypassword`,
115
+ ` rwn64 enc 'expires in 1 hour' -sw mypassword --expires 1h`,
116
+ ` rwn64 enc @notes.txt -sw mypassword`,
117
+ ` rwn64 denc 'rwn64:v2:...' -sw mypassword`,
118
+ ` rwn64 denc 'rwn64:v2:...' -sw mypassword --out result.txt`,
119
+ ` TOKEN=$(rwn64 enc 'text' -sw pass)`,
120
+ ` rwn64 denc "$TOKEN" -sw pass`,
121
+ ``,
122
+ ];
123
+ _ui(lines.join("\n") + "\n");
124
+ }
125
+ function row(label, value, color = _c.hi) {
126
+ const pad = " ".repeat(Math.max(1, 10 - label.length));
127
+ _ui(`${_c.dim}${label}${_c.r}${pad}${color}${value}${_c.r}\n`);
128
+ }
package/package.json ADDED
@@ -0,0 +1,31 @@
1
+ {
2
+ "name": "rwn64",
3
+ "version": "1.0.0",
4
+ "description": "ChaCha20-Poly1305 token encryption CLI and library",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "bin": {
8
+ "rwn64": "dist/cli.js"
9
+ },
10
+ "files": [
11
+ "dist",
12
+ "README.md"
13
+ ],
14
+ "scripts": {
15
+ "build": "tsc",
16
+ "build:bundle": "esbuild dist/cli.js --bundle --platform=node --outfile=dist/cli.bundle.js",
17
+ "build:obfuscate": "terser dist/cli.bundle.js -o dist/cli.js --compress passes=3 --mangle",
18
+ "prepublishOnly": "npm run build && npm run build:bundle && npm run build:obfuscate"
19
+ },
20
+ "keywords": ["encryption", "chacha20", "aes-256-gcm", "cli", "token", "crypto", "termux"],
21
+ "license": "MIT",
22
+ "engines": {
23
+ "node": ">=16"
24
+ },
25
+ "devDependencies": {
26
+ "@types/node": "^20.11.0",
27
+ "esbuild": "^0.27.3",
28
+ "terser": "^5.46.0",
29
+ "typescript": "^5.3.3"
30
+ }
31
+ }