mirror of
https://github.com/iv-org/invidious.git
synced 2026-05-18 22:21:23 -05:00
fix: handle cookies correctly on onion mirrors
Match cookie domain to the current request host so onion mirrors fall back to host-only cookies instead of reusing the configured clearnet domain. Also clear SID and PREFS cookies with explicit domain and path attributes to avoid leaving stale cookies behind when signing out or replacing anonymous preferences. Refs: #1421
This commit is contained in:
parent
f914ce8040
commit
4aecf4e6f0
@ -3,6 +3,24 @@ require "../spec_helper"
|
|||||||
CONFIG = Config.from_yaml(File.open("config/config.example.yml"))
|
CONFIG = Config.from_yaml(File.open("config/config.example.yml"))
|
||||||
|
|
||||||
Spectator.describe "Helper" do
|
Spectator.describe "Helper" do
|
||||||
|
describe "#cookie_domain" do
|
||||||
|
it "keeps the configured cookie domain for the matching host" do
|
||||||
|
expect(cookie_domain("example.com", "example.com")).to eq("example.com")
|
||||||
|
expect(cookie_domain("example.com", "example.com:3000")).to eq("example.com")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "falls back to host-only cookies for unrelated hosts such as onion mirrors" do
|
||||||
|
expect(cookie_domain("example.com", "exampleonionaddress.onion")).to be_nil
|
||||||
|
expect(cookie_domain("example.com", "other.example")).to be_nil
|
||||||
|
end
|
||||||
|
|
||||||
|
it "preserves shared-subdomain deployments when the configured domain starts with a dot" do
|
||||||
|
expect(cookie_domain(".example.com", "example.com")).to eq(".example.com")
|
||||||
|
expect(cookie_domain(".example.com", "www.example.com")).to eq(".example.com")
|
||||||
|
expect(cookie_domain(".example.com", "deep.www.example.com")).to eq(".example.com")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe "#produce_channel_search_continuation" do
|
describe "#produce_channel_search_continuation" do
|
||||||
it "correctly produces token for searching a specific channel" do
|
it "correctly produces token for searching a specific channel" do
|
||||||
expect(produce_channel_search_continuation("UCXuqSBlHAE6Xw-yeJA0Tunw", "", 100)).to eq("4qmFsgJqEhhVQ1h1cVNCbEhBRTZYdy15ZUpBMFR1bncaIEVnWnpaV0Z5WTJnd0FUZ0JZQUY2QkVkS2IxaTRBUUE9WgCaAilicm93c2UtZmVlZFVDWHVxU0JsSEFFNlh3LXllSkEwVHVud3NlYXJjaA%3D%3D")
|
expect(produce_channel_search_continuation("UCXuqSBlHAE6Xw-yeJA0Tunw", "", 100)).to eq("4qmFsgJqEhhVQ1h1cVNCbEhBRTZYdy15ZUpBMFR1bncaIEVnWnpaV0Z5WTJnd0FUZ0JZQUY2QkVkS2IxaTRBUUE9WgCaAilicm93c2UtZmVlZFVDWHVxU0JsSEFFNlh3LXllSkEwVHVud3NlYXJjaA%3D%3D")
|
||||||
|
|||||||
@ -279,6 +279,26 @@ def sha256(text)
|
|||||||
return digest.final.hexstring
|
return digest.final.hexstring
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def cookie_domain(configured_domain : String?, request_host : String?) : String?
|
||||||
|
return nil unless configured_domain
|
||||||
|
return nil unless request_host
|
||||||
|
|
||||||
|
normalized_domain = configured_domain.downcase.lchop(".")
|
||||||
|
normalized_host = request_host.downcase.sub(/:\d+\z/, "")
|
||||||
|
|
||||||
|
return configured_domain if normalized_host == normalized_domain
|
||||||
|
|
||||||
|
if configured_domain.starts_with?(".") && normalized_host.ends_with?(".#{normalized_domain}")
|
||||||
|
return configured_domain
|
||||||
|
end
|
||||||
|
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def cookie_domain(env : HTTP::Server::Context) : String?
|
||||||
|
cookie_domain(CONFIG.domain, env.request.headers["Host"]?)
|
||||||
|
end
|
||||||
|
|
||||||
def subscribe_pubsub(topic, key)
|
def subscribe_pubsub(topic, key)
|
||||||
case topic
|
case topic
|
||||||
when .match(/^UC[A-Za-z0-9_-]{22}$/)
|
when .match(/^UC[A-Za-z0-9_-]{22}$/)
|
||||||
|
|||||||
@ -128,10 +128,9 @@ module Invidious::Routes::Account
|
|||||||
Invidious::Database::SessionIDs.delete(email: user.email)
|
Invidious::Database::SessionIDs.delete(email: user.email)
|
||||||
PG_DB.exec("DROP MATERIALIZED VIEW #{view_name}")
|
PG_DB.exec("DROP MATERIALIZED VIEW #{view_name}")
|
||||||
|
|
||||||
env.request.cookies.each do |cookie|
|
domain = cookie_domain(env)
|
||||||
cookie.expires = Time.utc(1990, 1, 1)
|
env.response.cookies["SID"] = Invidious::User::Cookies.clear_sid(domain)
|
||||||
env.response.cookies << cookie
|
env.response.cookies["PREFS"] = Invidious::User::Cookies.clear_prefs(domain)
|
||||||
end
|
|
||||||
|
|
||||||
env.redirect referer
|
env.redirect referer
|
||||||
end
|
end
|
||||||
|
|||||||
@ -57,16 +57,14 @@ 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)
|
||||||
|
|
||||||
env.response.cookies["SID"] = Invidious::User::Cookies.sid(CONFIG.domain, sid)
|
env.response.cookies["SID"] = Invidious::User::Cookies.sid(cookie_domain(env), sid)
|
||||||
else
|
else
|
||||||
return error_template(401, "Wrong username or password")
|
return error_template(401, "Wrong username or password")
|
||||||
end
|
end
|
||||||
|
|
||||||
# Since this user has already registered, we don't want to overwrite their preferences
|
# Since this user has already registered, we don't want to overwrite their preferences
|
||||||
if env.request.cookies["PREFS"]?
|
if env.request.cookies["PREFS"]?
|
||||||
cookie = env.request.cookies["PREFS"]
|
env.response.cookies["PREFS"] = Invidious::User::Cookies.clear_prefs(cookie_domain(env))
|
||||||
cookie.expires = Time.utc(1990, 1, 1)
|
|
||||||
env.response.cookies << cookie
|
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
if !CONFIG.registration_enabled
|
if !CONFIG.registration_enabled
|
||||||
@ -123,15 +121,13 @@ 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)}")
|
||||||
|
|
||||||
env.response.cookies["SID"] = Invidious::User::Cookies.sid(CONFIG.domain, sid)
|
env.response.cookies["SID"] = Invidious::User::Cookies.sid(cookie_domain(env), sid)
|
||||||
|
|
||||||
if env.request.cookies["PREFS"]?
|
if env.request.cookies["PREFS"]?
|
||||||
user.preferences = env.get("preferences").as(Preferences)
|
user.preferences = env.get("preferences").as(Preferences)
|
||||||
Invidious::Database::Users.update_preferences(user)
|
Invidious::Database::Users.update_preferences(user)
|
||||||
|
|
||||||
cookie = env.request.cookies["PREFS"]
|
env.response.cookies["PREFS"] = Invidious::User::Cookies.clear_prefs(cookie_domain(env))
|
||||||
cookie.expires = Time.utc(1990, 1, 1)
|
|
||||||
env.response.cookies << cookie
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -164,10 +160,9 @@ module Invidious::Routes::Login
|
|||||||
|
|
||||||
Invidious::Database::SessionIDs.delete(sid: sid)
|
Invidious::Database::SessionIDs.delete(sid: sid)
|
||||||
|
|
||||||
env.request.cookies.each do |cookie|
|
domain = cookie_domain(env)
|
||||||
cookie.expires = Time.utc(1990, 1, 1)
|
env.response.cookies["SID"] = Invidious::User::Cookies.clear_sid(domain)
|
||||||
env.response.cookies << cookie
|
env.response.cookies["PREFS"] = Invidious::User::Cookies.clear_prefs(domain)
|
||||||
end
|
|
||||||
|
|
||||||
env.redirect referer
|
env.redirect referer
|
||||||
end
|
end
|
||||||
|
|||||||
@ -226,7 +226,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
|
||||||
env.response.cookies["PREFS"] = Invidious::User::Cookies.prefs(CONFIG.domain, preferences)
|
env.response.cookies["PREFS"] = Invidious::User::Cookies.prefs(cookie_domain(env), preferences)
|
||||||
end
|
end
|
||||||
|
|
||||||
env.redirect referer
|
env.redirect referer
|
||||||
@ -261,7 +261,7 @@ module Invidious::Routes::PreferencesRoute
|
|||||||
preferences.dark_mode = "dark"
|
preferences.dark_mode = "dark"
|
||||||
end
|
end
|
||||||
|
|
||||||
env.response.cookies["PREFS"] = Invidious::User::Cookies.prefs(CONFIG.domain, preferences)
|
env.response.cookies["PREFS"] = Invidious::User::Cookies.prefs(cookie_domain(env), preferences)
|
||||||
end
|
end
|
||||||
|
|
||||||
if redirect
|
if redirect
|
||||||
|
|||||||
@ -14,6 +14,7 @@ struct Invidious::User
|
|||||||
return HTTP::Cookie.new(
|
return HTTP::Cookie.new(
|
||||||
name: "SID",
|
name: "SID",
|
||||||
domain: domain,
|
domain: domain,
|
||||||
|
path: "/",
|
||||||
value: sid,
|
value: sid,
|
||||||
expires: Time.utc + 2.years,
|
expires: Time.utc + 2.years,
|
||||||
secure: SECURE,
|
secure: SECURE,
|
||||||
@ -28,6 +29,7 @@ struct Invidious::User
|
|||||||
return HTTP::Cookie.new(
|
return HTTP::Cookie.new(
|
||||||
name: "PREFS",
|
name: "PREFS",
|
||||||
domain: domain,
|
domain: domain,
|
||||||
|
path: "/",
|
||||||
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,
|
||||||
@ -35,5 +37,26 @@ struct Invidious::User
|
|||||||
samesite: HTTP::Cookie::SameSite::Lax
|
samesite: HTTP::Cookie::SameSite::Lax
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def clear_sid(domain : String?) : HTTP::Cookie
|
||||||
|
clear("SID", domain, http_only: true)
|
||||||
|
end
|
||||||
|
|
||||||
|
def clear_prefs(domain : String?) : HTTP::Cookie
|
||||||
|
clear("PREFS", domain, http_only: false)
|
||||||
|
end
|
||||||
|
|
||||||
|
private def clear(name : String, domain : String?, http_only : Bool) : HTTP::Cookie
|
||||||
|
return HTTP::Cookie.new(
|
||||||
|
name: name,
|
||||||
|
domain: domain,
|
||||||
|
path: "/",
|
||||||
|
value: "",
|
||||||
|
expires: Time.utc(1990, 1, 1),
|
||||||
|
secure: SECURE,
|
||||||
|
http_only: http_only,
|
||||||
|
samesite: HTTP::Cookie::SameSite::Lax
|
||||||
|
)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user