How to embed a web browser inside a web app made in node.js ? - node.js

I currently have a web app made in node.js. One feature of this app is to take notes. I want to provide the user with a way to browse the internet and select a text to add as a note in our web app without having to manually copy-pasting from one browser window to our app.
I know I can do this relatively simply using a Chrome extension that would be linked to the user account and would save the note to the database. However, I cannot use this approach since not all my users can install Google Chrome.
Therefore, I am looking for a way to browse the web from inside our web app. For example, it could be in an iFrame where we display a complete browser. That way, the user could navigate the web for information from inside the app, select text to save and click on a button (probably located outside the iFrame browser) to save the selected text as a note in our database.
How can I achieve such a thing in node.js ?

This is, essentially, impossible.
For you to get any data about the site the user was browsing you could either:
Restrict them to browsing sites willing to partner with you to give you permission to access their data via postMessage (a technical change on their part to work around the Same Origin Policy)
Proxy every request through your server which would:
Have large bandwidth requirements
Require a lot of rewriting of URLs (including dynamically generated ones in JS)
Require rewriting of X-Frames-Options and Access-Control-Allow-Origin headers
Need users who would trust you with all the data you passed through your system (including their passwords to third party sites)
Not work for Intranet sites (since your server could not reach them)

Related

How to avoid running entire client-side process in Blazor WebAssembly before Azure AD authentication?

I'm building a Blazor WASM app with Azure AD, and I'm struggling with what appears to be an inefficiency in the way it's designed. The entire application, including the home page, needs to be secured by [Authorize]. It works (with one exception noted below), but the initial load is painfully slow. Basically, on reaching the home page, Blazor loads the entire application -- running Program.Main in it's entirety, loading JS files from CDN or webpack bundles, loading all the .NET dlls, and THEN decides that it needs to redirect to Azure to authenticate. Once it returns, it does all that again. Loading the various files is not too much of a problem, since it gets them from the browser cache the second time. The problem is that is also needs to run Program.Main again.
In my rather large client app, it takes a few seconds to configure all the services (I'm using a lot of gRPC). The biggest culprit though is a call to the server API to get certain app settings that I don't want to expose to the client (basically doing this). Moreover, that API call doesn't even succeed, since the API endpoint is secured, and the user hasn't authenticated yet, but I don't know how to get the user info from within Program.Main. The log messages show that the user identity is not even created until sometime after Program.Main completes. (One of the settings is the roles-to-permissions mapping, so I can't even draw the app's menu without it. I've resorted to removing the auth requirement from the API controller for now, obviously not a permanent fix)
To replicate the behavior, just create a brand new Blazor WebAssembly app, selecting Auth Type = Microsoft identity platform, and checking the ASP.NET Core hosted box. Then just edit both appsettings.json files to provide your Azure login info; change the requested scope in Client.Program.Main (and change the one in WeatherForecastController to match); and add [Authorize] to the _imports.razor file, and [AllowAnonymous] to Authentication.razor. Finally add some logging Console.WriteLine("Running in Client.Program.Main"); near the end of that method.
In the basic Blazor app template as described above, this all runs pretty fast. Once there's a significant amount of startup code in Program.Main, though, it becomes quite noticeable, it can be several seconds both before and after the login redirect. And I can't make an authenticated API call.
Specifying endpoints.MapFallbackToFile("index.html").RequireAuthorization(); in the server side Startup doesn't seem to make any difference. Neither does adding options.FallbackPolicy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build(); to the AddAuthorization call.
So basically, I'm looking to:
Identify the user in Client.Program.Main, so I can make a secure call to the settings API
Identify the user in Client.Program.Main, so I can bypass all the time-consuming stuff myself on the first pass
Get Blazor (server?) to somehow recognize that a request for a protected page will fail for an unauthenticated user, and go directly to the Azure login page without all the usual ceremony
Any suggestions?

Unable to log in to Azure web app via VS2015 web performance test

How do I correctly handle the login/authentication scenario for an Azure web app in my VS2015 web performance test?
I created an XML file as a data source for the WAAD username and password. I bind the username and password to the Form Post Parameters: login and passwd respectively at request: https://login.microsoftonline.com/xxxx/login
But when I run the test, the Web Browser tab shows this error:
We can't sign you in
Your browser is currently set to block JavaScript. You need to allow
JavaScript to use this service.
To learn how to allow JavaScript or to find out whether your browser
supports JavaScript, check the online help in your web browser.
I also get a number of errors like this:
The value of the ExpectedResponseUrl property
Validation xxxx.azurewebsites.net/xxxx/docs/xxxx.aspx does
not equal the actual response URL
login.microsoftonline.com/xxxx/wsfed. QueryString
parameters were ignored.
Any idea how I can successfully log in to the Azure web app via the web performance test?
There are several methods of login and authentication that can be used. Just binding values to form post parameters may not be sufficient or correct. You will find the login form has hidden session identities that must be passed as well as the login data. I find that recording a test two times using as nearly as possible the same inputs and doing the same activities helps. These two tests can then be compared to find the dynamic data that needs to be handled.
In a comment the questioner added "I noticed these parameters, n1-43 are different but I have no idea what they represent. How do I handle them?". I can have no idea what they represent as I do not know the website you are testing. You could ask the website developers. Or, better, treat them as dynamic data. Find where the values come from, save them into context variables and use them as needed. This is basic web test development. Here and here are two good articles on what to do.
The message about JavaScript not being supported can be ignored. Visual Studio web tests do not support JavaScript or any other "active" parts of a web page, they only support the html part. Your job as a tester is to simulate what the JavaScript does for the specific user journeys you are testing. That simulation is generally just filling in the correct values (via context parameters) in the recorded requests.
Unexpected response urls can be due to earlier failures, such as teh login not working. I suggest not worrying about them until all of the other test problems are solved. Then, if you need help ask another new question.

