Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Fijxu
2025-05-20 15:14:56 -04:00
44 changed files with 529 additions and 428 deletions

View File

@@ -91,7 +91,7 @@ module Invidious::Database::Playlists
end
# -------------------
# Salect
# Select
# -------------------
def select(*, id : String) : InvidiousPlaylist?
@@ -113,7 +113,7 @@ module Invidious::Database::Playlists
end
# -------------------
# Salect (filtered)
# Select (filtered)
# -------------------
def select_like_iv(email : String) : Array(InvidiousPlaylist)
@@ -213,7 +213,7 @@ module Invidious::Database::PlaylistVideos
end
# -------------------
# Salect
# Select
# -------------------
def select(plid : String, index : VideoIndex, offset, limit = 100) : Array(PlaylistVideo)

View File

@@ -262,7 +262,7 @@ def get_referer(env, fallback = "/", unroll = true)
end
referer = referer.request_target
referer = "/" + referer.gsub(/[^\/?@&%=\-_.:,*0-9a-zA-Z]/, "").lstrip("/\\")
referer = "/" + referer.gsub(/[^\/?@&%=\-_.:,*0-9a-zA-Z+]/, "").lstrip("/\\")
if referer == env.request.path
referer = fallback

View File

@@ -97,7 +97,7 @@ module Invidious::Routes::BeforeAll
"font-src 'self' data:",
"connect-src 'self'" + extra_connect_csp,
"manifest-src 'self'",
"media-src 'self' blob:" + extra_media_csp,
"media-src 'self' blob:",
"child-src 'self' blob:",
"frame-src 'self'",
"frame-ancestors " + frame_ancestors,
@@ -162,6 +162,21 @@ module Invidious::Routes::BeforeAll
preferences.locale = locale
env.set "preferences", preferences
# Allow media resources to be loaded from google servers
# TODO: check if *.youtube.com can be removed
#
# `!preferences.local` has to be checked after setting and
# reading `preferences` from the "PREFS" cookie and
# saved user preferences from the database, otherwise
# `https://*.googlevideo.com:443 https://*.youtube.com:443`
# will not be set in the CSP header if
# `default_user_preferences.local` is set to true on the
# configuration file, causing preference “Proxy Videos”
# not to work while having it disabled and using medium quality.
if CONFIG.disabled?("local") || !preferences.local
env.response.headers["Content-Security-Policy"] = env.response.headers["Content-Security-Policy"].gsub("media-src", "media-src https://*.googlevideo.com:443 https://*.youtube.com:443")
end
current_page = env.request.path
if env.request.query
query = HTTP::Params.parse(env.request.query.not_nil!)

View File

@@ -21,9 +21,6 @@ module Invidious::Routes::Login
account_type = env.params.query["type"]?
account_type ||= "invidious"
captcha_type = env.params.query["captcha"]?
captcha_type ||= "image"
templated "user/login"
end
@@ -88,34 +85,14 @@ module Invidious::Routes::Login
password = password.byte_slice(0, 55)
if CONFIG.captcha_enabled
captcha_type = env.params.body["captcha_type"]?
answer = env.params.body["answer"]?
change_type = env.params.body["change_type"]?
if !captcha_type || change_type
if change_type
captcha_type = change_type
end
captcha_type ||= "image"
account_type = "invidious"
if captcha_type == "image"
captcha = Invidious::User::Captcha.generate_image(HMAC_KEY)
else
captcha = Invidious::User::Captcha.generate_text(HMAC_KEY)
end
return templated "user/login"
end
account_type = "invidious"
captcha = Invidious::User::Captcha.generate_image(HMAC_KEY)
tokens = env.params.body.select { |k, _| k.match(/^token\[\d+\]$/) }.map { |_, v| v }
answer ||= ""
captcha_type ||= "image"
case captcha_type
when "image"
if answer
answer = answer.lstrip('0')
answer = OpenSSL::HMAC.hexdigest(:sha256, HMAC_KEY, answer)
@@ -124,27 +101,8 @@ module Invidious::Routes::Login
rescue ex
return error_template(400, ex)
end
else # "text"
answer = Digest::MD5.hexdigest(answer.downcase.strip)
if tokens.empty?
return error_template(500, "Erroneous CAPTCHA")
end
found_valid_captcha = false
error_exception = Exception.new
tokens.each do |tok|
begin
validate_request(tok, answer, env.request, HMAC_KEY, locale)
found_valid_captcha = true
rescue ex
error_exception = ex
end
end
if !found_valid_captcha
return error_template(500, error_exception)
end
else
return templated "user/login"
end
end

