mirror of
https://github.com/iv-org/invidious.git
synced 2026-06-11 19:23:24 +05:30
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 63cb6db1a3 |
@@ -86,7 +86,7 @@ jobs:
|
|||||||
|
|
||||||
# https://github.com/marketplace/actions/docker-manifest-create-action
|
# https://github.com/marketplace/actions/docker-manifest-create-action
|
||||||
- name: Create and push manifest
|
- name: Create and push manifest
|
||||||
uses: int128/docker-manifest-create-action@v2.22.0
|
uses: int128/docker-manifest-create-action@v2.21.0
|
||||||
with:
|
with:
|
||||||
push: true
|
push: true
|
||||||
tags: quay.io/invidious/invidious:master
|
tags: quay.io/invidious/invidious:master
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ jobs:
|
|||||||
|
|
||||||
# https://github.com/marketplace/actions/docker-manifest-create-action
|
# https://github.com/marketplace/actions/docker-manifest-create-action
|
||||||
- name: Create and push manifest
|
- name: Create and push manifest
|
||||||
uses: int128/docker-manifest-create-action@v2.22.0
|
uses: int128/docker-manifest-create-action@v2.21.0
|
||||||
with:
|
with:
|
||||||
push: true
|
push: true
|
||||||
tags: quay.io/invidious/invidious:latest
|
tags: quay.io/invidious/invidious:latest
|
||||||
|
|||||||
@@ -151,26 +151,6 @@ db:
|
|||||||
##
|
##
|
||||||
domain:
|
domain:
|
||||||
|
|
||||||
##
|
|
||||||
## List of alternative domains where the invidious instance is being served.
|
|
||||||
## This needs to be set in order to be able to login and update user preferences
|
|
||||||
## when using a domain that is not the same as the `domain` configuration,
|
|
||||||
## like a .`onion` address, `.i2p` address, `.b32.i2p` address, etc.
|
|
||||||
##
|
|
||||||
## It will detect the alternative domain trough the `X-Forwarded-Host` header.
|
|
||||||
## https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-Host
|
|
||||||
##
|
|
||||||
## Accepted values: a list of fully qualified domain names (FQDN)
|
|
||||||
## Default: <none>
|
|
||||||
##
|
|
||||||
## Example:
|
|
||||||
## alternative_domains:
|
|
||||||
## - invidious.example.com
|
|
||||||
## - inv.example.com
|
|
||||||
## - videos.example.com
|
|
||||||
##
|
|
||||||
alternative_domains:
|
|
||||||
|
|
||||||
##
|
##
|
||||||
## Tell Invidious that it is behind a proxy that provides only
|
## Tell Invidious that it is behind a proxy that provides only
|
||||||
## HTTPS, so all links must use the https:// scheme. This
|
## HTTPS, so all links must use the https:// scheme. This
|
||||||
|
|||||||
@@ -121,8 +121,6 @@ class Config
|
|||||||
property hmac_key : String = ""
|
property hmac_key : String = ""
|
||||||
# Domain to be used for links to resources on the site where an absolute URL is required
|
# Domain to be used for links to resources on the site where an absolute URL is required
|
||||||
property domain : String?
|
property domain : String?
|
||||||
# Additional domain list that is going to be used for cookie domain validation
|
|
||||||
property alternative_domains : Array(String) = [] of String
|
|
||||||
# Subscribe to channels using PubSubHubbub (requires domain, hmac_key)
|
# Subscribe to channels using PubSubHubbub (requires domain, hmac_key)
|
||||||
property use_pubsub_feeds : Bool | Int32 = false
|
property use_pubsub_feeds : Bool | Int32 = false
|
||||||
property popular_enabled : Bool = true
|
property popular_enabled : Bool = true
|
||||||
|
|||||||
@@ -201,7 +201,7 @@ def error_redirect_helper(env : HTTP::Server::Context)
|
|||||||
<a href="/redirect?referer=#{env.get("current_page")}">#{switch_instance}</a>
|
<a href="/redirect?referer=#{env.get("current_page")}">#{switch_instance}</a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a rel="noreferrer noopener" href="https://www.youtube.com#{env.request.resource}">#{go_to_youtube}</a>
|
<a rel="noreferrer noopener" href="https://youtube.com#{env.request.resource}">#{go_to_youtube}</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
END_HTML
|
END_HTML
|
||||||
|
|||||||
@@ -32,8 +32,6 @@ module Invidious::Routes::BeforeAll
|
|||||||
env.response.headers["X-XSS-Protection"] = "1; mode=block"
|
env.response.headers["X-XSS-Protection"] = "1; mode=block"
|
||||||
env.response.headers["X-Content-Type-Options"] = "nosniff"
|
env.response.headers["X-Content-Type-Options"] = "nosniff"
|
||||||
|
|
||||||
env.set "header_x-forwarded-host", env.request.headers["X-Forwarded-Host"]?
|
|
||||||
|
|
||||||
# Only allow the pages at /embed/* to be embedded
|
# Only allow the pages at /embed/* to be embedded
|
||||||
if env.request.resource.starts_with?("/embed")
|
if env.request.resource.starts_with?("/embed")
|
||||||
frame_ancestors = "'self' file: http: https:"
|
frame_ancestors = "'self' file: http: https:"
|
||||||
|
|||||||
@@ -351,7 +351,7 @@ module Invidious::Routes::Channels
|
|||||||
invidious_url_params.delete_all("user")
|
invidious_url_params.delete_all("user")
|
||||||
|
|
||||||
begin
|
begin
|
||||||
resolved_url = YoutubeAPI.resolve_url("https://www.youtube.com#{env.request.path}#{yt_url_params.size > 0 ? "?#{yt_url_params}" : ""}")
|
resolved_url = YoutubeAPI.resolve_url("https://youtube.com#{env.request.path}#{yt_url_params.size > 0 ? "?#{yt_url_params}" : ""}")
|
||||||
ucid = resolved_url["endpoint"]["browseEndpoint"]["browseId"]
|
ucid = resolved_url["endpoint"]["browseEndpoint"]["browseId"]
|
||||||
rescue ex : InfoException | KeyError
|
rescue ex : InfoException | KeyError
|
||||||
return error_template(404, I18n.translate(locale, "This channel does not exist."))
|
return error_template(404, I18n.translate(locale, "This channel does not exist."))
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ module Invidious::Routes::ErrorRoutes
|
|||||||
if md = env.request.path.match(/^\/(?<id>([a-zA-Z0-9_-]{11})|(\w+))$/)
|
if md = env.request.path.match(/^\/(?<id>([a-zA-Z0-9_-]{11})|(\w+))$/)
|
||||||
item = md["id"]
|
item = md["id"]
|
||||||
|
|
||||||
# Check if item is branding URL e.g. https://www.youtube.com/gaming
|
# Check if item is branding URL e.g. https://youtube.com/gaming
|
||||||
response = YT_POOL.client &.get("/#{item}")
|
response = YT_POOL.client &.get("/#{item}")
|
||||||
|
|
||||||
if response.status_code == 301
|
if response.status_code == 301
|
||||||
|
|||||||
@@ -320,7 +320,7 @@ module Invidious::Routes::Feeds
|
|||||||
case attribute.name
|
case attribute.name
|
||||||
when "url", "href"
|
when "url", "href"
|
||||||
request_target = URI.parse(node[attribute.name]).request_target
|
request_target = URI.parse(node[attribute.name]).request_target
|
||||||
query_string_opt = request_target.starts_with?("/watch?v=") ? ("&#{params}" if !params.empty?) : ""
|
query_string_opt = request_target.starts_with?("/watch?v=") ? "&#{params}" : ""
|
||||||
node[attribute.name] = "#{HOST_URL}#{request_target}#{query_string_opt}"
|
node[attribute.name] = "#{HOST_URL}#{request_target}#{query_string_opt}"
|
||||||
else nil # Skip
|
else nil # Skip
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ module Invidious::Routes::Login
|
|||||||
|
|
||||||
def self.login(env)
|
def self.login(env)
|
||||||
locale = env.get("preferences").as(Preferences).locale
|
locale = env.get("preferences").as(Preferences).locale
|
||||||
host = env.get("header_x-forwarded-host")
|
|
||||||
|
|
||||||
referer = get_referer(env, "/feed/subscriptions")
|
referer = get_referer(env, "/feed/subscriptions")
|
||||||
|
|
||||||
@@ -58,11 +57,7 @@ module Invidious::Routes::Login
|
|||||||
sid = Base64.urlsafe_encode(Random::Secure.random_bytes(32))
|
sid = Base64.urlsafe_encode(Random::Secure.random_bytes(32))
|
||||||
Invidious::Database::SessionIDs.insert(sid, email)
|
Invidious::Database::SessionIDs.insert(sid, email)
|
||||||
|
|
||||||
if alt = CONFIG.alternative_domains.index(host)
|
env.response.cookies["SID"] = Invidious::User::Cookies.sid(CONFIG.domain, sid)
|
||||||
env.response.cookies["SID"] = Invidious::User::Cookies.sid(CONFIG.alternative_domains[alt], sid)
|
|
||||||
else
|
|
||||||
env.response.cookies["SID"] = Invidious::User::Cookies.sid(CONFIG.domain, sid)
|
|
||||||
end
|
|
||||||
else
|
else
|
||||||
return error_template(401, "Wrong username or password")
|
return error_template(401, "Wrong username or password")
|
||||||
end
|
end
|
||||||
@@ -128,11 +123,7 @@ module Invidious::Routes::Login
|
|||||||
view_name = "subscriptions_#{sha256(user.email)}"
|
view_name = "subscriptions_#{sha256(user.email)}"
|
||||||
PG_DB.exec("CREATE MATERIALIZED VIEW #{view_name} AS #{MATERIALIZED_VIEW_SQL.call(user.email)}")
|
PG_DB.exec("CREATE MATERIALIZED VIEW #{view_name} AS #{MATERIALIZED_VIEW_SQL.call(user.email)}")
|
||||||
|
|
||||||
if alt = CONFIG.alternative_domains.index(host)
|
env.response.cookies["SID"] = Invidious::User::Cookies.sid(CONFIG.domain, sid)
|
||||||
env.response.cookies["SID"] = Invidious::User::Cookies.sid(CONFIG.alternative_domains[alt], sid)
|
|
||||||
else
|
|
||||||
env.response.cookies["SID"] = Invidious::User::Cookies.sid(CONFIG.domain, sid)
|
|
||||||
end
|
|
||||||
|
|
||||||
if env.request.cookies["PREFS"]?
|
if env.request.cookies["PREFS"]?
|
||||||
user.preferences = env.get("preferences").as(Preferences)
|
user.preferences = env.get("preferences").as(Preferences)
|
||||||
|
|||||||
@@ -231,12 +231,7 @@ module Invidious::Routes::PreferencesRoute
|
|||||||
File.write("config/config.yml", CONFIG.to_yaml)
|
File.write("config/config.yml", CONFIG.to_yaml)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
host = env.get("header_x-forwarded-host")
|
env.response.cookies["PREFS"] = Invidious::User::Cookies.prefs(CONFIG.domain, preferences)
|
||||||
if alt = CONFIG.alternative_domains.index(host)
|
|
||||||
env.response.cookies["PREFS"] = Invidious::User::Cookies.prefs(CONFIG.alternative_domains[alt], preferences)
|
|
||||||
else
|
|
||||||
env.response.cookies["PREFS"] = Invidious::User::Cookies.prefs(CONFIG.domain, preferences)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
env.redirect referer
|
env.redirect referer
|
||||||
@@ -271,12 +266,7 @@ module Invidious::Routes::PreferencesRoute
|
|||||||
preferences.dark_mode = "dark"
|
preferences.dark_mode = "dark"
|
||||||
end
|
end
|
||||||
|
|
||||||
host = env.get("header_x-forwarded-host")
|
env.response.cookies["PREFS"] = Invidious::User::Cookies.prefs(CONFIG.domain, preferences)
|
||||||
if alt = CONFIG.alternative_domains.index(host)
|
|
||||||
env.response.cookies["PREFS"] = Invidious::User::Cookies.prefs(CONFIG.alternative_domains[alt], preferences)
|
|
||||||
else
|
|
||||||
env.response.cookies["PREFS"] = Invidious::User::Cookies.prefs(CONFIG.domain, preferences)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if redirect
|
if redirect
|
||||||
|
|||||||
@@ -6,24 +6,17 @@ struct Invidious::User
|
|||||||
|
|
||||||
# Note: we use ternary operator because the two variables
|
# Note: we use ternary operator because the two variables
|
||||||
# used in here are not booleans.
|
# used in here are not booleans.
|
||||||
@@secure = (Kemal.config.ssl || CONFIG.https_only) ? true : false
|
SECURE = (Kemal.config.ssl || CONFIG.https_only) ? true : false
|
||||||
|
|
||||||
# Session ID (SID) cookie
|
# Session ID (SID) cookie
|
||||||
# Parameter "domain" comes from the global config
|
# Parameter "domain" comes from the global config
|
||||||
def sid(domain : String?, sid) : HTTP::Cookie
|
def sid(domain : String?, sid) : HTTP::Cookie
|
||||||
# Not secure if it's being accessed from I2P
|
|
||||||
# Browsers expect the domain to include https. On I2P there is no HTTPS
|
|
||||||
# Tor browser works fine with secure being true
|
|
||||||
if (domain.try &.split(".").last == "i2p") && @@secure
|
|
||||||
@@secure = false
|
|
||||||
end
|
|
||||||
|
|
||||||
return HTTP::Cookie.new(
|
return HTTP::Cookie.new(
|
||||||
name: "SID",
|
name: "SID",
|
||||||
domain: domain,
|
domain: domain,
|
||||||
value: sid,
|
value: sid,
|
||||||
expires: Time.utc + 2.years,
|
expires: Time.utc + 2.years,
|
||||||
secure: @@secure,
|
secure: SECURE,
|
||||||
http_only: true,
|
http_only: true,
|
||||||
samesite: HTTP::Cookie::SameSite::Lax
|
samesite: HTTP::Cookie::SameSite::Lax
|
||||||
)
|
)
|
||||||
@@ -32,19 +25,12 @@ struct Invidious::User
|
|||||||
# Preferences (PREFS) cookie
|
# Preferences (PREFS) cookie
|
||||||
# Parameter "domain" comes from the global config
|
# Parameter "domain" comes from the global config
|
||||||
def prefs(domain : String?, preferences : Preferences) : HTTP::Cookie
|
def prefs(domain : String?, preferences : Preferences) : HTTP::Cookie
|
||||||
# Not secure if it's being accessed from I2P
|
|
||||||
# Browsers expect the domain to include https. On I2P there is no HTTPS
|
|
||||||
# Tor browser works fine with secure being true
|
|
||||||
if (domain.try &.split(".").last == "i2p") && @@secure
|
|
||||||
@@secure = false
|
|
||||||
end
|
|
||||||
|
|
||||||
return HTTP::Cookie.new(
|
return HTTP::Cookie.new(
|
||||||
name: "PREFS",
|
name: "PREFS",
|
||||||
domain: domain,
|
domain: domain,
|
||||||
value: URI.encode_www_form(preferences.to_json),
|
value: URI.encode_www_form(preferences.to_json),
|
||||||
expires: Time.utc + 2.years,
|
expires: Time.utc + 2.years,
|
||||||
secure: @@secure,
|
secure: SECURE,
|
||||||
http_only: false,
|
http_only: false,
|
||||||
samesite: HTTP::Cookie::SameSite::Lax
|
samesite: HTTP::Cookie::SameSite::Lax
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -480,7 +480,7 @@ module YoutubeAPI
|
|||||||
#
|
#
|
||||||
# ```
|
# ```
|
||||||
# # Valid channel "brand URL" gives the related UCID and browse ID
|
# # Valid channel "brand URL" gives the related UCID and browse ID
|
||||||
# channel_a = YoutubeAPI.resolve_url("https://www.youtube.com/c/google")
|
# channel_a = YoutubeAPI.resolve_url("https://youtube.com/c/google")
|
||||||
# channel_a # => {
|
# channel_a # => {
|
||||||
# "endpoint": {
|
# "endpoint": {
|
||||||
# "browseEndpoint": {
|
# "browseEndpoint": {
|
||||||
@@ -492,7 +492,7 @@ module YoutubeAPI
|
|||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
# # Invalid URL returns throws an InfoException
|
# # Invalid URL returns throws an InfoException
|
||||||
# channel_b = YoutubeAPI.resolve_url("https://www.youtube.com/c/invalid")
|
# channel_b = YoutubeAPI.resolve_url("https://youtube.com/c/invalid")
|
||||||
# ```
|
# ```
|
||||||
#
|
#
|
||||||
def resolve_url(url : String, client_config : ClientConfig | Nil = nil)
|
def resolve_url(url : String, client_config : ClientConfig | Nil = nil)
|
||||||
|
|||||||
Reference in New Issue
Block a user