VSCode cross-origin request inside WebView - visual-studio-code

I'm working on extension which based on VSCode WebView. Extension make integration with issue tracking system over HTTP API, like Jira. I want to render information about issue in WebView and create some forms for making comments and changing issue status. I don't want to use message passing between extension and WebView. When I try to create HTTP request to API inside WebView I got error:
Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access.
Server does't support Access-Control-Allow-Origin for "null" or "localhost" Origin.
Is the way to create HTTP request from WebView to server ignoring missing Access-Control-Allow-Origin header? Maybe I can setup some policy for WebView panel? Or create localhost proxy inside extension and make request over proxy?
Code example
import * as vscode from 'vscode';
export function activate(context: vscode.ExtensionContext) {
vscode.commands.registerCommand('catCoding.start', () => {
// Create and show panel
const panel = vscode.window.createWebviewPanel(
'catCoding',
'Cat Coding',
vscode.ViewColumn.One,
{enableScripts: true}
);
// And set its HTML content
panel.webview.html = getWebviewContent();
})
}
function getWebviewContent() {
return `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Cat Coding</title>
</head>
<body>
<script>
var xhr = new XMLHttpRequest();
xhr.open('GET', 'https://google.com', true);
xhr.send();
</script>
</body>
</html>`;
}

Answer from Github Issue
There is no vscode support for changing this. You should think of the webview more as an html view (one that does not have any server or origin) rather than a webpage
Posters on stackoverflow may have suggestions for workarounds

Support for Cross Origin Isolation was just added for Webview through the use of the vscode-coi url parameter; see https://github.com/microsoft/vscode/issues/137884

Related

Flutter web event listener on other windows

I have a flutter web application, Im trying to implement Okta oauth2 but whenever I call the url that I manage to create with some params using DIO package I end up with having html response instead of the actual response.
The endpoint I'm calling looks like this:
https://dev-xxxxxxxx.okta.com/oauth2/default/v1/authorize?response_type=code&scope=openid+profile+offline_access&client_id=xxxxxxxxxxxxxxxxxxxx&redirect_uri=http://localhost:8080/authorization-code/callback&code_challenge_method=S256&code_challenge=Wag0u2fyeYWJHy_baK-XbMWO9H2xwUBii7R4Nvj761Y&sessionToken=20111jWBb2P2BoPIL-Atd0pk5QDImstT7EmYULPFMg2GoCGPgOrxKFl&state=X7hih1mUow&nonce=lSfF1CxmmR
Whenever I call this url it shall be redirected to another url such as:
http://localhost:8080/authorization-code/callback?code=TCifQEab0a6HwEGeWQXlDQhPm22RlyemvO5GbipASEU&state=YLi4I2P4qd
So the main point using DIO is that its returning the response of the second url which is an html flutter content.
It can be solved if DIO don't follow the redirection and give status code 302 but its not doing that.
Currently I'm trying different approach, I'm trying to open the url in a new window which immediately change to the second url.
My problem is how should I get the code from the second url and the cookies that the second url provide from the new opened window.
final html.WindowBase newWindow = html.window.open(url, "callback");
so at least how can I get the href from the newly opened window knowing that it changes after a while into the the flutter correct rout that I sat up.
Knowing that newWidnow.location.href is write only.
Okay I managed to solve that, leaving the solution if anyone faced the same issue.
under your /web directory create an html file and call it for example callback.html.
then paste this code inside it.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Auth</title>
<meta name="description"
content="Simple, quick, standalone responsive placeholder without any additional resources">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<h2>Authentication Succeeded</h2>
<h3>Close this window if it didn't close by itself.</h3>
</body>
<script>
window.opener.postMessage(window.location.href, '*');
</script>
</html>
then set your Redirect URI as follows http://localhost:8080/callback.html
So in that case whenever you get the Redirect URI from oauth2 you get it as follows
http://localhost:8080/callback.html?code=TCifQEab0a6HwEGeWQXlDQhPm22RlyemvO5GbipASEU&state=YLi4I2P4qd
which will basically call the newly created html file callback.html.
In flutter side you'll need to do the following:
html.WindowBase popupWindow;
popupWindow = html.window.open(
url,
"Auth",
"width=400, height=500, scrollbars=yes",
);
String? code;
html.window.onMessage.listen((event) {
if (event.data.toString().contains('code=')) {
code = event.data.toString().split('code=')[1].split('&')[0];
}
});
await Future.delayed(const Duration(seconds: 2), () {
popupWindow.close();
});
Which will basically open the window, then capture the url and extract it, then close the window.
I hope this helps.
Use assign on Location to redirect to the Authorize endpoint of the Authorization Server.
window.location.assign('https://${yourOktaDomain}/oauth2/default/v1/authorize?...');