View File

@@ -58,7 +58,11 @@ module Invidious::Routes::Search
end
begin
items = query.process
if user
items = query.process(user.as(User))
else
items = query.process
end
rescue ex : ChannelSearchException
return error_template(404, "Unable to find channel with id of '#{HTML.escape(ex.channel)}'. Are you sure that's an actual channel id? It should look like 'UC4QobU6STFB0P71PMvOGN5A'.")
rescue ex

View File

@@ -4,8 +4,6 @@ struct Invidious::User
module Captcha
extend self
private TEXTCAPTCHA_URL = URI.parse("https://textcaptcha.com")
def generate_image(key)
second = Random::Secure.rand(12)
second_angle = second * 30
@@ -60,19 +58,5 @@ struct Invidious::User
tokens: {generate_response(answer, {":login"}, key, use_nonce: true)},
}
end
def generate_text(key)
response = make_client(TEXTCAPTCHA_URL, &.get("/github.com/iv.org/invidious.json").body)
response = JSON.parse(response)
tokens = response["a"].as_a.map do |answer|
generate_response(answer.as_s, {":login"}, key, use_nonce: true)
end
return {
question: response["q"].as_s,
tokens: tokens,
}
end
end
end

View File

@@ -11,91 +11,7 @@
<table id="jslicense-labels1">
<tr>
<td>
<a href="/<%= JS_PATH %>/_helpers.js?v=<%= ASSET_COMMIT %>">_helpers.js</a>
</td>
<td>
<a href="https://www.gnu.org/licenses/agpl-3.0.html">AGPL-3.0</a>
</td>
<td>
<a href="/<%= JS_PATH %>/_helpers.js?v=<%= ASSET_COMMIT %>"><%= translate(locale, "source") %></a>
</td>
</tr>
<tr>
<td>
<a href="/<%= JS_PATH %>/handlers.js?v=<%= ASSET_COMMIT %>">handlers.js</a>
</td>
<td>
<a href="https://www.gnu.org/licenses/agpl-3.0.html">AGPL-3.0</a>
</td>
<td>
<a href="/<%= JS_PATH %>/handlers.js?v=<%= ASSET_COMMIT %>"><%= translate(locale, "source") %></a>
</td>
</tr>
<tr>
<td>
<a href="/<%= JS_PATH %>/community.js?v=<%= ASSET_COMMIT %>">community.js</a>
</td>
<td>
<a href="https://www.gnu.org/licenses/agpl-3.0.html">AGPL-3.0</a>
</td>
<td>
<a href="/<%= JS_PATH %>/community.js?v=<%= ASSET_COMMIT %>"><%= translate(locale, "source") %></a>
</td>
</tr>
<tr>
<td>
<a href="/<%= JS_PATH %>/embed.js?v=<%= ASSET_COMMIT %>">embed.js</a>
</td>
<td>
<a href="https://www.gnu.org/licenses/agpl-3.0.html">AGPL-3.0</a>
</td>
<td>
<a href="/<%= JS_PATH %>/embed.js?v=<%= ASSET_COMMIT %>"><%= translate(locale, "source") %></a>
</td>
</tr>
<tr>
<td>
<a href="/<%= JS_PATH %>/notifications.js?v=<%= ASSET_COMMIT %>">notifications.js</a>
</td>
<td>
<a href="https://www.gnu.org/licenses/agpl-3.0.html">AGPL-3.0</a>
</td>
<td>
<a href="/<%= JS_PATH %>/notifications.js?v=<%= ASSET_COMMIT %>"><%= translate(locale, "source") %></a>
</td>
</tr>
<tr>
<td>
<a href="/<%= JS_PATH %>/player.js?v=<%= ASSET_COMMIT %>">player.js</a>
</td>
<td>
<a href="https://www.gnu.org/licenses/agpl-3.0.html">AGPL-3.0</a>
</td>
<td>
<a href="/<%= JS_PATH %>/player.js?v=<%= ASSET_COMMIT %>"><%= translate(locale, "source") %></a>
</td>
</tr>
<tr>
<td>
<a href="/<%= JS_PATH %>/silvermine-videojs-quality-selector.min.js?v=<%= ASSET_COMMIT %>">silvermine-videojs-quality-selector.min.js</a>
<a href="/js/silvermine-videojs-quality-selector.min.js?v=<%= ASSET_COMMIT %>">silvermine-videojs-quality-selector.min.js</a>
</td>
<td>
@@ -121,34 +37,6 @@
</td>
</tr>
<tr>
<td>
<a href="/<%= JS_PATH %>/subscribe_widget.js?v=<%= ASSET_COMMIT %>">subscribe_widget.js</a>
</td>
<td>
<a href="https://www.gnu.org/licenses/agpl-3.0.html">AGPL-3.0</a>
</td>
<td>
<a href="/<%= JS_PATH %>/subscribe_widget.js?v=<%= ASSET_COMMIT %>"><%= translate(locale, "source") %></a>
</td>
</tr>
<tr>
<td>
<a href="/<%= JS_PATH %>/themes.js?v=<%= ASSET_COMMIT %>">themes.js</a>
</td>
<td>
<a href="https://www.gnu.org/licenses/agpl-3.0.html">AGPL-3.0</a>
</td>
<td>
<a href="/<%= JS_PATH %>/themes.js?v=<%= ASSET_COMMIT %>"><%= translate(locale, "source") %></a>
</td>
</tr>
<tr>
<td>
<a href="/videojs/videojs-contrib-quality-levels/videojs-contrib-quality-levels.js?v=<%= ASSET_COMMIT %>">videojs-contrib-quality-levels.js</a>
@@ -289,19 +177,9 @@
</td>
</tr>
<tr>
<td>
<a href="/<%= JS_PATH %>/watch.js?v=<%= ASSET_COMMIT %>">watch.js</a>
</td>
<td>
<a href="https://www.gnu.org/licenses/agpl-3.0.html">AGPL-3.0</a>
</td>
<td>
<a href="/<%= JS_PATH %>/watch.js?v=<%= ASSET_COMMIT %>"><%= translate(locale, "source") %></a>
</td>
</tr>
<%- {% for row in run("../../../scripts/generate_js_licenses.cr").stringify.split('\n') %} %>
<%-= {{row.id}} -%>
<% {% end %} -%>
</table>
</body>
</html>