How to use dropbox API from chrome extension content script?

If I write a chrome extension, it normally consist of multiple parts:
One is the devtools page which is a normal HTML page with origin set to
"chrome-extension://<guid>/filename". On that page I can use
the Dropbox API to get user confirmation via HTML popup and then use
the saved auth info and do all work via the Dropbox javascript library.
Another part of extension is the content script which is executed
in the context of specified third-party web pages ("injected") and have
origin cookies and web storage shared with them.
Is it possible to also use the Dropbox JavaScript library in that content script?
I can't call authenticate in interactive mode since it will re-ask for confirmation for each different webpage I'm injected into. And calling authenticate without interactive will fail since the content script doesn't share the origin, cookies and web storage with the devtools extension page :(. Maybe there's some way to "pass" the Dropbox auth info from the part of the extension that offers GUI and where user successfully confirms dropbox usage to the parts of the extension that are GUI-less, like content script or background page?
I have managed to get Facebook working from code injected into a web app via a content script. I suspect there are multiple ways, but what I did was take advantage of the chrome.identity API to do the OAuth work for me, specifically the launchWebAuthFlow().
This can only be done in the background page (in my case an event page), but I send messages to the event page which replies with the access_token, which can then be used in URLs in the same was as the 'web' technique - i.e. in HTTP requests with XHR.
You can send/receive messages via the content script (using events on document), but I decided to do it directly using "external" messages with the chrome.runtime.sendMessage() API in the web app context, and chrome.runtime.onMessageExternal() in the background script. This requires adding "matches" for the URLs you're injecting code into in an "externally_connectable" section of the manifest.json.
I believe this can be adapted to make it work with Dropbox.

sending a message from a web app to an extension

I have an extension which provides a number of services to any web app that requires them. I had been assuming that a web app could use chrome.runtime.sendMessage(ext-id,message), but when I try, there is no sendMessage function on chrome.runtime.
Have I misunderstood where sendMessage can be used, and is there another technique that I can use to communicate from an arbitrary web app to my extension?
There are a few options.
First, http://developer.chrome.com/extensions/manifest/externally_connectable.html is the closest to how you're thinking about it right now. You're expecting to be able to add proprietary, Chrome-specific functionality to arbitrary web pages. externally_connectable will give you a limited version of (see http://developer.chrome.com/extensions/messaging.html#external-webpage for an example), but only for specific web pages (e.g., *.yourdomain.com but not *.com).
Second, you can postMessage from your web page to a content script (see http://developer.chrome.com/extensions/content_scripts.html#host-page-communication), which can do anything a content script can. If you need chrome.* APIs at that point, you can message from the content script to your extension's page, which has access to any chrome.* APIs that it's asked for.
Finally, depending on what your "number of services" actually is, you can always executeScript another script directly into a target webpage, which is similar to forcing the webpage to include it as if it were another <script> tag. (Only similar to, not identical to, because the injection typically happens after the page has loaded.)

Why does new Facebook Javascript SDK not violate the "same origin policy"?

The new Facebook Javascript SDK can let any website login as a Facebook user and fetch data of a user...
So it will be, www.example.com including some Javascript from Facebook, but as I recall, that script is considered to be of the origin of www.example.com and cannot fetch data from facebook.com, because it is a violation of the "same origin policy". Isn't that correct? If so, how does the script fetch data?
From here: https://developer.mozilla.org/en/Same_origin_policy_for_JavaScript
The same origin policy prevents a
document or script loaded from one
origin from getting or setting
properties of a document from another
origin. This policy dates all the way
back to Netscape Navigator 2.0.
and explained slightly differently here: http://docs.sun.com/source/816-6409-10/sec.htm
The same origin policy works as
follows: when loading a document from
one origin, a script loaded from a
different origin cannot get or set
specific properties of specific
browser and HTML objects in a window
or frame (see Table 14.2).
The Facebook script is not attempting to interact with script from your domain or reading DOM objects. It's just going to do its own post to Facebook. It gets yous site name, not by interacting with your page, or script from your site, but because the script itself that is generated when you fill out the form to get the "like" button. I registered a site named "http://www.bogussite.com" and got the code to put on my website. The first think in this code was
iframe src="http://www.facebook.com/plugins/like.php?href=http%3A%2F%2Fwww.bogussite.com&
so the script is clearly getting your site info by hard-coded URL parameters in the link to the iFrame.
Facebook's website is by far not alone in having you use scripts hosted on their servers. There are plenty of other scripts that work this way.. All of the Google APIs, for example, including Google Gears, Google Analytics, etc require you to use a script hosted on their server. Just last week, while I was trying to figure out how to do geolocation for our store finder for a mobile-friendly web app, I found a whole slew of geolocation services that had you use scripts hosted on their servers, rather than copying the script to your server.
I think, but am not sure, that they use the iframe method. At least the cross domain receiver and xfbml stuff for canvas apps uses that. Basically the javascript on your page creates an iframe within the facebook.com domain. That iframe then has permission to do whatever it needs with facebook. Communication back with the parent can be done with one of several methods, for example the url hash. But I'm not sure which if any method they use for that part.
If I recall, they use script tag insertion. So when a JS SDK call needs to call out to Facebook, it inserts a <script src="http://graph.facebook.com/whatever?params...&callback=some_function script tag into the current document. Then Facebook returns the data in JSON format as some_function({...}) where the actual data is inside the ... . This results in the function some_function being called in the origin of example.com using data from graph.facebook.com.

Resources