ChromeOS kiosk limitations: bypass framekiller - iframe

I'm developing a ChromeOS kiosk application (website + chrome extension) which suppose to run in Kiosk Mode on managed Chromebook devices. Application displays external web content which I don't own, I'm using sandboxed iframes to display that web content. These external websites should not escape their iframes, that's why I sandbox them. The app is basically a simple web browser but instead of tabs I use iframes, and the top frame (window.top) is the wrapper around these iframes.
With all ChromeOS technical limitations I was able to bypass most of the iframe checks (x-frame-options, csp, blocked 302...) using the extension. However there is one I'm stuck with - framekillers. I can't properly display websites which do self !== top type of checks.
Is there a way to bypass it too somehow? I'm fine with refactoring my app completely or use something else instead of iframe. The app has to fulfil only one condition though - kiosk mode on a managed chromebook.
It's unfortunate that Chrome Apps with <webview> tag were deprecated and Android apps can't run in Kiosk mode anymore. This would solve all my issues easily by just using something else than iframes.
I've tried injecting the following buster <script> via a content script but it doesn't seem to work, websites seems to be doing something more advanced.
buster.ts
function buster() {
if (top !== self) {
(window.self as any) = window.top;
(window.parent as any) = window.top;
}
}
buster();
content-script.ts
const b = document.createElement('script');
b.src = chrome.runtime.getURL('buster.js');
const el = document.head || document.documentElement;
el.insertBefore(b, el.firstChild);
console.debug('buster is injected');

solution based on #wOxxOm comment (for MV3 extension):
background.ts
chrome.scripting.registerContentScripts([
{
allFrames: true,
id: 'some-id',
js: ['buster.js'],
matches: ['<all_urls>'],
runAt: 'document_start',
world: 'MAIN',
},
]);
buster.ts
function buster() {
if (top !== self) {
(window.self as any) = window.top;
}
}
buster();

Related

Loading local file inside an iframe in Electron

