@jeffusion/bungee 5.11.0 → 5.12.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 (2) hide show
  1. package/dist/index.js +99 -1
  2. package/package.json +3 -3
package/dist/index.js CHANGED
@@ -3397,7 +3397,7 @@ import { createInterface } from "node:readline";
3397
3397
  // package.json
3398
3398
  var package_default = {
3399
3399
  name: "@jeffusion/bungee",
3400
- version: "5.11.0",
3400
+ version: "5.12.0",
3401
3401
  description: "High-performance reverse proxy server CLI",
3402
3402
  type: "module",
3403
3403
  bin: {
@@ -6049,9 +6049,107 @@ async function importCommand(options) {
6049
6049
  }
6050
6050
  }
6051
6051
 
6052
+ // ../core/src/oauth-callback.ts
6053
+ import { createServer } from "node:http";
6054
+ var CALLBACK_PATH = "/auth/callback";
6055
+ async function captureOAuthCallback(options = {}) {
6056
+ const port = options.port ?? 1455;
6057
+ const timeoutMs = options.timeoutMs ?? 5 * 60000;
6058
+ if (!Number.isInteger(port) || port < 0 || port > 65535 || !Number.isFinite(timeoutMs) || timeoutMs <= 0)
6059
+ throw new Error("Invalid callback listener options");
6060
+ let settle;
6061
+ let fail;
6062
+ let completed = false;
6063
+ const result = new Promise((resolve, reject) => {
6064
+ settle = resolve;
6065
+ fail = reject;
6066
+ });
6067
+ const reject = (message) => {
6068
+ if (completed)
6069
+ return;
6070
+ completed = true;
6071
+ fail(new Error(message));
6072
+ };
6073
+ const server = createServer({ maxHeaderSize: 8192 }, (request, response) => {
6074
+ response.setHeader("Content-Type", "text/plain; charset=utf-8");
6075
+ response.setHeader("Cache-Control", "no-store");
6076
+ response.setHeader("Referrer-Policy", "no-referrer");
6077
+ const address = server.address();
6078
+ const actualPort = address && typeof address === "object" ? address.port : port;
6079
+ const raw = request.url ?? "";
6080
+ let url;
6081
+ try {
6082
+ url = new URL(raw, `http://127.0.0.1:${actualPort}`);
6083
+ } catch {
6084
+ response.writeHead(400).end("Invalid callback.");
6085
+ return;
6086
+ }
6087
+ const code = url.searchParams.get("code");
6088
+ const state = url.searchParams.get("state");
6089
+ const clientId = url.searchParams.get("client_id");
6090
+ const valid = request.method === "GET" && raw.split("?")[0] === CALLBACK_PATH && raw.length <= 4096 && !url.hash && !url.searchParams.has("error") && !url.searchParams.has("error_description") && [...url.searchParams.keys()].every((key) => url.searchParams.getAll(key).length === 1) && [code, state].every((value) => typeof value === "string" && value.length > 0 && value.trim() === value && !/[\u0000-\u001f\u007f]/.test(value)) && typeof clientId === "string" && /^oaiapp_[A-Za-z0-9_-]{1,200}$/.test(clientId);
6091
+ if (!valid) {
6092
+ response.writeHead(400).end("Invalid callback. Continue with the Bungee authorization page.");
6093
+ return;
6094
+ }
6095
+ if (completed) {
6096
+ response.writeHead(409).end("Callback already captured.");
6097
+ return;
6098
+ }
6099
+ completed = true;
6100
+ response.writeHead(200).end("Callback captured. Paste the complete URL shown in your terminal into Bungee to finish signing in.");
6101
+ settle(url.toString());
6102
+ });
6103
+ server.on("error", () => reject("Cannot listen on 127.0.0.1. Check whether the callback port is occupied."));
6104
+ const abort = () => reject("Callback capture cancelled.");
6105
+ const timer = setTimeout(() => reject("Callback capture timed out. Start a new Bungee login."), timeoutMs);
6106
+ options.signal?.addEventListener("abort", abort, { once: true });
6107
+ try {
6108
+ if (options.signal?.aborted)
6109
+ abort();
6110
+ else
6111
+ server.listen(port, "127.0.0.1", () => {
6112
+ const address = server.address();
6113
+ if (address && typeof address === "object")
6114
+ options.onListening?.(address.port);
6115
+ });
6116
+ return await result;
6117
+ } finally {
6118
+ clearTimeout(timer);
6119
+ options.signal?.removeEventListener("abort", abort);
6120
+ server.closeIdleConnections();
6121
+ server.close();
6122
+ server.closeAllConnections();
6123
+ }
6124
+ }
6125
+ async function oauthCallbackCommand() {
6126
+ const controller = new AbortController;
6127
+ const cancel = () => controller.abort();
6128
+ process.once("SIGINT", cancel);
6129
+ process.once("SIGTERM", cancel);
6130
+ try {
6131
+ const url = await captureOAuthCallback({ signal: controller.signal, onListening: () => {
6132
+ console.error("Listening on 127.0.0.1:1455. Open the SIWC authorization URL from Bungee.");
6133
+ console.error("The printed callback contains a one-time login code. Paste it only into your Bungee login window.");
6134
+ } });
6135
+ console.log(url);
6136
+ } finally {
6137
+ process.removeListener("SIGINT", cancel);
6138
+ process.removeListener("SIGTERM", cancel);
6139
+ }
6140
+ }
6141
+
6052
6142
  // src/index.ts
6053
6143
  function createProgram() {
6054
6144
  const program = new Command2().name("bungee").description("High-performance reverse proxy server built with Bun and TypeScript").version(package_default.version);
6145
+ program.command("oauth-callback").description("Capture one SIWC browser callback on 127.0.0.1:1455 for manual submission to Bungee").action(async () => {
6146
+ try {
6147
+ await oauthCallbackCommand();
6148
+ } catch {
6149
+ console.error("OAuth callback capture failed or was cancelled. Check the local port and restart the login.");
6150
+ process.exitCode = 1;
6151
+ }
6152
+ });
6055
6153
  program.command("init").description("Initialize the Bungee SQLite data directory").action(initCommand);
6056
6154
  program.command("recover").description("Recover a stopped instance using bounded JSON from stdin or a 0600 file").option("--file <path>", "Owner-only 0600 recovery JSON input file").addHelpText("after", `
6057
6155
  Stop the instance first. Supply one JSON object via stdin or bungee recover --file recovery.json (chmod 600).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jeffusion/bungee",
3
- "version": "5.11.0",
3
+ "version": "5.12.0",
4
4
  "description": "High-performance reverse proxy server CLI",
5
5
  "type": "module",
6
6
  "bin": {
@@ -13,8 +13,8 @@
13
13
  "test": "bun test"
14
14
  },
15
15
  "dependencies": {
16
- "@jeffusion/bungee-core": "^5.11.0",
17
- "@jeffusion/bungee-types": "^5.11.0",
16
+ "@jeffusion/bungee-core": "^5.12.0",
17
+ "@jeffusion/bungee-types": "^5.12.0",
18
18
  "cli-progress": "^3.12.0",
19
19
  "commander": "^14.0.1"
20
20
  },