From 70cbe91776d1de10f2767c6a5ad5912fd705bdd3 Mon Sep 17 00:00:00 2001 From: leonklingele Date: Mon, 16 Mar 2020 06:46:08 +0900 Subject: Migrate to a good Content Security Policy (#1023) So attacks such as XSS (see [0]) will no longer be of an issue. [0]: https://github.com/omarroth/invidious/issues/1022 --- assets/js/handlers.js | 141 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 assets/js/handlers.js (limited to 'assets/js/handlers.js') diff --git a/assets/js/handlers.js b/assets/js/handlers.js new file mode 100644 index 00000000..68ba9f4f --- /dev/null +++ b/assets/js/handlers.js @@ -0,0 +1,141 @@ +'use strict'; + +(function() { + var n2a = function(n) { return Array.prototype.slice.call(n); }; + + var video_player = document.getElementById('player'); + if (video_player) { + video_player.onmouseenter = function() { video_player['data-title'] = video_player['title']; video_player['title'] = ''; }; + video_player.onmouseleave = function() { video_player['title'] = video_player['data-title']; video_player['data-title'] = ''; }; + video_player.oncontextmenu = function() { video_player['title'] = video_player['data-title']; }; + } + + // For dynamically inserted elements + document.addEventListener('click', function(e) { + if (!e || !e.target) { return; } + e = e.target; + var handler_name = e.getAttribute('data-onclick'); + switch (handler_name) { + case 'jump_to_time': + var time = e.getAttribute('data-jump-time'); + player.currentTime(time); + break; + case 'get_youtube_replies': + var load_more = e.getAttribute('data-load-more') !== null; + get_youtube_replies(e, load_more); + break; + default: + break; + } + }); + + n2a(document.querySelectorAll('[data-mouse="switch_classes"]')).forEach(function(e) { + var classes = e.getAttribute('data-switch-classes').split(','); + var ec = classes[0]; + var lc = classes[1]; + var onoff = function(on, off) { + var cs = e.getAttribute('class'); + cs = cs.split(off).join(on); + e.setAttribute('class', cs); + }; + e.onmouseenter = function() { onoff(ec, lc); }; + e.onmouseleave = function() { onoff(lc, ec); }; + }); + + n2a(document.querySelectorAll('[data-onsubmit="return_false"]')).forEach(function(e) { + e.onsubmit = function() { return false; }; + }); + + n2a(document.querySelectorAll('[data-onclick="toggle_parent"]')).forEach(function(e) { + e.onclick = function() { toggle_parent(e); }; + }); + n2a(document.querySelectorAll('[data-onclick="mark_watched"]')).forEach(function(e) { + e.onclick = function() { mark_watched(e); }; + }); + n2a(document.querySelectorAll('[data-onclick="mark_unwatched"]')).forEach(function(e) { + e.onclick = function() { mark_unwatched(e); }; + }); + n2a(document.querySelectorAll('[data-onclick="add_playlist_item"]')).forEach(function(e) { + e.onclick = function() { add_playlist_item(e); }; + }); + n2a(document.querySelectorAll('[data-onclick="remove_playlist_item"]')).forEach(function(e) { + e.onclick = function() { remove_playlist_item(e); }; + }); + n2a(document.querySelectorAll('[data-onclick="revoke_token"]')).forEach(function(e) { + e.onclick = function() { revoke_token(e); }; + }); + n2a(document.querySelectorAll('[data-onclick="remove_subscription"]')).forEach(function(e) { + e.onclick = function() { remove_subscription(e); }; + }); + n2a(document.querySelectorAll('[data-onclick="notification_requestPermission"]')).forEach(function(e) { + e.onclick = function() { Notification.requestPermission(); }; + }); + + n2a(document.querySelectorAll('[data-onrange="update_volume_value"]')).forEach(function(e) { + var cb = function() { update_volume_value(e); } + e.oninput = cb; + e.onchange = cb; + }); + + function update_volume_value(element) { + document.getElementById('volume-value').innerText = element.value; + } + + function revoke_token(target) { + var row = target.parentNode.parentNode.parentNode.parentNode.parentNode; + row.style.display = 'none'; + var count = document.getElementById('count'); + count.innerText = count.innerText - 1; + + var referer = window.encodeURIComponent(document.location.href); + var url = '/token_ajax?action_revoke_token=1&redirect=false' + + '&referer=' + referer + + '&session=' + target.getAttribute('data-session'); + var xhr = new XMLHttpRequest(); + xhr.responseType = 'json'; + xhr.timeout = 10000; + xhr.open('POST', url, true); + xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); + + xhr.onreadystatechange = function() { + if (xhr.readyState == 4) { + if (xhr.status != 200) { + count.innerText = parseInt(count.innerText) + 1; + row.style.display = ''; + } + } + } + + var csrf_token = target.parentNode.querySelector('input[name="csrf_token"]').value; + xhr.send('csrf_token=' + csrf_token); + } + + function remove_subscription(target) { + var row = target.parentNode.parentNode.parentNode.parentNode.parentNode; + row.style.display = 'none'; + var count = document.getElementById('count'); + count.innerText = count.innerText - 1; + + var referer = window.encodeURIComponent(document.location.href); + var url = '/subscription_ajax?action_remove_subscriptions=1&redirect=false' + + '&referer=' + referer + + '&c=' + target.getAttribute('data-ucid'); + var xhr = new XMLHttpRequest(); + xhr.responseType = 'json'; + xhr.timeout = 10000; + xhr.open('POST', url, true); + xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); + + xhr.onreadystatechange = function() { + if (xhr.readyState == 4) { + if (xhr.status != 200) { + count.innerText = parseInt(count.innerText) + 1; + row.style.display = ''; + } + } + } + + var csrf_token = target.parentNode.querySelector('input[name="csrf_token"]').value; + xhr.send('csrf_token=' + csrf_token); + } +})(); -- cgit v1.2.3 From bd7950b7579426d3acdf881262e802678e2c336d Mon Sep 17 00:00:00 2001 From: Omar Roth Date: Sun, 15 Mar 2020 18:52:49 -0400 Subject: Add toggle_parent to dynamic handlers --- assets/js/handlers.js | 86 +++++++++++++++++++++++++-------------------------- 1 file changed, 43 insertions(+), 43 deletions(-) (limited to 'assets/js/handlers.js') diff --git a/assets/js/handlers.js b/assets/js/handlers.js index 68ba9f4f..77062ca6 100644 --- a/assets/js/handlers.js +++ b/assets/js/handlers.js @@ -1,78 +1,78 @@ 'use strict'; -(function() { - var n2a = function(n) { return Array.prototype.slice.call(n); }; +(function () { + var n2a = function (n) { return Array.prototype.slice.call(n); }; var video_player = document.getElementById('player'); if (video_player) { - video_player.onmouseenter = function() { video_player['data-title'] = video_player['title']; video_player['title'] = ''; }; - video_player.onmouseleave = function() { video_player['title'] = video_player['data-title']; video_player['data-title'] = ''; }; - video_player.oncontextmenu = function() { video_player['title'] = video_player['data-title']; }; + video_player.onmouseenter = function () { video_player['data-title'] = video_player['title']; video_player['title'] = ''; }; + video_player.onmouseleave = function () { video_player['title'] = video_player['data-title']; video_player['data-title'] = ''; }; + video_player.oncontextmenu = function () { video_player['title'] = video_player['data-title']; }; } // For dynamically inserted elements - document.addEventListener('click', function(e) { + document.addEventListener('click', function (e) { if (!e || !e.target) { return; } e = e.target; var handler_name = e.getAttribute('data-onclick'); switch (handler_name) { - case 'jump_to_time': - var time = e.getAttribute('data-jump-time'); - player.currentTime(time); - break; - case 'get_youtube_replies': - var load_more = e.getAttribute('data-load-more') !== null; - get_youtube_replies(e, load_more); - break; - default: - break; + case 'jump_to_time': + var time = e.getAttribute('data-jump-time'); + player.currentTime(time); + break; + case 'get_youtube_replies': + var load_more = e.getAttribute('data-load-more') !== null; + get_youtube_replies(e, load_more); + break; + case 'toggle_parent': + toggle_parent(e); + break; + default: + break; } }); - n2a(document.querySelectorAll('[data-mouse="switch_classes"]')).forEach(function(e) { + n2a(document.querySelectorAll('[data-mouse="switch_classes"]')).forEach(function (e) { var classes = e.getAttribute('data-switch-classes').split(','); var ec = classes[0]; var lc = classes[1]; - var onoff = function(on, off) { + var onoff = function (on, off) { var cs = e.getAttribute('class'); cs = cs.split(off).join(on); e.setAttribute('class', cs); }; - e.onmouseenter = function() { onoff(ec, lc); }; - e.onmouseleave = function() { onoff(lc, ec); }; + e.onmouseenter = function () { onoff(ec, lc); }; + e.onmouseleave = function () { onoff(lc, ec); }; }); - n2a(document.querySelectorAll('[data-onsubmit="return_false"]')).forEach(function(e) { - e.onsubmit = function() { return false; }; + n2a(document.querySelectorAll('[data-onsubmit="return_false"]')).forEach(function (e) { + e.onsubmit = function () { return false; }; }); - n2a(document.querySelectorAll('[data-onclick="toggle_parent"]')).forEach(function(e) { - e.onclick = function() { toggle_parent(e); }; + n2a(document.querySelectorAll('[data-onclick="mark_watched"]')).forEach(function (e) { + e.onclick = function () { mark_watched(e); }; }); - n2a(document.querySelectorAll('[data-onclick="mark_watched"]')).forEach(function(e) { - e.onclick = function() { mark_watched(e); }; + n2a(document.querySelectorAll('[data-onclick="mark_unwatched"]')).forEach(function (e) { + e.onclick = function () { mark_unwatched(e); }; }); - n2a(document.querySelectorAll('[data-onclick="mark_unwatched"]')).forEach(function(e) { - e.onclick = function() { mark_unwatched(e); }; + n2a(document.querySelectorAll('[data-onclick="add_playlist_item"]')).forEach(function (e) { + e.onclick = function () { add_playlist_item(e); }; }); - n2a(document.querySelectorAll('[data-onclick="add_playlist_item"]')).forEach(function(e) { - e.onclick = function() { add_playlist_item(e); }; + n2a(document.querySelectorAll('[data-onclick="remove_playlist_item"]')).forEach(function (e) { + e.onclick = function () { remove_playlist_item(e); }; }); - n2a(document.querySelectorAll('[data-onclick="remove_playlist_item"]')).forEach(function(e) { - e.onclick = function() { remove_playlist_item(e); }; + n2a(document.querySelectorAll('[data-onclick="revoke_token"]')).forEach(function (e) { + e.onclick = function () { revoke_token(e); }; }); - n2a(document.querySelectorAll('[data-onclick="revoke_token"]')).forEach(function(e) { - e.onclick = function() { revoke_token(e); }; + n2a(document.querySelectorAll('[data-onclick="remove_subscription"]')).forEach(function (e) { + e.onclick = function () { remove_subscription(e); }; }); - n2a(document.querySelectorAll('[data-onclick="remove_subscription"]')).forEach(function(e) { - e.onclick = function() { remove_subscription(e); }; - }); - n2a(document.querySelectorAll('[data-onclick="notification_requestPermission"]')).forEach(function(e) { - e.onclick = function() { Notification.requestPermission(); }; + n2a(document.querySelectorAll('[data-onclick="notification_requestPermission"]')).forEach(function (e) { + e.onclick = function () { Notification.requestPermission(); }; }); - n2a(document.querySelectorAll('[data-onrange="update_volume_value"]')).forEach(function(e) { - var cb = function() { update_volume_value(e); } + n2a(document.querySelectorAll('[data-onrange="update_volume_value"]')).forEach(function (e) { + var cb = function () { update_volume_value(e); } e.oninput = cb; e.onchange = cb; }); @@ -97,7 +97,7 @@ xhr.open('POST', url, true); xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); - xhr.onreadystatechange = function() { + xhr.onreadystatechange = function () { if (xhr.readyState == 4) { if (xhr.status != 200) { count.innerText = parseInt(count.innerText) + 1; @@ -126,7 +126,7 @@ xhr.open('POST', url, true); xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); - xhr.onreadystatechange = function() { + xhr.onreadystatechange = function () { if (xhr.readyState == 4) { if (xhr.status != 200) { count.innerText = parseInt(count.innerText) + 1; -- cgit v1.2.3 From 0e58d99f4e17618d67fb78d79b10a11fb0b0811d Mon Sep 17 00:00:00 2001 From: Omar Roth Date: Fri, 27 Mar 2020 09:47:46 -0500 Subject: Fix player mouseover events --- assets/js/handlers.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'assets/js/handlers.js') diff --git a/assets/js/handlers.js b/assets/js/handlers.js index 77062ca6..7ecb5a02 100644 --- a/assets/js/handlers.js +++ b/assets/js/handlers.js @@ -3,7 +3,7 @@ (function () { var n2a = function (n) { return Array.prototype.slice.call(n); }; - var video_player = document.getElementById('player'); + var video_player = document.getElementById('player_html5_api'); if (video_player) { video_player.onmouseenter = function () { video_player['data-title'] = video_player['title']; video_player['title'] = ''; }; video_player.onmouseleave = function () { video_player['title'] = video_player['data-title']; video_player['data-title'] = ''; }; -- cgit v1.2.3 From 3f97bebd6956ee1b111a2c23057a4facd6cbef0a Mon Sep 17 00:00:00 2001 From: Omar Roth Date: Tue, 7 Apr 2020 13:34:40 -0500 Subject: Support adding video to playlist from watch page --- assets/js/handlers.js | 3 +++ assets/js/playlist_widget.js | 24 ++++++++++++++++++++++++ src/invidious.cr | 6 ++---- src/invidious/helpers/helpers.cr | 4 +--- src/invidious/views/add_playlist_items.ecr | 2 +- src/invidious/views/playlist.ecr | 2 +- src/invidious/views/watch.ecr | 25 +++++++++++++++++++++++++ 7 files changed, 57 insertions(+), 9 deletions(-) (limited to 'assets/js/handlers.js') diff --git a/assets/js/handlers.js b/assets/js/handlers.js index 7ecb5a02..b3da8d9b 100644 --- a/assets/js/handlers.js +++ b/assets/js/handlers.js @@ -55,6 +55,9 @@ n2a(document.querySelectorAll('[data-onclick="mark_unwatched"]')).forEach(function (e) { e.onclick = function () { mark_unwatched(e); }; }); + n2a(document.querySelectorAll('[data-onclick="add_playlist_video"]')).forEach(function (e) { + e.onclick = function () { add_playlist_video(e); }; + }); n2a(document.querySelectorAll('[data-onclick="add_playlist_item"]')).forEach(function (e) { e.onclick = function () { add_playlist_item(e); }; }); diff --git a/assets/js/playlist_widget.js b/assets/js/playlist_widget.js index a29d7ef0..0ec27859 100644 --- a/assets/js/playlist_widget.js +++ b/assets/js/playlist_widget.js @@ -1,5 +1,29 @@ var playlist_data = JSON.parse(document.getElementById('playlist_data').innerHTML); +function add_playlist_video(target) { + var select = target.parentNode.children[0].children[1]; + var option = select.children[select.selectedIndex]; + + var url = '/playlist_ajax?action_add_video=1&redirect=false' + + '&video_id=' + target.getAttribute('data-id') + + '&playlist_id=' + option.getAttribute('data-plid'); + var xhr = new XMLHttpRequest(); + xhr.responseType = 'json'; + xhr.timeout = 10000; + xhr.open('POST', url, true); + xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); + + xhr.onreadystatechange = function () { + if (xhr.readyState == 4) { + if (xhr.status == 200) { + option.innerText = '✓' + option.innerText; + } + } + } + + xhr.send('csrf_token=' + playlist_data.csrf_token); +} + function add_playlist_item(target) { var tile = target.parentNode.parentNode.parentNode.parentNode.parentNode; tile.style.display = 'none'; diff --git a/src/invidious.cr b/src/invidious.cr index 74d0c79f..1448c502 100644 --- a/src/invidious.cr +++ b/src/invidious.cr @@ -3131,9 +3131,7 @@ get "/feed/channel/:ucid" do |env| rss = YT_POOL.client &.get("/feeds/videos.xml?channel_id=#{channel.ucid}").body rss = XML.parse_html(rss) - videos = [] of SearchVideo - - rss.xpath_nodes("//feed/entry").each do |entry| + videos = rss.xpath_nodes("//feed/entry").map do |entry| video_id = entry.xpath_node("videoid").not_nil!.content title = entry.xpath_node("title").not_nil!.content @@ -3145,7 +3143,7 @@ get "/feed/channel/:ucid" do |env| description_html = entry.xpath_node("group/description").not_nil!.to_s views = entry.xpath_node("group/community/statistics").not_nil!.["views"].to_i64 - videos << SearchVideo.new( + SearchVideo.new( title: title, id: video_id, author: author, diff --git a/src/invidious/helpers/helpers.cr b/src/invidious/helpers/helpers.cr index 2341d3be..e168c55e 100644 --- a/src/invidious/helpers/helpers.cr +++ b/src/invidious/helpers/helpers.cr @@ -732,9 +732,7 @@ def cache_annotation(db, id, annotations) body = XML.parse(annotations) nodeset = body.xpath_nodes(%q(/document/annotations/annotation)) - if nodeset == 0 - return - end + return if nodeset == 0 has_legacy_annotations = false nodeset.each do |node| diff --git a/src/invidious/views/add_playlist_items.ecr b/src/invidious/views/add_playlist_items.ecr index 07295c1a..09eacbc8 100644 --- a/src/invidious/views/add_playlist_items.ecr +++ b/src/invidious/views/add_playlist_items.ecr @@ -27,7 +27,7 @@ }.to_pretty_json %> - +
<% videos.each_slice(4) do |slice| %> diff --git a/src/invidious/views/playlist.ecr b/src/invidious/views/playlist.ecr index ccda94d9..7316af14 100644 --- a/src/invidious/views/playlist.ecr +++ b/src/invidious/views/playlist.ecr @@ -76,7 +76,7 @@ }.to_pretty_json %> - + <% end %>
diff --git a/src/invidious/views/watch.ecr b/src/invidious/views/watch.ecr index 2a99dd5b..e43282cb 100644 --- a/src/invidious/views/watch.ecr +++ b/src/invidious/views/watch.ecr @@ -101,6 +101,31 @@ <% end %>

+ <% if user %> +
+
+ + +
+ + +
+ + + <% end %> + <% if CONFIG.dmca_content.includes?(video.id) || CONFIG.disabled?("downloads") %>

<%= translate(locale, "Download is disabled.") %>

<% else %> -- cgit v1.2.3