Почему этот фильтр не выводит IFRAME?

Я пытаюсь автоматически вставлять видео на YouTube для пользовательского контента. Мой фильтр ищет ссылки в целом, а затем проверяет их, чтобы убедиться, что они являются действительными видео YouTube. Если они есть, он должен встроить видео со стандартным кодом iframe. Если нет, то это просто ссылка. Однако фильтр вообще не выводит код iframe. Я предполагаю, что у этого есть что-то, чтобы предотвратить атаки межсайтовых сценариев, но я понятия не имею, как я могу обойти это.

function ytVidId(url) {
  var p = /^(?:https?:\/\/)?(?:www\.)?(?:youtu\.be\/|youtube\.com\/(?:embed\/|v\/|watch\?v=|watch\?.+&v=))((\w|-){11})(?:\S+)?$/;
  return (url.match(p)) ? RegExp.$1 : false;
}

myapp.filter('parseUrls', function() {
    //with protocol
    var urlPattern = /(http|ftp|https):\/\/[\w-]+(\.[\w-]+)+([\w.,@?^=%&:\/~+#-]*[\w@?^=%&\/~+#-])?/gi;
    return function(text, target, otherProp) {        
        if (text == null) {
            return "";
        }
        angular.forEach(text.match(urlPattern), function(url) {
            if(ytVidId(url)){
                text = text.replace(url, '<div class="video-container"><iframe src="//www.youtube.com/embed/'+ ytVidId(url) +'" frameborder="0" width="560" height="315"></iframe></div>');
            }else{
                text = text.replace(url, '<a target="' + target + '" href='+ url + '>' + url + '</a>');
            }

        });
        return text;        
    };
})

В использовании:

<span ng-bind-html="p.body | noHTML | newlines | parseUrls:'_blank'"></span>

person E-Madd    schedule 27.06.2014    source источник


Ответы (1)


Angular требует, чтобы вы передавали HTML через поставщика 'sce' (строгое контекстное экранирование).

Документация по поставщику SCE здесь

Так что это будет выглядеть примерно так (не проверено, но теоретически так и должно быть)

function ytVidId(url) {
  var p = /^(?:https?:\/\/)?(?:www\.)?(?:youtu\.be\/|youtube\.com\/(?:embed\/|v\/|watch\?v=|watch\?.+&v=))((\w|-){11})(?:\S+)?$/;
  return (url.match(p)) ? RegExp.$1 : false;
}    

myapp.filter('parseUrls', ['$sce', function() {
    //with protocol
    var urlPattern = /(http|ftp|https):\/\/[\w-]+(\.[\w-]+)+([\w.,@?^=%&amp;:\/~+#-]*[\w@?^=%&amp;\/~+#-])?/gi;
    return function(text, target, otherProp) {        
        if (text == null) {
            return "";
        }
        angular.forEach(text.match(urlPattern), function(url) {
            if(ytVidId(url)){
                text = text.replace(url, $sce.trustAs('html', '<div class="video-container"><iframe src="//www.youtube.com/embed/'+ ytVidId(url) +'" frameborder="0" width="560" height="315"></iframe></div>'));
            }else{
                text = text.replace(url, $sce.trustAs('html', '<a target="' + target + '" href='+ url + '>' + url + '</a>'));
            }    

        });
        return text;        
    };
}])`
person Roq Savage    schedule 27.06.2014
comment
Это было довольно близко. Я действительно обнаружил, что конвейер в этом фильтре работает... .filter('unsafe', function($sce) { return function(val) { return $sce.trustAsHtml(val); }; }) - person E-Madd; 27.06.2014