Make ExecuteScriptAsync visible from WebviewBridge
There is an interesting segment of code in SpiderEye.Bridge.WebviewBridge:
public async Task InvokeAsync(string id, object data)
{
string script = GetInvokeScript(id, data);
string? resultJson = await Application.Invoke(() => Webview.ExecuteScriptAsync(script));
ResolveEventResult(id, resultJson);
}
I'm actually using webview for automation instead of creating an interactable custom webpage so I found the ExecuteScriptAsync feature useful on the Windows Webview. Except I was trying to port my code to a Raspberry Pi and Webview currently doesn't work on Linux.
Given the code segment above, I think it might be possible to reproduce that behavior here if we could directly inject a custom javascript string instead of searching for a pre-registered function. I.e. skip the GetInvokeScript step and the ResolveEventResult step and just return resultJson directly.
Is this not done because the intent of the bridge was to work with well-defined endpoints? Or is it because calling ExecuteScriptAsync directly is inherently unstable and creates all sorts of unpredictable side effects? Did I happen to miss a function that actually does what I'm requesting already?
Bear in mind that I don't control the endpoint, so I can't insert custom code into the destination webpage. And I'm not desperate enough to encapsulate the endpoint into an iFrame just so I can embed tools in the parent container to manipulate whatever's in the iFrame.
That being said, here's an example of my code when I directly used Webview2.
var script = $@"
document.querySelector(""input[name='USER']"").value = ""{ kvp[0] }"";
document.querySelector(""input[name='PASSWORD']"").value = ""{ kvp[1] }"";
document.querySelector(""#logon_button"").click();
";
await signInView.ExecuteScriptAsync(script);
Set a user, set a password, then click a specific button. Wait for page loaded event to execute further actions.
Oh neat, it worked. Just need to clone the code, add the following to WebviewBridge
public async Task<string?> ExecuteScriptAsync(string script)
{
return await Application.Invoke(() => Webview.ExecuteScriptAsync(script));
}
Then add a definition to IWebviewBridge
Task<string?> ExecuteScriptAsync(string script);
Recompile and use the updated SpiderEye.Core library and now you can use window.Bridge.ExecuteScriptAsync
Tested the below simple case on Windows and Linux.
window.LoadUrl("https://www.google.com");
window.EnableDevTools = true;
var stage = "1"; // simple state machine to prevent an infinite pageloaded event loop
window.PageLoaded += async (s, e) =>
{
if (stage == "1")
await window.Bridge.ExecuteScriptAsync($@"
console.log(""Hello World"");
document.querySelectorAll('input[title=""Search""]')[0].value = ""Hello World"";
document.querySelectorAll('input[value=""Google Search""]')[0].click();");
stage = "2";
};
Stability of this change is unknown but it works on the simple stuff.
First time I've ever had to create a nullable string though. That's just weird when string is nullable already.