External resource not being loaded by AngularJs
Asked Answered
G

9

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

Goneness answered 22/1, 2014 at 19:25 Comment(2)
Could you also post your corodva's config.xml file?Respite
Right now I'm still testing in the browser so I haven't even started my phonegap debugging.Goneness
C
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

Catanddog answered 22/3, 2014 at 11:51 Comment(2)
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.Jory
nice, if you can use iframePoliomyelitis
H
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>
Hesione answered 1/7, 2014 at 20:51 Comment(1)
Best answer, more angular spirit and it worked where the others solutions didn't for some reasons. Thanks a lot!Illuminate
P
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(['**']);
});
Phalansterian answered 13/2, 2015 at 14:39 Comment(4)
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)Zima
This is a cleaner, global and secure way to go around this issue.Zachar
"Dialing out" is not a great term to use for someone trying to understand the issue.Poliomyelitis
Thanks @Poliomyelitis - I have added a comment to clarify.Phalansterian
I
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!

Indign answered 6/6, 2014 at 9:41 Comment(0)
U
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>
Unhandled answered 9/9, 2015 at 6:9 Comment(0)
P
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>
Pied answered 21/2, 2014 at 16:26 Comment(0)
T
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>
Tai answered 17/3, 2016 at 2:17 Comment(0)
A
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
Associative answered 22/1, 2014 at 20:2 Comment(7)
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 nothingGoneness
I mean are you sure that {{object.src}} returns a value? It might return undefined.Associative
{{object.src}} is returning a value. Tested it by using a <p></p> and a <a></a>Goneness
There is another alternative: using a directive.Associative
Probably going to have to, already found this and it looks pretty good. videogular.com/#. Thanks for the helpGoneness
So I was able to get the video to load without the use of directives by setting $sceProvider.enabled(false); and was able to load the video in safari, android, and ios but not chrome oddly enough. So I think the issue was with chrome's security settings.Goneness
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/$sceStokowski
A
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.

Assimilate answered 17/1, 2018 at 23:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.