From 8adb4650a02c4c3abb66119373b7da831230d46b Mon Sep 17 00:00:00 2001 From: Omar Roth Date: Wed, 15 Aug 2018 12:40:42 -0500 Subject: [PATCH] Add support for multiple sessions --- config/sql/users.sql | 4 ++-- src/invidious.cr | 22 +++++++++++++++------- src/invidious/helpers/helpers.cr | 2 +- src/invidious/users.cr | 14 +++++++------- 4 files changed, 25 insertions(+), 17 deletions(-) diff --git a/config/sql/users.sql b/config/sql/users.sql index 2abcb991..605e1f7f 100644 --- a/config/sql/users.sql +++ b/config/sql/users.sql @@ -2,9 +2,9 @@ -- DROP TABLE public.users; -CREATE TABLE public.users +CREATE TABLE public.users ( - id text COLLATE pg_catalog."default" NOT NULL, + id text[] COLLATE pg_catalog."default" NOT NULL, updated timestamp with time zone, notifications text[] COLLATE pg_catalog."default", subscriptions text[] COLLATE pg_catalog."default", diff --git a/src/invidious.cr b/src/invidious.cr index 97424c81..2f39862c 100644 --- a/src/invidious.cr +++ b/src/invidious.cr @@ -114,10 +114,11 @@ before_all do |env| # Invidious users only have SID if !env.request.cookies.has_key? "SSID" - user = PG_DB.query_one?("SELECT * FROM users WHERE id = $1", sid, as: User) + user = PG_DB.query_one?("SELECT * FROM users WHERE $1 = ANY(id)", sid, as: User) if user env.set "user", user + env.set "sid", sid end else begin @@ -125,6 +126,7 @@ before_all do |env| user = get_user(sid, client, headers, PG_DB, false) env.set "user", user + env.set "sid", sid rescue ex end end @@ -621,8 +623,8 @@ post "/login" do |env| end if Crypto::Bcrypt::Password.new(user.password.not_nil!) == password - sid = Base64.encode(Random::Secure.random_bytes(50)) - PG_DB.exec("UPDATE users SET id = $1 WHERE email = $2", sid, email) + sid = Base64.urlsafe_encode(Random::Secure.random_bytes(32)) + PG_DB.exec("UPDATE users SET id = id || $1 WHERE email = $2", [sid], email) if Kemal.config.ssl || CONFIG.https_only secure = true @@ -643,7 +645,7 @@ post "/login" do |env| next templated "error" end - sid = Base64.encode(Random::Secure.random_bytes(50)) + sid = Base64.urlsafe_encode(Random::Secure.random_bytes(32)) user = create_user(sid, email, password) user_array = user.to_a @@ -673,6 +675,12 @@ get "/signout" do |env| cookie.expires = Time.new(1990, 1, 1) end + if env.get? "user" + user = env.get("user").as(User) + sid = env.get("sid").as(String) + PG_DB.exec("UPDATE users SET id = array_remove(id, $1) WHERE email = $2", sid, user.email) + end + env.request.cookies.add_response_headers(env.response.headers) env.redirect referer end @@ -865,7 +873,7 @@ get "/subscription_manager" do |env| headers["Cookie"] = env.request.headers["Cookie"] client = make_client(YT_URL) - user = get_user(user.id, client, headers, PG_DB) + user = get_user(user.id[0], client, headers, PG_DB) end action_takeout = env.params.query["action_takeout"]?.try &.to_i? @@ -1173,7 +1181,7 @@ get "/feed/subscriptions" do |env| if !user.password client = make_client(YT_URL) - user = get_user(user.id, client, headers, PG_DB) + user = get_user(user.id[0], client, headers, PG_DB) end max_results = preferences.max_results @@ -1790,7 +1798,7 @@ get "/api/v1/comments/:id" do |env| reply_count = 1 else reply_count = reply_count.try &.to_i? - reply_count ||= 1 + reply_count ||= 1 end continuation = node_replies["continuations"].as_a[0]["nextContinuationData"]["continuation"].as_s diff --git a/src/invidious/helpers/helpers.cr b/src/invidious/helpers/helpers.cr index 5ad84269..53e3cb19 100644 --- a/src/invidious/helpers/helpers.cr +++ b/src/invidious/helpers/helpers.cr @@ -269,7 +269,7 @@ def generate_captcha(key) answer = "#{hour}:#{minute.to_s.rjust(2, '0')}" token = OpenSSL::HMAC.digest(:sha256, key, answer) - token = Base64.encode(token) + token = Base64.urlsafe_encode(token) return {challenge: challenge, token: token} end diff --git a/src/invidious/users.cr b/src/invidious/users.cr index be71cd94..bdaaccb5 100644 --- a/src/invidious/users.cr +++ b/src/invidious/users.cr @@ -10,7 +10,7 @@ class User end add_mapping({ - id: String, + id: Array(String), updated: Time, notifications: Array(String), subscriptions: Array(String), @@ -78,8 +78,8 @@ class Preferences end def get_user(sid, client, headers, db, refresh = true) - if db.query_one?("SELECT EXISTS (SELECT true FROM users WHERE id = $1)", sid, as: Bool) - user = db.query_one("SELECT * FROM users WHERE id = $1", sid, as: User) + if db.query_one?("SELECT EXISTS (SELECT true FROM users WHERE $1 = ANY(id))", sid, as: Bool) + user = db.query_one("SELECT * FROM users WHERE $1 = ANY(id)", sid, as: User) if refresh && Time.now - user.updated > 1.minute user = fetch_user(sid, client, headers, db) @@ -89,7 +89,7 @@ def get_user(sid, client, headers, db, refresh = true) args = arg_array(user_array) db.exec("INSERT INTO users VALUES (#{args}) \ - ON CONFLICT (email) DO UPDATE SET id = $1, updated = $2, subscriptions = $4", user_array) + ON CONFLICT (email) DO UPDATE SET id = users.id || $1, updated = $2, subscriptions = $4", user_array) end else user = fetch_user(sid, client, headers, db) @@ -99,7 +99,7 @@ def get_user(sid, client, headers, db, refresh = true) args = arg_array(user.to_a) db.exec("INSERT INTO users VALUES (#{args}) \ - ON CONFLICT (email) DO UPDATE SET id = $1, updated = $2, subscriptions = $4", user_array) + ON CONFLICT (email) DO UPDATE SET id = users.id || $1, updated = $2, subscriptions = $4", user_array) end return user @@ -132,7 +132,7 @@ def fetch_user(sid, client, headers, db) token = Base64.urlsafe_encode(Random::Secure.random_bytes(32)) - user = User.new(sid, Time.now, [] of String, channels, email, DEFAULT_USER_PREFERENCES, nil, token, [] of String) + user = User.new([sid], Time.now, [] of String, channels, email, DEFAULT_USER_PREFERENCES, nil, token, [] of String) return user end @@ -140,7 +140,7 @@ def create_user(sid, email, password) password = Crypto::Bcrypt::Password.create(password, cost: 10) token = Base64.urlsafe_encode(Random::Secure.random_bytes(32)) - user = User.new(sid, Time.now, [] of String, [] of String, email, DEFAULT_USER_PREFERENCES, password.to_s, token, [] of String) + user = User.new([sid], Time.now, [] of String, [] of String, email, DEFAULT_USER_PREFERENCES, password.to_s, token, [] of String) return user end