LinkedIn API calling in Javascript

I have used the LinkedIn Javascript API calls in my html page. I can see the "Sign In With LinkedIn" button . In "onLinkedInLoad" function calling the "IN.Event.on("IN", "auth", onLinkedInAuth);" is not firing. I have an alert message 'call2' in my code and its also not calling.
Basically I want to read a company updates and bind into a div. In Browser console I am getting the below URL and profile's response. There is no other request in browser console.
https://api.linkedin.com/v1/people::(~):(id,first-name,last-name,headline,picture-url)
I followed all the instructions in LinkedIn document before doing this to consume a company update.
I have a company page and with an update.
I have created an app and use that api key only in js function call.
In LinkedIn REST Console I can see my update.
Do I miss anything ? Thanks.
I use the actual api key and company id at my end.
See my code :
<html>
<head>
<title>
LinkedIn
</title>
<script type="text/javascript" src="https://platform.linkedin.com/in.js">
api_key: 0000000000000
onLoad: onLinkedInLoad
authorize: true
</script>
<script type="text/javascript">
function onLinkedInLoad() {
alert('call');
IN.Event.on("IN", "auth", onLinkedInAuth);
}
function onLinkedInAuth() {
alert('call2');
IN.API.Raw("/companies/000000/updates")
.method("GET")
.result(function(res) {
document.write(JSON.stringify(res));});
}
</script>
</head>
<body>
<script type="IN/Login">
</script>
</body>
</html>
I have used IN.User.authorize(onLinkedInAuth) instead of IN.Event.on("IN", "auth", onLinkedInAuth) for authorization and worked.

How to create a fan / like gate on Facebook?

I am trying to create a simple fan/like gate. Where you specify one content for none fans and other content for fans (if they pressed the like button). However when I run the page in the page tab it does not return a signed request and thus there is no way for me to figure out how to do it. Can someone post a tutorial, or have a fix for this? At this point I got the following code:
index.php
<?php
require dirname( __FILE__ ) . '/../api/facebook.php';
// Create our application instance
// (replace this with your appId and secret).
$facebook = new Facebook(array(
'appId' => '112458478872227',
'secret' => 'X',
'cookie' => true
));
$signed_request = $facebook->getSignedRequest();
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="nl">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Home</title>
</head>
<body>
<?php
if ( $signed_request['page']['liked'] )
{
echo 'A fan';
}
else
{
echo 'Not a fan yet.';
}
?>
</body>
</html>
Link:
http://www.facebook.com/talkieslifestylemagazine?sk=app_112458478872227
Faceook App:
Page Tab
Page Tab Name: Home
Page Tab URL: http://apps.talkiesmagazine.eu/facebook/home
Secure Page Tab URL :empty
Page Tab Edit URL : empty
It looks like the original poster switched to using Wildfire's like gate app. But anyway...
Your server is doing a redirect before your script is run. If you put your code in a folder such as http://apps.talkiesmagazine.eu/facebook/home/index.php - but you specify http://apps.talkiesmagazine.eu/facebook/home as your url - the webserver will see that http://apps.talkiesmagazine.eu/facebook/home is a folder and redirect to http://apps.talkiesmagazine.eu/facebook/home/. That redirect doesn't preserve the POST data which carries the signed request. You can see if you put http://apps.talkiesmagazine.eu/facebook/home in your browser, it is redirected to http://apps.talkiesmagazine.eu/facebook/home/.
Changing your tab url to http://apps.talkiesmagazine.eu/facebook/home/ will fix it.
However, Facebook requires that you have your server setup for securely serving your app over https and set the secure tab url to that url. You have the Secure Page Tab URL empty, so that would need to be changed as well to have a fully functional tab.
Not sure why the signed request isn't showing for you. It's still working.
code: http://fbmhell.com/2011/06/facebook-like-gating-in-iframe-tabs/
page tab: http://www.facebook.com/snipe.net?sk=app_207328155971716
Maybe it's something in the migration settings that you have to check/uncheck? They've made some changes over the past few months.
Let's try this:
1, Create a simple php file on the app root named index.php with the following code:
<?
echo "POST check<br /><pre>";
print_r ($_POST);
echo "</pre>";
?>
2, Go to your app tab, and check what is come up.
2a, If the "POST check" message only, check the app URL on the app settings page. May be forget to close the url with / or there is a space somewhere.
2b, If the "POST check" message followed by an array structure, something wrong with your SDK implementation.
Your example is using the Facebook PHP SDK by the looks of it. If you want something a bit simpler and relatively straight forward to implement, then take a look at this Facebook Fan / Like Gate over on GitHub.
I've used it on a bunch of Facebook tabs in the past and it's served me well. There's also a 'JavaScript setup' branch with the js sdk and application config setup and ready to go.

