neonctl 2.37.0 → 2.38.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.
Files changed (160) hide show
  1. package/{LICENSE.md → LICENSE} +27 -3
  2. package/README.md +15 -700
  3. package/bin/cli.js +3 -0
  4. package/package.json +8 -75
  5. package/dist/analytics.js +0 -168
  6. package/dist/api.js +0 -720
  7. package/dist/auth.js +0 -125
  8. package/dist/callback.html +0 -51
  9. package/dist/cli.js +0 -9
  10. package/dist/commands/api.js +0 -278
  11. package/dist/commands/auth.js +0 -214
  12. package/dist/commands/bootstrap.js +0 -481
  13. package/dist/commands/branches.js +0 -488
  14. package/dist/commands/bucket.js +0 -549
  15. package/dist/commands/checkout.js +0 -321
  16. package/dist/commands/config.js +0 -626
  17. package/dist/commands/connection_string.js +0 -172
  18. package/dist/commands/data_api.js +0 -284
  19. package/dist/commands/databases.js +0 -82
  20. package/dist/commands/deploy.js +0 -26
  21. package/dist/commands/dev.js +0 -698
  22. package/dist/commands/diff.js +0 -222
  23. package/dist/commands/env.js +0 -189
  24. package/dist/commands/functions.js +0 -373
  25. package/dist/commands/index.js +0 -62
  26. package/dist/commands/init.js +0 -73
  27. package/dist/commands/inspect.js +0 -65
  28. package/dist/commands/ip_allow.js +0 -137
  29. package/dist/commands/link.js +0 -1121
  30. package/dist/commands/neon_auth.js +0 -1028
  31. package/dist/commands/operations.js +0 -28
  32. package/dist/commands/orgs.js +0 -24
  33. package/dist/commands/projects.js +0 -413
  34. package/dist/commands/psql.js +0 -62
  35. package/dist/commands/roles.js +0 -65
  36. package/dist/commands/schema_diff.js +0 -151
  37. package/dist/commands/set_context.js +0 -29
  38. package/dist/commands/snapshots.js +0 -455
  39. package/dist/commands/status.js +0 -40
  40. package/dist/commands/user.js +0 -15
  41. package/dist/commands/vpc_endpoints.js +0 -134
  42. package/dist/config.js +0 -11
  43. package/dist/config_format.js +0 -72
  44. package/dist/context.js +0 -231
  45. package/dist/current_branch_fast_path.js +0 -55
  46. package/dist/dev/env.js +0 -244
  47. package/dist/dev/functions.js +0 -70
  48. package/dist/dev/inputs.js +0 -63
  49. package/dist/dev/runtime.js +0 -146
  50. package/dist/env.js +0 -36
  51. package/dist/env_file.js +0 -159
  52. package/dist/errors.js +0 -80
  53. package/dist/functions_api.js +0 -48
  54. package/dist/help.js +0 -146
  55. package/dist/index.js +0 -240
  56. package/dist/log.js +0 -18
  57. package/dist/parameters.gen.js +0 -480
  58. package/dist/pkg.js +0 -25
  59. package/dist/psql/cli.js +0 -53
  60. package/dist/psql/command/cmd_cond.js +0 -437
  61. package/dist/psql/command/cmd_connect.js +0 -820
  62. package/dist/psql/command/cmd_copy.js +0 -1035
  63. package/dist/psql/command/cmd_describe.js +0 -1815
  64. package/dist/psql/command/cmd_format.js +0 -948
  65. package/dist/psql/command/cmd_io.js +0 -2193
  66. package/dist/psql/command/cmd_lo.js +0 -393
  67. package/dist/psql/command/cmd_meta.js +0 -969
  68. package/dist/psql/command/cmd_misc.js +0 -187
  69. package/dist/psql/command/cmd_pipeline.js +0 -1148
  70. package/dist/psql/command/cmd_restrict.js +0 -171
  71. package/dist/psql/command/cmd_show.js +0 -766
  72. package/dist/psql/command/dispatch.js +0 -343
  73. package/dist/psql/command/inputQueue.js +0 -42
  74. package/dist/psql/command/shared.js +0 -71
  75. package/dist/psql/complete/filenames.js +0 -139
  76. package/dist/psql/complete/index.js +0 -104
  77. package/dist/psql/complete/matcher.js +0 -315
  78. package/dist/psql/complete/psqlVars.js +0 -249
  79. package/dist/psql/complete/queries.js +0 -493
  80. package/dist/psql/complete/rules.js +0 -2424
  81. package/dist/psql/core/common.js +0 -1253
  82. package/dist/psql/core/help.js +0 -576
  83. package/dist/psql/core/mainloop.js +0 -1360
  84. package/dist/psql/core/prompt.js +0 -439
  85. package/dist/psql/core/settings.js +0 -686
  86. package/dist/psql/core/sqlHelp.js +0 -1066
  87. package/dist/psql/core/startup.js +0 -846
  88. package/dist/psql/core/syncVars.js +0 -116
  89. package/dist/psql/core/variables.js +0 -287
  90. package/dist/psql/describe/formatters.js +0 -1330
  91. package/dist/psql/describe/processNamePattern.js +0 -270
  92. package/dist/psql/describe/queries.js +0 -2452
  93. package/dist/psql/describe/versionGate.js +0 -44
  94. package/dist/psql/index.js +0 -2030
  95. package/dist/psql/io/history.js +0 -299
  96. package/dist/psql/io/input.js +0 -120
  97. package/dist/psql/io/lineEditor/buffer.js +0 -325
  98. package/dist/psql/io/lineEditor/complete.js +0 -227
  99. package/dist/psql/io/lineEditor/filename.js +0 -159
  100. package/dist/psql/io/lineEditor/index.js +0 -893
  101. package/dist/psql/io/lineEditor/keymap.js +0 -745
  102. package/dist/psql/io/lineEditor/vt100.js +0 -363
  103. package/dist/psql/io/pgpass.js +0 -202
  104. package/dist/psql/io/pgservice.js +0 -194
  105. package/dist/psql/io/psqlrc.js +0 -422
  106. package/dist/psql/print/aligned.js +0 -1748
  107. package/dist/psql/print/asciidoc.js +0 -230
  108. package/dist/psql/print/crosstab.js +0 -463
  109. package/dist/psql/print/csv.js +0 -76
  110. package/dist/psql/print/html.js +0 -240
  111. package/dist/psql/print/json.js +0 -96
  112. package/dist/psql/print/latex.js +0 -379
  113. package/dist/psql/print/pager.js +0 -267
  114. package/dist/psql/print/troff.js +0 -240
  115. package/dist/psql/print/unaligned.js +0 -99
  116. package/dist/psql/print/units.js +0 -188
  117. package/dist/psql/scanner/slash.js +0 -515
  118. package/dist/psql/scanner/sql.js +0 -914
  119. package/dist/psql/scanner/stringutils.js +0 -394
  120. package/dist/psql/types/backslash.js +0 -1
  121. package/dist/psql/types/connection.js +0 -1
  122. package/dist/psql/types/index.js +0 -7
  123. package/dist/psql/types/printer.js +0 -1
  124. package/dist/psql/types/repl.js +0 -1
  125. package/dist/psql/types/scanner.js +0 -24
  126. package/dist/psql/types/settings.js +0 -1
  127. package/dist/psql/types/variables.js +0 -1
  128. package/dist/psql/wire/connection.js +0 -2857
  129. package/dist/psql/wire/copy.js +0 -108
  130. package/dist/psql/wire/notify.js +0 -59
  131. package/dist/psql/wire/pipeline.js +0 -521
  132. package/dist/psql/wire/protocol.js +0 -466
  133. package/dist/psql/wire/sasl.js +0 -294
  134. package/dist/psql/wire/tls.js +0 -602
  135. package/dist/storage_api.js +0 -147
  136. package/dist/test_utils/fixtures.js +0 -121
  137. package/dist/test_utils/oauth_server.js +0 -9
  138. package/dist/types.js +0 -1
  139. package/dist/utils/ai_gateway_notice.js +0 -180
  140. package/dist/utils/api_enums.js +0 -33
  141. package/dist/utils/auth.js +0 -5
  142. package/dist/utils/branch_notice.js +0 -22
  143. package/dist/utils/branch_picker.js +0 -103
  144. package/dist/utils/compute_units.js +0 -28
  145. package/dist/utils/config_diff.js +0 -185
  146. package/dist/utils/enrichers.js +0 -161
  147. package/dist/utils/esbuild.js +0 -158
  148. package/dist/utils/formats.js +0 -18
  149. package/dist/utils/git_diff.js +0 -90
  150. package/dist/utils/inspect_db.js +0 -153
  151. package/dist/utils/inspect_queries.js +0 -372
  152. package/dist/utils/middlewares.js +0 -20
  153. package/dist/utils/openapi.js +0 -114
  154. package/dist/utils/package_manager.js +0 -68
  155. package/dist/utils/point_in_time.js +0 -56
  156. package/dist/utils/psql.js +0 -120
  157. package/dist/utils/string.js +0 -5
  158. package/dist/utils/ui.js +0 -59
  159. package/dist/utils/zip.js +0 -4
  160. package/dist/writer.js +0 -97
