@quire-io/quire-cli 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGES.md +25 -0
- package/README.md +10 -0
- package/dist/cli.js +3 -1
- package/dist/cli.js.map +1 -1
- package/dist/commands/logout.js +2 -1
- package/dist/commands/logout.js.map +1 -1
- package/dist/config.js +23 -1
- package/dist/config.js.map +1 -1
- package/dist/credentials.js +0 -0
- package/dist/credentials.js.map +1 -1
- package/dist/oauth/config.js +2 -6
- package/dist/oauth/config.js.map +1 -1
- package/dist/oauth/loopback.js +32 -1
- package/dist/oauth/loopback.js.map +1 -1
- package/dist/util/attach-input.js +33 -21
- package/dist/util/attach-input.js.map +1 -1
- package/dist/util/bulk-input.js +7 -9
- package/dist/util/bulk-input.js.map +1 -1
- package/dist/util/read-sized.js +37 -0
- package/dist/util/read-sized.js.map +1 -0
- package/dist/util/retry-after.js +4 -1
- package/dist/util/retry-after.js.map +1 -1
- package/dist/util/text-input.js +8 -7
- package/dist/util/text-input.js.map +1 -1
- package/package.json +1 -1
package/CHANGES.md
CHANGED
|
@@ -1,5 +1,30 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.1 — 2026-05-08
|
|
4
|
+
|
|
5
|
+
Switch OAuth to the production Quire CLI app, plus a round of input-handling and OAuth-flow hardening.
|
|
6
|
+
|
|
7
|
+
### Auth
|
|
8
|
+
|
|
9
|
+
- **OAuth `client_id` switched** from the development Quire CLI app to the production app. Existing 0.1.0 users will need to re-run `quire login` after upgrading; refresh tokens issued by the dev app no longer work.
|
|
10
|
+
- OAuth loopback callback validates the `Host` header before completing the redirect.
|
|
11
|
+
- HTML-escaped messages on the OAuth loopback failure page.
|
|
12
|
+
- `quire logout --help` documents the no-server-revoke caveat: local credentials are deleted, but the refresh token remains valid server-side until the user removes the app from <https://quire.io/apps>.
|
|
13
|
+
|
|
14
|
+
### Input handling
|
|
15
|
+
|
|
16
|
+
- `quire task attach`, `quire comment attach`, `--from-file`, and `--text @file` now cap input size and tighten filename validation (no path separators, length-limited).
|
|
17
|
+
|
|
18
|
+
### Reliability
|
|
19
|
+
|
|
20
|
+
- 429 retry sleep gains ±10% jitter to spread out retry storms when many CLI processes hit the limit at once.
|
|
21
|
+
- Stderr warning when `QUIRE_API_SERVER` is set — surfaces non-default targets on every command.
|
|
22
|
+
|
|
23
|
+
### Build
|
|
24
|
+
|
|
25
|
+
- SEA-binary build verifies the auto-downloaded Node archive against a pinned SHA-256.
|
|
26
|
+
- macOS notarization stores credentials in a temporary keychain instead of passing them on `argv`.
|
|
27
|
+
|
|
3
28
|
## 0.1.0 — 2026-05-08
|
|
4
29
|
|
|
5
30
|
Initial release.
|
package/README.md
CHANGED
|
@@ -55,6 +55,16 @@ quire mine --all-orgs --json | jq '.[].name' # script-friendly
|
|
|
55
55
|
|
|
56
56
|
Full command reference will be added once the first commands land.
|
|
57
57
|
|
|
58
|
+
## Signing out
|
|
59
|
+
|
|
60
|
+
`quire logout` removes the local credentials file. It does **not** revoke
|
|
61
|
+
the OAuth refresh token on the Quire server — the public-PKCE flow gives
|
|
62
|
+
the CLI no way to authenticate a revoke call.
|
|
63
|
+
|
|
64
|
+
If you're signing out because the device is lost or compromised, also visit
|
|
65
|
+
<https://quire.io/apps> and remove the Quire CLI app to invalidate the
|
|
66
|
+
refresh token server-side.
|
|
67
|
+
|
|
58
68
|
## Related
|
|
59
69
|
|
|
60
70
|
- [Quire](https://quire.io) — the product this CLI talks to.
|
package/dist/cli.js
CHANGED
|
@@ -20,6 +20,7 @@ import { registerTaskCommand } from "./commands/task.js";
|
|
|
20
20
|
import { registerUndoCommand } from "./commands/undo.js";
|
|
21
21
|
import { registerUserCommand } from "./commands/user.js";
|
|
22
22
|
import { registerWhoamiCommand } from "./commands/whoami.js";
|
|
23
|
+
import { warnIfNonDefaultApiServer } from "./config.js";
|
|
23
24
|
import { handleError } from "./errors.js";
|
|
24
25
|
import { createLogger } from "./log.js";
|
|
25
26
|
import { readVersion } from "./version.js";
|
|
@@ -67,7 +68,7 @@ registerUndoCommand(program);
|
|
|
67
68
|
program.addHelpText("after", `
|
|
68
69
|
Auth:
|
|
69
70
|
quire login Sign in via OAuth (loopback + PKCE)
|
|
70
|
-
quire logout Remove
|
|
71
|
+
quire logout Remove local credentials (server-side token stays valid; revoke at quire.io/apps)
|
|
71
72
|
quire whoami Show the signed-in user
|
|
72
73
|
quire user get <oid> Show one user by OID
|
|
73
74
|
|
|
@@ -197,6 +198,7 @@ Reference:
|
|
|
197
198
|
quire colors List Quire's 48-slot palette (code, hex, name)
|
|
198
199
|
`);
|
|
199
200
|
async function main() {
|
|
201
|
+
warnIfNonDefaultApiServer();
|
|
200
202
|
await program.parseAsync(process.argv);
|
|
201
203
|
}
|
|
202
204
|
main().catch((err) => {
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
package/dist/commands/logout.js
CHANGED
|
@@ -18,7 +18,8 @@ export function registerLogoutCommand(program) {
|
|
|
18
18
|
}
|
|
19
19
|
deleteCredentials(root.profile);
|
|
20
20
|
if (root.quiet !== true) {
|
|
21
|
-
log.info(`Logged out — removed ${credentialsPath}
|
|
21
|
+
log.info(`Logged out — removed ${credentialsPath}.`);
|
|
22
|
+
log.warn("the refresh token is still valid on the Quire server. To fully revoke it, remove the app at https://quire.io/apps.");
|
|
22
23
|
}
|
|
23
24
|
});
|
|
24
25
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logout.js","sourceRoot":"","sources":["../../src/commands/logout.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACvE,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AASzC,MAAM,UAAU,qBAAqB,CAAC,OAAgB;IACpD,OAAO;SACJ,OAAO,CAAC,QAAQ,CAAC;SACjB,WAAW,CACV,iJAAiJ,CAClJ;SACA,MAAM,CAAC,GAAG,EAAE;QACX,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,EAAc,CAAC;QACxC,MAAM,GAAG,GAAG,YAAY,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,KAAK,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC;QAEpF,MAAM,MAAM,GAAG,eAAe,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC7C,MAAM,EAAE,eAAe,EAAE,GAAG,kBAAkB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAE7D,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,IAAI,IAAI,CAAC,KAAK,KAAK,IAAI,EAAE,CAAC;gBACxB,GAAG,CAAC,IAAI,CAAC,2BAA2B,eAAe,wBAAwB,CAAC,CAAC;YAC/E,CAAC;YACD,OAAO;QACT,CAAC;QAED,iBAAiB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAChC,IAAI,IAAI,CAAC,KAAK,KAAK,IAAI,EAAE,CAAC;YACxB,GAAG,CAAC,IAAI,
|
|
1
|
+
{"version":3,"file":"logout.js","sourceRoot":"","sources":["../../src/commands/logout.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACvE,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AASzC,MAAM,UAAU,qBAAqB,CAAC,OAAgB;IACpD,OAAO;SACJ,OAAO,CAAC,QAAQ,CAAC;SACjB,WAAW,CACV,iJAAiJ,CAClJ;SACA,MAAM,CAAC,GAAG,EAAE;QACX,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,EAAc,CAAC;QACxC,MAAM,GAAG,GAAG,YAAY,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,KAAK,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC;QAEpF,MAAM,MAAM,GAAG,eAAe,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC7C,MAAM,EAAE,eAAe,EAAE,GAAG,kBAAkB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAE7D,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,IAAI,IAAI,CAAC,KAAK,KAAK,IAAI,EAAE,CAAC;gBACxB,GAAG,CAAC,IAAI,CAAC,2BAA2B,eAAe,wBAAwB,CAAC,CAAC;YAC/E,CAAC;YACD,OAAO;QACT,CAAC;QAED,iBAAiB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAChC,IAAI,IAAI,CAAC,KAAK,KAAK,IAAI,EAAE,CAAC;YACxB,GAAG,CAAC,IAAI,CAAC,wBAAwB,eAAe,GAAG,CAAC,CAAC;YACrD,GAAG,CAAC,IAAI,CACN,oHAAoH,CACrH,CAAC;QACJ,CAAC;IACH,CAAC,CAAC,CAAC;AACP,CAAC"}
|
package/dist/config.js
CHANGED
|
@@ -31,7 +31,29 @@ export function ensureConfigDir(configDir) {
|
|
|
31
31
|
// recursive: true makes this idempotent.
|
|
32
32
|
mkdirSync(configDir, { recursive: true, mode: 0o700 });
|
|
33
33
|
}
|
|
34
|
+
export const DEFAULT_API_SERVER = "https://quire.io";
|
|
34
35
|
export function getApiServer() {
|
|
35
|
-
return process.env.QUIRE_API_SERVER ??
|
|
36
|
+
return process.env.QUIRE_API_SERVER ?? DEFAULT_API_SERVER;
|
|
37
|
+
}
|
|
38
|
+
// Per-process one-shot guard so repeated callers (cli startup + login)
|
|
39
|
+
// don't print the warning multiple times in the same invocation.
|
|
40
|
+
let apiServerWarned = false;
|
|
41
|
+
/**
|
|
42
|
+
* Print a stderr warning the first time it's called when `QUIRE_API_SERVER`
|
|
43
|
+
* is set to something other than the default. A persistent override (set
|
|
44
|
+
* in `.bashrc` or a parent shell) silently routes the OAuth flow through
|
|
45
|
+
* an attacker-controlled origin; a one-line warning gives the user a
|
|
46
|
+
* chance to spot it before clicking through the browser redirect.
|
|
47
|
+
*/
|
|
48
|
+
export function warnIfNonDefaultApiServer() {
|
|
49
|
+
if (apiServerWarned)
|
|
50
|
+
return;
|
|
51
|
+
const override = process.env.QUIRE_API_SERVER;
|
|
52
|
+
if (!override || override === DEFAULT_API_SERVER)
|
|
53
|
+
return;
|
|
54
|
+
apiServerWarned = true;
|
|
55
|
+
const useColor = process.stderr.isTTY === true && !process.env.NO_COLOR;
|
|
56
|
+
const prefix = useColor ? "\x1b[33mwarning:\x1b[0m" : "warning:";
|
|
57
|
+
process.stderr.write(`${prefix} using non-default API server ${override} (set via QUIRE_API_SERVER)\n`);
|
|
36
58
|
}
|
|
37
59
|
//# sourceMappingURL=config.js.map
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAQjC,SAAS,iBAAiB;IACxB,IAAI,OAAO,CAAC,GAAG,CAAC,iBAAiB;QAAE,OAAO,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC;IAExE,IAAI,QAAQ,EAAE,KAAK,OAAO,EAAE,CAAC;QAC3B,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,OAAO,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;QAC7E,OAAO,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAChC,CAAC;IAED,gEAAgE;IAChE,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC;IACxC,IAAI,GAAG;QAAE,OAAO,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IACnC,OAAO,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;AAC7C,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,OAAgB;IACjD,MAAM,SAAS,GAAG,iBAAiB,EAAE,CAAC;IACtC,MAAM,eAAe,GAAG,OAAO,IAAI,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,SAAS,CAAC;IAC1E,MAAM,eAAe,GACnB,eAAe,KAAK,SAAS;QAC3B,CAAC,CAAC,kBAAkB;QACpB,CAAC,CAAC,eAAe,eAAe,OAAO,CAAC;IAC5C,OAAO;QACL,SAAS;QACT,eAAe,EAAE,IAAI,CAAC,SAAS,EAAE,eAAe,CAAC;QACjD,OAAO,EAAE,eAAe;KACzB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,SAAiB;IAC/C,+DAA+D;IAC/D,yCAAyC;IACzC,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;AACzD,CAAC;AAED,MAAM,UAAU,YAAY;IAC1B,OAAO,OAAO,CAAC,GAAG,CAAC,gBAAgB,IAAI,kBAAkB,CAAC;AAC5D,CAAC"}
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAQjC,SAAS,iBAAiB;IACxB,IAAI,OAAO,CAAC,GAAG,CAAC,iBAAiB;QAAE,OAAO,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC;IAExE,IAAI,QAAQ,EAAE,KAAK,OAAO,EAAE,CAAC;QAC3B,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,OAAO,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;QAC7E,OAAO,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAChC,CAAC;IAED,gEAAgE;IAChE,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC;IACxC,IAAI,GAAG;QAAE,OAAO,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IACnC,OAAO,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;AAC7C,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,OAAgB;IACjD,MAAM,SAAS,GAAG,iBAAiB,EAAE,CAAC;IACtC,MAAM,eAAe,GAAG,OAAO,IAAI,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,SAAS,CAAC;IAC1E,MAAM,eAAe,GACnB,eAAe,KAAK,SAAS;QAC3B,CAAC,CAAC,kBAAkB;QACpB,CAAC,CAAC,eAAe,eAAe,OAAO,CAAC;IAC5C,OAAO;QACL,SAAS;QACT,eAAe,EAAE,IAAI,CAAC,SAAS,EAAE,eAAe,CAAC;QACjD,OAAO,EAAE,eAAe;KACzB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,SAAiB;IAC/C,+DAA+D;IAC/D,yCAAyC;IACzC,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;AACzD,CAAC;AAED,MAAM,CAAC,MAAM,kBAAkB,GAAG,kBAAkB,CAAC;AAErD,MAAM,UAAU,YAAY;IAC1B,OAAO,OAAO,CAAC,GAAG,CAAC,gBAAgB,IAAI,kBAAkB,CAAC;AAC5D,CAAC;AAED,uEAAuE;AACvE,iEAAiE;AACjE,IAAI,eAAe,GAAG,KAAK,CAAC;AAE5B;;;;;;GAMG;AACH,MAAM,UAAU,yBAAyB;IACvC,IAAI,eAAe;QAAE,OAAO;IAC5B,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC;IAC9C,IAAI,CAAC,QAAQ,IAAI,QAAQ,KAAK,kBAAkB;QAAE,OAAO;IACzD,eAAe,GAAG,IAAI,CAAC;IACvB,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,KAAK,KAAK,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC;IACxE,MAAM,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC,yBAAyB,CAAC,CAAC,CAAC,UAAU,CAAC;IACjE,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,GAAG,MAAM,iCAAiC,QAAQ,+BAA+B,CAClF,CAAC;AACJ,CAAC"}
|
package/dist/credentials.js
CHANGED
|
Binary file
|
package/dist/credentials.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"credentials.js","sourceRoot":"","sources":["../src/credentials.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EACV,YAAY,EACZ,UAAU,EACV,UAAU,EACV,aAAa,GACd,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"credentials.js","sourceRoot":"","sources":["../src/credentials.ts"],"names":[],"mappings":"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"}
|
package/dist/oauth/config.js
CHANGED
|
@@ -2,13 +2,9 @@
|
|
|
2
2
|
//
|
|
3
3
|
// Public client — no client_secret. Authorization is gated by PKCE (RFC 7636)
|
|
4
4
|
// and a loopback redirect URI per RFC 8252. The OAuth app is registered at
|
|
5
|
-
// <https://quire.io/apps/dev/quire_cli>; this constant is the
|
|
5
|
+
// <https://quire.io/apps/dev/quire_cli>; this constant is the published
|
|
6
6
|
// `client_id` from that page.
|
|
7
|
-
|
|
8
|
-
// !!! Development client_id !!!
|
|
9
|
-
// This is the *development* OAuth app. Swap for the production `client_id`
|
|
10
|
-
// before cutting the first public release.
|
|
11
|
-
export const QUIRE_CLI_CLIENT_ID = ":0000mVxxApzA5wCng9iFk3Nzw0v";
|
|
7
|
+
export const QUIRE_CLI_CLIENT_ID = "0mVxxApzA5wCng9iFk3Nzw0v";
|
|
12
8
|
// Fixed loopback port for the OAuth callback. The Quire OAuth app form
|
|
13
9
|
// requires an exact-match redirect URI (no RFC 8252 §7.3 port-wildcard
|
|
14
10
|
// support yet), so the CLI binds to a single known port and the OAuth app's
|
package/dist/oauth/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/oauth/config.ts"],"names":[],"mappings":"AAAA,gDAAgD;AAChD,EAAE;AACF,8EAA8E;AAC9E,2EAA2E;AAC3E,
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/oauth/config.ts"],"names":[],"mappings":"AAAA,gDAAgD;AAChD,EAAE;AACF,8EAA8E;AAC9E,2EAA2E;AAC3E,wEAAwE;AACxE,8BAA8B;AAC9B,MAAM,CAAC,MAAM,mBAAmB,GAAG,0BAA0B,CAAC;AAE9D,uEAAuE;AACvE,uEAAuE;AACvE,4EAA4E;AAC5E,iFAAiF;AACjF,EAAE;AACF,yEAAyE;AACzE,0EAA0E;AAC1E,8DAA8D;AAC9D,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,uBAAuB,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;AAChF,MAAM,CAAC,MAAM,uBAAuB,GAClC,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,QAAQ,GAAG,IAAI,IAAI,QAAQ,GAAG,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC"}
|
package/dist/oauth/loopback.js
CHANGED
|
@@ -5,12 +5,26 @@ const SUCCESS_HTML = `<!doctype html>
|
|
|
5
5
|
h1{font-size:1.4rem}p{color:#555}</style></head>
|
|
6
6
|
<body><h1>You're signed in to Quire.</h1><p>You can close this window and return to your terminal.</p></body></html>
|
|
7
7
|
`;
|
|
8
|
+
// HTML-encode `reason` before interpolation. The OAuth callback's `error`
|
|
9
|
+
// and `error_description` query params are attacker-controllable (a
|
|
10
|
+
// crafted link can hand any string to this code path), so unescaped
|
|
11
|
+
// interpolation would be reflected XSS at the `http://127.0.0.1:<port>`
|
|
12
|
+
// origin. Limited blast radius — no cross-site cookies — but a script
|
|
13
|
+
// loaded here can probe other localhost services on the same machine.
|
|
14
|
+
function escapeHtml(s) {
|
|
15
|
+
return s
|
|
16
|
+
.replace(/&/g, "&")
|
|
17
|
+
.replace(/</g, "<")
|
|
18
|
+
.replace(/>/g, ">")
|
|
19
|
+
.replace(/"/g, """)
|
|
20
|
+
.replace(/'/g, "'");
|
|
21
|
+
}
|
|
8
22
|
function failureHtml(reason) {
|
|
9
23
|
return `<!doctype html>
|
|
10
24
|
<html><head><meta charset="utf-8"><title>Quire CLI — login failed</title>
|
|
11
25
|
<style>body{font-family:-apple-system,Segoe UI,Roboto,sans-serif;max-width:32rem;margin:5rem auto;padding:0 1rem;color:#222;text-align:center}
|
|
12
26
|
h1{font-size:1.4rem;color:#b00020}p{color:#555}code{background:#f4f4f4;padding:.1rem .3rem;border-radius:3px}</style></head>
|
|
13
|
-
<body><h1>Login failed</h1><p><code>${reason}</code></p><p>You can close this window.</p></body></html>
|
|
27
|
+
<body><h1>Login failed</h1><p><code>${escapeHtml(reason)}</code></p><p>You can close this window.</p></body></html>
|
|
14
28
|
`;
|
|
15
29
|
}
|
|
16
30
|
/**
|
|
@@ -25,12 +39,28 @@ export async function startLoopbackServer(opts = {}) {
|
|
|
25
39
|
resolveResult = resolve;
|
|
26
40
|
rejectResult = reject;
|
|
27
41
|
});
|
|
42
|
+
// Set after server.listen() resolves; read by the handler on every request.
|
|
43
|
+
// Used to validate the incoming `Host:` header — see the check below.
|
|
44
|
+
let boundPort;
|
|
28
45
|
const handler = (req, res) => {
|
|
29
46
|
if (!req.url) {
|
|
30
47
|
res.writeHead(400, { "Content-Type": "text/plain" });
|
|
31
48
|
res.end("Bad request");
|
|
32
49
|
return;
|
|
33
50
|
}
|
|
51
|
+
// Reject any request whose Host header isn't the loopback we bound to.
|
|
52
|
+
// The legitimate browser redirect arrives as `Host: 127.0.0.1:<port>`;
|
|
53
|
+
// a remote site abusing DNS rebinding (attacker.com → 127.0.0.1) sends
|
|
54
|
+
// `Host: attacker.com:<port>`. Without this check, that remote request
|
|
55
|
+
// is enough to resolve the single-shot callback promise, killing the
|
|
56
|
+
// legitimate in-flight login.
|
|
57
|
+
const host = req.headers.host;
|
|
58
|
+
if (boundPort === undefined ||
|
|
59
|
+
(host !== `127.0.0.1:${boundPort}` && host !== `localhost:${boundPort}`)) {
|
|
60
|
+
res.writeHead(400, { "Content-Type": "text/plain" });
|
|
61
|
+
res.end("Bad host");
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
34
64
|
const url = new URL(req.url, "http://127.0.0.1");
|
|
35
65
|
if (url.pathname !== "/callback") {
|
|
36
66
|
res.writeHead(404, { "Content-Type": "text/plain" });
|
|
@@ -72,6 +102,7 @@ export async function startLoopbackServer(opts = {}) {
|
|
|
72
102
|
server.listen(port, "127.0.0.1", () => resolve());
|
|
73
103
|
});
|
|
74
104
|
const address = server.address();
|
|
105
|
+
boundPort = address.port;
|
|
75
106
|
const redirectUri = `http://127.0.0.1:${address.port}/callback`;
|
|
76
107
|
let closed = false;
|
|
77
108
|
const close = () => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loopback.js","sourceRoot":"","sources":["../../src/oauth/loopback.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAA6C,MAAM,WAAW,CAAC;AAiBpF,MAAM,YAAY,GAAG;;;;;CAKpB,CAAC;AAEF,SAAS,WAAW,CAAC,MAAc;IACjC,OAAO;;;;sCAI6B,MAAM;
|
|
1
|
+
{"version":3,"file":"loopback.js","sourceRoot":"","sources":["../../src/oauth/loopback.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,10 @@
|
|
|
1
|
-
import { readFileSync } from "node:fs";
|
|
2
1
|
import { basename } from "node:path";
|
|
3
2
|
import { ValidationError } from "../errors.js";
|
|
3
|
+
import { readBytesWithLimit } from "./read-sized.js";
|
|
4
|
+
// Cap attachments at 100 MiB. The Quire server enforces its own ceiling
|
|
5
|
+
// further down the stack; this is a sanity check so an accidental
|
|
6
|
+
// `attach <id> /var/log/system.log` fails fast instead of OOMing the CLI.
|
|
7
|
+
const MAX_ATTACHMENT_BYTES = 100 * 1024 * 1024;
|
|
4
8
|
const CONTENT_TYPE_BY_EXT = {
|
|
5
9
|
".bmp": "image/bmp",
|
|
6
10
|
".csv": "text/csv",
|
|
@@ -30,30 +34,38 @@ const CONTENT_TYPE_BY_EXT = {
|
|
|
30
34
|
* and the filename defaults to its `basename`.
|
|
31
35
|
*/
|
|
32
36
|
export async function resolveAttachInput(path, opts = {}) {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
if (path === "-") {
|
|
36
|
-
if (opts.filename === undefined) {
|
|
37
|
-
throw new ValidationError("--filename is required when reading attachment data from stdin (`-`).");
|
|
38
|
-
}
|
|
39
|
-
const chunks = [];
|
|
40
|
-
for await (const chunk of process.stdin)
|
|
41
|
-
chunks.push(chunk);
|
|
42
|
-
bytes = Buffer.concat(chunks);
|
|
43
|
-
filename = opts.filename;
|
|
44
|
-
}
|
|
45
|
-
else {
|
|
46
|
-
bytes = readFileSync(path);
|
|
47
|
-
filename = opts.filename ?? basename(path);
|
|
48
|
-
}
|
|
49
|
-
if (filename.includes("/")) {
|
|
50
|
-
throw new ValidationError(`Attachment filename cannot contain "/" — got "${filename}".`);
|
|
37
|
+
if (path === "-" && opts.filename === undefined) {
|
|
38
|
+
throw new ValidationError("--filename is required when reading attachment data from stdin (`-`).");
|
|
51
39
|
}
|
|
40
|
+
const bytes = await readBytesWithLimit(path, MAX_ATTACHMENT_BYTES, "Attachment");
|
|
41
|
+
const filename = path === "-"
|
|
42
|
+
? opts.filename
|
|
43
|
+
: opts.filename ?? basename(path);
|
|
44
|
+
validateFilename(filename);
|
|
45
|
+
const contentType = opts.contentType ?? guessContentType(filename);
|
|
46
|
+
return { filename, bytes, contentType };
|
|
47
|
+
}
|
|
48
|
+
// Reject a filename before we send it to the server. Defense-in-depth on
|
|
49
|
+
// top of whatever the server itself validates: catch the obvious
|
|
50
|
+
// path-traversal / control-char shapes here so failures surface as a
|
|
51
|
+
// clean ValidationError instead of a confusing 4xx round-trip.
|
|
52
|
+
function validateFilename(filename) {
|
|
52
53
|
if (filename.length === 0) {
|
|
53
54
|
throw new ValidationError("Attachment filename cannot be empty.");
|
|
54
55
|
}
|
|
55
|
-
|
|
56
|
-
|
|
56
|
+
if (filename === "." || filename === "..") {
|
|
57
|
+
throw new ValidationError(`Attachment filename "${filename}" is not allowed.`);
|
|
58
|
+
}
|
|
59
|
+
// Path separators (POSIX `/`, Windows `\`) and ASCII control characters
|
|
60
|
+
// (0x00–0x1f, including NUL — null bytes are a string-truncation classic
|
|
61
|
+
// for downstream C-based consumers).
|
|
62
|
+
const bad = filename.match(/[\x00-\x1f/\\]/);
|
|
63
|
+
if (bad) {
|
|
64
|
+
const ch = bad[0];
|
|
65
|
+
const code = ch.charCodeAt(0);
|
|
66
|
+
const display = code < 0x20 ? `\\x${code.toString(16).padStart(2, "0")}` : ch;
|
|
67
|
+
throw new ValidationError(`Attachment filename contains a disallowed character "${display}" — got "${filename}".`);
|
|
68
|
+
}
|
|
57
69
|
}
|
|
58
70
|
function guessContentType(filename) {
|
|
59
71
|
const dot = filename.lastIndexOf(".");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"attach-input.js","sourceRoot":"","sources":["../../src/util/attach-input.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"attach-input.js","sourceRoot":"","sources":["../../src/util/attach-input.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAErC,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAErD,wEAAwE;AACxE,kEAAkE;AAClE,0EAA0E;AAC1E,MAAM,oBAAoB,GAAG,GAAG,GAAG,IAAI,GAAG,IAAI,CAAC;AAE/C,MAAM,mBAAmB,GAAqC;IAC5D,MAAM,EAAE,WAAW;IACnB,MAAM,EAAE,UAAU;IAClB,MAAM,EAAE,WAAW;IACnB,OAAO,EAAE,WAAW;IACpB,OAAO,EAAE,YAAY;IACrB,MAAM,EAAE,YAAY;IACpB,OAAO,EAAE,kBAAkB;IAC3B,MAAM,EAAE,YAAY;IACpB,KAAK,EAAE,eAAe;IACtB,MAAM,EAAE,iBAAiB;IACzB,MAAM,EAAE,WAAW;IACnB,MAAM,EAAE,eAAe;IACvB,MAAM,EAAE,mBAAmB;IAC3B,MAAM,EAAE,YAAY;IACpB,OAAO,EAAE,YAAY;IACrB,MAAM,EAAE,iBAAiB;IACzB,OAAO,EAAE,kBAAkB;IAC3B,MAAM,EAAE,kBAAkB;IAC1B,MAAM,EAAE,iBAAiB;CAC1B,CAAC;AAeF;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,IAAY,EACZ,OAA6B,EAAE;IAE/B,IAAI,IAAI,KAAK,GAAG,IAAI,IAAI,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;QAChD,MAAM,IAAI,eAAe,CAAC,uEAAuE,CAAC,CAAC;IACrG,CAAC;IACD,MAAM,KAAK,GAAG,MAAM,kBAAkB,CAAC,IAAI,EAAE,oBAAoB,EAAE,YAAY,CAAC,CAAC;IACjF,MAAM,QAAQ,GAAG,IAAI,KAAK,GAAG;QAC3B,CAAC,CAAE,IAAI,CAAC,QAAmB;QAC3B,CAAC,CAAC,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC;IAEpC,gBAAgB,CAAC,QAAQ,CAAC,CAAC;IAE3B,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,IAAI,gBAAgB,CAAC,QAAQ,CAAC,CAAC;IACnE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC;AAC1C,CAAC;AAED,yEAAyE;AACzE,iEAAiE;AACjE,qEAAqE;AACrE,+DAA+D;AAC/D,SAAS,gBAAgB,CAAC,QAAgB;IACxC,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,MAAM,IAAI,eAAe,CAAC,sCAAsC,CAAC,CAAC;IACpE,CAAC;IACD,IAAI,QAAQ,KAAK,GAAG,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;QAC1C,MAAM,IAAI,eAAe,CAAC,wBAAwB,QAAQ,mBAAmB,CAAC,CAAC;IACjF,CAAC;IACD,wEAAwE;IACxE,yEAAyE;IACzE,qCAAqC;IACrC,MAAM,GAAG,GAAG,QAAQ,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC;IAC7C,IAAI,GAAG,EAAE,CAAC;QACR,MAAM,EAAE,GAAG,GAAG,CAAC,CAAC,CAAW,CAAC;QAC5B,MAAM,IAAI,GAAG,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;QAC9B,MAAM,OAAO,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC9E,MAAM,IAAI,eAAe,CACvB,wDAAwD,OAAO,YAAY,QAAQ,IAAI,CACxF,CAAC;IACJ,CAAC;AACH,CAAC;AAED,SAAS,gBAAgB,CAAC,QAAgB;IACxC,MAAM,GAAG,GAAG,QAAQ,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IACtC,IAAI,GAAG,GAAG,CAAC;QAAE,OAAO,0BAA0B,CAAC;IAC/C,MAAM,GAAG,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,CAAC;IAC9C,OAAO,mBAAmB,CAAC,GAAG,CAAC,IAAI,0BAA0B,CAAC;AAChE,CAAC"}
|
package/dist/util/bulk-input.js
CHANGED
|
@@ -1,18 +1,16 @@
|
|
|
1
|
-
import { readFileSync } from "node:fs";
|
|
2
1
|
import { ValidationError } from "../errors.js";
|
|
2
|
+
import { readBytesWithLimit } from "./read-sized.js";
|
|
3
|
+
// Cap bulk-input files at 25 MiB. A 300-task bulk payload (the server's
|
|
4
|
+
// per-call ceiling) fits comfortably in well under 1 MiB; 25 MiB is the
|
|
5
|
+
// "you almost certainly aimed at the wrong file" line.
|
|
6
|
+
const MAX_BULK_BYTES = 25 * 1024 * 1024;
|
|
3
7
|
/**
|
|
4
8
|
* Read text from a file path or stdin (`-`). Used by the bulk subcommands
|
|
5
9
|
* so users can either point at a file or pipe `jq` output directly.
|
|
6
10
|
*/
|
|
7
11
|
export async function readFromFile(filename) {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
for await (const chunk of process.stdin) {
|
|
11
|
-
chunks.push(chunk);
|
|
12
|
-
}
|
|
13
|
-
return Buffer.concat(chunks).toString("utf8");
|
|
14
|
-
}
|
|
15
|
-
return readFileSync(filename, "utf8");
|
|
12
|
+
const bytes = await readBytesWithLimit(filename, MAX_BULK_BYTES, "--from-file input");
|
|
13
|
+
return bytes.toString("utf8");
|
|
16
14
|
}
|
|
17
15
|
/**
|
|
18
16
|
* Parse an `--from-file` source as a JSON array of objects (for `bulk-create`
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bulk-input.js","sourceRoot":"","sources":["../../src/util/bulk-input.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"bulk-input.js","sourceRoot":"","sources":["../../src/util/bulk-input.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAErD,wEAAwE;AACxE,wEAAwE;AACxE,uDAAuD;AACvD,MAAM,cAAc,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC;AAExC;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,QAAgB;IACjD,MAAM,KAAK,GAAG,MAAM,kBAAkB,CAAC,QAAQ,EAAE,cAAc,EAAE,mBAAmB,CAAC,CAAC;IACtF,OAAO,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;AAChC,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,QAAgB;IAClD,MAAM,IAAI,GAAG,MAAM,YAAY,CAAC,QAAQ,CAAC,CAAC;IAC1C,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC5B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,eAAe,CAAC,8BAA8B,QAAQ,MAAO,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;IAClG,CAAC;IACD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAC3B,MAAM,IAAI,eAAe,CAAC,6BAA6B,QAAQ,IAAI,CAAC,CAAC;IACvE,CAAC;IACD,KAAK,MAAM,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,EAAE,EAAE,CAAC;QACzC,IAAI,IAAI,KAAK,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;YACrE,MAAM,IAAI,eAAe,CAAC,WAAW,CAAC,QAAQ,QAAQ,qBAAqB,CAAC,CAAC;QAC/E,CAAC;IACH,CAAC;IACD,OAAO,MAAmC,CAAC;AAC7C,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,QAAgB;IACjD,MAAM,IAAI,GAAG,MAAM,YAAY,CAAC,QAAQ,CAAC,CAAC;IAC1C,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;IAC5B,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAEpC,IAAI,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QAC5B,IAAI,MAAe,CAAC;QACpB,IAAI,CAAC;YACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAC/B,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,IAAI,eAAe,CAAC,8BAA8B,QAAQ,MAAO,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;QAClG,CAAC;QACD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YAC3B,MAAM,IAAI,eAAe,CAAC,qCAAqC,QAAQ,IAAI,CAAC,CAAC;QAC/E,CAAC;QACD,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;YACzB,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,OAAO,CAAC,KAAK,QAAQ;gBAAE,OAAO,CAAC,CAAC;YAC7D,MAAM,IAAI,eAAe,CAAC,WAAW,CAAC,QAAQ,QAAQ,8BAA8B,CAAC,CAAC;QACxF,CAAC,CAAC,CAAC;IACL,CAAC;IAED,OAAO,OAAO;SACX,KAAK,CAAC,OAAO,CAAC;SACd,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;SAC1B,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;SAC1D,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AAC5E,CAAC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { readFileSync, statSync } from "node:fs";
|
|
2
|
+
import { ValidationError } from "../errors.js";
|
|
3
|
+
function formatSize(bytes) {
|
|
4
|
+
if (bytes >= 1024 * 1024)
|
|
5
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)} MiB`;
|
|
6
|
+
if (bytes >= 1024)
|
|
7
|
+
return `${(bytes / 1024).toFixed(1)} KiB`;
|
|
8
|
+
return `${bytes} B`;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Read bytes from a file path (or stdin via `-`) with a hard size cap.
|
|
12
|
+
* Checked against `stat().size` for files (cheap) and accumulated
|
|
13
|
+
* byte-by-byte for stdin so a runaway pipe can't fill memory.
|
|
14
|
+
*
|
|
15
|
+
* Throws `ValidationError` (exit 3) when the input exceeds `maxBytes`.
|
|
16
|
+
*/
|
|
17
|
+
export async function readBytesWithLimit(path, maxBytes, label) {
|
|
18
|
+
if (path === "-") {
|
|
19
|
+
const chunks = [];
|
|
20
|
+
let total = 0;
|
|
21
|
+
for await (const chunk of process.stdin) {
|
|
22
|
+
const c = chunk;
|
|
23
|
+
total += c.length;
|
|
24
|
+
if (total > maxBytes) {
|
|
25
|
+
throw new ValidationError(`${label} from stdin exceeds the ${formatSize(maxBytes)} cap.`);
|
|
26
|
+
}
|
|
27
|
+
chunks.push(c);
|
|
28
|
+
}
|
|
29
|
+
return Buffer.concat(chunks);
|
|
30
|
+
}
|
|
31
|
+
const size = statSync(path).size;
|
|
32
|
+
if (size > maxBytes) {
|
|
33
|
+
throw new ValidationError(`${label} "${path}" is ${formatSize(size)} (cap: ${formatSize(maxBytes)}).`);
|
|
34
|
+
}
|
|
35
|
+
return readFileSync(path);
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=read-sized.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"read-sized.js","sourceRoot":"","sources":["../../src/util/read-sized.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEjD,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAE/C,SAAS,UAAU,CAAC,KAAa;IAC/B,IAAI,KAAK,IAAI,IAAI,GAAG,IAAI;QAAE,OAAO,GAAG,CAAC,KAAK,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC;IAC7E,IAAI,KAAK,IAAI,IAAI;QAAE,OAAO,GAAG,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC;IAC7D,OAAO,GAAG,KAAK,IAAI,CAAC;AACtB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,IAAY,EACZ,QAAgB,EAChB,KAAa;IAEb,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;QACjB,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,IAAI,KAAK,GAAG,CAAC,CAAC;QACd,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;YACxC,MAAM,CAAC,GAAG,KAAe,CAAC;YAC1B,KAAK,IAAI,CAAC,CAAC,MAAM,CAAC;YAClB,IAAI,KAAK,GAAG,QAAQ,EAAE,CAAC;gBACrB,MAAM,IAAI,eAAe,CACvB,GAAG,KAAK,2BAA2B,UAAU,CAAC,QAAQ,CAAC,OAAO,CAC/D,CAAC;YACJ,CAAC;YACD,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACjB,CAAC;QACD,OAAO,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAC/B,CAAC;IACD,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC;IACjC,IAAI,IAAI,GAAG,QAAQ,EAAE,CAAC;QACpB,MAAM,IAAI,eAAe,CACvB,GAAG,KAAK,KAAK,IAAI,QAAQ,UAAU,CAAC,IAAI,CAAC,UAAU,UAAU,CAAC,QAAQ,CAAC,IAAI,CAC5E,CAAC;IACJ,CAAC;IACD,OAAO,YAAY,CAAC,IAAI,CAAC,CAAC;AAC5B,CAAC"}
|
package/dist/util/retry-after.js
CHANGED
|
@@ -49,7 +49,10 @@ export async function withRetryOn429(fn, opts = {}) {
|
|
|
49
49
|
throw new CliError(`Quire API rate limited; retry in ${waitSec}s`, ExitCode.ApiError);
|
|
50
50
|
}
|
|
51
51
|
opts.onRetry?.(waitSec);
|
|
52
|
-
|
|
52
|
+
// Add ±10% jitter so N parallel CLIs that all tripped the limit
|
|
53
|
+
// don't wake up at exactly the same instant and stampede again.
|
|
54
|
+
const jitterMs = waitSec * 1000 * (0.9 + Math.random() * 0.2);
|
|
55
|
+
await sleep(Math.ceil(jitterMs));
|
|
53
56
|
return await fn();
|
|
54
57
|
}
|
|
55
58
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"retry-after.js","sourceRoot":"","sources":["../../src/util/retry-after.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAElD,MAAM,eAAe,GAAG,EAAE,CAAC;AAC3B,MAAM,mBAAmB,GAAG,qBAAqB,CAAC;AAClD,sEAAsE;AACtE,MAAM,mBAAmB,GAAG,qCAAqC,CAAC;AAElE,SAAS,kBAAkB,CAAC,OAAe;IACzC,MAAM,CAAC,GAAG,mBAAmB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC5C,IAAI,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IACpB,MAAM,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACrD,MAAM,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACrD,MAAM,KAAK,GAAG,OAAO,GAAG,EAAE,GAAG,OAAO,CAAC;IACrC,OAAO,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;AAClC,CAAC;AAED,SAAS,aAAa,CAAC,GAAY;IACjC,OAAO,GAAG,YAAY,KAAK,IAAI,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,mBAAmB,CAAC,CAAC;AAC7E,CAAC;AAED,MAAM,KAAK,GAAG,CAAC,EAAU,EAAiB,EAAE,CAC1C,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;AAEpD,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,EAAoB,EACpB,OAAiE,EAAE;IAEnE,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,IAAI,eAAe,CAAC;IAC3C,IAAI,CAAC;QACH,OAAO,MAAM,EAAE,EAAE,CAAC;IACpB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC;YAAE,MAAM,GAAG,CAAC;QACnC,MAAM,OAAO,GAAG,kBAAkB,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAChD,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;YACrB,MAAM,IAAI,QAAQ,CAChB,uEAAuE,EACvE,QAAQ,CAAC,QAAQ,CAClB,CAAC;QACJ,CAAC;QACD,IAAI,OAAO,GAAG,GAAG,EAAE,CAAC;YAClB,MAAM,IAAI,QAAQ,CAChB,oCAAoC,OAAO,GAAG,EAC9C,QAAQ,CAAC,QAAQ,CAClB,CAAC;QACJ,CAAC;QACD,IAAI,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,CAAC;QACxB,MAAM,
|
|
1
|
+
{"version":3,"file":"retry-after.js","sourceRoot":"","sources":["../../src/util/retry-after.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAElD,MAAM,eAAe,GAAG,EAAE,CAAC;AAC3B,MAAM,mBAAmB,GAAG,qBAAqB,CAAC;AAClD,sEAAsE;AACtE,MAAM,mBAAmB,GAAG,qCAAqC,CAAC;AAElE,SAAS,kBAAkB,CAAC,OAAe;IACzC,MAAM,CAAC,GAAG,mBAAmB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC5C,IAAI,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IACpB,MAAM,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACrD,MAAM,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACrD,MAAM,KAAK,GAAG,OAAO,GAAG,EAAE,GAAG,OAAO,CAAC;IACrC,OAAO,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;AAClC,CAAC;AAED,SAAS,aAAa,CAAC,GAAY;IACjC,OAAO,GAAG,YAAY,KAAK,IAAI,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,mBAAmB,CAAC,CAAC;AAC7E,CAAC;AAED,MAAM,KAAK,GAAG,CAAC,EAAU,EAAiB,EAAE,CAC1C,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;AAEpD,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,EAAoB,EACpB,OAAiE,EAAE;IAEnE,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,IAAI,eAAe,CAAC;IAC3C,IAAI,CAAC;QACH,OAAO,MAAM,EAAE,EAAE,CAAC;IACpB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC;YAAE,MAAM,GAAG,CAAC;QACnC,MAAM,OAAO,GAAG,kBAAkB,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAChD,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;YACrB,MAAM,IAAI,QAAQ,CAChB,uEAAuE,EACvE,QAAQ,CAAC,QAAQ,CAClB,CAAC;QACJ,CAAC;QACD,IAAI,OAAO,GAAG,GAAG,EAAE,CAAC;YAClB,MAAM,IAAI,QAAQ,CAChB,oCAAoC,OAAO,GAAG,EAC9C,QAAQ,CAAC,QAAQ,CAClB,CAAC;QACJ,CAAC;QACD,IAAI,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,CAAC;QACxB,gEAAgE;QAChE,gEAAgE;QAChE,MAAM,QAAQ,GAAG,OAAO,GAAG,IAAI,GAAG,CAAC,GAAG,GAAG,IAAI,CAAC,MAAM,EAAE,GAAG,GAAG,CAAC,CAAC;QAC9D,MAAM,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;QACjC,OAAO,MAAM,EAAE,EAAE,CAAC;IACpB,CAAC;AACH,CAAC"}
|
package/dist/util/text-input.js
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { readBytesWithLimit } from "./read-sized.js";
|
|
2
|
+
// Cap text inputs (descriptions, comments, notification messages) at
|
|
3
|
+
// 5 MiB. Anything bigger is almost certainly the wrong file.
|
|
4
|
+
const MAX_TEXT_BYTES = 5 * 1024 * 1024;
|
|
2
5
|
/**
|
|
3
6
|
* Resolve a `--text`-style flag value into actual text. Three forms:
|
|
4
7
|
*
|
|
@@ -12,14 +15,12 @@ import { readFileSync } from "node:fs";
|
|
|
12
15
|
*/
|
|
13
16
|
export async function resolveTextInput(value) {
|
|
14
17
|
if (value === "-") {
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
chunks.push(chunk);
|
|
18
|
-
}
|
|
19
|
-
return Buffer.concat(chunks).toString("utf8");
|
|
18
|
+
const bytes = await readBytesWithLimit("-", MAX_TEXT_BYTES, "Text input");
|
|
19
|
+
return bytes.toString("utf8");
|
|
20
20
|
}
|
|
21
21
|
if (value.startsWith("@")) {
|
|
22
|
-
|
|
22
|
+
const bytes = await readBytesWithLimit(value.slice(1), MAX_TEXT_BYTES, "Text input");
|
|
23
|
+
return bytes.toString("utf8");
|
|
23
24
|
}
|
|
24
25
|
return value;
|
|
25
26
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"text-input.js","sourceRoot":"","sources":["../../src/util/text-input.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"text-input.js","sourceRoot":"","sources":["../../src/util/text-input.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAErD,qEAAqE;AACrE,6DAA6D;AAC7D,MAAM,cAAc,GAAG,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC;AAEvC;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,KAAa;IAClD,IAAI,KAAK,KAAK,GAAG,EAAE,CAAC;QAClB,MAAM,KAAK,GAAG,MAAM,kBAAkB,CAAC,GAAG,EAAE,cAAc,EAAE,YAAY,CAAC,CAAC;QAC1E,OAAO,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IAChC,CAAC;IACD,IAAI,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QAC1B,MAAM,KAAK,GAAG,MAAM,kBAAkB,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,YAAY,CAAC,CAAC;QACrF,OAAO,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IAChC,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
|