Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for proxies that require basic username/password authentication #561

Merged
merged 2 commits into from
Jul 1, 2021
Merged

Conversation

nfichter
Copy link

See issue #545

Electron has a login event that allows automatic handling of basic username/password authentication. Because this event includes a callback function, it's difficult to forward it back to Electron.NET.

So, this PR provides a workaround by adding optional Proxy and ProxyCredentials fields to the BrowserWindowOptions and BrowserViewConstructorOptions classes. If these fields are included, browserWindow.ts and browserView.ts make use of them in their handlers of the createBrowserWindow and createBrowserView events, respectively. These files share access to a global proxyToCredentialsMap which maps the proxy (host:port) to its credentials (username:password format). If only a Proxy is supplied, they call the webContents.session.setProxy method, providing an alternative to explicitly calling that function in Electron.NET. If both a Proxy and its ProxyCredentials are supplied, they add an entry to proxyToCredentialsMap. Supplying only ProxyCredentials has no effect.

Finally, browserWindow.ts adds an event listener for the app's login event. This listener uses the authInfo.isProxy field to check if the type of basic authorization requested is for a proxy (i.e. the server returned a 407 status code) — there are cases in which basic authorization is used for restricting access to a site (example here) in which case a 401 status code is returned instead.

The authInfo object also provides information about the host and port of the request (in the case of a 401 status code) or proxy (in the case of a 407 status code). This login handler checks if the proxy, ${authInfo.port}:${authInfo.host}, exists as a key in the global proxyToCredentialsMap. If it does, and its corresponding value contains only 1 semicolon (as it should, since credentials should be in username:password format), then it splits on the semicolon to retrieve the username and password, and submits the callback function which provides authentication to the proxy server.


Example usage (in Startup.cs):

        public async void ElectronBootstrap()
        {
            var browserWindow = await Electron.WindowManager.CreateWindowAsync(new BrowserWindowOptions
            {
                Width = 1152,
                Height = 940,
                Show = true,
                Proxy = "host:port", // Replace with your own proxy
                ProxyCredentials = "username:password", // Replace with your own credentials
            }, "");

            var browserView = await Electron.WindowManager.CreateBrowserViewAsync(new BrowserViewConstructorOptions
            {
                WebPreferences = new WebPreferences(){
                    Partition = "test-partition", // Partitioning ensures that the BrowserWindow and its BrowserView don't share a session, in case you want to provide separate proxies to each
                },
                Proxy = "host:port", // Replace with your own proxy
                ProxyCredentials = "username:password", // Replace with your own credentials
            });
            browserWindow.SetBrowserView(browserView);

            var bounds = new Rectangle();
            bounds.X = 26;
            bounds.Y = 500;
            bounds.Width = 1100;
            bounds.Height = 400;
            browserView.Bounds = bounds;

            await browserView.WebContents.LoadURLAsync("https://whatismyipaddress.com");
            await browserWindow.WebContents.LoadURLAsync("https://whatismyipaddress.com");

            browserWindow.Show();
            browserWindow.SetTitle(Configuration["DemoTitleInSettings"]);
        }

In this example, I used separate proxies for the browserWindow and the browserView. Here is a screenshot of the result:

Screen Shot 2021-04-26 at 2 33 39 PM

The window on the left is a normal Safari window that contains my actual IP. The window on the right is the Electron window — the top half is the BrowserWindow, and the bottom half contains its embedded BrowserView. Notice that each IP is different because of the proxies supplied to each window.

@ppostman
Copy link

This is exactly what I need for my project. Is there any ETA when this will be merged to the public NuGet package?

@silent-juiced
Copy link

This is exactly what I need for my project. Is there any ETA when this will be merged to the public NuGet package?

@ppostman -- if you need this sooner than when they merge it in (if they ever do), what I did was fork the project, implement this, and publish it to NuGet. My .NET project uses my version of ElectronNET on NuGet, instead of the official version. Follow the "Working with this Repo" section of the README, there's a good video to help you out with how to implement this.

@GregorBiswanger GregorBiswanger self-assigned this Jul 1, 2021
@GregorBiswanger GregorBiswanger added this to the 13.5.1 milestone Jul 1, 2021
@GregorBiswanger GregorBiswanger merged commit bff71dc into ElectronNET:master Jul 1, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants