PWA install prompt when setting manifest dynamically - javascript

We have a web app which fulfills the PWA criteria. So far, when opening the app on an Android device, we received the PWA installation prompt.
Now, if possible, we would like to generate the manifest.json dynamically on the client-side. I’m following the steps outlined in the following article, which look quite promising:
How to Setup Your Web App Manifest Dynamically Using Javascript
We generate the JSON and set it as blob URL through client-side JS:
const stringManifest = JSON.stringify(manifest);
const blob = new Blob([stringManifest], { type: 'application/json' });
const manifestUrl = URL.createObjectURL(blob);
document.querySelector('#manifest-placeholder').setAttribute('href', manifestUrl);
But now, when I open the app on an Android device I no longer see the PWA prompt. Yet, the manifest file obviously get interpreted, as e.g. the icon and start_url are correctly set when I try to add the app to the home screen.
Any experience here whether setting the manifest.json is possible at all for a PWA? Anything I might be missing?

I faced a similar issue. I came to the conclusion this issue could be due to the browser checking for a valid manifest before your dynamically-created manifest has been inserted into the DOM.
If the browser thinks there is no valid manifest available for PWA installation, then the install prompt will not show, which is stated clearly enough in the documentations. However, debugging this issue is rather confusing, as tools, such as Lighthouse in the Google Chrome Audit DevTool tab will say that the app is installable and everything is fine and dandy...
It could be the case that the browser only checks for a valid manifest once during page load - unfortunately I can't find any firm details anywhere about this.
I was able to solve this issue by ensuring the html document's initial render has a valid manifest for PWA-installation, containing some default values (in my case, the values were based off of window.location.pathname). Then later on, when I have all the appropriate data available, I can create my desired manifest and replace it in the DOM. Then, when is ready to install the PWA, the browser uses the data from the desired manifest.

Related

Cordova - Access device functionality from remote HTML

I have a Cordova application that waits for the deviceready event and, when that event fires, sets the window.location.href to a remote site, say, http://foo.bar.com/lander.html. From that page, I have several links to other pages - say page1.html and page2.html. I want to put a button in page1.html that calls Cordova's navigator.notification.vibrate function.
I have the above set up and everything appears to work, except that navigation.notification is undefined when I click the button in page1.html to try to get the device to vibrate. I have copied cordova.js onto foo.bar.com and am referencing it from page1.html. Do I have to include other javascript source files on foo.bar.com? Will this approach ever work?
Would it work if instead of changing the window location I were to get the content by AJAX and put the content in a div container in the index.html page that underlies the Cordova app?
This is all on iOS if that matters. I included the dialogs and vibration plugins only. I am receiving the deviceready event in the Cordova app and successfully redirecting to the remote site. Please let me know if there are other factors which I need to take into consideration. Thanks.
UPDATE 1: I got vibration working from the Cordova app's local index.html by using navigator.vibrate instead of navigator.notification.vibrate. Changing this on the remote site did not help. I also tried including copies of vibration.js, Cordova.js and cordova_plugins.js from the remote page - still no luck.
UPDATE 2: I found in the Cordova docs where what I'm asking about is discussed: Invoking Cordova JavaScript functions from a remotely-loaded HTML page (an HTML page not stored locally on the device) is an unsupported configuration. This is because Cordova was not designed for this, and the Apache Cordova community does no testing of this configuration. While it can work in some circumstances, it is not recommended nor supported. There are challenges with the same origin policy, keeping the JavaScript and native portions of Cordova synchronized at the same version (since they are coupled via private APIs which may change), the trustworthiness of remote content calling native local functions, and potential app store rejection.
The display of remotely-loaded HTML content in a webview should be done using Cordova's InAppBrowser. The InAppBrowser is designed so that JavaScript running there does not have access to the Cordova JavaScript APIs for the reasons listed above. Please refer to the Security Guide.
Based on this, it sounds possible but like we'd be out on our own. Still, if anybody is successfully doing this, we'd like to give it a try.
I thinhk what you are looking for is a push notification. There is a plugin for this.
http://ngcordova.com/docs/plugins/pushNotifications/
You need a task running on your app though.
Hope this is helpfull.

Trick a browser into loading <script> or <link rel="stylesheet"> URLs from local setup/server?

I'm debugging a CSS/JS problem on a live website, and in this situation it is unfeasible to clone the entire production system onto a local machine to fiddle with 2 lines of code.
I would LOVE it if there were a simple way to trick a browser (FF, Chrome, anything - I'm not fussy) into loading the live site but redirecting certain internal URLs to a local webserver. Any ideas?
eg. I want to load the entire live website, except one specific Javascript file. The attempt to access http://...production.../js/map.js should be rerouted to http://localhost/debug/js/map.js, which I can edit locally until the problem is fixed.
Edit re-read your issue, if you aren't happy to find/edit the SQL database for the file in question, you could always just add an adblock rule against it, and manually run your own script from console/greasemonkey it in.
Answer to question in the title:
HTML5 has a feature called an "application cache" just for this. It involves adding a manifest attribute to your <html> tag.
<html manifest="what_to_cache.appcache">
Then in what_to_cache.appcache,
CACHE MANIFEST
http://...production.../js/map.js
Future requests of items listed in the manifest will thereafter be loaded from the cache, if available, even if the user is offline. The file is stored in an SQL database for that website, so you can thereafter edit the database.
You can do this with fiddler.
Use the AutoResponder to intercept URLs and return content from local file or different server.
http://fiddler2.com/
I have found a Chrome extension which, despite its bugs, achieves precisely this behaviour. DevTools Redirect: https://chrome.google.com/webstore/detail/devtools-redirect/jmhdebkkippcccflcoddckhjjfgnfhnp
This allows developers to specify JS or CSS files to redirect, and a new URL to grab them from (eg. http://localhost/.../debug.js).
For future readers I would like to answer this question. Have a look at
Requestly - A Chrome Extension to modify Network Requests.
You can setup a Redirect Rule Request following these steps:
Select Redirect Request Rule Type
Create a new Redirect Rule
Disclaimer: I have created this So you can blame me if you do not find this helpful :)

What is "chrome-extension://"

I found the some strange <script/> tags on a site:
<script src="chrome-extension://lifbcibllhkdhoafpjfnlhfpfgnpldfl/document_iterator.js"></script>
<script src="chrome-extension://lifbcibllhkdhoafpjfnlhfpfgnpldfl/find_proxy.js"></script>
...
I haven't been able to find much information on this, but I highly doubt this is actually related to Google Chrome since this site in particular is still using <table>s for layout, and the source in question was retrieved with curl not a graphical web browser.
So,
What on earth is this?
What is chrome-extension://
Why is it using lifbcibllhkdhoafpjfnlhfpfgnpldfl as a directory name
Why is it pretending to be valid URL to a javascript file?
Why would I need find_proxy or document_iterator
Solved. As far as I know...
chrixian was right, It seems that only on this and a few select other pages, someone had re-saved them from Chrome's source-view with the Skype extension installed.
Thanks everyone for all your help, +1's for all! enjoy!
That is actually Skype Click to Call chrome extension.
Manage and view it using this link
chrome://extensions/?id=lifbcibllhkdhoafpjfnlhfpfgnpldfl
If you are using cURL to get the page, you're getting the HTML as it exists on the server--so I think a safe assumption would be: the author of the page initially saved the page from Chrome, he had an extension installed that inserted these script tages and lastly he didn't remove the script tags for one reason or another before putting the page on the server.
This is added by chrome as the page loads, to inject the extension's Javascript code into the page, so it can access the HTML document.
The Skype extension causes it by inserting all kinds of junk in webpages that you visit.
Do you have the Skype browser extension installed for Chrome?
Just disable the extension.
Chrome, like Firefox, provides developers with an easy API to extend the functionality of the web browser without needing to actually download and build the browser to do so.
They also provide a robust delivery system. In Google's case, it's the Google Chrome Web Store.
Extensions are installed locally on your computer, and use long strings as directory names to reduce the risk of collisions with another extension. In other words, if you and I both named our extensions "mycoolextension", then there would be a problem if a person tried to install your extension and my extension. The long string helps prevent collisions such as this.
The chrome-extension:// protocol is used by the browser to make requests to these local resources. Chrome extensions are developed using HTML5, JavaScript, and CSS, along with an API exposed to allow the local JavaScript to perform actions it would not normally be able to do on the Internet.
When you see these in the Chrome developer tools, it's just the extension doing it's thing, whatever that may be.
If you're seeing these, then you likely installed some extensions from the Chrome Web Store. To view them, go to the Tools menu and select "Extensions". This will show you a list of all installed Chrome extensions and apps.
To learn more about extension development, see the Getting Started Tutorial.
Also, as someone else mentioned, you're using the Skype Call Extension. However, an app using that directory name doesn't appear in the first page of the search results. It might be worth doing some more research to make sure you got that extension from a legitimate source, whether that be Skype or the Chrome Web Store.
If you're seeing it in Chrome developer tools for every request you make, it means it has access to all your websites, which could be benign, like if they're just making phone numbers clickable, or it could be malicious, if it's scraping your bank account info and shipping it off to some third party server. :)
It's a Chrome extension, and chrome-extension:// is a URL for extensions to address their contents via Javascript.
lifbcibllhkdhoafpjfnlhfpfgnpldfl is the unique identifier for the extension. I can't find it with a search, but apparently it might be Skype.
It's not pretending... it is a valid URL. The Javascript file is located in the extension. If you were to look on your harddrive you'd probably find that very file in the extensions folder.
The functions its calling probably are some sort of detection used by the extension to see if it needs to enable itself.
See this for some additional information:
Checking if user has a certain extension installed

How to check the authenticity of a Chrome extension?

The Context:
You have a web server which has to provide an exclusive content only if your client has your specific Chrome extension installed.
You have two possibilities to provide the Chrome extension package:
From the Chrome Web Store
From your own server
The problem:
There is a plethora of solutions allowing to know that a Chrome extension is installed:
Inserting an element when a web page is loaded by using Content Scripts.
Sending specific headers to the server by using Web Requests.
Etc.
But there seems to be no solution to check if the Chrome extension which is interacting with your web page is genuine.
Indeed, as the source code of the Chrome extension can be viewed and copied by anyone who want to, there seems to be no way to know if the current Chrome extension interacting with your web page is the one you have published or a cloned version (and maybe somewhat altered) by another person.
It seems that you are only able to know that some Chrome extension is interacting with your web page in an "expected way" but you cannot verify its authenticity.
The solution?
One solution may consist in using information contained in the Chrome extension package and which cannot be altered or copied by anyone else:
Sending the Chrome extension's ID to the server? But how?
The ID has to be sent by you and your JavaScript code and there seems to be no way to do it with an "internal" Chrome function.
So if someone else just send the same ID to your server (some kind of Chrome extension's ID spoofing) then your server will consider his Chrome extension as a genuine one!
Using the private key which served when you packaged the application? But how?
There seems to be no way to access or use in any way this key programmatically!
One other solution my consist in using NPAPI Plugins and embed authentication methods like GPG, etc. But this solution is not desirable mostly because of the big "Warning" section of its API's doc.
Is there any other solution?
Notes
This question attempts to raise a real security problem in the Chrome extension's API: How to check the authenticity of your Chrome extension when it comes to interact with your services.
If there are any missing possibilities, or any misunderstandings please feel free to ask me in comments.
I'm sorry to say but this problem as posed by you is in essence unsolvable because of one simple problem: You can't trust the client. And since the client can see the code then you can't solve the problem.
Any information coming from the client side can be replicated by other means. It is essentially the same problem as trying to prove that when a user logs into their account it is actually the user not somebody else who found out or was given their username and password.
The internet security models are built around 2 parties trying to communicate without a third party being able to imitate one, modify or listen the conversation. Without hiding the source code of the extension the client becomes indistinguishable from the third party (A file among copies - no way to determine which is which).
If the source code is hidden it becomes a whole other story. Now the user or malicious party doesn't have access to the secrets the real client knows and all the regular security models apply. However it is doubtful that Chrome will allow hidden source code in extensions, because it would produce other security issues.
Some source code can be hidden using NPAPI Plugins as you stated, but it comes with a price as you already know.
Coming back to the current state of things:
Now it becomes a question of what is meant by interaction.
If interaction means that while the user is on the page you want to know if it is your extension or some other then the closest you can get is to list your page in the extensions manifest under app section as documented here
This will allow you to ask on the page if the app is installed by using
chrome.app.isInstalled
This will return boolean showing wether your app is installed or not. The command is documented here
However this does not really solve the problem, since the extension may be installed, but not enabled and there is another extension mocking the communication with your site.
Furthermore the validation is on the client side so any function that uses that validation can be overwritten to ignore the result of this variable.
If however the interaction means making XMLHttpRequests then you are out of luck. Can't be done using current methods because of the visibility of source code as discussed above.
However if it is limiting your sites usability to authorized entities I suggest using regular means of authentication: having the user log in will allow you to create a session. This session will be propagated to all requests made by the extension so you are down to regular client log in trust issues like account sharing etc. These can of course be managed by making the user log in say via their Google account, which most are reluctant to share and further mitigated by blocking accounts that seem to be misused.
I would suggest to do something similar to what Git utilises(have a look at http://git-scm.com/book/en/Git-Internals-Git-Objects to understand how git implements it), i.e.
Creating SHA1 values of the content of every file in your
chrome-extension and then re-create another SHA1 value of the
concatenated SHA1 values obtained earlier.
In this way, you can share the SHA1 value with your server and authenticate your extension, as the SHA1 value will change just in case any person, changes any of your file.
Explaining it in more detail with some pseudo code:
function get_authentication_key(){
var files = get_all_files_in_extension,
concatenated_sha_values = '',
authentication_key;
for(file in files){
concatenated_sha_values += Digest::SHA1.hexdigest(get_file_content(file));
}
$.ajax({
url: 'http://example.com/getauthkey',
type: 'post'
async: false,
success:function(data){
authentication_key = data;
}
})
//You may return either SHA value of concatenated values or return the concatenated SHA values
return authentication_key;
}
// Server side code
get('/getauthkey') do
// One can apply several type of encryption algos on the string passed, to make it unbreakable
authentication_key = Digest::<encryption>.hexdigest($_GET['string']);
return authentication_key;
end
This method allows you to check if any kind of file has been changed maybe an image file or a video file or any other file. Would be glad to know if this thing can be broken as well.

How to use the javascript SDK from a desktop application

I'm writing a desktop application to interact with facebook by using an embedded browser which is running HTML \ javascript from local files.
I was able to use the login dialog to retrieve a token (using the method described in the facebook documentation for desktop applications), but i'm still failing call basic SDK functions, such as FB.init() and FB.getLoginStatus().
When executing FB.init():
FB.init({
appId: '120260327220',
status: true, // check login status
oauth: true // enable OAuth 2.0
});
I get the HTTP response (through HTTP sniffer):
<span>Given URL is not allowed by the Application configuration.: One or more of the given URLs is not allowed by the Application configuration. It must match one of the Connect or Canvas URLs or domain must be the same as or a subdomain of one of the Application's base domains.</span>
And when executing FB.getLoginStatus():
FB.getLoginStatus(function (response) {
if (response.authResponse) {
alert("logged in and connected user, someone you know");
} else {
alert("no user session available, someone you dont know");
}
});
i get nothing!
The application is completely client based, meaning i have no server side, thus there's no URL to register the facebook application with. Running on IE.
Does anyone know if and how i can use the facebook javascript SDK from a local javascript file (for desktop application)?
EDIT: configuring the application URL to be http://localhost is not a valid option, since eventually this script should be able to run on any machine, whether localhost is configured or not.
Thanks.
Related:
The JS SDK is designed to be used on websites (per definition served and accessible over http or https) and we do not plan to support the use of file: or any other protocols.
This is consistent with plugins in general, where http/https URIs are usable as identifiers (open graph amongst others), but where file:// URIs are not.
You can try initializing the SDK inside a web accessible document including using an iframe - note then that you will have to add logic to ensure correct resizing.
As an answer to a Facebook bug report.
As you mentioned that you have an embedded browser within your Desktop app so in this case what you can do is host the app's page that has facebook related functionality over the web and pull this same page's url inside your embedded browser. This way you will be able to provide a valid domain in app's settings and not localhost. Also you can make valid calls to facebook APIs from your page and your Desktop app can then make use of all these facebook related data as they are being pulled onto your embedded browser.
In a nutshell your Desktop app will be much like the Facebook's canvas where the app's page is pulled and displayed inside the canvas. However in your case you will be having a complete control of how, when, where and which parts of the page gets displayed and moreover a properly glued and well structured UI will make the external page and Desktop app blend together and users will never come to know the difference.
Since I got no acceptable answer here are my realizations and what I eneded up doing::
There's no way to use the Facebook SDK on local page due to cross domain ajax issues.
The way to work around it is using JSONP ajax calls to Facebook's graph API (JSONP is allowed for cross domain).
The login process is done by navigation (in a new window) to the login page, with specific URL parameters to set the page's attributes.
If you are using PhoneGap 1.0 and Xcode 4, start by following these instructions: http://www.pushittolive.com/post/1239874936/facebook-login-on-iphone-phonegap
My installation looks like: http://cl.ly/AHQ1
Be sure to move the ChildBrowser.js file out of the plugins folder and into the root of your www folder. Also be sure to link to that ChildBrowser.js in your index.html file.
Then follow these 3 steps, http://collingo.com/2011/08/18/installing-childbrowser-ios-phonegap-plugin-in-xcode-4/
Lastly, update your PhoneGap.plist file as mentioned in this post: http://wiki.phonegap.com/w/page/43708792/How%20to%20Install%20a%20PhoneGap%20Plugin%20for%20iOS, mine looks like: http://cl.ly/AHAH
What is the Application URL that you have set on the application's Developer page? I'm just guessing based on the FB.init() error message that you need the to set the URL to be "http://localhost/start page name". When debugging our application we run it locally and have the URL of the application set this way.

Categories

Resources