oauth2-forwarder 1.4.6 → 1.4.8

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.
@@ -1,2 +1,2 @@
1
1
  #!/usr/bin/env node
2
- !function(e,r){"object"==typeof exports&&"object"==typeof module?module.exports=r():"function"==typeof define&&define.amd?define([],r):"object"==typeof exports?exports["oauth-forwarder"]=r():e["oauth-forwarder"]=r()}(this,()=>(()=>{"use strict";var e={113(e,r,t){Object.defineProperty(r,"__esModule",{value:!0}),r.buildBrowserHelper=function(e){return async r=>{const{logger:t}=e;if(!r)return t.warn("No URL argument present"),void e.onExit.failure();t.debug(`Received url "${r}"`);const n=(0,o.getDomain)(r)??"unknown";try{const o=await e.credentialForwarder(r);if(t.info(`Completed request for ${n}`),t.debug(`Result type: ${o.type}`),"error"===o.type)return t.error(`Error during credential forwarding: ${o.message}`),void e.onExit.failure();t.debug("Exiting on success"),e.onExit.success()}catch(r){t.error(`Browser helper error: ${r}`),e.onExit.failure()}}};const o=t(512)},472(e,r,t){var o=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(r,"__esModule",{value:!0}),r.buildCredentialForwarder=function(e){const{logger:r}=e;return async t=>{r.debug(`Starting credential forwarding for URL: "${t}"`);const{redirectUrl:o,requestId:s}=await(t=>new Promise((o,s)=>{const i={path:"/",method:"POST"};i.port=e.port,i.host=e.host;const a=n.default.request(i,e=>{let t="";e.setEncoding("utf8"),e.on("data",e=>{r.debug(`Data chunk received: "${e}"`),t+=e}),e.on("error",e=>{r.error(`Response error: ${e}`),s(e)}),e.on("end",()=>{const{statusCode:n,statusMessage:i}=e;if(r.debug(`Status: ${n??"No Code"}-${i??"No message"}`),200!==n)return void s(`Http request failed: Status: ${n??"No Code"}-${i??"No message"}`);r.debug(`Final output: "${t}"`);const a=JSON.parse(t);"url"in a?"requestId"in a?o({redirectUrl:a.url,requestId:a.requestId}):s("Response did not contain 'requestId' property"):s("Response did not contain 'url' property")}),e.on("close",()=>{r.debug("Response closed")})});a.on("error",e=>{r.error(`Request error: ${e}`),s(e)});const u={url:t},c=JSON.stringify(u);r.debug(`Sending request body: "${c}"`),a.write(c),r.debug("Ending request"),a.end()}))(t);r.debug(`Received redirectUrl: "${o}", requestId: "${s}"`),r.debug(`Performing redirect to: "${o}"`);const i=await e.redirect(o);var a;return r.debug(`Redirect result type: "${i.type}"`),r.debug(`Sending completion report for requestId: "${s}"`),await(a={requestId:s,result:i},new Promise((t,o)=>{const s={path:"/complete",method:"POST"};s.port=e.port,s.host=e.host;const i=n.default.request(s,e=>{e.on("error",e=>{r.error(`Completion response error: ${e}`),o(e)}),e.on("end",()=>{const{statusCode:n,statusMessage:s}=e;r.debug(`Completion status: ${n??"No Code"}-${s??"No message"}`),200===n?t():o(`Completion request failed: Status: ${n??"No Code"}-${s??"No message"}`)}),e.on("data",()=>{})});i.on("error",e=>{r.error(`Completion request error: ${e}`),o(e)});const u=JSON.stringify(a);r.debug(`Sending completion report: "${u}"`),i.write(u),i.end()})),r.debug("Completion report sent successfully"),i}};const n=o(t(611))},737(e,r,t){var o=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(r,"__esModule",{value:!0}),r.buildRedirect=function(e){const{logger:r}=e,t=(e,t)=>new Promise((o,s)=>{const i=setTimeout(()=>{s(new Error("Request timed out after 30000ms"))},3e4),a=new URL(e),u={hostname:a.hostname.replace(/^\[|\]$/g,""),port:a.port||80,path:a.pathname+a.search,method:"GET"};t&&(u.headers={Host:t});const c=n.default.request(u,e=>{clearTimeout(i);const r=[];e.on("data",e=>{r.push(e)}),e.on("end",()=>{const t=Buffer.concat(r).toString("utf8"),n=e.headers.location;o({statusCode:e.statusCode??0,location:n,body:t})}),e.on("error",e=>{s(e)})});c.on("error",e=>{clearTimeout(i),r.error(`Request error: ${JSON.stringify(e)}`),s(e)}),c.end()}),o=async(e,n)=>{if(r.debug(`Making GET request to url: "${e}" (${n} redirects remaining)`),n<=0)return{type:"error",message:"Exceeded maximum number of redirects (10)"};let i;try{i=await(async e=>{if((0,s.isLoopbackUrl)(e)){const o=new URL(e).host,n=(0,s.convertLoopbackUrl)(e,"127.0.0.1"),i=(0,s.convertLoopbackUrl)(e,"[::1]");r.debug("Loopback URL detected, will try IPv4 then IPv6"),r.debug(`Preserving original Host header: ${o}`);try{return r.debug(`Trying IPv4: ${n}`),await t(n,o)}catch(e){const n=e;if("ECONNREFUSED"===n.code){r.debug(`IPv4 connection refused, trying IPv6: ${i}`);try{return await t(i,o)}catch(e){const r=e;throw new Error(`Connection refused on both IPv4 and IPv6. IPv4 error: ${n.message}, IPv6 error: ${r.message}`)}}throw e}}return await t(e)})(e)}catch(e){return{type:"error",message:e instanceof Error?e.message:String(e)}}if(r.debug(`Received status ${i.statusCode}`),301===i.statusCode||302===i.statusCode){const e=i.location;return e?(r.debug(`Redirect to: ${e}`),(0,s.isLoopbackUrl)(e)?(r.debug("Following localhost redirect"),o(e,n-1)):{type:"redirect",location:e}):{type:"error",message:`Received ${i.statusCode} without Location header`}}return 200===i.statusCode?(r.debug(`Success with body length: ${i.body.length}`),{type:"success",body:i.body||void 0}):{type:"error",message:`Request returned unexpected status: ${i.statusCode}`}};return e=>o(e,10)};const n=o(t(611)),s=t(580)},377(e,r,t){Object.defineProperty(r,"__esModule",{value:!0}),r.parseServerInfo=function(e){const r=e.match(/^(.+):(\d+)$/);if(r){const[,e,t]=r;if(!e)return o.Result.failure(new Error("No host defined"));if(!t)return o.Result.failure(new Error("No port defined"));const n=parseInt(t,10);return isNaN(n)||n<0||n>65535?o.Result.failure(new Error(`Not a valid port: ${n}`)):o.Result.success({host:e,port:n})}return o.Result.failure(new Error("Invalid server info format, must be either a host:port or a valid socket path"))};const o=t(728)},478(e,r){Object.defineProperty(r,"__esModule",{value:!0}),r.color=function(e,r){return`${t[r]}${e}`};const t={black:"",red:"",green:"",yellow:"",blue:"",magenta:"",cyan:"",white:""}},950(e,r){Object.defineProperty(r,"__esModule",{value:!0}),r.EnvKey=void 0,r.EnvKey={PORT:"OAUTH2_FORWARDER_PORT",SERVER:"OAUTH2_FORWARDER_SERVER",DEBUG:"OAUTH2_FORWARDER_DEBUG",PASSTHROUGH:"OAUTH2_FORWARDER_PASSTHROUGH",LOGIN_TIMEOUT:"OAUTH2_FORWARDER_LOGIN_TIMEOUT"}},465(e,r,t){var o=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(r,"__esModule",{value:!0}),r.rotateOnLaunch=a,r.rotateIfNeeded=function(e,r=5242880,t=3){if((0,i.ensureDirectory)(s.default.dirname(e)),!n.default.existsSync(e))return!1;try{if(n.default.statSync(e).size<r)return!1}catch{return!1}return a(e,t),!0},r.createLogFileStream=function(e){return(0,i.ensureDirectory)(s.default.dirname(e)),n.default.createWriteStream(e,{flags:"a"})};const n=o(t(896)),s=o(t(928)),i=t(125);function a(e,r=5){if((0,i.ensureDirectory)(s.default.dirname(e)),!n.default.existsSync(e))return;const t=`${e}.${r}`;n.default.existsSync(t)&&n.default.unlinkSync(t);for(let t=r-1;t>=1;t--){const r=`${e}.${t}`,o=`${e}.${t+1}`;n.default.existsSync(r)&&n.default.renameSync(r,o)}n.default.renameSync(e,`${e}.1`)}},741(e,r,t){Object.defineProperty(r,"__esModule",{value:!0}),r.buildLogger=function(e){const{level:r,stream:t=process.stderr,prefix:a="",useFileFormat:u=!1}=e,c=s[r],d=(e,r)=>{if(s[e]>=c){const s=a?`[${a}] `:"",c=`[${e.toUpperCase()}]`,d=(0,n.sanitize)(r);let l;if(u)l=`${(new Date).toISOString()} ${s}${c} ${d}\n`;else{const r=i[e];l=(0,o.color)(`${s}${c} ${d}`,r)+"\n"}t.write(l)}};return{error:e=>d("error",e),warn:e=>d("warn",e),info:e=>d("info",e),debug:e=>d("debug",e)}};const o=t(478),n=t(638),s={debug:0,info:1,warn:2,error:3},i={error:"red",warn:"yellow",info:"cyan",debug:"magenta"}},580(e,r){Object.defineProperty(r,"__esModule",{value:!0}),r.LOOPBACK_PATTERNS=void 0,r.isLoopbackUrl=function(e){return r.LOOPBACK_PATTERNS.some(r=>r.test(e))},r.convertLoopbackUrl=function(e,r){return e.replace(/^(http:\/\/)localhost(:\d+)?/,`$1${r}$2`).replace(/^(http:\/\/)127\.0\.0\.1(:\d+)?/,`$1${r}$2`).replace(/^(http:\/\/)\[::1\](:\d+)?/,`$1${r}$2`)},r.LOOPBACK_PATTERNS=[/^http:\/\/localhost(?::(\d{1,5}))?(?:\/.*)?$/,/^http:\/\/127\.0\.0\.1(?::(\d{1,5}))?(?:\/.*)?$/,/^http:\/\/\[::1\](?::(\d{1,5}))?(?:\/.*)?$/]},125(e,r,t){var o=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(r,"__esModule",{value:!0}),r.ensureDirectory=function(e){n.default.existsSync(e)||n.default.mkdirSync(e,{recursive:!0})},r.getLogFilePath=function(e){const r=u();return s.default.join(r,`o2f-${e}.log`)},r.getLogDir=function(){return u()},r.getConfigDir=function(){return c()},r.getLegacyConfigDir=function(){return d()},r.resolveConfigFile=function(e){const r=s.default.join(d(),e),t=s.default.join(c(),e);return n.default.existsSync(r)?{path:r,isLegacy:!0}:{path:t,isLegacy:!1}},r.getPreferredConfigDescription=function(){switch(i.default.platform()){case"darwin":return"~/Library/Application Support/oauth2-forwarder/";case"win32":return"%LOCALAPPDATA%\\oauth2-forwarder\\";default:return"~/.config/oauth2-forwarder/ (or $XDG_CONFIG_HOME/oauth2-forwarder/)"}};const n=o(t(896)),s=o(t(928)),i=o(t(857)),a="oauth2-forwarder";function u(){const e=i.default.platform(),r=i.default.homedir();switch(e){case"darwin":return s.default.join(r,"Library","Logs",a);case"win32":{const e=process.env.LOCALAPPDATA||s.default.join(r,"AppData","Local");return s.default.join(e,a,"logs")}default:{const e=process.env.XDG_STATE_HOME||s.default.join(r,".local","state");return s.default.join(e,a)}}}function c(){const e=i.default.platform(),r=i.default.homedir();switch(e){case"darwin":return s.default.join(r,"Library","Application Support",a);case"win32":{const e=process.env.LOCALAPPDATA||s.default.join(r,"AppData","Local");return s.default.join(e,a)}default:{const e=process.env.XDG_CONFIG_HOME||s.default.join(r,".config");return s.default.join(e,a)}}}function d(){return s.default.join(i.default.homedir(),".oauth2-forwarder")}},728(e,r){var t;Object.defineProperty(r,"__esModule",{value:!0}),r.Result=r.ResultType=void 0,function(e){e[e.success=0]="success",e[e.failure=1]="failure"}(t||(r.ResultType=t={})),r.Result={success:e=>({type:t.success,value:e}),isSuccess:e=>e.type===t.success,failure:e=>({type:t.failure,error:e}),isFailure:e=>e.type===t.failure}},638(e,r){Object.defineProperty(r,"__esModule",{value:!0}),r.sanitize=function(e){return e.replace(/((code|code_challenge)=)([^"&\n]*)/gi,(e,r)=>`${r}********`)}},512(e,r){Object.defineProperty(r,"__esModule",{value:!0}),r.getDomain=function(e){try{return new URL(e).hostname.toLowerCase()}catch{return null}}},541(e,r,t){var o=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(r,"__esModule",{value:!0}),r.getVersion=function(){return n.default.version};const n=o(t(330))},896(e){e.exports=require("fs")},611(e){e.exports=require("http")},857(e){e.exports=require("os")},928(e){e.exports=require("path")},330(e){e.exports=JSON.parse('{"name":"oauth2-forwarder","version":"1.4.6","description":"utilities for forwarding oauth2 interactive flow (e.g. container to host)","main":"dist/index.js","bin":{"o2f-server":"./dist/o2f-server.js","o2f-client":"./dist/o2f-client.js","o2f-browser":"./browser-global.sh"},"scripts":{"build":"rimraf ./dist && webpack && node prepend-shebang.js","zip-release":"./release.sh","test":"vitest","e2e-test":"vitest --config vitest.e2e.config.ts","lint":"eslint .","fix-formatting":"prettier --write --config ./prettier.config.js ./src/","check-formatting":"prettier --check --config ./prettier.config.js ./src/"},"author":"Sam Davidoff","license":"MIT","repository":{"type":"git","url":"https://github.com/sam-mfb/oauth2-forwarder.git"},"files":["dist","browser.sh","browser-global.sh"],"keywords":["oauth2","docker","container","authentication","browser"],"engines":{"node":">=24.0.0"},"devDependencies":{"@eslint/js":"^9.25.1","@types/eslint__js":"^8.42.3","@types/node":"^24.0.0","eslint":"^9.25.1","prettier":"^3.5.3","rimraf":"^6.0.1","ts-loader":"^9.5.2","typescript":"^5.8.3","typescript-eslint":"^8.31.1","vitest":"^3.0.5","webpack":"^5.99.7","webpack-cli":"^6.0.1"},"dependencies":{"nanoid":"^5.1.5","open":"^11.0.0"},"overrides":{"glob@>=10.2.0 <=10.4.5":"10.5.0","glob@>=11.0.0 <=11.0.3":"11.1.0","js-yaml@<3.14.2":"3.14.2","js-yaml@>=4.0.0 <4.1.1":"4.1.1","serialize-javascript@<=7.0.2":"7.0.3"}}')}},r={};function t(o){var n=r[o];if(void 0!==n)return n.exports;var s=r[o]={exports:{}};return e[o].call(s.exports,s,s.exports,t),s.exports}var o={};return(()=>{var e=o;Object.defineProperty(e,"__esModule",{value:!0});const r=t(541),n=t(950),s=t(741),i=t(125),a=t(465),u=t(728),c=t(512),d=t(113),l=t(472),f=t(737),p=t(377);(process.argv.includes("--version")||process.argv.includes("-v"))&&(console.log(`o2f-client v${(0,r.getVersion)()}`),process.exit(0));const g=process.env[n.EnvKey.DEBUG]?"debug":"info",h=(0,i.getLogFilePath)("client");(0,a.rotateIfNeeded)(h,5242880,3);const m=(0,a.createLogFileStream)(h),v=(0,s.buildLogger)({level:g,stream:m,prefix:"client",useFileFormat:!0}),y=process.env[n.EnvKey.SERVER];y||(v.error(`The environmental variable ${[n.EnvKey.SERVER]} was not defined`),process.exit(1));const b=(0,p.parseServerInfo)(y);u.Result.isFailure(b)&&(v.error(`Invalid server info: "${b.error.message}"`),process.exit(1));const w=b.value,$=(0,f.buildRedirect)({logger:v}),_=(0,l.buildCredentialForwarder)({host:w.host,port:w.port,redirect:$,logger:v}),R=(0,d.buildBrowserHelper)({onExit:{success:function(){process.exit(0)},failure:function(){process.exit(1)}},credentialForwarder:_,logger:v}),O=process.argv[2];v.info(`Processing request for ${O?(0,c.getDomain)(O)??"(invalid URL)":"(none)"}`),v.debug(`Full URL: ${O??"(none)"}`),R(O).catch(e=>v.error(String(e)))})(),o})());
2
+ !function(e,r){"object"==typeof exports&&"object"==typeof module?module.exports=r():"function"==typeof define&&define.amd?define([],r):"object"==typeof exports?exports["oauth-forwarder"]=r():e["oauth-forwarder"]=r()}(this,()=>(()=>{"use strict";var e={113(e,r,t){Object.defineProperty(r,"__esModule",{value:!0}),r.buildBrowserHelper=function(e){return async r=>{const{logger:t}=e;if(!r)return t.warn("No URL argument present"),void e.onExit.failure();t.debug(`Received url "${r}"`);const n=(0,o.getDomain)(r)??"unknown";try{const o=await e.credentialForwarder(r);if(t.info(`Completed request for ${n}`),t.debug(`Result type: ${o.type}`),"error"===o.type)return t.error(`Error during credential forwarding: ${o.message}`),void e.onExit.failure();t.debug("Exiting on success"),e.onExit.success()}catch(r){t.error(`Browser helper error: ${r}`),e.onExit.failure()}}};const o=t(512)},472(e,r,t){var o=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(r,"__esModule",{value:!0}),r.buildCredentialForwarder=function(e){const{logger:r}=e;return async t=>{r.debug(`Starting credential forwarding for URL: "${t}"`);const{redirectUrl:o,requestId:s}=await(t=>new Promise((o,s)=>{const i={path:"/",method:"POST"};i.port=e.port,i.host=e.host;const a=n.default.request(i,e=>{let t="";e.setEncoding("utf8"),e.on("data",e=>{r.debug(`Data chunk received: "${e}"`),t+=e}),e.on("error",e=>{r.error(`Response error: ${e}`),s(e)}),e.on("end",()=>{const{statusCode:n,statusMessage:i}=e;if(r.debug(`Status: ${n??"No Code"}-${i??"No message"}`),200!==n)return void s(`Http request failed: Status: ${n??"No Code"}-${i??"No message"}`);r.debug(`Final output: "${t}"`);const a=JSON.parse(t);"url"in a?"requestId"in a?o({redirectUrl:a.url,requestId:a.requestId}):s("Response did not contain 'requestId' property"):s("Response did not contain 'url' property")}),e.on("close",()=>{r.debug("Response closed")})});a.on("error",e=>{r.error(`Request error: ${e}`),s(e)});const u={url:t},c=JSON.stringify(u);r.debug(`Sending request body: "${c}"`),a.write(c),r.debug("Ending request"),a.end()}))(t);r.debug(`Received redirectUrl: "${o}", requestId: "${s}"`),r.debug(`Performing redirect to: "${o}"`);const i=await e.redirect(o);var a;return r.debug(`Redirect result type: "${i.type}"`),r.debug(`Sending completion report for requestId: "${s}"`),await(a={requestId:s,result:i},new Promise((t,o)=>{const s={path:"/complete",method:"POST"};s.port=e.port,s.host=e.host;const i=n.default.request(s,e=>{e.on("error",e=>{r.error(`Completion response error: ${e}`),o(e)}),e.on("end",()=>{const{statusCode:n,statusMessage:s}=e;r.debug(`Completion status: ${n??"No Code"}-${s??"No message"}`),200===n?t():o(`Completion request failed: Status: ${n??"No Code"}-${s??"No message"}`)}),e.on("data",()=>{})});i.on("error",e=>{r.error(`Completion request error: ${e}`),o(e)});const u=JSON.stringify(a);r.debug(`Sending completion report: "${u}"`),i.write(u),i.end()})),r.debug("Completion report sent successfully"),i}};const n=o(t(611))},737(e,r,t){var o=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(r,"__esModule",{value:!0}),r.buildRedirect=function(e){const{logger:r}=e,t=(e,t)=>new Promise((o,s)=>{const i=setTimeout(()=>{s(new Error("Request timed out after 30000ms"))},3e4),a=new URL(e),u={hostname:a.hostname.replace(/^\[|\]$/g,""),port:a.port||80,path:a.pathname+a.search,method:"GET"};t&&(u.headers={Host:t});const c=n.default.request(u,e=>{clearTimeout(i);const r=[];e.on("data",e=>{r.push(e)}),e.on("end",()=>{const t=Buffer.concat(r).toString("utf8"),n=e.headers.location;o({statusCode:e.statusCode??0,location:n,body:t})}),e.on("error",e=>{s(e)})});c.on("error",e=>{clearTimeout(i),r.error(`Request error: ${JSON.stringify(e)}`),s(e)}),c.end()}),o=async(e,n)=>{if(r.debug(`Making GET request to url: "${e}" (${n} redirects remaining)`),n<=0)return{type:"error",message:"Exceeded maximum number of redirects (10)"};let i;try{i=await(async e=>{if((0,s.isLoopbackUrl)(e)){const o=new URL(e).host,n=(0,s.convertLoopbackUrl)(e,"127.0.0.1"),i=(0,s.convertLoopbackUrl)(e,"[::1]");r.debug("Loopback URL detected, will try IPv4 then IPv6"),r.debug(`Preserving original Host header: ${o}`);try{return r.debug(`Trying IPv4: ${n}`),await t(n,o)}catch(e){const n=e;if("ECONNREFUSED"===n.code){r.debug(`IPv4 connection refused, trying IPv6: ${i}`);try{return await t(i,o)}catch(e){const r=e;throw new Error(`Connection refused on both IPv4 and IPv6. IPv4 error: ${n.message}, IPv6 error: ${r.message}`)}}throw e}}return await t(e)})(e)}catch(e){return{type:"error",message:e instanceof Error?e.message:String(e)}}if(r.debug(`Received status ${i.statusCode}`),301===i.statusCode||302===i.statusCode){const e=i.location;return e?(r.debug(`Redirect to: ${e}`),(0,s.isLoopbackUrl)(e)?(r.debug("Following localhost redirect"),o(e,n-1)):{type:"redirect",location:e}):{type:"error",message:`Received ${i.statusCode} without Location header`}}return 200===i.statusCode?(r.debug(`Success with body length: ${i.body.length}`),{type:"success",body:i.body||void 0}):{type:"error",message:`Request returned unexpected status: ${i.statusCode}`}};return e=>o(e,10)};const n=o(t(611)),s=t(580)},377(e,r,t){Object.defineProperty(r,"__esModule",{value:!0}),r.parseServerInfo=function(e){const r=e.match(/^(.+):(\d+)$/);if(r){const[,e,t]=r;if(!e)return o.Result.failure(new Error("No host defined"));if(!t)return o.Result.failure(new Error("No port defined"));const n=parseInt(t,10);return isNaN(n)||n<0||n>65535?o.Result.failure(new Error(`Not a valid port: ${n}`)):o.Result.success({host:e,port:n})}return o.Result.failure(new Error("Invalid server info format, must be either a host:port or a valid socket path"))};const o=t(728)},478(e,r){Object.defineProperty(r,"__esModule",{value:!0}),r.color=function(e,r){return`${t[r]}${e}`};const t={black:"",red:"",green:"",yellow:"",blue:"",magenta:"",cyan:"",white:""}},950(e,r){Object.defineProperty(r,"__esModule",{value:!0}),r.EnvKey=void 0,r.EnvKey={PORT:"OAUTH2_FORWARDER_PORT",SERVER:"OAUTH2_FORWARDER_SERVER",DEBUG:"OAUTH2_FORWARDER_DEBUG",PASSTHROUGH:"OAUTH2_FORWARDER_PASSTHROUGH",LOGIN_TIMEOUT:"OAUTH2_FORWARDER_LOGIN_TIMEOUT"}},465(e,r,t){var o=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(r,"__esModule",{value:!0}),r.rotateOnLaunch=a,r.rotateIfNeeded=function(e,r=5242880,t=3){if((0,i.ensureDirectory)(s.default.dirname(e)),!n.default.existsSync(e))return!1;try{if(n.default.statSync(e).size<r)return!1}catch{return!1}return a(e,t),!0},r.createLogFileStream=function(e){return(0,i.ensureDirectory)(s.default.dirname(e)),n.default.createWriteStream(e,{flags:"a"})};const n=o(t(896)),s=o(t(928)),i=t(125);function a(e,r=5){if((0,i.ensureDirectory)(s.default.dirname(e)),!n.default.existsSync(e))return;const t=`${e}.${r}`;n.default.existsSync(t)&&n.default.unlinkSync(t);for(let t=r-1;t>=1;t--){const r=`${e}.${t}`,o=`${e}.${t+1}`;n.default.existsSync(r)&&n.default.renameSync(r,o)}n.default.renameSync(e,`${e}.1`)}},741(e,r,t){Object.defineProperty(r,"__esModule",{value:!0}),r.buildLogger=function(e){const{level:r,stream:t=process.stderr,prefix:a="",useFileFormat:u=!1}=e,c=s[r],d=(e,r)=>{if(s[e]>=c){const s=a?`[${a}] `:"",c=`[${e.toUpperCase()}]`,d=(0,n.sanitize)(r);let l;if(u)l=`${(new Date).toISOString()} ${s}${c} ${d}\n`;else{const r=i[e];l=(0,o.color)(`${s}${c} ${d}`,r)+"\n"}t.write(l)}};return{error:e=>d("error",e),warn:e=>d("warn",e),info:e=>d("info",e),debug:e=>d("debug",e)}};const o=t(478),n=t(638),s={debug:0,info:1,warn:2,error:3},i={error:"red",warn:"yellow",info:"cyan",debug:"magenta"}},580(e,r){Object.defineProperty(r,"__esModule",{value:!0}),r.LOOPBACK_PATTERNS=void 0,r.isLoopbackUrl=function(e){return r.LOOPBACK_PATTERNS.some(r=>r.test(e))},r.convertLoopbackUrl=function(e,r){return e.replace(/^(http:\/\/)localhost(:\d+)?/,`$1${r}$2`).replace(/^(http:\/\/)127\.0\.0\.1(:\d+)?/,`$1${r}$2`).replace(/^(http:\/\/)\[::1\](:\d+)?/,`$1${r}$2`)},r.LOOPBACK_PATTERNS=[/^http:\/\/localhost(?::(\d{1,5}))?(?:\/.*)?$/,/^http:\/\/127\.0\.0\.1(?::(\d{1,5}))?(?:\/.*)?$/,/^http:\/\/\[::1\](?::(\d{1,5}))?(?:\/.*)?$/]},125(e,r,t){var o=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(r,"__esModule",{value:!0}),r.ensureDirectory=function(e){n.default.existsSync(e)||n.default.mkdirSync(e,{recursive:!0})},r.getLogFilePath=function(e){const r=u();return s.default.join(r,`o2f-${e}.log`)},r.getLogDir=function(){return u()},r.getConfigDir=function(){return c()},r.getLegacyConfigDir=function(){return d()},r.resolveConfigFile=function(e){const r=s.default.join(d(),e),t=s.default.join(c(),e);return n.default.existsSync(r)?{path:r,isLegacy:!0}:{path:t,isLegacy:!1}},r.getPreferredConfigDescription=function(){switch(i.default.platform()){case"darwin":return"~/Library/Application Support/oauth2-forwarder/";case"win32":return"%LOCALAPPDATA%\\oauth2-forwarder\\";default:return"~/.config/oauth2-forwarder/ (or $XDG_CONFIG_HOME/oauth2-forwarder/)"}};const n=o(t(896)),s=o(t(928)),i=o(t(857)),a="oauth2-forwarder";function u(){const e=i.default.platform(),r=i.default.homedir();switch(e){case"darwin":return s.default.join(r,"Library","Logs",a);case"win32":{const e=process.env.LOCALAPPDATA||s.default.join(r,"AppData","Local");return s.default.join(e,a,"logs")}default:{const e=process.env.XDG_STATE_HOME||s.default.join(r,".local","state");return s.default.join(e,a)}}}function c(){const e=i.default.platform(),r=i.default.homedir();switch(e){case"darwin":return s.default.join(r,"Library","Application Support",a);case"win32":{const e=process.env.LOCALAPPDATA||s.default.join(r,"AppData","Local");return s.default.join(e,a)}default:{const e=process.env.XDG_CONFIG_HOME||s.default.join(r,".config");return s.default.join(e,a)}}}function d(){return s.default.join(i.default.homedir(),".oauth2-forwarder")}},728(e,r){var t;Object.defineProperty(r,"__esModule",{value:!0}),r.Result=r.ResultType=void 0,function(e){e[e.success=0]="success",e[e.failure=1]="failure"}(t||(r.ResultType=t={})),r.Result={success:e=>({type:t.success,value:e}),isSuccess:e=>e.type===t.success,failure:e=>({type:t.failure,error:e}),isFailure:e=>e.type===t.failure}},638(e,r){Object.defineProperty(r,"__esModule",{value:!0}),r.sanitize=function(e){return e.replace(/((code|code_challenge)=)([^"&\n]*)/gi,(e,r)=>`${r}********`)}},512(e,r){Object.defineProperty(r,"__esModule",{value:!0}),r.getDomain=function(e){try{return new URL(e).hostname.toLowerCase()}catch{return null}}},541(e,r,t){var o=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(r,"__esModule",{value:!0}),r.getVersion=function(){return n.default.version};const n=o(t(330))},896(e){e.exports=require("fs")},611(e){e.exports=require("http")},857(e){e.exports=require("os")},928(e){e.exports=require("path")},330(e){e.exports=JSON.parse('{"name":"oauth2-forwarder","version":"1.4.8","description":"utilities for forwarding oauth2 interactive flow (e.g. container to host)","main":"dist/index.js","bin":{"o2f-server":"./dist/o2f-server.js","o2f-client":"./dist/o2f-client.js","o2f-browser":"./browser-global.sh"},"scripts":{"build":"rimraf ./dist && webpack && node prepend-shebang.js","zip-release":"./release.sh","test":"vitest","e2e-test":"vitest --config vitest.e2e.config.ts","lint":"eslint .","fix-formatting":"prettier --write --config ./prettier.config.js ./src/","check-formatting":"prettier --check --config ./prettier.config.js ./src/"},"author":"Sam Davidoff","license":"MIT","repository":{"type":"git","url":"https://github.com/sam-mfb/oauth2-forwarder.git"},"files":["dist","browser.sh","browser-global.sh"],"keywords":["oauth2","docker","container","authentication","browser"],"engines":{"node":">=24.0.0"},"devDependencies":{"@eslint/js":"^9.25.1","@types/eslint__js":"^8.42.3","@types/node":"^24.0.0","eslint":"^9.25.1","prettier":"^3.5.3","rimraf":"^6.0.1","ts-loader":"^9.5.2","typescript":"^5.8.3","typescript-eslint":"^8.31.1","vitest":"^3.0.5","webpack":"^5.99.7","webpack-cli":"^6.0.1"},"dependencies":{"nanoid":"^5.1.5","open":"^11.0.0"},"overrides":{"glob@>=10.2.0 <=10.4.5":"10.5.0","glob@>=11.0.0 <=11.0.3":"11.1.0","js-yaml@<3.14.2":"3.14.2","js-yaml@>=4.0.0 <4.1.1":"4.1.1","serialize-javascript@<=7.0.2":"7.0.3","flatted@<=3.4.1":"3.4.2","brace-expansion@<1.1.13":"1.1.13","brace-expansion@>=4.0.0 <5.0.5":"5.0.5","picomatch@<=2.3.1":"2.3.2","picomatch@>=4.0.0 <=4.0.3":"4.0.4"}}')}},r={};function t(o){var n=r[o];if(void 0!==n)return n.exports;var s=r[o]={exports:{}};return e[o].call(s.exports,s,s.exports,t),s.exports}var o={};return(()=>{var e=o;Object.defineProperty(e,"__esModule",{value:!0});const r=t(541),n=t(950),s=t(741),i=t(125),a=t(465),u=t(728),c=t(512),d=t(113),l=t(472),f=t(737),p=t(377);(process.argv.includes("--version")||process.argv.includes("-v"))&&(console.log(`o2f-client v${(0,r.getVersion)()}`),process.exit(0));const g=process.env[n.EnvKey.DEBUG]?"debug":"info",h=(0,i.getLogFilePath)("client");(0,a.rotateIfNeeded)(h,5242880,3);const m=(0,a.createLogFileStream)(h),v=(0,s.buildLogger)({level:g,stream:m,prefix:"client",useFileFormat:!0}),y=process.env[n.EnvKey.SERVER];y||(v.error(`The environmental variable ${[n.EnvKey.SERVER]} was not defined`),process.exit(1));const b=(0,p.parseServerInfo)(y);u.Result.isFailure(b)&&(v.error(`Invalid server info: "${b.error.message}"`),process.exit(1));const w=b.value,$=(0,f.buildRedirect)({logger:v}),_=(0,l.buildCredentialForwarder)({host:w.host,port:w.port,redirect:$,logger:v}),R=(0,d.buildBrowserHelper)({onExit:{success:function(){process.exit(0)},failure:function(){process.exit(1)}},credentialForwarder:_,logger:v}),O=process.argv[2];v.info(`Processing request for ${O?(0,c.getDomain)(O)??"(invalid URL)":"(none)"}`),v.debug(`Full URL: ${O??"(none)"}`),R(O).catch(e=>v.error(String(e)))})(),o})());
@@ -1,2 +1,2 @@
1
1
  #!/usr/bin/env node
2
- !function(e,r){"object"==typeof exports&&"object"==typeof module?module.exports=r():"function"==typeof define&&define.amd?define([],r):"object"==typeof exports?exports["oauth-forwarder"]=r():e["oauth-forwarder"]=r()}(this,()=>(()=>{"use strict";var e={478(e,r){Object.defineProperty(r,"__esModule",{value:!0}),r.color=function(e,r){return`${t[r]}${e}`};const t={black:"",red:"",green:"",yellow:"",blue:"",magenta:"",cyan:"",white:""}},950(e,r){Object.defineProperty(r,"__esModule",{value:!0}),r.EnvKey=void 0,r.EnvKey={PORT:"OAUTH2_FORWARDER_PORT",SERVER:"OAUTH2_FORWARDER_SERVER",DEBUG:"OAUTH2_FORWARDER_DEBUG",PASSTHROUGH:"OAUTH2_FORWARDER_PASSTHROUGH",LOGIN_TIMEOUT:"OAUTH2_FORWARDER_LOGIN_TIMEOUT"}},51(e,r,t){Object.defineProperty(r,"__esModule",{value:!0}),r.extractPort=function(e){let r=null;for(const t of n.LOOPBACK_PATTERNS)if(r=e.match(t),r)break;if(!r)return o.Result.failure(new Error("Invalid URL format"));const t=r[1]?parseInt(r[1],10):void 0;return void 0===t?o.Result.success(void 0):isNaN(t)||t<0||t>65535?o.Result.failure(new Error(`Not a valid port: ${t}`)):o.Result.success(t)};const o=t(728),n=t(580)},465(e,r,t){var o=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(r,"__esModule",{value:!0}),r.rotateOnLaunch=a,r.rotateIfNeeded=function(e,r=5242880,t=3){if((0,s.ensureDirectory)(i.default.dirname(e)),!n.default.existsSync(e))return!1;try{if(n.default.statSync(e).size<r)return!1}catch{return!1}return a(e,t),!0},r.createLogFileStream=function(e){return(0,s.ensureDirectory)(i.default.dirname(e)),n.default.createWriteStream(e,{flags:"a"})};const n=o(t(896)),i=o(t(928)),s=t(125);function a(e,r=5){if((0,s.ensureDirectory)(i.default.dirname(e)),!n.default.existsSync(e))return;const t=`${e}.${r}`;n.default.existsSync(t)&&n.default.unlinkSync(t);for(let t=r-1;t>=1;t--){const r=`${e}.${t}`,o=`${e}.${t+1}`;n.default.existsSync(r)&&n.default.renameSync(r,o)}n.default.renameSync(e,`${e}.1`)}},741(e,r,t){Object.defineProperty(r,"__esModule",{value:!0}),r.buildLogger=function(e){const{level:r,stream:t=process.stderr,prefix:a="",useFileFormat:c=!1}=e,l=i[r],d=(e,r)=>{if(i[e]>=l){const i=a?`[${a}] `:"",l=`[${e.toUpperCase()}]`,d=(0,n.sanitize)(r);let u;if(c)u=`${(new Date).toISOString()} ${i}${l} ${d}\n`;else{const r=s[e];u=(0,o.color)(`${i}${l} ${d}`,r)+"\n"}t.write(u)}};return{error:e=>d("error",e),warn:e=>d("warn",e),info:e=>d("info",e),debug:e=>d("debug",e)}};const o=t(478),n=t(638),i={debug:0,info:1,warn:2,error:3},s={error:"red",warn:"yellow",info:"cyan",debug:"magenta"}},580(e,r){Object.defineProperty(r,"__esModule",{value:!0}),r.LOOPBACK_PATTERNS=void 0,r.isLoopbackUrl=function(e){return r.LOOPBACK_PATTERNS.some(r=>r.test(e))},r.convertLoopbackUrl=function(e,r){return e.replace(/^(http:\/\/)localhost(:\d+)?/,`$1${r}$2`).replace(/^(http:\/\/)127\.0\.0\.1(:\d+)?/,`$1${r}$2`).replace(/^(http:\/\/)\[::1\](:\d+)?/,`$1${r}$2`)},r.LOOPBACK_PATTERNS=[/^http:\/\/localhost(?::(\d{1,5}))?(?:\/.*)?$/,/^http:\/\/127\.0\.0\.1(?::(\d{1,5}))?(?:\/.*)?$/,/^http:\/\/\[::1\](?::(\d{1,5}))?(?:\/.*)?$/]},76(e,r,t){Object.defineProperty(r,"__esModule",{value:!0}),r.buildOutputWriter=function(e){return r=>{e.stream.write((0,o.color)((0,n.sanitize)(r),e.color)+"\n")}};const o=t(478),n=t(638)},876(e,r,t){Object.defineProperty(r,"__esModule",{value:!0}),r.parseOauth2Url=function(e){if(!e)return o.Result.failure(new Error("Url parameter was undefined"));const r=["client_id","response_type","redirect_uri"];let t;try{t=new URL(e)}catch(r){return o.Result.failure(new Error(`Invalid URL: ${e} (${r})`))}const n=Object.fromEntries(t.searchParams.entries());for(const e of r)if(!n[e])return o.Result.failure(new Error(`Missing required parameter: ${e}`));const i=Boolean(n.code_challenge);if(i!==Boolean(n.code_challenge_method))return o.Result.failure(new Error("PKCE parameters must be used together: both code_challenge and code_challenge_method are required, or neither"));if(n.code_challenge_method&&!["S256","plain"].includes(n.code_challenge_method))return o.Result.failure(new Error(`${n.code_challenge_method} is not valid for "code_challenge_method" property`));if(n.response_mode&&!["query","fragment","form_post"].includes(n.response_mode))return o.Result.failure(new Error(`${n.response_mode} is not valid for "response_mode" property`));if(n.prompt){const e=["login","none","consent","select_account"],r=n.prompt.split(" ").filter(Boolean).filter(r=>!e.includes(r));if(r.length>0)return o.Result.failure(new Error(`${r.join(", ")} is not valid for "prompt" property`))}const s=i?{client_id:n.client_id,response_type:n.response_type,redirect_uri:n.redirect_uri,scope:n.scope,response_mode:n.response_mode,state:n.state,prompt:n.prompt,login_hint:n.login_hint,domain_hint:n.domain_hint,"x-client-SKU":n["x-client-SKU"],"x-client-VER":n["x-client-VER"],"x-client-OS":n["x-client-OS"],"x-client-CPU":n["x-client-CPU"],client_info:n.client_info,code_challenge:n.code_challenge,code_challenge_method:n.code_challenge_method}:{client_id:n.client_id,response_type:n.response_type,redirect_uri:n.redirect_uri,scope:n.scope,response_mode:n.response_mode,state:n.state,prompt:n.prompt,login_hint:n.login_hint,domain_hint:n.domain_hint,"x-client-SKU":n["x-client-SKU"],"x-client-VER":n["x-client-VER"],"x-client-OS":n["x-client-OS"],"x-client-CPU":n["x-client-CPU"],client_info:n.client_info};return o.Result.success(s)};const o=t(728)},125(e,r,t){var o=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(r,"__esModule",{value:!0}),r.ensureDirectory=function(e){n.default.existsSync(e)||n.default.mkdirSync(e,{recursive:!0})},r.getLogFilePath=function(e){const r=c();return i.default.join(r,`o2f-${e}.log`)},r.getLogDir=function(){return c()},r.getConfigDir=function(){return l()},r.getLegacyConfigDir=function(){return d()},r.resolveConfigFile=function(e){const r=i.default.join(d(),e),t=i.default.join(l(),e);return n.default.existsSync(r)?{path:r,isLegacy:!0}:{path:t,isLegacy:!1}},r.getPreferredConfigDescription=function(){switch(s.default.platform()){case"darwin":return"~/Library/Application Support/oauth2-forwarder/";case"win32":return"%LOCALAPPDATA%\\oauth2-forwarder\\";default:return"~/.config/oauth2-forwarder/ (or $XDG_CONFIG_HOME/oauth2-forwarder/)"}};const n=o(t(896)),i=o(t(928)),s=o(t(857)),a="oauth2-forwarder";function c(){const e=s.default.platform(),r=s.default.homedir();switch(e){case"darwin":return i.default.join(r,"Library","Logs",a);case"win32":{const e=process.env.LOCALAPPDATA||i.default.join(r,"AppData","Local");return i.default.join(e,a,"logs")}default:{const e=process.env.XDG_STATE_HOME||i.default.join(r,".local","state");return i.default.join(e,a)}}}function l(){const e=s.default.platform(),r=s.default.homedir();switch(e){case"darwin":return i.default.join(r,"Library","Application Support",a);case"win32":{const e=process.env.LOCALAPPDATA||i.default.join(r,"AppData","Local");return i.default.join(e,a)}default:{const e=process.env.XDG_CONFIG_HOME||i.default.join(r,".config");return i.default.join(e,a)}}}function d(){return i.default.join(s.default.homedir(),".oauth2-forwarder")}},728(e,r){var t;Object.defineProperty(r,"__esModule",{value:!0}),r.Result=r.ResultType=void 0,function(e){e[e.success=0]="success",e[e.failure=1]="failure"}(t||(r.ResultType=t={})),r.Result={success:e=>({type:t.success,value:e}),isSuccess:e=>e.type===t.success,failure:e=>({type:t.failure,error:e}),isFailure:e=>e.type===t.failure}},638(e,r){Object.defineProperty(r,"__esModule",{value:!0}),r.sanitize=function(e){return e.replace(/((code|code_challenge)=)([^"&\n]*)/gi,(e,r)=>`${r}********`)}},802(e,r,t){var o=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(r,"__esModule",{value:!0}),r.buildCredentialProxy=function(e){return async()=>{const{logger:r}=e,t=e.pendingRequestTtlMs??3e5,o=new Map,l=(t,o,n)=>{if((0,c.isUrlAllowed)(t,e.whitelist))return!1;const i=`Domain '${(0,c.getDomain)(t)??"unknown"}' is not in the whitelist`,s=n?"Whitelist rejection (passthrough)":"Whitelist rejection";return r.warn(`${s}: ${i}`),o.writeHead(403,i),o.end(),!0},d=n.default.createServer((e,t)=>{r.debug(`Request received at ${e.headers.host}${e.url??"/"}`);const o=[];e.on("close",()=>{r.debug("Request closed")}),e.on("error",e=>{r.error(`Request error: ${e}`)}),e.on("data",e=>{o.push(e)}),e.on("end",()=>{r.debug("Request ended");const n=o.join("");r.debug(`Received body: "${n}"`),"/complete"===(e.url??"/")?u(n,t):f(n,t)})}),u=(e,t)=>{let n;r.debug("Handling /complete request");try{n=JSON.parse(e)}catch{const e="Invalid JSON in completion request body";return r.warn(e),t.writeHead(400,e),void t.end()}if(!n.requestId||!n.result){const e="Completion request missing requestId or result";return r.warn(e),t.writeHead(400,e),void t.end()}const i=o.get(n.requestId);if(!i){const e=`No pending request found for requestId: ${n.requestId}`;return r.warn(e),t.writeHead(404,e),void t.end()}clearTimeout(i.timeoutId),o.delete(n.requestId),r.info(`Completed OAuth request for ${i.domain}`),r.debug(`Request ${n.requestId} completed with result: ${n.result.type}`),i.complete(n.result),t.writeHead(200),t.end()},f=(n,d)=>{let u,f;try{u=JSON.parse(n)}catch{const e="Invalid JSON in request body";return r.warn(e),d.writeHead(400,e),void d.end()}if(!("url"in u)){const e="Received body does not contain a 'url' property";return r.warn(e),d.writeHead(400,e),void d.end()}{const t=(0,i.parseOauth2Url)(u.url);if(s.Result.isFailure(t)){if(r.debug(`OAuth parse error: ${t.error.message}`),e.passthrough){if(l(u.url,d,!0))return;const o=(0,c.getDomain)(u.url)??"unknown";r.info(`Passthrough: opening ${o} in browser`),e.openBrowser(u.url).catch(e=>{r.error(`Failed to open browser: ${e}`)}),d.writeHead(400,`${t.error.message}; URL opened in browser (passthrough mode)`)}else d.writeHead(400,t.error.message);return void d.end()}if(f=t.value,f.code_challenge||r.debug("OAuth2 request does not include PKCE parameters"),l(u.url,d,!1))return}const p=(0,a.extractPort)(f.redirect_uri);if(s.Result.isFailure(p)){if(r.debug(`Port extraction error: ${p.error.message}`),e.passthrough){if(l(u.url,d,!0))return;const t=(0,c.getDomain)(u.url)??"unknown";r.info(`Passthrough: opening ${t} in browser`),e.openBrowser(u.url).catch(e=>{r.error(`Failed to open browser: ${e}`)}),d.writeHead(400,`${p.error.message}; URL opened in browser (passthrough mode)`)}else d.writeHead(400,p.error.message);return void d.end()}const m=p.value??80;r.debug(`Using port number: ${m}`);const g=(0,c.getDomain)(u.url)??"unknown";r.info(`Received OAuth request for ${g}`),e.interactiveLogin(u.url,m).then(({callbackUrl:e,requestId:n,complete:i})=>{r.debug(`Interactive login received callback, requestId: ${n}`);const s=setTimeout(()=>{r.warn(`Pending request ${n} expired after ${t}ms, cleaning up`),o.delete(n)},t);o.set(n,{complete:i,timeoutId:s,domain:g}),r.debug(`Stored pending request ${n} with TTL ${t}ms`),r.debug("Sending callback URL and requestId to client"),d.writeHead(200);const a={url:e,requestId:n};r.debug(`Ending response with output: "${JSON.stringify(a)}"`),d.end(JSON.stringify(a))}).catch(e=>{r.error(`Interactive login error: "${JSON.stringify(e)}"`),d.writeHead(500,JSON.stringify(e)),d.end()})};return r.debug("Starting credential proxy..."),d.listen(e.port,e.host),{close:()=>{for(const[e,t]of o)r.debug(`Clearing pending request timeout for ${e} on shutdown`),clearTimeout(t.timeoutId);o.clear(),d.close()}}}};const n=o(t(611)),i=t(876),s=t(728),a=t(51),c=t(564)},516(e,r,t){var o=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(r,"__esModule",{value:!0}),r.buildInteractiveLogin=function(e){const r=e.loginTimeoutMs??3e5,{logger:t}=e;return async(o,s)=>new Promise((a,c)=>{const l=(0,i.nanoid)();let d;t.debug(`Generated requestId: ${l}`);const u=n.default.createServer((e,r)=>{d&&(clearTimeout(d),d=void 0),t.debug(`Received a ${e.method??"undefined"} request`),e.on("error",e=>{t.error(`Request error: ${JSON.stringify(e)}`),r.writeHead(500,JSON.stringify(e)),r.end(),u.close(),c(e)}),e.on("data",e=>{t.debug(`Received data chunk: ${e}`)}),e.on("close",()=>{t.debug("Redirect request closed")}),e.on("end",()=>{if(t.debug("Request ended"),!e.headers.host){const e="Missing Host header in redirect request";return t.warn(e),r.writeHead(400,e),r.end(),u.close(),void c(new Error(e))}const o="http://"+e.headers.host+e.url;t.debug(`Received callback url: "${o}"`),t.debug("Holding browser response pending completion"),t.debug("Closing listening socket (keeping response connection open)"),u.close(),a({callbackUrl:o,requestId:l,complete:e=>{switch(t.debug(`Completing request ${l} with result type: ${e.type}`),e.type){case"redirect":t.debug(`Redirecting browser to: ${e.location}`),r.writeHead(302,{Location:e.location}),r.end();break;case"success":t.debug("Sending success response to browser"),r.writeHead(200,{"Content-Type":"text/html"}),e.body?r.end(e.body):r.end("Authentication completed. You may close this page now.");break;case"error":t.debug(`Sending error response to browser: ${e.message}`),r.writeHead(500,{"Content-Type":"text/html"}),r.end(`Authentication failed: ${e.message}`)}}})})});t.debug(`Starting temporary redirect server on port ${s}...`),u.listen(s,"127.0.0.1",()=>{t.debug("Temporary redirect server is listening"),t.debug(`Setting login timeout: ${r}ms`),d=setTimeout(()=>{t.warn(`Login timeout exceeded (${r}ms), closing server on port ${s}`),u.close(),c(new Error(`Login timeout: user did not complete OAuth2 flow within ${r}ms`))},r),t.info("Opening browser for interactive login"),e.openBrowser(o)})})};const n=o(t(611)),i=t(641)},515(e,r,t){Object.defineProperty(r,"__esModule",{value:!0}),r.findAvailablePort=void 0;const o=t(611),n=t(23);r.findAvailablePort=async e=>{const t=Math.floor(64512*Math.random()+1024);return new Promise(i=>{const s=(0,o.createServer)();s.listen(t,()=>{s.close(async()=>{await(0,n.promisify)(setTimeout)(250),i(t)})}).on("error",()=>{i((0,r.findAvailablePort)(e))})})}},561(e,r,t){var o=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(r,"__esModule",{value:!0});const n=t(541),i=t(950),s=t(76),a=t(741),c=t(125),l=t(465),d=t(516),u=t(802),f=t(515),p=t(564),m=o(t(397));(process.argv.includes("--version")||process.argv.includes("-v"))&&(console.log(`o2f-server v${(0,n.getVersion)()}`),process.exit(0));const g=process.env[i.EnvKey.DEBUG],h="true"===process.env[i.EnvKey.PASSTHROUGH],w="127.0.0.1";let y;const b=process.env[i.EnvKey.LOGIN_TIMEOUT];if(b){const e=parseInt(b);!isNaN(e)&&e>0&&(y=1e3*e)}const v=g?"debug":"info",_=!0===process.stdout.isTTY;let S,x;if(_)S=process.stdout,x=!1;else{const e=(0,c.getLogFilePath)("server");(0,l.rotateOnLaunch)(e,5),S=(0,l.createLogFileStream)(e),x=!0}const P=(0,a.buildLogger)({level:v,stream:S,prefix:"server",useFileFormat:x}),O=(0,s.buildOutputWriter)({color:"yellow",stream:process.stdout}),$=(0,s.buildOutputWriter)({color:"white",stream:process.stdout});let R=null;const E=process.env[i.EnvKey.PORT];if(E){const e=parseInt(E);isNaN(e)||(R=e)}const A=async e=>{await(0,m.default)(e)},L=(0,d.buildInteractiveLogin)({openBrowser:A,logger:P,loginTimeoutMs:y});(async()=>{P.info(`o2f-server v${(0,n.getVersion)()}`),R&&P.info(`Attempting to use user specified port ${R}`);const e=R??await(0,f.findAvailablePort)(w),r=(0,p.loadWhitelist)();if(r.enabled)P.info(`URL whitelist enabled with ${r.domains.size} domain(s): ${Array.from(r.domains).join(", ")}`),r.usingLegacyPath&&P.warn(`Config location ~/.oauth2-forwarder/ is deprecated. Please move your config to ${r.preferredLocation}`);else switch(r.disabledReason){case"parse-error":P.error(`URL whitelist disabled: failed to parse ${r.configPath}: ${r.parseError}`);break;case"empty-domains":P.warn(`URL whitelist disabled: no domains listed in ${r.configPath}`);break;case"file-not-found":P.info(`URL whitelist disabled (no config file found at ${r.configPath})`);break;default:P.info(`URL whitelist disabled (reason not specified for ${r.configPath})`)}const t=(0,u.buildCredentialProxy)({host:w,port:e,interactiveLogin:L,openBrowser:A,passthrough:h,pendingRequestTtlMs:y,whitelist:r,logger:P});P.info(`Starting TCP server listening on ${w}:${e}`),h&&P.info("Passthrough mode enabled: malformed URLs will be opened in browser"),_&&(O("Run the following command in your docker container:\n"),$(` export ${i.EnvKey.SERVER}="host.docker.internal:${e}"\n`),O("\nIn addition, you need to set the BROWSER env variable to point to the client script in the docker container.\n"),O("If you installed via npm (recommended):\n"),$(" export BROWSER=o2f-browser\n"),O("If you installed manually to the default location:\n"),$(" export BROWSER=~/o2f/browser.sh\n"));try{await t(),P.info("Server started. Press Ctrl+C to stop.")}catch(e){P.error(JSON.stringify(e)),process.exit(1)}})().catch(e=>{P.error(JSON.stringify(e)),process.exit(1)})},564(e,r,t){var o=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(r,"__esModule",{value:!0}),r.getDomain=void 0,r.loadWhitelist=function(){const{path:e,isLegacy:r}=(0,s.resolveConfigFile)("whitelist.json"),t=(0,s.getPreferredConfigDescription)();if(!n.default.existsSync(e))return{enabled:!1,domains:new Set,configPath:e,usingLegacyPath:!1,preferredLocation:t,disabledReason:"file-not-found"};try{const o=n.default.readFileSync(e,"utf-8"),i=JSON.parse(o);if(!Array.isArray(i.domains)||0===i.domains.length)return{enabled:!1,domains:new Set,configPath:e,usingLegacyPath:r,preferredLocation:t,disabledReason:"empty-domains"};const s=new Set(i.domains.map(e=>e.toLowerCase().trim()).filter(e=>e.length>0));return{enabled:s.size>0,domains:s,configPath:e,usingLegacyPath:r,preferredLocation:t,disabledReason:s.size>0?void 0:"empty-domains"}}catch(o){return{enabled:!1,domains:new Set,configPath:e,usingLegacyPath:r,preferredLocation:t,disabledReason:"parse-error",parseError:o instanceof Error?o.message:String(o)}}},r.isUrlAllowed=function(e,r){if(!r.enabled)return!0;const t=(0,i.getDomain)(e);return!!t&&r.domains.has(t)};const n=o(t(896)),i=t(512);Object.defineProperty(r,"getDomain",{enumerable:!0,get:function(){return i.getDomain}});const s=t(125)},512(e,r){Object.defineProperty(r,"__esModule",{value:!0}),r.getDomain=function(e){try{return new URL(e).hostname.toLowerCase()}catch{return null}}},541(e,r,t){var o=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(r,"__esModule",{value:!0}),r.getVersion=function(){return n.default.version};const n=o(t(330))},896(e){e.exports=require("fs")},611(e){e.exports=require("http")},857(e){e.exports=require("os")},928(e){e.exports=require("path")},23(e){e.exports=require("util")},641(e,r,t){t.r(r),t.d(r,{customAlphabet:()=>d,customRandom:()=>l,nanoid:()=>u,random:()=>c,urlAlphabet:()=>n});const o=require("node:crypto"),n="useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict";let i,s;function a(e){!i||i.length<e?(i=Buffer.allocUnsafe(128*e),o.webcrypto.getRandomValues(i),s=0):s+e>i.length&&(o.webcrypto.getRandomValues(i),s=0),s+=e}function c(e){return a(e|=0),i.subarray(s-e,s)}function l(e,r,t){let o=(2<<31-Math.clz32(e.length-1|1))-1,n=Math.ceil(1.6*o*r/e.length);return(i=r)=>{if(!i)return"";let s="";for(;;){let r=t(n),a=n;for(;a--;)if(s+=e[r[a]&o]||"",s.length>=i)return s}}}function d(e,r=21){return l(e,r,c)}function u(e=21){a(e|=0);let r="";for(let t=s-e;t<s;t++)r+=n[63&i[t]];return r}},397(e,r,t){t.r(r),t.d(r,{apps:()=>W,default:()=>K,openApp:()=>F});const o=require("node:process"),n=require("node:path"),i=require("node:url"),s=require("node:child_process"),a=require("node:fs/promises"),c=require("node:os"),l=require("node:fs");let d,u;function f(){return void 0===u&&(u=(()=>{try{return l.statSync("/run/.containerenv"),!0}catch{return!1}})()||(void 0===d&&(d=function(){try{return l.statSync("/.dockerenv"),!0}catch{return!1}}()||function(){try{return l.readFileSync("/proc/self/cgroup","utf8").includes("docker")}catch{return!1}}()),d)),u}const p=()=>{if("linux"!==o.platform)return!1;if(c.release().toLowerCase().includes("microsoft"))return!f();try{if(l.readFileSync("/proc/version","utf8").toLowerCase().includes("microsoft"))return!f()}catch{}return!(!l.existsSync("/proc/sys/fs/binfmt_misc/WSLInterop")&&!l.existsSync("/run/WSL")||f())},m=o.env.__IS_WSL_TEST__?p:p(),g=require("node:util"),h=require("node:buffer"),w=(0,g.promisify)(s.execFile),y=()=>`${o.env.SYSTEMROOT||o.env.windir||String.raw`C:\Windows`}\\System32\\WindowsPowerShell\\v1.0\\powershell.exe`,b=async(e,r={})=>{const{powerShellPath:t,...o}=r,n=b.encodeCommand(e);return w(t??y(),[...b.argumentsPrefix,n],{encoding:"utf8",...o})};b.argumentsPrefix=["-NoProfile","-NonInteractive","-ExecutionPolicy","Bypass","-EncodedCommand"],b.encodeCommand=e=>h.Buffer.from(e,"utf16le").toString("base64"),b.escapeArgument=e=>`'${String(e).replaceAll("'","''")}'`;const v=(0,g.promisify)(s.execFile),_=(()=>{const e="/mnt/";let r;return async function(){if(r)return r;const t="/etc/wsl.conf";let o=!1;try{await a.access(t,a.constants.F_OK),o=!0}catch{}if(!o)return e;const n=function(e){for(const r of e.split("\n")){if(/^\s*#/.test(r))continue;const e=/^\s*root\s*=\s*(?<mountPoint>"[^"]*"|'[^']*'|[^#]*)/.exec(r);if(e)return e.groups.mountPoint.trim().replaceAll(/^["']|["']$/g,"")}}(await a.readFile(t,{encoding:"utf8"}));return void 0===n?e:(r=n,r=r.endsWith("/")?r:`${r}/`,r)}})(),S=m?async()=>`${await _()}c/Windows/System32/WindowsPowerShell/v1.0/powershell.exe`:y;let x;function P(e,r,t){const o=t=>Object.defineProperty(e,r,{value:t,enumerable:!0,writable:!0});return Object.defineProperty(e,r,{configurable:!0,enumerable:!0,get(){const e=t();return o(e),e},set(e){o(e)}}),e}const O=(0,g.promisify)(s.execFile),$={MSEdgeHTM:{name:"Edge",id:"com.microsoft.edge"},MSEdgeBHTML:{name:"Edge Beta",id:"com.microsoft.edge.beta"},MSEdgeDHTML:{name:"Edge Dev",id:"com.microsoft.edge.dev"},AppXq0fevzme2pys62n3e0fbqa7peapykr8v:{name:"Edge",id:"com.microsoft.edge.old"},ChromeHTML:{name:"Chrome",id:"com.google.chrome"},ChromeBHTML:{name:"Chrome Beta",id:"com.google.chrome.beta"},ChromeDHTML:{name:"Chrome Dev",id:"com.google.chrome.dev"},ChromiumHTM:{name:"Chromium",id:"org.chromium.Chromium"},BraveHTML:{name:"Brave",id:"com.brave.Browser"},BraveBHTML:{name:"Brave Beta",id:"com.brave.Browser.beta"},BraveDHTML:{name:"Brave Dev",id:"com.brave.Browser.dev"},BraveSSHTM:{name:"Brave Nightly",id:"com.brave.Browser.nightly"},FirefoxURL:{name:"Firefox",id:"org.mozilla.firefox"},OperaStable:{name:"Opera",id:"com.operasoftware.Opera"},VivaldiHTM:{name:"Vivaldi",id:"com.vivaldi.Vivaldi"},"IE.HTTP":{name:"Internet Explorer",id:"com.microsoft.ie"}},R=new Map(Object.entries($));class E extends Error{}const A=(0,g.promisify)(s.execFile),L=(0,g.promisify)(s.execFile);async function T(e){return async function(e,{humanReadableOutput:r=!0,signal:t}={}){if("darwin"!==o.platform)throw new Error("macOS only");const n=r?[]:["-ss"],i={};t&&(i.signal=t);const{stdout:s}=await L("osascript",["-e",e,n],i);return s.trim()}(`tell application "Finder" to set app_path to application file id "${e}" as string\ntell application "System Events" to get value of property list item "CFBundleName" of property list file (app_path & ":Contents:Info.plist")`)}const C=(0,g.promisify)(s.execFile);const M=Boolean(o.env.SSH_CONNECTION||o.env.SSH_CLIENT||o.env.SSH_TTY),j=Symbol("fallbackAttempt"),U=n.dirname((0,i.fileURLToPath)("file:///home/runner/work/oauth2-forwarder/oauth2-forwarder/node_modules/open/index.js")),q=n.join(U,"xdg-open"),{platform:I,arch:H}=o,D=async(e,r)=>{if(0===e.length)return;const t=[];for(const o of e)try{return await r(o)}catch(e){t.push(e)}throw new AggregateError(t,"Failed to open in all supported apps")},B=async e=>{const r=!0===(e={wait:!1,background:!1,newInstance:!1,allowNonzeroExitCode:!1,...e})[j];if(delete e[j],Array.isArray(e.app))return D(e.app,r=>B({...e,app:r,[j]:!0}));let t,{name:n,arguments:i=[]}=e.app??{};if(i=[...i],Array.isArray(n))return D(n,r=>B({...e,app:{name:r,arguments:i},[j]:!0}));if("browser"===n||"browserPrivate"===n){const r={"com.google.chrome":"chrome","google-chrome.desktop":"chrome","com.brave.browser":"brave","org.mozilla.firefox":"firefox","firefox.desktop":"firefox","com.microsoft.msedge":"edge","com.microsoft.edge":"edge","com.microsoft.edgemac":"edge","microsoft-edge.desktop":"edge","com.apple.safari":"safari"},t={chrome:"--incognito",brave:"--incognito",firefox:"--private-window",edge:"--inPrivate"};let s;if(m){const e=await(async()=>{const e=await S(),r=String.raw`(Get-ItemProperty -Path "HKCU:\Software\Microsoft\Windows\Shell\Associations\UrlAssociations\http\UserChoice").ProgId`,{stdout:t}=await b(r,{powerShellPath:e});return t.trim()})();s=R.get(e)??{}}else s=await async function(){if("darwin"===o.platform){const e=await async function(){if("darwin"!==o.platform)throw new Error("macOS only");const{stdout:e}=await A("defaults",["read","com.apple.LaunchServices/com.apple.launchservices.secure","LSHandlers"]),r=/LSHandlerRoleAll = "(?!-)(?<id>[^"]+?)";\s+?LSHandlerURLScheme = (?:http|https);/.exec(e),t=r?.groups.id??"com.apple.Safari";return"com.apple.safari"===t?"com.apple.Safari":t}();return{name:await T(e),id:e}}if("linux"===o.platform){const{stdout:e}=await C("xdg-mime",["query","default","x-scheme-handler/http"]),r=e.trim();return{name:r.replace(/.desktop$/,"").replace("-"," ").toLowerCase().replaceAll(/(?:^|\s|-)\S/g,e=>e.toUpperCase()),id:r}}if("win32"===o.platform)return async function(e=O){const{stdout:r}=await e("reg",["QUERY"," HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\Shell\\Associations\\UrlAssociations\\http\\UserChoice","/v","ProgId"]),t=/ProgId\s*REG_SZ\s*(?<id>\S+)/.exec(r);if(!t)throw new E(`Cannot find Windows browser in stdout: ${JSON.stringify(r)}`);const{id:o}=t.groups,n=o.lastIndexOf("."),i=o.lastIndexOf("-"),s=-1===n?void 0:o.slice(0,n),a=-1===i?void 0:o.slice(0,i);return $[o]??$[s]??$[a]??{name:o,id:o}}();throw new Error("Only macOS, Linux, and Windows are supported")}();if(s.id in r){const o=r[s.id.toLowerCase()];if("browserPrivate"===n){if("safari"===o)throw new Error("Safari doesn't support opening in private mode via command line");i.push(t[o])}return B({...e,app:{name:W[o],arguments:i}})}throw new Error(`${s.name} is not supported as a default browser`)}const c=[],l={};let d=!1;if(!m||f()||M||n||(d=await(async()=>(x??=(async()=>{try{const e=await S();return await a.access(e,a.constants.X_OK),!0}catch{return!1}})(),x))()),"darwin"===I)t="open",e.wait&&c.push("--wait-apps"),e.background&&c.push("--background"),e.newInstance&&c.push("--new"),n&&c.push("-a",n);else if("win32"===I||d){t=await S(),c.push(...b.argumentsPrefix),m||(l.windowsVerbatimArguments=!0),m&&e.target&&(e.target=await(async e=>{if(/^[a-z]+:\/\//i.test(e))return e;try{const{stdout:r}=await v("wslpath",["-aw",e],{encoding:"utf8"});return r.trim()}catch{return e}})(e.target));const r=["$ProgressPreference = 'SilentlyContinue';","Start"];e.wait&&r.push("-Wait"),n?(r.push(b.escapeArgument(n)),e.target&&i.push(e.target)):e.target&&r.push(b.escapeArgument(e.target)),i.length>0&&(i=i.map(e=>b.escapeArgument(e)),r.push("-ArgumentList",i.join(","))),e.target=b.encodeCommand(r.join(" ")),e.wait||(l.stdio="ignore")}else{if(n)t=n;else{const e=!U||"/"===U;let r=!1;try{await a.access(q,a.constants.X_OK),r=!0}catch{}t=o.versions.electron??("android"===I||e||!r)?"xdg-open":q}i.length>0&&c.push(...i),e.wait||(l.stdio="ignore",l.detached=!0)}"darwin"===I&&i.length>0&&c.push("--args",...i),e.target&&c.push(e.target);const u=s.spawn(t,c,l);return e.wait?new Promise((r,t)=>{u.once("error",t),u.once("close",o=>{e.allowNonzeroExitCode||0===o?r(u):t(new Error(`Exited with code ${o}`))})}):r?new Promise((e,r)=>{u.once("error",r),u.once("spawn",()=>{u.once("close",t=>{u.off("error",r),0===t?(u.unref(),e(u)):r(new Error(`Exited with code ${t}`))})})}):(u.unref(),new Promise((e,r)=>{u.once("error",r),u.once("spawn",()=>{u.off("error",r),e(u)})}))},F=(e,r)=>{if("string"!=typeof e&&!Array.isArray(e))throw new TypeError("Expected a valid `name`");const{arguments:t=[]}=r??{};if(null!=t&&!Array.isArray(t))throw new TypeError("Expected `appArguments` as Array type");return B({...r,app:{name:e,arguments:t}})};function k(e){if("string"==typeof e||Array.isArray(e))return e;const{[H]:r}=e;if(!r)throw new Error(`${H} is not supported`);return r}function N({[I]:e},{wsl:r}={}){if(r&&m)return k(r);if(!e)throw new Error(`${I} is not supported`);return k(e)}const W={browser:"browser",browserPrivate:"browserPrivate"};P(W,"chrome",()=>N({darwin:"google chrome",win32:"chrome",linux:["google-chrome","google-chrome-stable","chromium","chromium-browser"]},{wsl:{ia32:"/mnt/c/Program Files (x86)/Google/Chrome/Application/chrome.exe",x64:["/mnt/c/Program Files/Google/Chrome/Application/chrome.exe","/mnt/c/Program Files (x86)/Google/Chrome/Application/chrome.exe"]}})),P(W,"brave",()=>N({darwin:"brave browser",win32:"brave",linux:["brave-browser","brave"]},{wsl:{ia32:"/mnt/c/Program Files (x86)/BraveSoftware/Brave-Browser/Application/brave.exe",x64:["/mnt/c/Program Files/BraveSoftware/Brave-Browser/Application/brave.exe","/mnt/c/Program Files (x86)/BraveSoftware/Brave-Browser/Application/brave.exe"]}})),P(W,"firefox",()=>N({darwin:"firefox",win32:String.raw`C:\Program Files\Mozilla Firefox\firefox.exe`,linux:"firefox"},{wsl:"/mnt/c/Program Files/Mozilla Firefox/firefox.exe"})),P(W,"edge",()=>N({darwin:"microsoft edge",win32:"msedge",linux:["microsoft-edge","microsoft-edge-dev"]},{wsl:"/mnt/c/Program Files (x86)/Microsoft/Edge/Application/msedge.exe"})),P(W,"safari",()=>N({darwin:"Safari"}));const K=(e,r)=>{if("string"!=typeof e)throw new TypeError("Expected a `target`");return B({...r,target:e})}},330(e){e.exports=JSON.parse('{"name":"oauth2-forwarder","version":"1.4.6","description":"utilities for forwarding oauth2 interactive flow (e.g. container to host)","main":"dist/index.js","bin":{"o2f-server":"./dist/o2f-server.js","o2f-client":"./dist/o2f-client.js","o2f-browser":"./browser-global.sh"},"scripts":{"build":"rimraf ./dist && webpack && node prepend-shebang.js","zip-release":"./release.sh","test":"vitest","e2e-test":"vitest --config vitest.e2e.config.ts","lint":"eslint .","fix-formatting":"prettier --write --config ./prettier.config.js ./src/","check-formatting":"prettier --check --config ./prettier.config.js ./src/"},"author":"Sam Davidoff","license":"MIT","repository":{"type":"git","url":"https://github.com/sam-mfb/oauth2-forwarder.git"},"files":["dist","browser.sh","browser-global.sh"],"keywords":["oauth2","docker","container","authentication","browser"],"engines":{"node":">=24.0.0"},"devDependencies":{"@eslint/js":"^9.25.1","@types/eslint__js":"^8.42.3","@types/node":"^24.0.0","eslint":"^9.25.1","prettier":"^3.5.3","rimraf":"^6.0.1","ts-loader":"^9.5.2","typescript":"^5.8.3","typescript-eslint":"^8.31.1","vitest":"^3.0.5","webpack":"^5.99.7","webpack-cli":"^6.0.1"},"dependencies":{"nanoid":"^5.1.5","open":"^11.0.0"},"overrides":{"glob@>=10.2.0 <=10.4.5":"10.5.0","glob@>=11.0.0 <=11.0.3":"11.1.0","js-yaml@<3.14.2":"3.14.2","js-yaml@>=4.0.0 <4.1.1":"4.1.1","serialize-javascript@<=7.0.2":"7.0.3"}}')}},r={};function t(o){var n=r[o];if(void 0!==n)return n.exports;var i=r[o]={exports:{}};return e[o].call(i.exports,i,i.exports,t),i.exports}return t.d=(e,r)=>{for(var o in r)t.o(r,o)&&!t.o(e,o)&&Object.defineProperty(e,o,{enumerable:!0,get:r[o]})},t.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),t.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},t(561)})());
2
+ !function(e,r){"object"==typeof exports&&"object"==typeof module?module.exports=r():"function"==typeof define&&define.amd?define([],r):"object"==typeof exports?exports["oauth-forwarder"]=r():e["oauth-forwarder"]=r()}(this,()=>(()=>{"use strict";var e={478(e,r){Object.defineProperty(r,"__esModule",{value:!0}),r.color=function(e,r){return`${t[r]}${e}`};const t={black:"",red:"",green:"",yellow:"",blue:"",magenta:"",cyan:"",white:""}},950(e,r){Object.defineProperty(r,"__esModule",{value:!0}),r.EnvKey=void 0,r.EnvKey={PORT:"OAUTH2_FORWARDER_PORT",SERVER:"OAUTH2_FORWARDER_SERVER",DEBUG:"OAUTH2_FORWARDER_DEBUG",PASSTHROUGH:"OAUTH2_FORWARDER_PASSTHROUGH",LOGIN_TIMEOUT:"OAUTH2_FORWARDER_LOGIN_TIMEOUT"}},51(e,r,t){Object.defineProperty(r,"__esModule",{value:!0}),r.extractPort=function(e){let r=null;for(const t of n.LOOPBACK_PATTERNS)if(r=e.match(t),r)break;if(!r)return o.Result.failure(new Error("Invalid URL format"));const t=r[1]?parseInt(r[1],10):void 0;return void 0===t?o.Result.success(void 0):isNaN(t)||t<0||t>65535?o.Result.failure(new Error(`Not a valid port: ${t}`)):o.Result.success(t)};const o=t(728),n=t(580)},465(e,r,t){var o=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(r,"__esModule",{value:!0}),r.rotateOnLaunch=a,r.rotateIfNeeded=function(e,r=5242880,t=3){if((0,s.ensureDirectory)(i.default.dirname(e)),!n.default.existsSync(e))return!1;try{if(n.default.statSync(e).size<r)return!1}catch{return!1}return a(e,t),!0},r.createLogFileStream=function(e){return(0,s.ensureDirectory)(i.default.dirname(e)),n.default.createWriteStream(e,{flags:"a"})};const n=o(t(896)),i=o(t(928)),s=t(125);function a(e,r=5){if((0,s.ensureDirectory)(i.default.dirname(e)),!n.default.existsSync(e))return;const t=`${e}.${r}`;n.default.existsSync(t)&&n.default.unlinkSync(t);for(let t=r-1;t>=1;t--){const r=`${e}.${t}`,o=`${e}.${t+1}`;n.default.existsSync(r)&&n.default.renameSync(r,o)}n.default.renameSync(e,`${e}.1`)}},741(e,r,t){Object.defineProperty(r,"__esModule",{value:!0}),r.buildLogger=function(e){const{level:r,stream:t=process.stderr,prefix:a="",useFileFormat:c=!1}=e,l=i[r],d=(e,r)=>{if(i[e]>=l){const i=a?`[${a}] `:"",l=`[${e.toUpperCase()}]`,d=(0,n.sanitize)(r);let u;if(c)u=`${(new Date).toISOString()} ${i}${l} ${d}\n`;else{const r=s[e];u=(0,o.color)(`${i}${l} ${d}`,r)+"\n"}t.write(u)}};return{error:e=>d("error",e),warn:e=>d("warn",e),info:e=>d("info",e),debug:e=>d("debug",e)}};const o=t(478),n=t(638),i={debug:0,info:1,warn:2,error:3},s={error:"red",warn:"yellow",info:"cyan",debug:"magenta"}},580(e,r){Object.defineProperty(r,"__esModule",{value:!0}),r.LOOPBACK_PATTERNS=void 0,r.isLoopbackUrl=function(e){return r.LOOPBACK_PATTERNS.some(r=>r.test(e))},r.convertLoopbackUrl=function(e,r){return e.replace(/^(http:\/\/)localhost(:\d+)?/,`$1${r}$2`).replace(/^(http:\/\/)127\.0\.0\.1(:\d+)?/,`$1${r}$2`).replace(/^(http:\/\/)\[::1\](:\d+)?/,`$1${r}$2`)},r.LOOPBACK_PATTERNS=[/^http:\/\/localhost(?::(\d{1,5}))?(?:\/.*)?$/,/^http:\/\/127\.0\.0\.1(?::(\d{1,5}))?(?:\/.*)?$/,/^http:\/\/\[::1\](?::(\d{1,5}))?(?:\/.*)?$/]},76(e,r,t){Object.defineProperty(r,"__esModule",{value:!0}),r.buildOutputWriter=function(e){return r=>{e.stream.write((0,o.color)((0,n.sanitize)(r),e.color)+"\n")}};const o=t(478),n=t(638)},876(e,r,t){Object.defineProperty(r,"__esModule",{value:!0}),r.parseOauth2Url=function(e,r){if(!e)return o.Result.failure(new Error("Url parameter was undefined"));const t=["client_id","redirect_uri"];let n;try{n=new URL(e)}catch(r){return o.Result.failure(new Error(`Invalid URL: ${e} (${r})`))}const i=Object.fromEntries(n.searchParams.entries());for(const e of t)if(!i[e])return o.Result.failure(new Error(`Missing required parameter: ${e}`));i.response_type||r?.warn("Missing response_type parameter. This is required by the OAuth2 spec (RFC 6749) but some providers omit it.");const s=Boolean(i.code_challenge);if(s!==Boolean(i.code_challenge_method))return o.Result.failure(new Error("PKCE parameters must be used together: both code_challenge and code_challenge_method are required, or neither"));if(i.code_challenge_method&&!["S256","plain"].includes(i.code_challenge_method))return o.Result.failure(new Error(`${i.code_challenge_method} is not valid for "code_challenge_method" property`));if(i.response_mode&&!["query","fragment","form_post"].includes(i.response_mode))return o.Result.failure(new Error(`${i.response_mode} is not valid for "response_mode" property`));if(i.prompt){const e=["login","none","consent","select_account"],r=i.prompt.split(" ").filter(Boolean).filter(r=>!e.includes(r));if(r.length>0)return o.Result.failure(new Error(`${r.join(", ")} is not valid for "prompt" property`))}const a=s?{client_id:i.client_id,response_type:i.response_type,redirect_uri:i.redirect_uri,scope:i.scope,response_mode:i.response_mode,state:i.state,prompt:i.prompt,login_hint:i.login_hint,domain_hint:i.domain_hint,"x-client-SKU":i["x-client-SKU"],"x-client-VER":i["x-client-VER"],"x-client-OS":i["x-client-OS"],"x-client-CPU":i["x-client-CPU"],client_info:i.client_info,code_challenge:i.code_challenge,code_challenge_method:i.code_challenge_method}:{client_id:i.client_id,response_type:i.response_type,redirect_uri:i.redirect_uri,scope:i.scope,response_mode:i.response_mode,state:i.state,prompt:i.prompt,login_hint:i.login_hint,domain_hint:i.domain_hint,"x-client-SKU":i["x-client-SKU"],"x-client-VER":i["x-client-VER"],"x-client-OS":i["x-client-OS"],"x-client-CPU":i["x-client-CPU"],client_info:i.client_info};return o.Result.success(a)};const o=t(728)},125(e,r,t){var o=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(r,"__esModule",{value:!0}),r.ensureDirectory=function(e){n.default.existsSync(e)||n.default.mkdirSync(e,{recursive:!0})},r.getLogFilePath=function(e){const r=c();return i.default.join(r,`o2f-${e}.log`)},r.getLogDir=function(){return c()},r.getConfigDir=function(){return l()},r.getLegacyConfigDir=function(){return d()},r.resolveConfigFile=function(e){const r=i.default.join(d(),e),t=i.default.join(l(),e);return n.default.existsSync(r)?{path:r,isLegacy:!0}:{path:t,isLegacy:!1}},r.getPreferredConfigDescription=function(){switch(s.default.platform()){case"darwin":return"~/Library/Application Support/oauth2-forwarder/";case"win32":return"%LOCALAPPDATA%\\oauth2-forwarder\\";default:return"~/.config/oauth2-forwarder/ (or $XDG_CONFIG_HOME/oauth2-forwarder/)"}};const n=o(t(896)),i=o(t(928)),s=o(t(857)),a="oauth2-forwarder";function c(){const e=s.default.platform(),r=s.default.homedir();switch(e){case"darwin":return i.default.join(r,"Library","Logs",a);case"win32":{const e=process.env.LOCALAPPDATA||i.default.join(r,"AppData","Local");return i.default.join(e,a,"logs")}default:{const e=process.env.XDG_STATE_HOME||i.default.join(r,".local","state");return i.default.join(e,a)}}}function l(){const e=s.default.platform(),r=s.default.homedir();switch(e){case"darwin":return i.default.join(r,"Library","Application Support",a);case"win32":{const e=process.env.LOCALAPPDATA||i.default.join(r,"AppData","Local");return i.default.join(e,a)}default:{const e=process.env.XDG_CONFIG_HOME||i.default.join(r,".config");return i.default.join(e,a)}}}function d(){return i.default.join(s.default.homedir(),".oauth2-forwarder")}},728(e,r){var t;Object.defineProperty(r,"__esModule",{value:!0}),r.Result=r.ResultType=void 0,function(e){e[e.success=0]="success",e[e.failure=1]="failure"}(t||(r.ResultType=t={})),r.Result={success:e=>({type:t.success,value:e}),isSuccess:e=>e.type===t.success,failure:e=>({type:t.failure,error:e}),isFailure:e=>e.type===t.failure}},638(e,r){Object.defineProperty(r,"__esModule",{value:!0}),r.sanitize=function(e){return e.replace(/((code|code_challenge)=)([^"&\n]*)/gi,(e,r)=>`${r}********`)}},802(e,r,t){var o=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(r,"__esModule",{value:!0}),r.buildCredentialProxy=function(e){return async()=>{const{logger:r}=e,t=e.pendingRequestTtlMs??3e5,o=new Map,l=(t,o,n)=>{if((0,c.isUrlAllowed)(t,e.whitelist))return!1;const i=`Domain '${(0,c.getDomain)(t)??"unknown"}' is not in the whitelist`,s=n?"Whitelist rejection (passthrough)":"Whitelist rejection";return r.warn(`${s}: ${i}`),o.writeHead(403,i),o.end(),!0},d=n.default.createServer((e,t)=>{r.debug(`Request received at ${e.headers.host}${e.url??"/"}`);const o=[];e.on("close",()=>{r.debug("Request closed")}),e.on("error",e=>{r.error(`Request error: ${e}`)}),e.on("data",e=>{o.push(e)}),e.on("end",()=>{r.debug("Request ended");const n=o.join("");r.debug(`Received body: "${n}"`),"/complete"===(e.url??"/")?u(n,t):f(n,t)})}),u=(e,t)=>{let n;r.debug("Handling /complete request");try{n=JSON.parse(e)}catch{const e="Invalid JSON in completion request body";return r.warn(e),t.writeHead(400,e),void t.end()}if(!n.requestId||!n.result){const e="Completion request missing requestId or result";return r.warn(e),t.writeHead(400,e),void t.end()}const i=o.get(n.requestId);if(!i){const e=`No pending request found for requestId: ${n.requestId}`;return r.warn(e),t.writeHead(404,e),void t.end()}clearTimeout(i.timeoutId),o.delete(n.requestId),r.info(`Completed OAuth request for ${i.domain}`),r.debug(`Request ${n.requestId} completed with result: ${n.result.type}`),i.complete(n.result),t.writeHead(200),t.end()},f=(n,d)=>{let u,f;try{u=JSON.parse(n)}catch{const e="Invalid JSON in request body";return r.warn(e),d.writeHead(400,e),void d.end()}if(!("url"in u)){const e="Received body does not contain a 'url' property";return r.warn(e),d.writeHead(400,e),void d.end()}{const t=(0,i.parseOauth2Url)(u.url,r);if(s.Result.isFailure(t)){if(r.debug(`OAuth parse error: ${t.error.message}`),e.passthrough){if(l(u.url,d,!0))return;const o=(0,c.getDomain)(u.url)??"unknown";r.info(`Passthrough: opening ${o} in browser`),e.openBrowser(u.url).catch(e=>{r.error(`Failed to open browser: ${e}`)}),d.writeHead(400,`${t.error.message}; URL opened in browser (passthrough mode)`)}else d.writeHead(400,t.error.message);return void d.end()}if(f=t.value,f.code_challenge||r.debug("OAuth2 request does not include PKCE parameters"),l(u.url,d,!1))return}const p=(0,a.extractPort)(f.redirect_uri);if(s.Result.isFailure(p)){if(r.debug(`Port extraction error: ${p.error.message}`),e.passthrough){if(l(u.url,d,!0))return;const t=(0,c.getDomain)(u.url)??"unknown";r.info(`Passthrough: opening ${t} in browser`),e.openBrowser(u.url).catch(e=>{r.error(`Failed to open browser: ${e}`)}),d.writeHead(400,`${p.error.message}; URL opened in browser (passthrough mode)`)}else d.writeHead(400,p.error.message);return void d.end()}const m=p.value??80;r.debug(`Using port number: ${m}`);const g=(0,c.getDomain)(u.url)??"unknown";r.info(`Received OAuth request for ${g}`),e.interactiveLogin(u.url,m).then(({callbackUrl:e,requestId:n,complete:i})=>{r.debug(`Interactive login received callback, requestId: ${n}`);const s=setTimeout(()=>{r.warn(`Pending request ${n} expired after ${t}ms, cleaning up`),o.delete(n)},t);o.set(n,{complete:i,timeoutId:s,domain:g}),r.debug(`Stored pending request ${n} with TTL ${t}ms`),r.debug("Sending callback URL and requestId to client"),d.writeHead(200);const a={url:e,requestId:n};r.debug(`Ending response with output: "${JSON.stringify(a)}"`),d.end(JSON.stringify(a))}).catch(e=>{r.error(`Interactive login error: "${JSON.stringify(e)}"`),d.writeHead(500,JSON.stringify(e)),d.end()})};return r.debug("Starting credential proxy..."),d.listen(e.port,e.host),{close:()=>{for(const[e,t]of o)r.debug(`Clearing pending request timeout for ${e} on shutdown`),clearTimeout(t.timeoutId);o.clear(),d.close()}}}};const n=o(t(611)),i=t(876),s=t(728),a=t(51),c=t(564)},516(e,r,t){var o=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(r,"__esModule",{value:!0}),r.buildInteractiveLogin=function(e){const r=e.loginTimeoutMs??3e5,{logger:t}=e;return async(o,s)=>new Promise((a,c)=>{const l=(0,i.nanoid)();let d;t.debug(`Generated requestId: ${l}`);const u=n.default.createServer((e,r)=>{d&&(clearTimeout(d),d=void 0),t.debug(`Received a ${e.method??"undefined"} request`),e.on("error",e=>{t.error(`Request error: ${JSON.stringify(e)}`),r.writeHead(500,JSON.stringify(e)),r.end(),u.close(),c(e)}),e.on("data",e=>{t.debug(`Received data chunk: ${e}`)}),e.on("close",()=>{t.debug("Redirect request closed")}),e.on("end",()=>{if(t.debug("Request ended"),!e.headers.host){const e="Missing Host header in redirect request";return t.warn(e),r.writeHead(400,e),r.end(),u.close(),void c(new Error(e))}const o="http://"+e.headers.host+e.url;t.debug(`Received callback url: "${o}"`),t.debug("Holding browser response pending completion"),t.debug("Closing listening socket (keeping response connection open)"),u.close(),a({callbackUrl:o,requestId:l,complete:e=>{switch(t.debug(`Completing request ${l} with result type: ${e.type}`),e.type){case"redirect":t.debug(`Redirecting browser to: ${e.location}`),r.writeHead(302,{Location:e.location}),r.end();break;case"success":t.debug("Sending success response to browser"),r.writeHead(200,{"Content-Type":"text/html"}),e.body?r.end(e.body):r.end("Authentication completed. You may close this page now.");break;case"error":t.debug(`Sending error response to browser: ${e.message}`),r.writeHead(500,{"Content-Type":"text/html"}),r.end(`Authentication failed: ${e.message}`)}}})})});t.debug(`Starting temporary redirect server on port ${s}...`),u.listen(s,"127.0.0.1",()=>{t.debug("Temporary redirect server is listening"),t.debug(`Setting login timeout: ${r}ms`),d=setTimeout(()=>{t.warn(`Login timeout exceeded (${r}ms), closing server on port ${s}`),u.close(),c(new Error(`Login timeout: user did not complete OAuth2 flow within ${r}ms`))},r),t.info("Opening browser for interactive login"),e.openBrowser(o)})})};const n=o(t(611)),i=t(641)},515(e,r,t){Object.defineProperty(r,"__esModule",{value:!0}),r.findAvailablePort=void 0;const o=t(611),n=t(23);r.findAvailablePort=async e=>{const t=Math.floor(64512*Math.random()+1024);return new Promise(i=>{const s=(0,o.createServer)();s.listen(t,()=>{s.close(async()=>{await(0,n.promisify)(setTimeout)(250),i(t)})}).on("error",()=>{i((0,r.findAvailablePort)(e))})})}},561(e,r,t){var o=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(r,"__esModule",{value:!0});const n=t(541),i=t(950),s=t(76),a=t(741),c=t(125),l=t(465),d=t(516),u=t(802),f=t(515),p=t(564),m=o(t(397));(process.argv.includes("--version")||process.argv.includes("-v"))&&(console.log(`o2f-server v${(0,n.getVersion)()}`),process.exit(0));const g=process.env[i.EnvKey.DEBUG],h="true"===process.env[i.EnvKey.PASSTHROUGH],w="127.0.0.1";let y;const b=process.env[i.EnvKey.LOGIN_TIMEOUT];if(b){const e=parseInt(b);!isNaN(e)&&e>0&&(y=1e3*e)}const v=g?"debug":"info",_=!0===process.stdout.isTTY;let S,x;if(_)S=process.stdout,x=!1;else{const e=(0,c.getLogFilePath)("server");(0,l.rotateOnLaunch)(e,5),S=(0,l.createLogFileStream)(e),x=!0}const P=(0,a.buildLogger)({level:v,stream:S,prefix:"server",useFileFormat:x}),O=(0,s.buildOutputWriter)({color:"yellow",stream:process.stdout}),$=(0,s.buildOutputWriter)({color:"white",stream:process.stdout});let R=null;const E=process.env[i.EnvKey.PORT];if(E){const e=parseInt(E);isNaN(e)||(R=e)}const A=async e=>{await(0,m.default)(e)},L=(0,d.buildInteractiveLogin)({openBrowser:A,logger:P,loginTimeoutMs:y});(async()=>{P.info(`o2f-server v${(0,n.getVersion)()}`),R&&P.info(`Attempting to use user specified port ${R}`);const e=R??await(0,f.findAvailablePort)(w),r=(0,p.loadWhitelist)();if(r.enabled)P.info(`URL whitelist enabled with ${r.domains.size} domain(s): ${Array.from(r.domains).join(", ")}`),r.usingLegacyPath&&P.warn(`Config location ~/.oauth2-forwarder/ is deprecated. Please move your config to ${r.preferredLocation}`);else switch(r.disabledReason){case"parse-error":P.error(`URL whitelist disabled: failed to parse ${r.configPath}: ${r.parseError}`);break;case"empty-domains":P.warn(`URL whitelist disabled: no domains listed in ${r.configPath}`);break;case"file-not-found":P.info(`URL whitelist disabled (no config file found at ${r.configPath})`);break;default:P.info(`URL whitelist disabled (reason not specified for ${r.configPath})`)}const t=(0,u.buildCredentialProxy)({host:w,port:e,interactiveLogin:L,openBrowser:A,passthrough:h,pendingRequestTtlMs:y,whitelist:r,logger:P});P.info(`Starting TCP server listening on ${w}:${e}`),h&&P.info("Passthrough mode enabled: malformed URLs will be opened in browser"),_&&(O("Run the following command in your docker container:\n"),$(` export ${i.EnvKey.SERVER}="host.docker.internal:${e}"\n`),O("\nIn addition, you need to set the BROWSER env variable to point to the client script in the docker container.\n"),O("If you installed via npm (recommended):\n"),$(" export BROWSER=o2f-browser\n"),O("If you installed manually to the default location:\n"),$(" export BROWSER=~/o2f/browser.sh\n"));try{await t(),P.info("Server started. Press Ctrl+C to stop.")}catch(e){P.error(JSON.stringify(e)),process.exit(1)}})().catch(e=>{P.error(JSON.stringify(e)),process.exit(1)})},564(e,r,t){var o=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(r,"__esModule",{value:!0}),r.getDomain=void 0,r.loadWhitelist=function(){const{path:e,isLegacy:r}=(0,s.resolveConfigFile)("whitelist.json"),t=(0,s.getPreferredConfigDescription)();if(!n.default.existsSync(e))return{enabled:!1,domains:new Set,configPath:e,usingLegacyPath:!1,preferredLocation:t,disabledReason:"file-not-found"};try{const o=n.default.readFileSync(e,"utf-8"),i=JSON.parse(o);if(!Array.isArray(i.domains)||0===i.domains.length)return{enabled:!1,domains:new Set,configPath:e,usingLegacyPath:r,preferredLocation:t,disabledReason:"empty-domains"};const s=new Set(i.domains.map(e=>e.toLowerCase().trim()).filter(e=>e.length>0));return{enabled:s.size>0,domains:s,configPath:e,usingLegacyPath:r,preferredLocation:t,disabledReason:s.size>0?void 0:"empty-domains"}}catch(o){return{enabled:!1,domains:new Set,configPath:e,usingLegacyPath:r,preferredLocation:t,disabledReason:"parse-error",parseError:o instanceof Error?o.message:String(o)}}},r.isUrlAllowed=function(e,r){if(!r.enabled)return!0;const t=(0,i.getDomain)(e);return!!t&&r.domains.has(t)};const n=o(t(896)),i=t(512);Object.defineProperty(r,"getDomain",{enumerable:!0,get:function(){return i.getDomain}});const s=t(125)},512(e,r){Object.defineProperty(r,"__esModule",{value:!0}),r.getDomain=function(e){try{return new URL(e).hostname.toLowerCase()}catch{return null}}},541(e,r,t){var o=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(r,"__esModule",{value:!0}),r.getVersion=function(){return n.default.version};const n=o(t(330))},896(e){e.exports=require("fs")},611(e){e.exports=require("http")},857(e){e.exports=require("os")},928(e){e.exports=require("path")},23(e){e.exports=require("util")},641(e,r,t){t.r(r),t.d(r,{customAlphabet:()=>d,customRandom:()=>l,nanoid:()=>u,random:()=>c,urlAlphabet:()=>n});const o=require("node:crypto"),n="useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict";let i,s;function a(e){!i||i.length<e?(i=Buffer.allocUnsafe(128*e),o.webcrypto.getRandomValues(i),s=0):s+e>i.length&&(o.webcrypto.getRandomValues(i),s=0),s+=e}function c(e){return a(e|=0),i.subarray(s-e,s)}function l(e,r,t){let o=(2<<31-Math.clz32(e.length-1|1))-1,n=Math.ceil(1.6*o*r/e.length);return(i=r)=>{if(!i)return"";let s="";for(;;){let r=t(n),a=n;for(;a--;)if(s+=e[r[a]&o]||"",s.length>=i)return s}}}function d(e,r=21){return l(e,r,c)}function u(e=21){a(e|=0);let r="";for(let t=s-e;t<s;t++)r+=n[63&i[t]];return r}},397(e,r,t){t.r(r),t.d(r,{apps:()=>W,default:()=>K,openApp:()=>F});const o=require("node:process"),n=require("node:path"),i=require("node:url"),s=require("node:child_process"),a=require("node:fs/promises"),c=require("node:os"),l=require("node:fs");let d,u;function f(){return void 0===u&&(u=(()=>{try{return l.statSync("/run/.containerenv"),!0}catch{return!1}})()||(void 0===d&&(d=function(){try{return l.statSync("/.dockerenv"),!0}catch{return!1}}()||function(){try{return l.readFileSync("/proc/self/cgroup","utf8").includes("docker")}catch{return!1}}()),d)),u}const p=()=>{if("linux"!==o.platform)return!1;if(c.release().toLowerCase().includes("microsoft"))return!f();try{if(l.readFileSync("/proc/version","utf8").toLowerCase().includes("microsoft"))return!f()}catch{}return!(!l.existsSync("/proc/sys/fs/binfmt_misc/WSLInterop")&&!l.existsSync("/run/WSL")||f())},m=o.env.__IS_WSL_TEST__?p:p(),g=require("node:util"),h=require("node:buffer"),w=(0,g.promisify)(s.execFile),y=()=>`${o.env.SYSTEMROOT||o.env.windir||String.raw`C:\Windows`}\\System32\\WindowsPowerShell\\v1.0\\powershell.exe`,b=async(e,r={})=>{const{powerShellPath:t,...o}=r,n=b.encodeCommand(e);return w(t??y(),[...b.argumentsPrefix,n],{encoding:"utf8",...o})};b.argumentsPrefix=["-NoProfile","-NonInteractive","-ExecutionPolicy","Bypass","-EncodedCommand"],b.encodeCommand=e=>h.Buffer.from(e,"utf16le").toString("base64"),b.escapeArgument=e=>`'${String(e).replaceAll("'","''")}'`;const v=(0,g.promisify)(s.execFile),_=(()=>{const e="/mnt/";let r;return async function(){if(r)return r;const t="/etc/wsl.conf";let o=!1;try{await a.access(t,a.constants.F_OK),o=!0}catch{}if(!o)return e;const n=function(e){for(const r of e.split("\n")){if(/^\s*#/.test(r))continue;const e=/^\s*root\s*=\s*(?<mountPoint>"[^"]*"|'[^']*'|[^#]*)/.exec(r);if(e)return e.groups.mountPoint.trim().replaceAll(/^["']|["']$/g,"")}}(await a.readFile(t,{encoding:"utf8"}));return void 0===n?e:(r=n,r=r.endsWith("/")?r:`${r}/`,r)}})(),S=m?async()=>`${await _()}c/Windows/System32/WindowsPowerShell/v1.0/powershell.exe`:y;let x;function P(e,r,t){const o=t=>Object.defineProperty(e,r,{value:t,enumerable:!0,writable:!0});return Object.defineProperty(e,r,{configurable:!0,enumerable:!0,get(){const e=t();return o(e),e},set(e){o(e)}}),e}const O=(0,g.promisify)(s.execFile),$={MSEdgeHTM:{name:"Edge",id:"com.microsoft.edge"},MSEdgeBHTML:{name:"Edge Beta",id:"com.microsoft.edge.beta"},MSEdgeDHTML:{name:"Edge Dev",id:"com.microsoft.edge.dev"},AppXq0fevzme2pys62n3e0fbqa7peapykr8v:{name:"Edge",id:"com.microsoft.edge.old"},ChromeHTML:{name:"Chrome",id:"com.google.chrome"},ChromeBHTML:{name:"Chrome Beta",id:"com.google.chrome.beta"},ChromeDHTML:{name:"Chrome Dev",id:"com.google.chrome.dev"},ChromiumHTM:{name:"Chromium",id:"org.chromium.Chromium"},BraveHTML:{name:"Brave",id:"com.brave.Browser"},BraveBHTML:{name:"Brave Beta",id:"com.brave.Browser.beta"},BraveDHTML:{name:"Brave Dev",id:"com.brave.Browser.dev"},BraveSSHTM:{name:"Brave Nightly",id:"com.brave.Browser.nightly"},FirefoxURL:{name:"Firefox",id:"org.mozilla.firefox"},OperaStable:{name:"Opera",id:"com.operasoftware.Opera"},VivaldiHTM:{name:"Vivaldi",id:"com.vivaldi.Vivaldi"},"IE.HTTP":{name:"Internet Explorer",id:"com.microsoft.ie"}},R=new Map(Object.entries($));class E extends Error{}const A=(0,g.promisify)(s.execFile),L=(0,g.promisify)(s.execFile);async function T(e){return async function(e,{humanReadableOutput:r=!0,signal:t}={}){if("darwin"!==o.platform)throw new Error("macOS only");const n=r?[]:["-ss"],i={};t&&(i.signal=t);const{stdout:s}=await L("osascript",["-e",e,n],i);return s.trim()}(`tell application "Finder" to set app_path to application file id "${e}" as string\ntell application "System Events" to get value of property list item "CFBundleName" of property list file (app_path & ":Contents:Info.plist")`)}const C=(0,g.promisify)(s.execFile);const M=Boolean(o.env.SSH_CONNECTION||o.env.SSH_CLIENT||o.env.SSH_TTY),j=Symbol("fallbackAttempt"),q=n.dirname((0,i.fileURLToPath)("file:///home/runner/work/oauth2-forwarder/oauth2-forwarder/node_modules/open/index.js")),U=n.join(q,"xdg-open"),{platform:I,arch:H}=o,D=async(e,r)=>{if(0===e.length)return;const t=[];for(const o of e)try{return await r(o)}catch(e){t.push(e)}throw new AggregateError(t,"Failed to open in all supported apps")},B=async e=>{const r=!0===(e={wait:!1,background:!1,newInstance:!1,allowNonzeroExitCode:!1,...e})[j];if(delete e[j],Array.isArray(e.app))return D(e.app,r=>B({...e,app:r,[j]:!0}));let t,{name:n,arguments:i=[]}=e.app??{};if(i=[...i],Array.isArray(n))return D(n,r=>B({...e,app:{name:r,arguments:i},[j]:!0}));if("browser"===n||"browserPrivate"===n){const r={"com.google.chrome":"chrome","google-chrome.desktop":"chrome","com.brave.browser":"brave","org.mozilla.firefox":"firefox","firefox.desktop":"firefox","com.microsoft.msedge":"edge","com.microsoft.edge":"edge","com.microsoft.edgemac":"edge","microsoft-edge.desktop":"edge","com.apple.safari":"safari"},t={chrome:"--incognito",brave:"--incognito",firefox:"--private-window",edge:"--inPrivate"};let s;if(m){const e=await(async()=>{const e=await S(),r=String.raw`(Get-ItemProperty -Path "HKCU:\Software\Microsoft\Windows\Shell\Associations\UrlAssociations\http\UserChoice").ProgId`,{stdout:t}=await b(r,{powerShellPath:e});return t.trim()})();s=R.get(e)??{}}else s=await async function(){if("darwin"===o.platform){const e=await async function(){if("darwin"!==o.platform)throw new Error("macOS only");const{stdout:e}=await A("defaults",["read","com.apple.LaunchServices/com.apple.launchservices.secure","LSHandlers"]),r=/LSHandlerRoleAll = "(?!-)(?<id>[^"]+?)";\s+?LSHandlerURLScheme = (?:http|https);/.exec(e),t=r?.groups.id??"com.apple.Safari";return"com.apple.safari"===t?"com.apple.Safari":t}();return{name:await T(e),id:e}}if("linux"===o.platform){const{stdout:e}=await C("xdg-mime",["query","default","x-scheme-handler/http"]),r=e.trim();return{name:r.replace(/.desktop$/,"").replace("-"," ").toLowerCase().replaceAll(/(?:^|\s|-)\S/g,e=>e.toUpperCase()),id:r}}if("win32"===o.platform)return async function(e=O){const{stdout:r}=await e("reg",["QUERY"," HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\Shell\\Associations\\UrlAssociations\\http\\UserChoice","/v","ProgId"]),t=/ProgId\s*REG_SZ\s*(?<id>\S+)/.exec(r);if(!t)throw new E(`Cannot find Windows browser in stdout: ${JSON.stringify(r)}`);const{id:o}=t.groups,n=o.lastIndexOf("."),i=o.lastIndexOf("-"),s=-1===n?void 0:o.slice(0,n),a=-1===i?void 0:o.slice(0,i);return $[o]??$[s]??$[a]??{name:o,id:o}}();throw new Error("Only macOS, Linux, and Windows are supported")}();if(s.id in r){const o=r[s.id.toLowerCase()];if("browserPrivate"===n){if("safari"===o)throw new Error("Safari doesn't support opening in private mode via command line");i.push(t[o])}return B({...e,app:{name:W[o],arguments:i}})}throw new Error(`${s.name} is not supported as a default browser`)}const c=[],l={};let d=!1;if(!m||f()||M||n||(d=await(async()=>(x??=(async()=>{try{const e=await S();return await a.access(e,a.constants.X_OK),!0}catch{return!1}})(),x))()),"darwin"===I)t="open",e.wait&&c.push("--wait-apps"),e.background&&c.push("--background"),e.newInstance&&c.push("--new"),n&&c.push("-a",n);else if("win32"===I||d){t=await S(),c.push(...b.argumentsPrefix),m||(l.windowsVerbatimArguments=!0),m&&e.target&&(e.target=await(async e=>{if(/^[a-z]+:\/\//i.test(e))return e;try{const{stdout:r}=await v("wslpath",["-aw",e],{encoding:"utf8"});return r.trim()}catch{return e}})(e.target));const r=["$ProgressPreference = 'SilentlyContinue';","Start"];e.wait&&r.push("-Wait"),n?(r.push(b.escapeArgument(n)),e.target&&i.push(e.target)):e.target&&r.push(b.escapeArgument(e.target)),i.length>0&&(i=i.map(e=>b.escapeArgument(e)),r.push("-ArgumentList",i.join(","))),e.target=b.encodeCommand(r.join(" ")),e.wait||(l.stdio="ignore")}else{if(n)t=n;else{const e=!q||"/"===q;let r=!1;try{await a.access(U,a.constants.X_OK),r=!0}catch{}t=o.versions.electron??("android"===I||e||!r)?"xdg-open":U}i.length>0&&c.push(...i),e.wait||(l.stdio="ignore",l.detached=!0)}"darwin"===I&&i.length>0&&c.push("--args",...i),e.target&&c.push(e.target);const u=s.spawn(t,c,l);return e.wait?new Promise((r,t)=>{u.once("error",t),u.once("close",o=>{e.allowNonzeroExitCode||0===o?r(u):t(new Error(`Exited with code ${o}`))})}):r?new Promise((e,r)=>{u.once("error",r),u.once("spawn",()=>{u.once("close",t=>{u.off("error",r),0===t?(u.unref(),e(u)):r(new Error(`Exited with code ${t}`))})})}):(u.unref(),new Promise((e,r)=>{u.once("error",r),u.once("spawn",()=>{u.off("error",r),e(u)})}))},F=(e,r)=>{if("string"!=typeof e&&!Array.isArray(e))throw new TypeError("Expected a valid `name`");const{arguments:t=[]}=r??{};if(null!=t&&!Array.isArray(t))throw new TypeError("Expected `appArguments` as Array type");return B({...r,app:{name:e,arguments:t}})};function k(e){if("string"==typeof e||Array.isArray(e))return e;const{[H]:r}=e;if(!r)throw new Error(`${H} is not supported`);return r}function N({[I]:e},{wsl:r}={}){if(r&&m)return k(r);if(!e)throw new Error(`${I} is not supported`);return k(e)}const W={browser:"browser",browserPrivate:"browserPrivate"};P(W,"chrome",()=>N({darwin:"google chrome",win32:"chrome",linux:["google-chrome","google-chrome-stable","chromium","chromium-browser"]},{wsl:{ia32:"/mnt/c/Program Files (x86)/Google/Chrome/Application/chrome.exe",x64:["/mnt/c/Program Files/Google/Chrome/Application/chrome.exe","/mnt/c/Program Files (x86)/Google/Chrome/Application/chrome.exe"]}})),P(W,"brave",()=>N({darwin:"brave browser",win32:"brave",linux:["brave-browser","brave"]},{wsl:{ia32:"/mnt/c/Program Files (x86)/BraveSoftware/Brave-Browser/Application/brave.exe",x64:["/mnt/c/Program Files/BraveSoftware/Brave-Browser/Application/brave.exe","/mnt/c/Program Files (x86)/BraveSoftware/Brave-Browser/Application/brave.exe"]}})),P(W,"firefox",()=>N({darwin:"firefox",win32:String.raw`C:\Program Files\Mozilla Firefox\firefox.exe`,linux:"firefox"},{wsl:"/mnt/c/Program Files/Mozilla Firefox/firefox.exe"})),P(W,"edge",()=>N({darwin:"microsoft edge",win32:"msedge",linux:["microsoft-edge","microsoft-edge-dev"]},{wsl:"/mnt/c/Program Files (x86)/Microsoft/Edge/Application/msedge.exe"})),P(W,"safari",()=>N({darwin:"Safari"}));const K=(e,r)=>{if("string"!=typeof e)throw new TypeError("Expected a `target`");return B({...r,target:e})}},330(e){e.exports=JSON.parse('{"name":"oauth2-forwarder","version":"1.4.8","description":"utilities for forwarding oauth2 interactive flow (e.g. container to host)","main":"dist/index.js","bin":{"o2f-server":"./dist/o2f-server.js","o2f-client":"./dist/o2f-client.js","o2f-browser":"./browser-global.sh"},"scripts":{"build":"rimraf ./dist && webpack && node prepend-shebang.js","zip-release":"./release.sh","test":"vitest","e2e-test":"vitest --config vitest.e2e.config.ts","lint":"eslint .","fix-formatting":"prettier --write --config ./prettier.config.js ./src/","check-formatting":"prettier --check --config ./prettier.config.js ./src/"},"author":"Sam Davidoff","license":"MIT","repository":{"type":"git","url":"https://github.com/sam-mfb/oauth2-forwarder.git"},"files":["dist","browser.sh","browser-global.sh"],"keywords":["oauth2","docker","container","authentication","browser"],"engines":{"node":">=24.0.0"},"devDependencies":{"@eslint/js":"^9.25.1","@types/eslint__js":"^8.42.3","@types/node":"^24.0.0","eslint":"^9.25.1","prettier":"^3.5.3","rimraf":"^6.0.1","ts-loader":"^9.5.2","typescript":"^5.8.3","typescript-eslint":"^8.31.1","vitest":"^3.0.5","webpack":"^5.99.7","webpack-cli":"^6.0.1"},"dependencies":{"nanoid":"^5.1.5","open":"^11.0.0"},"overrides":{"glob@>=10.2.0 <=10.4.5":"10.5.0","glob@>=11.0.0 <=11.0.3":"11.1.0","js-yaml@<3.14.2":"3.14.2","js-yaml@>=4.0.0 <4.1.1":"4.1.1","serialize-javascript@<=7.0.2":"7.0.3","flatted@<=3.4.1":"3.4.2","brace-expansion@<1.1.13":"1.1.13","brace-expansion@>=4.0.0 <5.0.5":"5.0.5","picomatch@<=2.3.1":"2.3.2","picomatch@>=4.0.0 <=4.0.3":"4.0.4"}}')}},r={};function t(o){var n=r[o];if(void 0!==n)return n.exports;var i=r[o]={exports:{}};return e[o].call(i.exports,i,i.exports,t),i.exports}return t.d=(e,r)=>{for(var o in r)t.o(r,o)&&!t.o(e,o)&&Object.defineProperty(e,o,{enumerable:!0,get:r[o]})},t.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),t.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},t(561)})());
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oauth2-forwarder",
3
- "version": "1.4.6",
3
+ "version": "1.4.8",
4
4
  "description": "utilities for forwarding oauth2 interactive flow (e.g. container to host)",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -61,6 +61,11 @@
61
61
  "glob@>=11.0.0 <=11.0.3": "11.1.0",
62
62
  "js-yaml@<3.14.2": "3.14.2",
63
63
  "js-yaml@>=4.0.0 <4.1.1": "4.1.1",
64
- "serialize-javascript@<=7.0.2": "7.0.3"
64
+ "serialize-javascript@<=7.0.2": "7.0.3",
65
+ "flatted@<=3.4.1": "3.4.2",
66
+ "brace-expansion@<1.1.13": "1.1.13",
67
+ "brace-expansion@>=4.0.0 <5.0.5": "5.0.5",
68
+ "picomatch@<=2.3.1": "2.3.2",
69
+ "picomatch@>=4.0.0 <=4.0.3": "4.0.4"
65
70
  }
66
71
  }