Disabling same-origin policy in Electron (need this to work with iframes) - iframe

I'll try to be as short as possible since there's no need for code - I put an iframe tag in my Electron app and I want JavaScript to retrieve some information from it but due to same-origin policy, I can't do that. Can I disable it? Note: I am the owner of the page in the iframe.
var validate = document.getElementById('validate');
validate.onclick = function() {
var input = document.getElementById('serial').value;
var validator = document.createElement('iframe');
validator.src = "http://**********.com/?wvkey=" + input;
body.appendChild(validator);
var status = validator.contentWindow.document.getElementById('status').innerHTML;
if (status === "Key Status: Active") {
window.location.assign("../dashboard/index.html");
}
else {
window.location.assign("../support/keys/invalid/index.html");
}
}
When clicking a button on the page, the code is supposed to check for a text with the value of "Key Status: Active" in the iframe. If the condition is true, it should redirect the user to another page. If false, it should redirect him to an error page. In my app, however, the iframe just appears in the background and doesn't do anything - no redirects.
main.js (part of it):
win = new BrowserWindow({
height: 700,
resizable: false,
show: false,
webPreferences: {
nodeIntegration: true,
webSecurity: false
},
width: 790
})
EDIT (Updated)
var validate = document.getElementById('validate');
validate.onclick = function() {
var input = document.getElementById('serial').value;
var validator = document.createElement('iframe');
validator.onload = function() {
var status = validator.contentWindow.document.getElementById('status').innerHTML;
if (status === "Key Status: Active") {
window.location.assign("../dashboard/index.html");
}
else {
window.location.assign("../support/keys/invalid/index.html");
}
};
validator.src = "http://awebsite.com/?wvkey=" + input;
body.appendChild(validator);
}

Since your question is how to disable security features like CORS in an Electron window, here is the setting you can use:
win = new BrowserWindow({
webPreferences: {
webSecurity: false
}
});
I'd however only use this as a last resort and rather have your website send the appropriate CORS headers.
* Edit *
After seeing your source code I believe there is an issue with your code:
var validator = document.createElement('iframe');
validator.src = "http://**********.com/?wvkey=" + input;
This will load your website into the <iframe> object however this happens asynchronously. Means you need to wait for the page to finish loading before you can continue with:
var status = validator.contentWindow.document.getElementById('status').innerHTML;
Change your code to something like this:
var validator = document.createElement('iframe');
validator.onload = function() {
var status = validator.contentWindow.document.getElementById('status').innerHTML;
[...]
};
validator.src = "http://**********.com/?wvkey=" + input;
body.appendChild(validator);
Note that you will still need the webSecurity or CORS settings to be able to access the validator frame content.

Related

Fullcalendar using resources as a function with select menu

