mhartington
mhartington

Reputation: 7025

External resource not being loaded by AngularJs

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

Upvotes: 198

Views: 129722

Answers (9)

Guy Sopher
Guy Sopher

Reputation: 4462

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

Upvotes: 271

ecoologic
ecoologic

Reputation: 10420

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.

Upvotes: 0

superluminary
superluminary

Reputation: 49132

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(['**']);
});

Upvotes: 77

GONeale
GONeale

Reputation: 26494

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>

Upvotes: 2

Kajal M. Bambhaniya
Kajal M. Bambhaniya

Reputation: 41

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>

Upvotes: 4

David Boyd
David Boyd

Reputation: 6601

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>

Upvotes: 271

zumek
zumek

Reputation: 608

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!

Upvotes: 21

cagan
cagan

Reputation: 39

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>

Upvotes: 2

roland
roland

Reputation: 7775

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

Upvotes: 1

Related Questions