I've tried different approaches but all are problematic.
So first of all I was using webview, but as per electron documentation, this tag is undergoing major architectural changes and it's recommended to use iframe or other alternatives. Furthermore, the webview tag gives me a warning while used alongside VueJS that the component is not registered. I understand this component doesn't exist within HTML standards and is something specific to electron, so I am not sure how to tell Vue to ignore or recognize it in the use case of an electron app.
Coming to the iframe problem, approach one of loading the file directly via src, gives me the obvious error Not allowed to load local resource:. Turning off webSecurity though allows the file to load but I read it's not recommended to turn it off. I am not sure if there are specific use case where it's safe to turn it off or shouldn't be at all.
I decided to try via file protocol as I already have it in place. The protocol code:
protocol.registerFileProtocol('downloads', (request, callback) => {
const url = request.url.substring('downloads:///'.length)
const location = path.normalize(paths.downloads(url))
callback({ path: location })
})
Though when I load the file this way, the renderer process crash without errors. Is there something in addition to the above which would help loading local files via iframe?
Edit 1
My use case is the following: I have a typical entry point to an index.html which contains code for a VueJS app.
if (app.isPackaged) {
window.loadFile(join(__dirname, '../renderer/index.html'))
} else {
// 🚧 Use ['ENV_NAME'] avoid vite:define plugin
const url = `http://${process.env['VITE_DEV_SERVER_HOST']}:${process.env['VITE_DEV_SERVER_PORT']}`
window.loadURL(url)
window.webContents.openDevTools()
}
Inside that VueJS app, I require to list html files from a directory. I am able to achieve so via webview but I have tried to move away from it for the reason mentioned above. I tried using iframe but encountered issues as well. If there's a setting that doesn't turn off all security and allows me to load the file via iframe, that would be ideal.
This is kind of the reverse of this question where they're using an iframe, running into the "not allowed to load local resource" and being told to use a <webview> instead.
The <webview> docs list BrowserView as another alternative which is what I would recommend here. That should be much easier to work with than an iframe.
const { app, BrowserView, BrowserWindow } = require('electron')
app.whenReady().then(() => {
const win = new BrowserWindow()
const view = new BrowserView()
win.setBrowserView(view)
view.setBounds({ x: 0, y: 0, width: 300, height: 300 })
view.webContents.loadFile('<yourFile>')
})
Even though it is not recommended to use webview tag, I decided to go forward as it's the only thing that works for me. The only issue then was this error where Vue does not recognize the tag. To work around that error/warning, I had to update my vite.js config:
plugins: [
vue({
template: {
compilerOptions: {
isCustomElement: (tag) => tag === 'webview'
}
}
}),
// ...

Ionic: External link in iframe opens in webview (embed youtube player)

In my ionic (v1.2.4) app there is an embedded youtube player with a link "watch on youtube". If a user clicks this link, youtube website is opened in web view of cordova. It destroys current state of my app. I want to open that link in system's web browser (cordova in app browser plugin).
Same with any link in any iframe (vimeo, soundcloud...)
This link can't be modified with JS from outside the iframe, because cross domain security issues. So i can't update target attribute from _blank to _system.
Show a dialog onbeforeunload is not really an option because it looks ugly :)
Is there a possibility to avoid a page being loaded into the same webview or in the system's web browser?
Breaking links by using iframe's sandbox attribute is not an option because it breaks youtube player completely.
Thanks and cheers
ps: i asked this question here but couldn't get any helpful information
Thanks thepio for the hint with allow-intent and allow-navigation. First time i really digged into cordova-whitelist-plugin. Finally i fixed my issue on android by setting the correct allow attributes in config.xml
<!-- Allow links to web pages to open in a browser -->
<allow-intent href="http://*/*" />
<allow-intent href="https://*/*" />
No allow-navigation for android. Perfect white label solution. Couldn't find out how to do this on iOS, because iOS needs allow-navigation attributes to load iframe content at all.
To fix my issues on iOS in a dirty way, i added this to my config.xml:
<platform name="ios">
<allow-navigation href="https://w.soundcloud.com/player/*"/>
<allow-navigation href="https://www.youtube.com/embed/*"/>
<allow-navigation href="https://player.vimeo.com/video/*"/>
</platform>
Now only the iframe content itself is loaded. Lucky me, every link (watch on YouTube, share, like on vimeo...) inside the iframe is pointing to another domain/subdomain so it is blocked on iOS.
If there are any suggestions, how to create a white label solution for iOS, i am all ears.
Thanks
Ok, this is kind of a hardcore solutions for this and should probably be re-written/coded. This solution uses a cordova hook and opens ALL links with http or https protocol to a native web browser when they are clicked from a a-tag. For example <a href="https://www.youtube.com/embed">. This does not only affect iframes but all links.
Be careful since this might affect some unwanted links in your app.
I'm running
Cordova 6.1.1
Cordova-ios 4.1.1
Cordova-android 5.1.1
First of all you need to create a hook in the hooks/after_platform_add folder. This will run the hook only when you use ionic platform add <platform> or cordova platform add <platform>. If you do not have a folder called after_platform_add just create one. Then create a file "01_ios_external_links_hook.js".
Also please read Cordova hooks documentation:
https://cordova.apache.org/docs/en/latest/guide/appdev/hooks/
There are several ways of defining hooks and creating folders for them seems to be deprecated so you should use the config.xml to attach hooks.
https://cordova.apache.org/docs/en/latest/guide/appdev/hooks/index.html#via-hooks-directory-deprecated
You can call your file anything and if you are doing it with folders just remember to add access rights to the file. Typically in terminal:
chmod +x project/hooks/after_platform_add/01_ios_external_links_hook.js.
Please note that this fix is intended only for iOS devices since on android you can handle this with setting <allow-intent href="http://*/*" /> and setting <access origin="*" />. But on the latest Cordova-ios and whitelist-plugin you need to set <allow-navigation href="*.youtube.com" /> or similar to allow the content of iframe to load on iOS. This will lead to a situation which you described which is that external urls from the iframe will open in the webview.
But back to the solution. This is the code which I have inside the 01_ios_external_links.js file:
#!/usr/bin/env node
var fs = require('fs');
var replace = require('replace');
if (fs.existsSync('platforms/ios/CordovaLib/Classes/Private/Plugins/CDVUIWebViewEngine/CDVUIWebViewDelegate.m')) {
console.log('platforms/ios/CordovaLib/Classes/Private/Plugins/CDVUIWebViewEngine/CDVUIWebViewDelegate.m - FOUND: fixing');
replace({
regex: /.*BOOL shouldLoad = YES;*./g,
replacement: 'BOOL shouldLoad = YES; NSURL * requesturl = [request URL]; NSString * url = [[request URL]absoluteString]; NSString * documenturl = [[request mainDocumentURL]absoluteString]; if ((navigationType == UIWebViewNavigationTypeLinkClicked && ([[requesturl scheme] isEqualToString:#"http"] || [[requesturl scheme] isEqualToString:#"https"])) || (([url isEqualToString:documenturl]) && ([[requesturl scheme] isEqualToString:#"http"] || [[requesturl scheme] isEqualToString:#"https"]))) { [[UIApplication sharedApplication] openURL:requesturl]; return NO;}',
paths: ['platforms/ios/CordovaLib/Classes/Private/Plugins/CDVUIWebViewEngine/CDVUIWebViewDelegate.m'],
recursive: true,
silent: true,
});
} else {
console.log('platforms/ios/CordovaLib/Classes/Private/Plugins/CDVUIWebViewEngine/CDVUIWebViewDelegate.m - NOT FOUND');
}
Please note that this is a risky operation to be done, but I had no other means of dealing with this problem at the time. The above code searches if there is a file called CDVUIWebViewDelegate.m in the path given and then tries to find a piece of code in there and replace it with another piece of code. But in a nutshell the code above will modify the platform specific code for iOS in the CDVUIWebViewDelegate and add a if statement of the following kind to this file:
NSURL * requesturl = [request URL];
NSString * url = [[request URL]absoluteString]; // URL that was requested
NSString * documenturl = [[request mainDocumentURL]absoluteString]; // Main document URL
if ((navigationType == UIWebViewNavigationTypeLinkClicked && ([[requesturl scheme] isEqualToString:#"http"] || [[requesturl scheme] isEqualToString:#"https"])) || (([url isEqualToString:documenturl]) && ([[requesturl scheme] isEqualToString:#"http"] || [[requesturl scheme] isEqualToString:#"https"]))) {
[[UIApplication sharedApplication] openURL:requesturl]; // forward to application router
return NO;
}
Consider that I'm not a objective-c coder and this is all new to myself also and I made this solution because I did not find any other solutions to my problem which worked. The above if statement could and should be modified to your needs. I have only used this code on development environment and will need to investigate further and improve this method before implementing it to a production environment.
Remember that you need to remove and add the platform for this to take effect. This only occurs when adding a platform as stated above.
But that is it. Now your iOS application will open all urls in a native browser. Hopefully this helps you in the right direction for finding a (better?) solution to this problem.
I also faced the same problem and was able to solve with the following code.
$('iframe#youtube').get(0).contentWindow.open = function (url) {
cordova.InAppBrowser.open(url, "_system");
};
This code works only on iOS.

Blank page in IE8 and 9

I've recently built and launched this page: http://www.thaiestatenetwork.com
It works great in Chrome, Safari, Firefox and even IE10, but in IE8 and 9 all I get is a blank page.
I've read through post here on SO about similar issues and based on that I've tried this:
going over my templates in an attempt to find DOM errors.
Tried setting position:static on html and body
commented out #font-face in my CSS (since I was getting an error in IE on BrowserStack related to #font-face)
Checked for potential CORS issues. Found none.
None of it works.
Strangely too, when I tunnel to my local dev machine through BrowserStack, everything works like a charm.
I should add that the site is built using router https://github.com/tmeasday/meteor-router and runs on Heroku using this build pack: https://github.com/oortcloud/heroku-buildpack-meteorite
I really hope someone out there has that fresh pair of eyes that will lead me on the right track.
I've solved it!
The issue turned out to be related to the way I was initializing Google Analytics (GA). I was doing this:
Template.menu.created = function() {
// GA initialization code here
};
I had to do this:
Template.menu.rendered = function() {
if ( typeof ga === 'undefined' ) {
// GA initialization code here
}
};
So basically I was attempting to initialise GA on first creation of my menu template, but instead I had to latch on to the rendered callback and add a conditional to make sure I only initialise GA once.
Overall I am not thrilled with my approach to initialising GA, but that is another matter entirely. It works.

How can I apply GA download tracking with Sitecore?

I'm posting this question to Stackflow b/c after doing much research into an answer to this very question online, I did not come across a straight forward answer and had to do my own sleuthwork to resolve this.
Basically, Sitecore uses a handler file .ASHX for all files uploaded to the Media Library. Since the 3rd party GA tracking tool I was using (entourage.js or gatags.js) does not recognize .ashx as a whitelisted download file, it was not adding the appropriate GA tracking syntax to the GA pixel tracker (__utm.gif).
So the solution turns out to be simple but sadly, not retroactive, meaning all files previously uploaded to the Media Library in the Sitecore content tree will continue to use the ashx extension unless you reupload the image. In your web.config file, search for the "Media.RequestExtension" setting. If you change the value associated with this setting from "ashx" to a blank string, this will force Sitecore to use the originalextension of the file and image in the Sitecore Media Library.
Aside from interfering with GA analytics, this method of turning every downloadable file extension into an ashx file is poor SEO practice. AND, Sitecore will not point you in the right direction of getting around this other than a round-about way (google Sitecore dynamic linking and configuration) because they want you to use their Sitecore OMS download tracking capability. And that's it! Two days of research led me to this conclusion.
So the solution turns out to be simple but sadly, not retroactive,
meaning all files previously uploaded to the Media Library in the
Sitecore content tree will continue to use the ashx extension unless
you reupload the image.
Not sure where you got this information, but it's incorrect. You can blank out the Media.RequestExtension setting and all existing files will use their original extension. In IIS7 Integrated Mode, you should be able to make this change without having to make other server configuration changes.
Edit: More Info
If you analyze Sitecore.Configuration.Settings.Media.RequestExtension (the API equivalent to this settings) in a decompiler, you can see that it's only used by the MediaProvider when constructing the Media URL. Sitecore should remember the original extension of the media and can serve it with its original URL, regardless of what this setting was when it was uploaded. That's my experience, anyway, and it seems to be validated by looking into Sitecore.Kernel.
You could use this script to track download events via Google Analytics.
if (typeof jQuery != 'undefined') {
jQuery(document).ready(function($) {
var filetypes = /\.(zip|pdf|doc*|xls*|ppt*|jpg|ashx)$/i;
var baseHref = '';
if (jQuery('base').attr('href') != undefined) baseHref = jQuery('base').attr('href');
jQuery('a').each(function() {
var href = jQuery(this).attr('href');
if (href) {
if (href.indexOf('?') != '-1') {
href = href.substring(0, href.indexOf('?'));
}
if (href.match(filetypes)) {
jQuery(this).click(function() {
var extension = String((/[.]/.exec(href)) ? /[^.]+$/.exec(href) : undefined);
var filePath = String(href);
_gaq.push(['_trackEvent', 'Download', extension, filePath]);
if (jQuery(this).attr('target') != undefined && jQuery(this).attr('target').toLowerCase() != '_blank') {
setTimeout(function() {
location.href = baseHref + href;
}, 200);
return false;
}
});
}
}
});
});
}
Just add in the required file types here at this line -
var filetypes = /.(zip|pdf|doc*|xls*|ppt*|jpg|ashx)$/i;
Having done a quick google for gatags.js, I can see that you can add an extension to the whitelist on line 24:
var isDoc = path.match(/\.(?:doc|eps|jpg|png|svg|xls|ppt|pdf|xls|zip|txt|vsd|vxd|js|css|rar|exe|wma|mov|avi|wmv|mp3)($|\&|\?)/);
Change it to:
var isDoc = path.match(/\.(?:ashx|doc|eps|jpg|png|svg|xls|ppt|pdf|xls|zip|txt|vsd|vxd|js|css|rar|exe|wma|mov|avi|wmv|mp3)($|\&|\?)/);
Alternatively, you could attach the Google Analytics _trackEvent yourself with a dom selector and a click event.
Either way, I think OMS can track media library files regardless of extension - removing the default ashx extension doesn't stop the file being handled by Sitecore.

Facebook fan-box stopped respecting the “css” attribute?

Looks like this doesn’t work anymore. Maybe Facebook stopped respecting the “css” attribute? Does this still work for anyone?
Facebook has deprecated the Fan Box (introduced in 2009) in favor of the new Like Box. While the features of each are similar, they use different JavaScript APIs.
You can still customize the appearance of the Fan Box with your own external CSS, but it's unclear how long Facebook will continue to support this ability.
Here's some sample FBML code that shows how the Fan Box accepts external CSS:
<div id="fb-root"></div>
<fb:fan
profile_id="104818966496"
backgroundshow_faces="true"
stream="false"
header="false"
connections="8"
css="http://example.com/css/stylesheet.css?1310162522">
</fb:fan>
<script>
// Initialize Facebook JavaScript SDK
// http://developers.facebook.com/docs/reference/javascript/FB.init
window.fbAsyncInit = function() {
FB.init({
appId: '136570223089806',
xfbml: true
});
};
// Asynchronously Load Facebook Fan Box Social Plugin
(function () {
var e = document.createElement('script');
e.src = document.location.protocol + '//connect.facebook.net/en_US/all.js';
e.async = true;
document.getElementById('fb-root').appendChild(e);
}());
</script>
Some things to keep in mind:
Your custom CSS will be filtered through Facebook's content rendering servers and needs to be public facing. (Meaning, you'll have to upload/edit your CSS file to a web server to test how it looks when making changes).
It's recommended to append (and update) a query string to your CSS during development, since Facebook will heavily cache your CSS. After making a change, update your query string variable to instruct Facebook to fetch a new copy of your stylesheet.
Facebook will prefix all your HTML/CSS/JS elements with a "namespace" created using your application id. By doing this, Facebook ensures that your CSS can't manipulate standard Facebook elements and layouts.
Be aware, not all CSS properties and selectors are allowed, and Facebook will remove many CSS3 rules from your CSS.
Most frustrating of all though, is that Facebook seems to remove allow some vendor prefixes while disallowing others. For example, Facebook removes Webkit vendor prefixes (-webkit-border-radius) but allows Mozilla prefixes (-moz-border-radius). Annoying!
This means that rounded corners, drop-shadows and other vendor specific CSS may not appear in all browsers for your custom Facebook Fan Box. So, try as you might, you just may not be able to get your Facebook Fan Box to look the same in all browsers.

Resources