Using Fullcalendar 4, I am trying to show/hide my resources using a select menu. When the user selects one of the providers from a menu, I want to only show that one resourc's events.
Above my fullcalendar I have my select menu:
<select id="toggle_providers_calendar" class="form-control" >
<option value="1" selected>Screech Powers</option>
<option value="2">Slater</option>
</select>
I am gathering the resources I need using an ajax call on my included fullcalendar.php page. I am storing them in an object and then trying to control which resources are shown onscreen:
document.addEventListener('DOMContentLoaded', function() {
var resourceData = [];
$.getJSON('ajax_get_json.php?what=schedule_providers_at_location',
function(data) {
$.each(data, function(index) {
resourceData.push({
id: data[index].value,
title: data[index].text
});
});
console.log(resourceData);
});
//below, set the visible resources to whatever is selected in the menu
//using 1 in order for that to show at start
var visibleResourceIds = ["1"];
//below, get the selected id when the the menu is changed and use that in the toggle resource function
$('#toggle_providers_calendar').change(function() {
toggleResource($('#toggle_providers_calendar').val());
});
var calendar_full = document.getElementById('calendar_full');
var calendar = new FullCalendar.Calendar(calendar_full, {
events: {
url: 'ajax_get_json.php?what=location_appointments'
},
height: 700,
resources: function(fetchInfo, successCallback, failureCallback) {
// below, I am trying to filter resources by whether their id is in visibleResourceIds.
var filteredResources = [];
filteredResources = resourceData.filter(function(x) {
return visibleResourceIds.indexOf(x.id) !== -1;
});
successCallback(filteredResources);
},
...
});
// below, my toggle_providers_calendar will trigger this function. Feed it resourceId.
function toggleResource(resourceId) {
var index = visibleResourceIds.indexOf(resourceId);
if (index !== -1) {
visibleResourceIds.splice(index, 1);
} else {
visibleResourceIds.push(resourceId);
}
calendar.refetchResources();
}
To make sure the getJSON is working, I have console.log(resourceData). The information in the console once it's gathered is:
[{id: '1', title: 'Screech Powers'}, {id: '2', title: 'Slater}]
... the above are the correct resources that can be chosen/rendered. So that seems to be okay.
On page load, no resources show at all, when resource id of '1' (Screech Powers) should be shown per my code. Well, at least, that's what I am trying to do right now.
When the menu changes, resources will show/hide, but not based on what's selected; the logic of only showing what is selected in the menu doesn't seem to be working.
I used to use a URL request for my resources: 'ajax_get_json.php?what=schedule_providers_at_location', and it worked fine! All resources show then their events properly. I am just trying to modify it by using a menu to show/hide the resources as needed.
Here's what I'm doing to make it happen so far! In case someone comes across this post ever, this will help.
Here's my code before my fullcalendar code.
var resourceData = [];
var visibleResourceIds = [];
$.getJSON('ajax_get_json.php?what=schedule_providers_at_location',
function(data) {
$.each(data, function(index) {
resourceData.push({
id: data[index].value,
title: data[index].text
});
});
});
$('#toggle_providers_calendar').change(function() {
toggleResource($('#toggle_providers_calendar').val());
});
My select menu with id 'toggle_providers_calendar' is the same as my original post. My fullcalendar resources as a function is the same too.
After the calendar is rendered, here are the changes I made to my toggle resources function:
// menu button/dropdown will trigger this function. Feed it resourceId.
function toggleResource(resourceId) {
visibleResourceIds = [];
//if select all... see if undefined from loading on initial load = true
if ((resourceId == '') || (resourceId === undefined)) {
$.map( resourceData, function( value, index ) {
visibleResourceIds.push(value.id);
});
}
var index = visibleResourceIds.indexOf(resourceId);
if (index !== -1) {
visibleResourceIds.splice(index, 1);
} else {
visibleResourceIds.push(resourceId);
}
calendar.refetchResources();
}
This causes the resources to show and hide properly. If the user selects "Show All" that works too!
In order to have a default resource show on load, I add this to my fullcalendar script:
loading: function(bool) {
if (bool) {
//insert code if still loading
$('.loader').show();
} else {
$('.loader').hide();
if (initial_load) {
initial_load = false;
//code here once done loading and initial_load = true
var default_resource_to_show = "<?php echo $default_provider; ?>";
if (default_resource_to_show) {
//set the menu to that provider and trigger the change event to toggleresrource()
$('#toggle_providers_calendar').val(default_provider).change();
} else {
//pass in nothing meaning 'select all' providers for scheduler to see
toggleResource();
}
}
}
},
I am using a bool variable of initial_load to see if the page was just loaded (basically not loading data without a page refresh). The bool of initial_load = true is set outside of DOMContentLoaded
<script>
//show selected date in title box
var initial_load = true;
document.addEventListener('DOMContentLoaded', function() {
My only current problem is that when toggleResource function is called, the all day vertical time block boundaries don't line up with the rest of the scheduler. Once I start navigating, they do, but I don't understand why it looks like this on initial load or when toggleResource() is called:
Any thoughts on how to correct the alignment of the allday vertical blocks?

Integrate MPGS session.js in Aurelia SPA

I am trying to integrate the MasterCard Payment Gateway services to a SPA using Aurelia.
I am trying to use the hosted checkout mechanism to integrate MPGS.
I am writing code in the attached event of the Aurelia viewmodel to load the session.js library and on load of the library adding another script element to initialize the session.
The attached method is listed below.
this.mpgsSessionScript = `if (self === top) { var antiClickjack = document.getElementById("antiClickjack"); antiClickjack.parentNode.removeChild(antiClickjack); } else { top.location = self.location; } PaymentSession.configure({ fields: { card: { number: "#card-number", securityCode: "#card-cvv", expiryMonth: "#card-expiry-month", expiryYear: "#card-expiry-year" } }, frameEmbeddingMitigation: ["javascript"], callbacks: { initialized: function(response) { console.log(response); }, formSessionUpdate: function(response) { } } }); function pay() { PaymentSession.updateSessionFromForm('card'); }`;
this.styleElement = document.createElement('style');
this.styleElement.setAttribute('id', "antiClickjack");
this.styleElement.innerText = "body{display:none !important;}";
document.head.appendChild(this.styleElement);
this.scriptElement = document.createElement('script');
this.scriptElement.src = this.sessionJs;
this.scriptElement.onload = () => {
const innerScriptElement = document.createElement('script');
innerScriptElement.innerText = this.mpgsSessionScript;
document.body.appendChild(innerScriptElement);
};
document.body.appendChild(this.scriptElement);
I can successfully run the code the and the script elements are added to DOM and also, the antiClickjack style gets removed, which indicates that the script element gets added.
But the issue is, the card number and the cvv elements are not getting enabled for input. If successfully initialized, the card number and the cvv elements should get enabled.
I do not see any errors in the console. Any help would be appreciated.

How to make Chrome Extension run for each new Iframe added?

I created a Chrome Extension as a solution to override the helpText bubbles in SalesForce Console pages. The helpText bubbles show up the text without the ability to link URLs. It looks like this:
The extension is taking the helpText bubble (which in the SalesForce console window, is inside an iFrame) and makes the URL click-able. It also adds word wrap and marks the links in blue.
The solution works fine when the page loads with the initial iFrame (or iFrames) on it, meaning when you open the SalesForce console the first time (https://eu3.salesforce.com/console).
When a new tab is created at the SalesForce console, my inject script doesn't run.
Can you please assist in understanding how to inject the script on each and every new Tab SalesForce Console is creating?
The Extension as follows:
manifest.js:
{
"browser_action": {
"default_icon": "icons/icon16.png"
},
"content_scripts": [ {
"all_frames": true,
"js": [ "js/jquery/jquery.js", "src/inject/inject.js" ],
"matches": [ "https://*.salesforce.com/*", "http://*.salesforce.com/*" ]
} ],
"default_locale": "en",
"description": "This extension Fix SalesForce help bubbles",
"icons": {
"128": "icons/icon128.png",
"16": "icons/icon16.png",
"48": "icons/icon48.png"
},
"manifest_version": 2,
"name": "--Fix SalesForce bubble text--",
"permissions": [ "https://*.salesforce.com/*", "http://*.salesforce.com/*" ],
"update_url": "https://clients2.google.com/service/update2/crx",
"version": "5"
}
And this is the inject.js:
chrome.extension.sendMessage({}, function(response) {
var readyStateCheckInterval = setInterval(function() {
if (document.readyState === "complete") {
clearInterval(readyStateCheckInterval);
var frame = jQuery('#servicedesk iframe.x-border-panel');
frame = frame.contents();
function linkify(inputText) {
var replacedText, replacePattern1, replacePattern2, replacePattern3;
var originalText = inputText;
//URLs starting with http://, https://, file:// or ftp://
replacePattern1 = /(\b(https?|ftp|file):\/\/[-A-Z0-9+&##\/%?=~_|!:,.;]*[-A-Z0-9+&##\/%=~_|])/gim;
replacedText = inputText.replace(replacePattern1, '$1');
//URLs starting with "www." (without // before it, or it'd re-link the ones done above).
replacePattern2 = /(^|[^\/f])(www\.[\S]+(\b|$))/gim;
replacedText = replacedText.replace(replacePattern2, '$1$2');
//Change email addresses to mailto:: links.
replacePattern3 = /(([a-zA-Z0-9\-\_\.])+#[a-zA-Z\_]+?(\.[a-zA-Z]{2,6})+)/gim;
replacedText = replacedText.replace(replacePattern3, '$1');
//If there are hrefs in the original text, let's split
// the text up and only work on the parts that don't have urls yet.
var count = originalText.match(/<a href/g) || [];
if(count.length > 0){
var combinedReplacedText;
//Keep delimiter when splitting
var splitInput = originalText.split(/(<\/a>)/g);
for (i = 0 ; i < splitInput.length ; i++){
if(splitInput[i].match(/<a href/g) == null){
splitInput[i] = splitInput[i].replace(replacePattern1, '$1').replace(replacePattern2, '$1$2').replace(replacePattern3, '$1');
}
}
combinedReplacedText = splitInput.join('');
return combinedReplacedText;
} else {
return replacedText;
}
}
var helpOrbReady = setInterval(function() {
var helpOrb = frame.find('.helpOrb');
if (helpOrb) {
clearInterval(helpOrbReady)
} else {
return;
}
helpOrb.on('mouseout', function(event) {
event.stopPropagation();
event.preventDefault();
setTimeout(function() {
var helpText = frame.find('.helpText')
helpText.css('display', 'block');
helpText.css('opacity', '1');
helpText.css('word-wrap', 'break-word');
var text = helpText.html()
text = text.substr(text.indexOf('http'))
text = text.substr(0, text.indexOf(' '))
var newHtml = helpText.html()
helpText.html(linkify(newHtml))
}, 500); });
}, 1000);
}
}, 1000);
});
It is possible (I have not tested it, but it sounds plausible from a few questions I've seen here) that Chrome does not automatically inject manifest-specified code into newly-created <iframe> elements.
In that case, you will have to use a background script to re-inject your script:
chrome.runtime.onMessage.addListener( function(request, sender, sendResponse) {
if(request.reinject) {
chrome.tabs.executeScript(
sender.tab.id,
{ file: "js/jquery/jquery.js", "all_frames": true },
function(){
chrome.tabs.executeScript(
sender.tab.id,
{ file: "js/inject/inject.js", "all_frames": true }
);
}
);
});
Content script:
// Before everything: include guard, ensure injected only once
if(injected) return;
var injected = true;
function onNewIframe(){
chrome.runtime.sendMessage({reinject: true});
}
Now, I have many questions about your code, which are not directly related to your question.
Why the pointless sendMessage wrapper? No-one is even listening, so your code basically returns with an error set.
Why all the intervals? Use events instead of polling.
If you are waiting on document to become ready, jQuery offers $(document).ready(...)
If you're waiting on DOM modifications, learn to use DOM Mutation Observers, as documented and as outlined here or here. This would be, by the way, the preferred way to call onNewIframe().

Switch to iframe with phantom.js

I would like to switch to an iframe using pure phantom.js code
Here is my first attempt
var page = new WebPage();
var url = 'http://www.theurltofectch'
page.open(url, function (status) {
if ('success' !== status) {
console.log("Error");
} else {
page.switchToFrame("thenameoftheiframe");
console.log(page.content);
phantom.exit();
}
});
It produces only the source code of the main page. Any idea ?
Notice that the iframe domain is different from the main page domain.
Please give this a try I believe it may be an async issues meaning the iframe is not present when trying to access it. I received the below snippet from another post.
var page = require('webpage').create(),
testindex = 0,
loadInProgress = false;
page.onConsoleMessage = function(msg) {
console.log(msg);
};
page.onLoadStarted = function() {
loadInProgress = true;
console.log("load started");
};
page.onLoadFinished = function() {
loadInProgress = false;
console.log("load finished");
};
/*
page.onNavigationRequested = function(url, type, willNavigate, main) {
console.log('Trying to navigate to: ' + url);
console.log('Caused by: ' + type);
console.log('Will actually navigate: ' + willNavigate);
console.log('Sent from the page\'s main frame: ' + main);
};
*/
/*
The steps array represents a finite set of steps in order to perform the unit test
*/
var steps = [
function() {
//Load Login Page
page.open("https://www.yourpage.com");
},
function() {
//access your iframe here
page.evaluate(function() {
});
},
function() {
//any other step you want
page.evaluate(function() {
});
},
function() {
// Output content of page to stdout after form has been submitted
page.evaluate(function() {
//console.log(document.querySelectorAll('html')[0].outerHTML);
});
//render a test image to see if login passed
page.render('test.png');
}
];
interval = setInterval(function() {
if (!loadInProgress && typeof steps[testindex] === "function") {
console.log("step " + (testindex + 1));
steps[testindex]();
testindex++;
}
if (typeof steps[testindex] !== "function") {
console.log("test complete!");
phantom.exit();
}
}, 50);
replace
console.log(page.content);
with
console.log(page.frameContent);
Should return the contents of the frame phantomjs switched to.
If the iframe is from another domain you may need to add the --web-security=no option like this:
phantomjs --web-security=no myscript.js
As an additional information, what xMythicx said could be true. Some iframes are rendered via Javascript after page finishes loading. If the iframe contents are empty, then you will need to wait for all resources to finish loading, before you start grabbing stuff from the page. But this is another issue, if you need an answer on this, I suggest you ask a new question about it, and I will answer there.
Had the same problem for iframes and
phantomjs --web-security=no
helped in my case :]

Facebook FriendsList window not opening in Internet Explorer 8

I'm using the FB.UI() JavaScript SDK to get the selected friends id, when the user selects friends from Friendslist request dialog window.
The selected friends id is passed to a handler file.
The above situation is working fine in Firefox, that is, I am able to get the friends Id, but the same is not working in Internet Explorer 8.
In IE8, I am getting the error below when I click the button to open the friends request dialog.
API Error Code: 191 API Error Description: The specified URL is not
owned by the application Error Message: redirect_uri is not owned by
the application.
I had given the redirect_uri also but I'm not getting the friends id.
The code is given below:
function sendRequestToManyRecipients() {
alert("sendRequestToManyRecipients");
FB.ui({method: 'apprequests',
appId : '',
display: 'popup',
message: 'My Group'
}, requestCallback);
}
function requestCallback(response) {
getMultipleRequests(response.request_ids);
}
var friend=new Array();
var sfriend="";
function getMultipleRequests(request_ids)
{
if (response && request_ids)
{
var ids = request_ids;
var _batch = [];
for (var i = 0; i < ids.length; i++)
{
_batch.push({ "method": "get", "relative_url":ids[i] });
}
if (_batch.length > 0)
{
FB.api('/', 'POST', { batch: _batch }, function (res)
{
for (var j = 0; j < res.length; j++)
{
body = res[j].body;
var myObject = eval('(' + body + ')');
friendID = myObject.to.id;
friend[j]=friendID.toString();
}
});
}
}
showfriends();
}
function showfriends()
{
for (var i = 0; i < friend.length; i++)
{
sfriend=sfriend+","+friend[i].toString();
}
if(sfriend != null)
{
window.open("Friends.ashx?id="+sfriend,'WinName','width=900,height=500,left=200,top=200'); }
}
I'm searching for a solution but I am not able to find the correct one.
Does anyone have a solution to this?
Are you want to get the friend id that the user have sent in the apprequest dialog?
Consider using request 2.0 efficient, which can help you get the ids without calling another api after sending the request
I have answered a similar question before, please take a look:
how to get user id on facebook request dialog
updated: 2011-11-29
For your ref, I use this code before for a project on fb app, which works on both IE8, Firefox 7, chrome 15
FB.ui({
method : "apprequests",
title : "title",
message : "messafe!!",
display : "iframe"
},
inviteCallback
);
function inviteCallback(response) {
// Requests 2.0 Efficient
// {
// request: ‘request_id’
// to:[array of user_ids]
// }
if (response.request) {
var receiverIDs = response.to;
document.inviteForm.receivers.value = receiverIDs.join(",");
document.inviteForm.submit();
}
}

Resources