feat: multi-profile proxy#913
Conversation
Introduce multiple proxy profiles (HTTP CONNECT and SOCKS5) assignable per website. Includes resolver-backed routing, ALS context, and Electron partition apply. Adds settings UI with connection test and remote bypass handling.
Skip session-created system proxy on persist partitions to avoid racing ensurePartitionProxy. Use session proxyRules without embedded auth and handle 407 via session login.
Chromium webviews ignore credentials in proxyRules and need separate HTTP/HTTPS rules. Register a single app-level login handler and show a loader while proxy setup completes.
Remove local readString/readNumber helpers added during proxy work. Keep fetchWithInstagramProxy and match the pre-proxy response style.
Add shared createProxyAgent helper and trim unused resolver exports. Align startup proxy persistence tests with schema v2 behavior.
Route Http via node agents or cached chromium sessions. Remove proxy-context, drop global fetch patch, and add routing tests.
Inject websiteId via website-scoped platform instead of ALS wrappers. Use fetchForWebsite for instagram and bluesky; keep telegram on socks5-only fallback.
Update proxy settings labels and remote connection test wiring.
|
Technically this was already supported through electron --proxy-pac-url and this pr simply moves it to the ui side from command line? Genuinely, whats the point of having separate proxy for each website? If one works for one, it will mostly work for others too, wouldn't it? Im the one who implemented mtproto proxy support in the first place and in that case it was reasonable because mtproto is the only custom protocol of all websites which uses different bypass methods, im wondering whats the use case for having separate proxy settings for each website |
|
@leaftail1880 you're right that it's better to use the native "--proxy-pac-url" option and the "POSTYBIRB_TELEGRAM_MTPROXY" environment variable, but unfortunately, I didn't find any initial mention of this. At the very least, this should be highlighted for regular users who use the program under blocked conditions or to avoid Cloudflare CAPTCHAs more often (at least in my case, it helped), so they can use everything directly rather than routing through Throne/v2rayn, etc. (if we're not just talking about VLess) And as I later figured out, you're most likely referring to what was in v3 - that is, the "proxy" section in the settings, where we simply specified it directly without authorization. But my version is more user-friendly, with support for proxy authorization (via username:password@host:port). I don't deny that the multi-profile option is excessive and that a single profile for all sites would suffice. |
|
The v3 solution was added mostly because i didn't know about system wide vpn settings :) Current version of postybirb already uses system settings for vpn set by vpn client and sends requests through tunnel vpn creates, thus proxy setting for v4 was never added. Personally i see that using Throne/v2ray routing settings is better because they give more flexibility then any program can provide in settings even though they may be not user friendly (user must know domains website uses and its not always the obvious website domain, e.g. video upload domain for bsky is different) I do agree that there is extreme lack of docs on this topic though. Mostly because i though users would start vpn and it will just work like it did for many. |
|
So you see the use case of this mostly of:
Right? |
|
@leaftail1880 what if we keep support for this behavior and add a built-in proxy on top of it for users who don't want to bother with Throne/v2rayn, etc., directly in the UI? What do you think? This won't break the old behavior, but it will add a more explicit and obvious configuration option. |
|
Wouldn't it be simplier to use app.setProxyConfig's proxyRules (https://www.electronjs.org/docs/latest/api/app#appsetproxyconfig) instead of passing proxy data everywhere and simply add ui for it? Currently all app requests are routed through electron network stack already. This would allow a lot more flexible configuration, will allow to get rid of POSTYBIRB_TELEGRAM_MTPROXY workaround and using the old behavior by specifying the mode to system And there add some kind of docs about which domains are used by which website and proxy behavior too |
|
Seems like proxy rules only support routing by protocol, not by domain. Well, we still can host local pac script (pac scripts only support loading from url) which will be generated on the fly based on user preferences |
|
@leaftail1880 if possible, we can continue this detailed discussion on discord |
Serve PAC scripts from Nest and apply v3 proxy config across Electron sessions.
Replace per-partition proxy IPC with a single global apply path for webviews.
Persist mode/pool/routing in startup.json and apply global proxy config on save.
Add mode selector, proxy pool editor, and per-website PAC routing table.
Use netFetch via defaultSession for Instagram/Bluesky and drop profile-agent routing.
Read global proxy config for Teleproto and invalidate cached clients on save.
Bootstrap proxy from ProxyService on startup, broadcast apply events to renderers, and remove the global proxy ready gate from login webviews.
| 'apps/client-server/src/app/proxy/proxy.service' | ||
| ); | ||
| await nestApp.get(ProxyService).apply(); | ||
|
|
There was a problem hiding this comment.
Proxy apply runs after listen() because in PAC mode Chromium loads the script from https://127.0.0.1:{port}/api/proxy/pac/... - that route only exists once Nest is listening. Apply earlier and PAC (and the first real traffic) can fail or use the wrong proxy
There was a problem hiding this comment.
The first real traffic only starts after client-server is loaded. Why can't we apply configuration at client-server load time?
Align TypeScript types with @IsOptional() validation for PATCH requests.
Persist non-proxy fields through StartupOptionsManager.set again instead of building a manual patch object field by field.
Move bootstrap apply to client-server after listen. Serve PAC over HTTPS with session cert trust. Resolve static PAC domains from website instances instead of probe accounts.
Use HttpResponse from @postybirb/http/types again instead of the inline response shape.
Move Teleproto proxy resolution into telegram.website.ts. Use platform getParsedProxiesFor and keep only SOCKS from the chain.
Inline instagram oauth partition id in collectManagedPartitionIds. Remove dead helpers and stop re-exporting partitions from @postybirb/http.
Phase 0 Electron PAC validation is covered by electron-proxy tests.
Restore the Linux guard when saving startup settings.
Implement StartupOptions again with required fields and @IsOptional().
Drop proxy reload and main-frame loading workarounds from login-webview.
Integrate main's Electron refactor while preserving multi-profile proxy preload and broadcast hooks.
|
@leRisen @leaftail1880 I'm going to hop in here for a second. I am going to admit I know practically nothing about proxies. I know why they are valued and used but that is about it. Based on prior discussion in this chat it sounds like the original intent can be satisfied through the pac url variable. Do proxies not already work at the network layer of a computer? Why is additional code injection really necessary into the code base? What else is actually being worked on that cannot be resolved through those other methods? While I have not read through the full PR yet, based on the size and my general lack of knowledge of proxies I am already erring on the side of shutting this down as I have no desire to maintain it in the future, especially if it is achievable outside of the app with a proper user guide. I generally try to be lenient on additions to the application, but this is no small change and appears more hooked into the actual application layer which might get in the way of things I want to do in the future. I will be upfront in saying that I will not maintain it and will rip it out should it become problematic for me and the original contributor does not plan on being available for long-term support of a feature like this. My thoughts might change once this is formally up for official review by me, but just giving a heads up of where my thoughts are at currently. |
|
@mvdicarlo this adds more flexibility and support for different proxy behaviors directly within the app, rather than having to explain to the user how to use it, especially when it comes to PAC, and certainly rather than having to rely on various system level programs (Throne/v2rayN). Yes, it might be difficult to maintain, and no one will want to delve deeply into it, but I'm willing to vouch for the entire code and quickly adapt it to new versions if necessary, though the final decision is, of course, up to you. |
# Conflicts: # apps/client-server/src/app/account/account.module.ts
|
Very sorry I haven't gotten a full PR on this. I have a couple large refactors that have been in process (mostly the relay posting changes). As soon as that is done (merged or abandoned) I promise I will read through this. Incredibly sorry for the slowness here. |
|
@mvdicarlo everything's fine. I've gotten rid of a ton of unnecessary code and tried to adapt it to the current architecture and structure of the app. There are still a few things I'd like to polish up, so don't rush it. |
Multi-profile proxy
Adds per-website proxy profiles so different sites can use different egress without a single global proxy setting.
Why
Lets users route traffic through their own proxies directly in PostyBirb - no need for separate system-wide tools.
Each site can use a different profile from one settings screen, which is easier to configure and reason about than juggling external apps.
Settings UI
Runtime routing
fetchForWebsite()(e.g. Discord, Instagram API, Bluesky uploads)Proxy settings apply to known partitions on save (accounts, Instagram OAuth partitions, headless website partitions) without restarting the app.
Each website instance gets a scoped platform that injects
websiteIdinto HTTP(S) calls so partition-less requests still resolve the correct profile.