Connect to Facebook with Javascript Client Library using Adobe AIR

I'm having an issue connecting to Facebook through the Javascript Client Library in Adobe AIR. It works fine in the browser but in Adobe AIR it seems to not be able to find the Facebook functions. Here is some code I copied from the Facebook website: (Oh and I have the xd_receiver.htm file in the correct path too)
<textarea style="width: 1000px; height: 300px;" id="_traceTextBox">
</textarea>
<script src="http://static.ak.connect.facebook.com/js/api_lib/v0.4/FeatureLoader.js.php" type="text/javascript"></script>
//
var api = FB.Facebook.apiClient;
// require user to login
api.requireLogin(function(exception){
FB.FBDebug.logLevel=1;
FB.FBDebug.dump("Current user id is " + api.get_session().uid);
// Get friends list
//5-14-09: this code below is broken, correct code follows
//api.friends_get(null, function(result){
// Debug.dump(result, 'friendsResult from non-batch execution ');
// });
api.friends_get(new Array(), function(result, exception){
FB.FBDebug.dump(result, 'friendsResult from non-batch execution ');
});
});
});
//]]>
</script>
It's not that simple actually man, the problem with loading external script files from the application sandbox is that it's not supported. Technically, by using iframes, you should be able to do this and it works but it's still impossible to use XFBML in the root document after from my experience. After two days of trial and error, the easiest way to do use Facebook Connect in an html/ajax adobe air application is to download the actionscript library and include it as such:
<script type="application/x-shockwave-flash" src="lib/facebook.swf"></script>
<script type="text/javascript">
var FB = window.runtime.com.facebook;
var fb = new FB.Facebook();
var session = new FB.utils.DesktopSessionHelper();
//etc...
</script>
then just refer to the documentation. my only problem now it that I still haven't found an efficient enough way of using XFBML in adobe air, simply adding the facebook namespace to the html tag doesn't do the trick unfortunately. If any knows, please do share thanks
you also need to change xml namespace (main html tag) to this:
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:fb="http://www.facebook.com/2008/fbml" xml:lang="en-gb" lang="en-gb">

Is it possible to register a http+domain-based URL Scheme for iPhone apps, like YouTube and Maps?