@@ -1,294 +0,0 @@
1
- /**
2
- * SASL / SCRAM-SHA-256[-PLUS] client for the psql wire layer (WP-03).
3
- *
4
- * Ported from node-postgres' `packages/pg/lib/crypto/sasl.js` (MIT,
5
- * Copyright (c) 2010-2020 Brian Carlson). Adaptations from upstream:
6
- *
7
- * - Pure Node `node:crypto` (sync PBKDF2 / HMAC) instead of SubtleCrypto;
8
- * this module is sync because the wire layer drives it from a state
9
- * machine that already buffers bytes.
10
- * - The `pg` `Connection` / `Stream` plumbing is removed. Channel binding
11
- * data (the certificate hash) is passed in as `Buffer` by the caller,
12
- * not derived from a TLS socket. The caller (WP-02) is responsible for
13
- * extracting `tls-server-end-point` per RFC 5929 (i.e. SHA-256 over
14
- * the cert's `tbsCertificate`, or the cert's own signature hash when
15
- * strong enough — that policy lives upstream of this module).
16
- * - Returns Buffer-typed messages because the wire framer consumes
17
- * Buffers; upstream pg works in strings because its message reader
18
- * does the same.
19
- * - SASLprep: ported upstream's permissive minimal SASLprep (the three
20
- * transformations that actually change byte content). The full RFC
21
- * 4013 prohibition + bidi tables are *not* implemented — matches
22
- * libpq's and pg's behaviour, see comment on `saslprep` below.
23
- *
24
- * Server signature verification uses `crypto.timingSafeEqual` to avoid
25
- * leaking timing information about the comparison result.
26
- */
27
- import { createHash, createHmac, randomBytes as nodeRandomBytes, pbkdf2Sync, timingSafeEqual, } from "node:crypto";
28
- export class SaslMechanismError extends Error {
29
- constructor(message) {
30
- super(message);
31
- this.name = "SaslMechanismError";
32
- }
33
- }
34
- export class SaslVerificationError extends Error {
35
- constructor(message) {
36
- super(message);
37
- this.name = "SaslVerificationError";
38
- }
39
- }
40
- export class SaslProtocolError extends Error {
41
- constructor(message) {
42
- super(message);
43
- this.name = "SaslProtocolError";
44
- }
45
- }
46
- export function createScramClient(opts) {
47
- const { mechanism, gs2Header, cbindInput } = chooseMechanism(opts.mechanisms, opts.channelBinding);
48
- const rng = opts.randomBytes ?? nodeRandomBytes;
49
- // 18 raw bytes => 24 base64 chars; same width as upstream pg.
50
- // Commas are not part of the base64 alphabet, so the nonce is automatically
51
- // SCRAM-safe (RFC 5802 §5.1 forbids `,` in `r=`).
52
- const clientNonce = rng(18).toString("base64");
53
- const internal = {
54
- state: "init",
55
- mechanism,
56
- clientNonce,
57
- gs2Header,
58
- cbindInput,
59
- password: opts.password,
60
- serverSignature: null,
61
- };
62
- return {
63
- mechanism,
64
- start: () => start(internal),
65
- continue: (serverFirst) => continueSession(internal, serverFirst),
66
- finish: (serverFinal) => {
67
- finishSession(internal, serverFinal);
68
- },
69
- };
70
- }
71
- function chooseMechanism(advertised, channelBinding) {
72
- const hasPlus = advertised.includes("SCRAM-SHA-256-PLUS");
73
- const hasPlain = advertised.includes("SCRAM-SHA-256");
74
- if (channelBinding && hasPlus) {
75
- const gs2 = "p=tls-server-end-point,,";
76
- return {
77
- mechanism: "SCRAM-SHA-256-PLUS",
78
- gs2Header: gs2,
79
- cbindInput: Buffer.concat([
80
- Buffer.from(gs2, "utf8"),
81
- channelBinding.data,
82
- ]),
83
- };
84
- }
85
- if (hasPlain) {
86
- // Client has channel-binding data but server doesn't advertise PLUS: per
87
- // RFC 5802 §6 the client must signal this with `y` so a downgrade attack
88
- // is detected (the server, if PLUS-capable, would have advertised it).
89
- const gs2 = channelBinding ? "y,," : "n,,";
90
- return {
91
- mechanism: "SCRAM-SHA-256",
92
- gs2Header: gs2,
93
- cbindInput: Buffer.from(gs2, "utf8"),
94
- };
95
- }
96
- throw new SaslMechanismError(`SASL: server offered [${advertised.join(", ")}] but only SCRAM-SHA-256 and SCRAM-SHA-256-PLUS are supported`);
97
- }
98
- function start(s) {
99
- if (s.state !== "init") {
100
- throw new SaslProtocolError(`SASL: start() called in state ${s.state}`);
101
- }
102
- // n=,r=<nonce> — the username field is empty because PostgreSQL ignores it
103
- // (the actual user was sent in StartupMessage) and an empty `n=` matches
104
- // libpq's wire output. Note pg sends `n=*` instead; both interoperate.
105
- const clientFirstBare = `n=,r=${s.clientNonce}`;
106
- const clientFirstMessage = Buffer.from(s.gs2Header + clientFirstBare, "utf8");
107
- s.state = "sent-first";
108
- return { mechanism: s.mechanism, clientFirstMessage };
109
- }
110
- function continueSession(s, serverFirst) {
111
- if (s.state !== "sent-first") {
112
- throw new SaslProtocolError(`SASL: continue() called in state ${s.state}`);
113
- }
114
- const serverFirstStr = serverFirst.toString("utf8");
115
- const parsed = parseServerFirst(serverFirstStr);
116
- if (!parsed.nonce.startsWith(s.clientNonce)) {
117
- throw new SaslProtocolError("SASL: server nonce does not start with client nonce");
118
- }
119
- if (parsed.nonce.length === s.clientNonce.length) {
120
- throw new SaslProtocolError("SASL: server nonce is too short");
121
- }
122
- const clientFirstBare = `n=,r=${s.clientNonce}`;
123
- const serverFirstString = `r=${parsed.nonce},s=${parsed.salt},i=${String(parsed.iteration)}`;
124
- // c=<base64 of GS2 header || optional CB data>
125
- const channelBindingB64 = s.cbindInput.toString("base64");
126
- const clientFinalWithoutProof = `c=${channelBindingB64},r=${parsed.nonce}`;
127
- const authMessage = `${clientFirstBare},${serverFirstString},${clientFinalWithoutProof}`;
128
- const saltBytes = Buffer.from(parsed.salt, "base64");
129
- // SASLprep the password before PBKDF2 (RFC 5802 §2.2). Our impl is minimal;
130
- // see saslprep() comment for the deviation from full RFC 4013.
131
- const normalizedPassword = saslprep(s.password);
132
- const saltedPassword = pbkdf2Sync(Buffer.from(normalizedPassword, "utf8"), saltBytes, parsed.iteration, 32, "sha256");
133
- const clientKey = hmac(saltedPassword, "Client Key");
134
- const storedKey = sha256(clientKey);
135
- const clientSignature = hmac(storedKey, authMessage);
136
- const clientProof = xor(clientKey, clientSignature);
137
- const serverKey = hmac(saltedPassword, "Server Key");
138
- s.serverSignature = hmac(serverKey, authMessage);
139
- s.state = "sent-final";
140
- return Buffer.from(`${clientFinalWithoutProof},p=${clientProof.toString("base64")}`, "utf8");
141
- }
142
- function finishSession(s, serverFinal) {
143
- if (s.state !== "sent-final") {
144
- throw new SaslProtocolError(`SASL: finish() called in state ${s.state}`);
145
- }
146
- if (s.serverSignature === null) {
147
- // Defensive: should be impossible because state machine guards it.
148
- throw new SaslProtocolError("SASL: no server signature recorded");
149
- }
150
- const parsed = parseServerFinal(serverFinal.toString("utf8"));
151
- const received = Buffer.from(parsed.serverSignature, "base64");
152
- // Constant-time comparison: defeats timing side channels that could let an
153
- // attacker (with control over `v=`) learn the prefix of our derived signature.
154
- if (received.length !== s.serverSignature.length ||
155
- !timingSafeEqual(received, s.serverSignature)) {
156
- throw new SaslVerificationError("SASL: server signature does not match — possible MITM or wrong password");
157
- }
158
- s.state = "done";
159
- }
160
- function parseServerFirst(text) {
161
- const attrs = parseAttributePairs(text);
162
- const nonce = attrs.get("r");
163
- if (!nonce) {
164
- throw new SaslProtocolError("SASL: server-first missing `r=` (nonce)");
165
- }
166
- if (!isPrintableChars(nonce)) {
167
- throw new SaslProtocolError("SASL: server-first nonce contains non-printable characters");
168
- }
169
- const salt = attrs.get("s");
170
- if (!salt) {
171
- throw new SaslProtocolError("SASL: server-first missing `s=` (salt)");
172
- }
173
- if (!isBase64(salt)) {
174
- throw new SaslProtocolError("SASL: server-first salt is not base64");
175
- }
176
- const iterStr = attrs.get("i");
177
- if (!iterStr) {
178
- throw new SaslProtocolError("SASL: server-first missing `i=` (iterations)");
179
- }
180
- if (!/^[1-9][0-9]*$/.test(iterStr)) {
181
- throw new SaslProtocolError(`SASL: server-first iteration count is not a positive integer: ${iterStr}`);
182
- }
183
- return { nonce, salt, iteration: parseInt(iterStr, 10) };
184
- }
185
- function parseServerFinal(text) {
186
- const attrs = parseAttributePairs(text);
187
- const errorAttr = attrs.get("e");
188
- if (errorAttr) {
189
- throw new SaslVerificationError(`SASL: server-final returned error: ${errorAttr}`);
190
- }
191
- const v = attrs.get("v");
192
- if (!v) {
193
- throw new SaslProtocolError("SASL: server-final missing `v=` (server signature)");
194
- }
195
- if (!isBase64(v)) {
196
- throw new SaslProtocolError("SASL: server-final `v=` is not base64");
197
- }
198
- return { serverSignature: v };
199
- }
200
- function parseAttributePairs(text) {
201
- const out = new Map();
202
- for (const pair of text.split(",")) {
203
- if (pair.length < 2 || pair[1] !== "=") {
204
- throw new SaslProtocolError(`SASL: malformed attribute pair: ${JSON.stringify(pair)}`);
205
- }
206
- const key = pair[0];
207
- // RFC 5802 attribute lists never repeat an attribute; a duplicate is
208
- // malformed server input. Reject it rather than silently last-wins,
209
- // so a non-conformant/hostile server can't smuggle a shadow value
210
- // (e.g. `v=<good>,v=<evil>`) past the parse.
211
- if (out.has(key)) {
212
- throw new SaslProtocolError(`SASL: duplicate attribute ${JSON.stringify(key)} in message`);
213
- }
214
- out.set(key, pair.substring(2));
215
- }
216
- return out;
217
- }
218
- // printable = %x21-2B / %x2D-7E ;; printable ASCII except ","
219
- function isPrintableChars(text) {
220
- for (let i = 0; i < text.length; i++) {
221
- const c = text.charCodeAt(i);
222
- if (!((c >= 0x21 && c <= 0x2b) || (c >= 0x2d && c <= 0x7e))) {
223
- return false;
224
- }
225
- }
226
- return true;
227
- }
228
- function isBase64(text) {
229
- return /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(text);
230
- }
231
- // ---------------------------------------------------------------------------
232
- // Crypto helpers
233
- // ---------------------------------------------------------------------------
234
- function hmac(key, msg) {
235
- const h = createHmac("sha256", key);
236
- h.update(msg);
237
- return h.digest();
238
- }
239
- function sha256(data) {
240
- return createHash("sha256").update(data).digest();
241
- }
242
- function xor(a, b) {
243
- if (a.length !== b.length) {
244
- throw new SaslProtocolError(`SASL: XOR length mismatch (${String(a.length)} vs ${String(b.length)})`);
245
- }
246
- const out = Buffer.alloc(a.length);
247
- for (let i = 0; i < a.length; i++) {
248
- out[i] = a[i] ^ b[i];
249
- }
250
- return out;
251
- }
252
- // ---------------------------------------------------------------------------
253
- // SASLprep
254
- // ---------------------------------------------------------------------------
255
- /**
256
- * Minimal SASLprep (RFC 4013) — exactly the three transformations that
257
- * change byte content, ported from node-postgres' implementation:
258
- *
259
- * 1. RFC 3454 Table C.1.2 (non-ASCII space) -> U+0020 SPACE.
260
- * 2. RFC 3454 Table B.1 (commonly mapped to nothing) -> empty.
261
- * 3. NFKC normalization.
262
- *
263
- * We deliberately *skip* the RFC 4013 §2.3 prohibition table and the §6
264
- * bidi checks. libpq is forgiving on those paths and PostgreSQL's own
265
- * SASLprep matches that leniency for legacy roles — implementing strict
266
- * RFC 4013 here would lock out passwords that already auth against the
267
- * server. This deviation matches upstream pg.
268
- *
269
- * The character classes below intentionally contain combining marks and
270
- * zero-width joiners (RFC 3454 Table B.1) and named spaces (Table C.1.2);
271
- * they are spelled with `\u` escapes so the source is portable across
272
- * encodings.
273
- */
274
- // Built once at module load: regex character classes for the two SASLprep
275
- // transformations. They are constructed from \uXXXX escape sequences in a
276
- // string so the source file stays ASCII-only and so we sidestep ESLint's
277
- // `no-irregular-whitespace` and `no-misleading-character-class` rules —
278
- // those only inspect raw regex literals, not dynamically-built patterns.
279
- const NON_ASCII_SPACE_RE = new RegExp("[" + "\u00A0\u1680" + "\u2000-\u200B" + "\u202F\u205F\u3000" + "]", "g");
280
- // Combining marks and ZWJ are intentionally in this class; RFC 3454 Table B.1
281
- // strips them precisely because they combine with neighbouring code points.
282
- const MAPPED_TO_NOTHING_RE = new RegExp("[" +
283
- "\u00AD\u034F\u1806" +
284
- "\u180B-\u180D" +
285
- "\u200C\u200D\u2060" +
286
- "\uFE00-\uFE0F" +
287
- "\uFEFF" +
288
- "]", "g");
289
- function saslprep(password) {
290
- return password
291
- .replace(NON_ASCII_SPACE_RE, " ")
292
- .replace(MAPPED_TO_NOTHING_RE, "")
293
- .normalize("NFKC");
294
- }