198

Using Angular and Phonegap, I'm trying to load a video that is on a remote server but came across an issue. In my JSON, the URL is entered as a plain HTTP URL.

"src" : "http://www.somesite.com/myvideo.mp4" 

My video template

 <video controls poster="img/poster.png"> <source ng-src="{{object.src}}" type="video/mp4"/> </video> 

All my other data gets loaded but when I look my console, I get this error:

Error: [$interpolate:interr] Can't interpolate: {{object.src}} Error: [$sce:insecurl] Blocked loading resource from url not allowed by $sceDelegate policy. URL 

I tried in adding $compileProvider in my config set up but it did not resolve my issue.

$compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|ftp|mailto|file|tel):/); 

I saw this post about cross domain issues but I'm not sure how to resolve this or what direction I should go in. Any ideas? Any help is appreciated

2
  • 1
    Could you also post your corodva's config.xml file? Commented Jan 22, 2014 at 19:30
  • 1
    Right now I'm still testing in the browser so I haven't even started my phonegap debugging. Commented Jan 22, 2014 at 19:31

9 Answers 9

271

This is the only solution that worked for me:

var app = angular.module('plunker', ['ngSanitize']); app.controller('MainCtrl', function($scope, $sce) { $scope.trustSrc = function(src) { return $sce.trustAsResourceUrl(src); } $scope.movie = {src:"http://www.youtube.com/embed/Lx7ycjC8qjE", title:"Egghead.io AngularJS Binding"}; }); 

Then in an iframe:

<iframe class="youtube-player" type="text/html" width="640" height="385" ng-src="{{trustSrc(movie.src)}}" allowfullscreen frameborder="0"> </iframe> 

http://plnkr.co/edit/tYq22VjwB10WmytQO9Pb?p=preview

Sign up to request clarification or add additional context in comments.

2 Comments

Is this possible without an iFrame? I need to embed a video where the session info determines whether or not the consumer is allowed to see the video. The session information is not carried through the iFrame.
nice, if you can use iframe
271

Another simple solution is to create a filter:

app.filter('trusted', ['$sce', function ($sce) { return function(url) { return $sce.trustAsResourceUrl(url); }; }]); 

Then specify the filter in ng-src:

<video controls poster="img/poster.png"> <source ng-src="{{object.src | trusted}}" type="video/mp4"/> </video> 

1 Comment

Best answer, more angular spirit and it worked where the others solutions didn't for some reasons. Thanks a lot!
77

Whitelist the resource with $sceDelegateProvider

This is caused by a new security policy put in place in Angular 1.2. It makes XSS harder by preventing a hacker from dialling out (i.e. making a request to a foreign URL, potentially containing a payload).

To get around it properly you need to whitelist the domains you want to allow, like this:

angular.module('myApp',['ngSanitize']).config(function($sceDelegateProvider) { $sceDelegateProvider.resourceUrlWhitelist([ // Allow same origin resource loads. 'self', // Allow loading from our assets domain. Notice the difference between * and **. 'http://srv*.assets.example.com/**' ]); // The blacklist overrides the whitelist so the open redirect here is blocked. $sceDelegateProvider.resourceUrlBlacklist([ 'http://myapp.example.com/clickThru**' ]); }); 

This example is lifted from the documentation which you can read here:

https://docs.angularjs.org/api/ng/provider/$sceDelegateProvider

Be sure to include ngSanitize in your app to make this work.

Disabling the feature

If you want to turn off this useful feature, and you're sure your data is secure, you can simply allow **, like so:

angular.module('app').config(function($sceDelegateProvider) { $sceDelegateProvider.resourceUrlWhitelist(['**']); }); 

4 Comments

Note: if resourceUrlWhitelist somehow doesn't work for you, check if you don't have double slash after domain name (easy for this to happen when concatenating stuff from variables and they both have slashes)
This is a cleaner, global and secure way to go around this issue.
"Dialing out" is not a great term to use for someone trying to understand the issue.
Thanks @Ringo - I have added a comment to clarify.
21

Had the same issue here. I needed to bind to Youtube links. What worked for me, as a global solution, was to add the following to my config:

.config(['$routeProvider', '$sceDelegateProvider', function ($routeProvider, $sceDelegateProvider) { $sceDelegateProvider.resourceUrlWhitelist(['self', new RegExp('^(http[s]?):\/\/(w{3}.)?youtube\.com/.+$')]); }]); 

Adding 'self' in there is important - otherwise will fail to bind to any URL. From the angular docs

'self' - The special string, 'self', can be used to match against all URLs of the same domain as the application document using the same protocol.

With that in place, I'm now able to bind directly to any Youtube link.

You'll obviously have to customise the regex to your needs. Hope it helps!

Comments

4

The best and easy solution for solving this issue is pass your data from this function in controller.

$scope.trustSrcurl = function(data) { return $sce.trustAsResourceUrl(data); } 

In html page

<iframe class="youtube-player" type="text/html" width="640" height="385" ng-src="{{trustSrcurl(video.src)}}" allowfullscreen frameborder="0"></iframe> 

Comments

2

I ran into the same problem using Videogular. I was getting the following when using ng-src:

Error: [$interpolate:interr] Can't interpolate: {{url}} Error: [$sce:insecurl] Blocked loading resource from url not allowed by $sceDelegate policy 

I fixed the problem by writing a basic directive:

angular.module('app').directive('dynamicUrl', function () { return { restrict: 'A', link: function postLink(scope, element, attrs) { element.attr('src', scope.content.fullUrl); } }; }); 

The html:

 <div videogular vg-width="200" vg-height="300" vg-theme="config.theme"> <video class='videoPlayer' controls preload='none'> <source dynamic-url src='' type='{{ content.mimeType }}'> </video> </div> 

Comments

2

If anybody is looking for a TypeScript solution:

.ts file (change variables where applicable):

module App.Filters { export class trustedResource { static $inject:string[] = ['$sce']; static filter($sce:ng.ISCEService) { return (value) => { return $sce.trustAsResourceUrl(value) }; } } } filters.filter('trustedResource', App.Filters.trusted.filter); 

Html:

<video controls ng-if="HeaderVideoUrl != null"> <source ng-src="{{HeaderVideoUrl | trustedResource}}" type="video/mp4"/> </video> 

Comments

1

Based on the error message, your problem seems to be related to interpolation (typically your expression {{}}), not to a cross-domain issue. Basically ng-src="{{object.src}}" sucks.

ng-src was designed with img tag in mind IMO. It might not be appropriate for <source>. See http://docs.angularjs.org/api/ng.directive:ngSrc

If you declare <source src="somesite.com/myvideo.mp4"; type="video/mp4"/>, it will be working, right? (note that I remove ng-src in favor of src) If not it must be fixed first.

Then ensure that {{object.src}} returns the expected value (outside of <video>):

<span>{{object.src}}</span> <video>...</video> 

If it returns the expected value, the following statement should be working:

<source src="{{object.src}}"; type="video/mp4"/> //src instead of ng-src 

7 Comments

Using just src and hard coding the url, everything work as I want. As soon as I use {{object.src}} though the src attribute isn't even passed thought. I went ahead and even remove the source tag and put the src inline with the video tag but still nothing
I mean are you sure that {{object.src}} returns a value? It might return undefined.
{{object.src}} is returning a value. Tested it by using a <p></p> and a <a></a>
Probably going to have to, already found this and it looks pretty good. videogular.com/#. Thanks for the help
This has nothing to do with ng-src being broken (it isn't broken). It has to do with AngularJS's security policy: docs.angularjs.org/api/ng/service/$sce
|
0

I had this error in tests, the directive templateUrl wasn't trusted, but only for the spec, so I added the template directory:

beforeEach(angular.mock.module('app.templates')); 

My main directory is app.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.