View File

@@ -25,44 +25,17 @@
<% end %>
<% if captcha %>
<% case captcha_type when %>
<% when "image" %>
<% captcha = captcha.not_nil! %>
<img style="width:50%" src='<%= captcha[:question] %>'/>
<% captcha[:tokens].each_with_index do |token, i| %>
<input type="hidden" name="token[<%= i %>]" value="<%= HTML.escape(token) %>">
<% end %>
<input type="hidden" name="captcha_type" value="image">
<label for="answer"><%= translate(locale, "Time (h:mm:ss):") %></label>
<input type="text" name="answer" type="text" placeholder="h:mm:ss">
<% else # "text" %>
<% captcha = captcha.not_nil! %>
<% captcha[:tokens].each_with_index do |token, i| %>
<input type="hidden" name="token[<%= i %>]" value="<%= HTML.escape(token) %>">
<% end %>
<input type="hidden" name="captcha_type" value="text">
<label for="answer"><%= captcha[:question] %></label>
<input type="text" name="answer" type="text" placeholder="<%= translate(locale, "Answer") %>">
<% captcha = captcha.not_nil! %>
<img style="width:50%" src='<%= captcha[:question] %>'/>
<% captcha[:tokens].each_with_index do |token, i| %>
<input type="hidden" name="token[<%= i %>]" value="<%= HTML.escape(token) %>">
<% end %>
<label for="answer"><%= translate(locale, "Time (h:mm:ss):") %></label>
<input type="text" name="answer" type="text" placeholder="h:mm:ss">
<button type="submit" name="action" value="signin" class="pure-button pure-button-primary">
<%= translate(locale, "Register") %>
</button>
<% case captcha_type when %>
<% when "image" %>
<label>
<button type="submit" name="change_type" class="pure-button pure-button-primary" value="text">
<%= translate(locale, "Text CAPTCHA") %>
</button>
</label>
<% else # "text" %>
<label>
<button type="submit" name="change_type" class="pure-button pure-button-primary" value="image">
<%= translate(locale, "Image CAPTCHA") %>
</button>
</label>
<% end %>
<% else %>
<button type="submit" name="action" value="signin" class="pure-button pure-button-primary">
<%= translate(locale, "Sign In") %>/<%= translate(locale, "Register") %>

View File

@@ -132,7 +132,7 @@ private module Parsers
badges = VideoBadges::None
item_contents["badges"]?.try &.as_a.each do |badge|
b = badge["metadataBadgeRenderer"]
case b["label"].as_s
case b["label"]?.try &.as_s
when "LIVE"
badges |= VideoBadges::LiveNow
when "New"