I'd like to have iOS to open URLs from my domain (e.g. http://martijnthe.nl) with my app whenever the app is installed on the phone, and with Mobile Safari in case it is not.
I read it is possible to create a unique protocol suffix for this and register it in the Info.plist, but Mobile Safari will give an error in case the app is not installed.
What would be a workaround?
One idea:
1) Use http:// URLs that open in any desktop browser and render the service through the browser
2) Check the User-Agent and in case it's Mobile Safari, open a myprotocol:// URL to (attempt) to open the iPhone app and have it open Mobile iTunes to the download of the app in case the attempt fails
Not sure if this will work... suggestions? Thanks!
I think the least intrusive way of doing this is as follows:
Check if the user-agent is that of an iPhone/iPod Touch
Check for an appInstalled cookie
If the cookie exists and is set to true, set window.location to your-uri:// (or do the redirect server side)
If the cookie doesn't exist, open a "Did you know Your Site Name has an iPhone application?" modal with a "Yep, I've already got it", "Nope, but I'd love to try it", and "Leave me alone" button.
The "Yep" button sets the cookie to true and redirects to your-uri://
The "Nope" button redirects to "http://itunes.com/apps/yourappname" which will open the App Store on the device
The "Leave me alone" button sets the cookie to false and closes the modal
The other option I've played with but found a little clunky was to do the following in Javascript:
setTimeout(function() {
window.location = "http://itunes.com/apps/yourappname";
}, 25);
// If "custom-uri://" is registered the app will launch immediately and your
// timer won't fire. If it's not set, you'll get an ugly "Cannot Open Page"
// dialogue prior to the App Store application launching
window.location = "custom-uri://";
It's quite possible to do this in JavaScript as long as your fallback is another applink. Building on Nathan's suggestion:
<html>
<head>
<meta name="viewport" content="width=device-width" />
</head>
<body>
<h2><a id="applink1" href="fb://profile/116201417">open facebook with fallback to appstore</a></h2>
<h2><a id="applink2" href="unknown://nowhere">open unknown with fallback to appstore</a></h2>
<p><i>Only works on iPhone!</i></p>
<script type="text/javascript">
// To avoid the "protocol not supported" alert, fail must open another app.
var appstorefail = "itms://itunes.apple.com/us/app/facebook/id284882215?mt=8&uo=6";
function applink(fail){
return function(){
var clickedAt = +new Date;
// During tests on 3g/3gs this timeout fires immediately if less than 500ms.
setTimeout(function(){
// To avoid failing on return to MobileSafari, ensure freshness!
if (+new Date - clickedAt < 2000){
window.location = fail;
}
}, 500);
};
}
document.getElementById("applink1").onclick = applink(appstorefail);
document.getElementById("applink2").onclick = applink(appstorefail);
</script>
</body>
</html>
Check out a live demo here.
For iOS 6 devices, there is an option: Promoting Apps with Smart App Banners
I found that the selected answer works for the browser apps but I was having issues with the code working in non browser apps that implement a UIWebView.
The problem for me was a user on the Twitter app would click a link that would take them to my site through a UIWebView in the Twitter app. Then when they clicked a button from my site Twitter tries to be fancy and only complete the window.location if the site is reachable. So what happens is a UIAlertView pops up saying are you sure you want to continue and then immediately redirects to the App Store without a second popup.
My solution involves iframes. This avoids the UIAlertView being presented allowing for a simple and elegant user experience.
jQuery
var redirect = function (location) {
$('body').append($('<iframe></iframe>').attr('src', location).css({
width: 1,
height: 1,
position: 'absolute',
top: 0,
left: 0
}));
};
setTimeout(function () {
redirect('http://itunes.apple.com/app/id');
}, 25);
redirect('custom-uri://');
Javascript
var redirect = function (location) {
var iframe = document.createElement('iframe');
iframe.setAttribute('src', location);
iframe.setAttribute('width', '1px');
iframe.setAttribute('height', '1px');
iframe.setAttribute('position', 'absolute');
iframe.setAttribute('top', '0');
iframe.setAttribute('left', '0');
document.documentElement.appendChild(iframe);
iframe.parentNode.removeChild(iframe);
iframe = null;
};
setTimeout(function () {
redirect('http://itunes.apple.com/app/id');
}, 25);
redirect('custom-uri://');
EDIT:
Add position absolute to the iframe so when inserted there isn't a random bit of whitespace at the bottom of the page.
Also it's important to note that I have not found a need for this approach with Android. Using window.location.href should work fine.
In iOS9 Apple finally introduced the possibility to register your app to handle certain http:// URLs: Universal Links.
A very rough explanation of how it works:
You declare interest in opening http:// URLs for certain domains (web urls) in your app.
On the server of the specified domains you have to indicate which URLs to open in which app that has declared interest in opening URLs from the server's domain.
The iOS URL loading service checks all attempts to open http:// URLs for a setup as explained above and opens the correct app automatically if installed; without going through Safari first...
This is the cleanest way to do deep linking on iOS, unfortunately it works only in iOS9 and newer...
BUILDING Again on Nathan and JB's Answer:
How To Launch App From url w/o Extra Click
If you prefer a solution that does not include the interim step of clicking a link, the following can be used. With this javascript, I was able to return a Httpresponse object from Django/Python that successfully launches an app if it is installed or alternatively launches the app store in the case of a time out. Note I also needed to adjust the timeout period from 500 to 100 in order for this to work on an iPhone 4S. Test and tweak to get it right for your situation.
<html>
<head>
<meta name="viewport" content="width=device-width" />
</head>
<body>
<script type="text/javascript">
// To avoid the "protocol not supported" alert, fail must open another app.
var appstorefail = "itms://itunes.apple.com/us/app/facebook/id284882215?mt=8&uo=6";
var loadedAt = +new Date;
setTimeout(
function(){
if (+new Date - loadedAt < 2000){
window.location = appstorefail;
}
}
,100);
function LaunchApp(){
window.open("unknown://nowhere","_self");
};
LaunchApp()
</script>
</body>
</html>
window.location = appurl;// fb://method/call..
!window.document.webkitHidden && setTimeout(function () {
setTimeout(function () {
window.location = weburl; // http://itunes.apple.com/..
}, 100);
}, 600);
document.webkitHidden is to detect if your app is already invoked and current safari tab to going to the background, this code is from www.baidu.com
If you add an iframe on your web page with the src set to custom scheme for your App, iOS will automatically redirect to that location in the App. If the app is not installed, nothing will happen. This allows you to deep link into the App if it is installed, or redirect to the App Store if it is not installed.
For example, if you have the twitter app installed, and navigate to a webpage containing the following markup, you would be immediately directed to the app.
<!DOCTYPE html>
<html>
<head>
<title>iOS Automatic Deep Linking</title>
</head>
<body>
<iframe src="twitter://" width="0" height="0"></iframe>
<p>Website content.</p>
</body>
</html>
Here is a more thorough example that redirects to the App store if the App is not installed:
<!DOCTYPE html>
<html>
<head>
<title>iOS Automatic Deep Linking</title>
<script src='//code.jquery.com/jquery-1.11.2.min.js'></script>
<script src='//mobileesp.googlecode.com/svn/JavaScript/mdetect.js'></script>
<script>
(function ($, MobileEsp) {
// On document ready, redirect to the App on the App store.
$(function () {
if (typeof MobileEsp.DetectIos !== 'undefined' && MobileEsp.DetectIos()) {
// Add an iframe to twitter://, and then an iframe for the app store
// link. If the first fails to redirect to the Twitter app, the
// second will redirect to the app on the App Store. We use jQuery
// to add this after the document is fully loaded, so if the user
// comes back to the browser, they see the content they expect.
$('body').append('<iframe class="twitter-detect" src="twitter://" />')
.append('<iframe class="twitter-detect" src="itms-apps://itunes.com/apps/twitter" />');
}
});
})(jQuery, MobileEsp);
</script>
<style type="text/css">
.twitter-detect {
display: none;
}
</style>
</head>
<body>
<p>Website content.</p>
</body>
</html>
Heres a solution.
Setup a boolean sitiation using blur and focus
//see if our window is active
window.isActive = true;
$(window).focus(function() { this.isActive = true; });
$(window).blur(function() { this.isActive = false; });
Bind your link with a jquery click handler that calls something like this.
function startMyApp(){
document.location = 'fb://';
setTimeout( function(){
if (window.isActive) {
document.location = 'http://facebook.com';
}
}, 1000);
}
if the app opens, we'll lose focus on the window and the timer ends. otherwise we get nothing and we load the usual facebook url.
You can't, as far as I know, make the entire OS understand an http:+domain URL. You can only register new schemes (I use x-darkslide: in my app). If the app is installed, Mobile Safari will launch the app correctly.
However, you would have to handle the case where the app isn't installed with a "Still here? Click this link to download the app from iTunes." in your web page.
Check the User-Agent and in case it's
Mobile Safari, open a myprotocol://
URL to (attempt) to open the iPhone
app and have it open Mobile iTunes to
the download of the app in case the
attempt fails
This sounds a reasonable approach to me, but I don't think you'll be able to get it to open mobile itunes as a second resort. I think you'll have to pick one or the other - either redirect to your app or to itunes.
i.e. if you redirect to myprotocol://, and the app isn't on the phone, you won't get a second chance to redirect to itunes.
You could perhaps first redirect to an (iphone optimised) landing page and give the user the option to click through to your app, or to itunes to get the app if they don't have it? But, you'll be relying on the user to do the right thing there. (Edit: though you could set a cookie so that is a first-time thing only?)
In seeking to fix the problem of pop-up, I discovered that Apple had a way around this concern.
Indeed, when you click on this link, if you installed the application, it is rerouted to it; otherwise, you will be redirected to the webpage, without any pop-up.
It also possible to check tab activity by document.hidden property
Possible solution
document.location = 'app://deep-link';
setInterval( function(){
if (!document.hidden) {
document.location = 'https://app.store.link';
}
}, 1000);
But seems like this not works in Safari