forked from midou/invidious
		
	Store session_ids in separate table
This commit is contained in:
		
							
								
								
									
										24
									
								
								config/sql/session_ids.sql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								config/sql/session_ids.sql
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,24 @@ | ||||
| -- Table: public.session_ids | ||||
|  | ||||
| -- DROP TABLE public.session_ids; | ||||
|  | ||||
| CREATE TABLE public.session_ids | ||||
| ( | ||||
|   id text NOT NULL, | ||||
|   email text, | ||||
|   issued timestamp with time zone, | ||||
|   CONSTRAINT session_ids_pkey PRIMARY KEY (id) | ||||
| ); | ||||
|  | ||||
| GRANT ALL ON TABLE public.channel_videos TO kemal; | ||||
|  | ||||
| -- Index: public.session_ids_id_idx | ||||
|  | ||||
| -- DROP INDEX public.session_ids_id_idx; | ||||
|  | ||||
| CREATE INDEX session_ids_id_idx | ||||
|   ON public.session_ids | ||||
|   USING btree | ||||
|   (id COLLATE pg_catalog."default"); | ||||
|  | ||||
|    | ||||
| @@ -4,7 +4,6 @@ | ||||
|  | ||||
| CREATE TABLE public.users | ||||
| ( | ||||
|   id text[] NOT NULL, | ||||
|   updated timestamp with time zone, | ||||
|   notifications text[], | ||||
|   subscriptions text[], | ||||
|   | ||||
| @@ -163,9 +163,10 @@ 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 $1 = ANY(id)", sid, as: User) | ||||
|       email = PG_DB.query_one?("SELECT email FROM session_ids WHERE id = $1", sid, as: String) | ||||
|  | ||||
|       if user | ||||
|       if email | ||||
|         user = PG_DB.query_one("SELECT * FROM users WHERE email = $1", email, as: User) | ||||
|         challenge, token = create_response(user.email, "sign_out", HMAC_KEY, PG_DB, 1.week) | ||||
|  | ||||
|         env.set "challenge", challenge | ||||
| @@ -177,7 +178,7 @@ before_all do |env| | ||||
|       end | ||||
|     else | ||||
|       begin | ||||
|         user = get_user(sid, headers, PG_DB, false) | ||||
|         user, sid = get_user(sid, headers, PG_DB, false) | ||||
|  | ||||
|         challenge, token = create_response(user.email, "sign_out", HMAC_KEY, PG_DB, 1.week) | ||||
|         env.set "challenge", challenge | ||||
| @@ -312,7 +313,7 @@ get "/watch" do |env| | ||||
|   end | ||||
|  | ||||
|   if watched && !watched.includes? id | ||||
|     PG_DB.exec("UPDATE users SET watched = watched || $1 WHERE $2 = id", [id], user.as(User).id) | ||||
|     PG_DB.exec("UPDATE users SET watched = watched || $1 WHERE email = $2", [id], user.as(User).email) | ||||
|   end | ||||
|  | ||||
|   if nojs | ||||
| @@ -880,7 +881,7 @@ post "/login" do |env| | ||||
|  | ||||
|       sid = login.cookies["SID"].value | ||||
|  | ||||
|       user = get_user(sid, headers, PG_DB) | ||||
|       user, sid = get_user(sid, headers, PG_DB) | ||||
|  | ||||
|       # We are now logged in | ||||
|  | ||||
| @@ -986,7 +987,7 @@ post "/login" do |env| | ||||
|  | ||||
|       if Crypto::Bcrypt::Password.new(user.password.not_nil!) == password | ||||
|         sid = Base64.urlsafe_encode(Random::Secure.random_bytes(32)) | ||||
|         PG_DB.exec("UPDATE users SET id = id || $1 WHERE LOWER(email) = LOWER($2)", [sid], email) | ||||
|         PG_DB.exec("INSERT INTO session_ids VALUES ($1, $2, $3)", sid, email, Time.now) | ||||
|  | ||||
|         if Kemal.config.ssl || CONFIG.https_only | ||||
|           secure = true | ||||
| @@ -1024,13 +1025,14 @@ post "/login" do |env| | ||||
|       end | ||||
|  | ||||
|       sid = Base64.urlsafe_encode(Random::Secure.random_bytes(32)) | ||||
|       user = create_user(sid, email, password) | ||||
|       user, sid = create_user(sid, email, password) | ||||
|       user_array = user.to_a | ||||
|  | ||||
|       user_array[5] = user_array[5].to_json | ||||
|       args = arg_array(user_array) | ||||
|  | ||||
|       PG_DB.exec("INSERT INTO users VALUES (#{args})", user_array) | ||||
|       PG_DB.exec("INSERT INTO session_ids VALUES ($1, $2, $3)", sid, email, Time.now) | ||||
|  | ||||
|       view_name = "subscriptions_#{sha256(user.email)[0..7]}" | ||||
|       PG_DB.exec("CREATE MATERIALIZED VIEW #{view_name} AS \ | ||||
| @@ -1078,7 +1080,7 @@ get "/signout" do |env| | ||||
|  | ||||
|     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) | ||||
|     PG_DB.exec("DELETE FROM session_ids * WHERE id = $1", sid) | ||||
|  | ||||
|     env.request.cookies.each do |cookie| | ||||
|       cookie.expires = Time.new(1990, 1, 1) | ||||
| @@ -1252,7 +1254,7 @@ get "/mark_watched" do |env| | ||||
|   if user | ||||
|     user = user.as(User) | ||||
|     if !user.watched.includes? id | ||||
|       PG_DB.exec("UPDATE users SET watched = watched || $1 WHERE $2 = id", [id], user.id) | ||||
|       PG_DB.exec("UPDATE users SET watched = watched || $1 WHERE email = $2", [id], user.email) | ||||
|     end | ||||
|   end | ||||
|  | ||||
| @@ -1347,9 +1349,10 @@ get "/subscription_manager" do |env| | ||||
|   locale = LOCALES[env.get("locale").as(String)]? | ||||
|  | ||||
|   user = env.get? "user" | ||||
|   sid = env.get? "sid" | ||||
|   referer = get_referer(env, "/") | ||||
|  | ||||
|   if !user | ||||
|   if !user && !sid | ||||
|     next env.redirect referer | ||||
|   end | ||||
|  | ||||
| @@ -1360,7 +1363,7 @@ get "/subscription_manager" do |env| | ||||
|     headers = HTTP::Headers.new | ||||
|     headers["Cookie"] = env.request.headers["Cookie"] | ||||
|  | ||||
|     user = get_user(user.id[0], headers, PG_DB) | ||||
|     user, sid = get_user(sid, headers, PG_DB) | ||||
|   end | ||||
|  | ||||
|   action_takeout = env.params.query["action_takeout"]?.try &.to_i? | ||||
| @@ -1756,10 +1759,12 @@ get "/feed/subscriptions" do |env| | ||||
|   locale = LOCALES[env.get("locale").as(String)]? | ||||
|  | ||||
|   user = env.get? "user" | ||||
|   sid = env.get? "sid" | ||||
|   referer = get_referer(env) | ||||
|  | ||||
|   if user | ||||
|     user = user.as(User) | ||||
|     sid = sid.as(String) | ||||
|     preferences = user.preferences | ||||
|  | ||||
|     if preferences.unseen_only | ||||
| @@ -1771,7 +1776,7 @@ get "/feed/subscriptions" do |env| | ||||
|     headers["Cookie"] = env.request.headers["Cookie"] | ||||
|  | ||||
|     if !user.password | ||||
|       user = get_user(user.id[0], headers, PG_DB) | ||||
|       user, sid = get_user(sid, headers, PG_DB) | ||||
|     end | ||||
|  | ||||
|     max_results = preferences.max_results | ||||
|   | ||||
| @@ -12,7 +12,6 @@ class User | ||||
|   end | ||||
|  | ||||
|   add_mapping({ | ||||
|     id:            Array(String), | ||||
|     updated:       Time, | ||||
|     notifications: Array(String), | ||||
|     subscriptions: Array(String), | ||||
| @@ -126,18 +125,21 @@ class Preferences | ||||
| end | ||||
|  | ||||
| def get_user(sid, headers, db, refresh = true) | ||||
|   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 email = db.query_one?("SELECT email FROM session_ids WHERE id = $1", sid, as: String) | ||||
|     user = db.query_one("SELECT * FROM users WHERE email = $1", email, as: User) | ||||
|  | ||||
|     if refresh && Time.now - user.updated > 1.minute | ||||
|       user = fetch_user(sid, headers, db) | ||||
|       user, sid = fetch_user(sid, headers, db) | ||||
|       user_array = user.to_a | ||||
|  | ||||
|       user_array[5] = user_array[5].to_json | ||||
|       args = arg_array(user_array) | ||||
|  | ||||
|       db.exec("INSERT INTO users VALUES (#{args}) \ | ||||
|       ON CONFLICT (email) DO UPDATE SET id = users.id || $1, updated = $2, subscriptions = $4", user_array) | ||||
|       ON CONFLICT (email) DO UPDATE SET updated = $1, subscriptions = $3", user_array) | ||||
|  | ||||
|       db.exec("INSERT INTO session_ids VALUES ($1,$2,$3) \ | ||||
|       ON CONFLICT (id) DO NOTHING", sid, user.email, Time.now) | ||||
|  | ||||
|       begin | ||||
|         view_name = "subscriptions_#{sha256(user.email)[0..7]}" | ||||
| @@ -149,14 +151,17 @@ def get_user(sid, headers, db, refresh = true) | ||||
|       end | ||||
|     end | ||||
|   else | ||||
|     user = fetch_user(sid, headers, db) | ||||
|     user, sid = fetch_user(sid, headers, db) | ||||
|     user_array = user.to_a | ||||
|  | ||||
|     user_array[5] = user_array[5].to_json | ||||
|     args = arg_array(user.to_a) | ||||
|  | ||||
|     db.exec("INSERT INTO users VALUES (#{args}) \ | ||||
|     ON CONFLICT (email) DO UPDATE SET id = users.id || $1, updated = $2, subscriptions = $4", user_array) | ||||
|     ON CONFLICT (email) DO UPDATE SET updated = $1, subscriptions = $3", user_array) | ||||
|  | ||||
|     db.exec("INSERT INTO session_ids VALUES ($1,$2,$3) \ | ||||
|     ON CONFLICT (id) DO NOTHING", sid, user.email, Time.now) | ||||
|  | ||||
|     begin | ||||
|       view_name = "subscriptions_#{sha256(user.email)[0..7]}" | ||||
| @@ -168,7 +173,7 @@ def get_user(sid, headers, db, refresh = true) | ||||
|     end | ||||
|   end | ||||
|  | ||||
|   return user | ||||
|   return user, sid | ||||
| end | ||||
|  | ||||
| def fetch_user(sid, headers, db) | ||||
| @@ -196,17 +201,17 @@ def fetch_user(sid, 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) | ||||
|   return user | ||||
|   user = User.new(Time.now, [] of String, channels, email, DEFAULT_USER_PREFERENCES, nil, token, [] of String) | ||||
|   return user, sid | ||||
| end | ||||
|  | ||||
| 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(Time.now, [] of String, [] of String, email, DEFAULT_USER_PREFERENCES, password.to_s, token, [] of String) | ||||
|  | ||||
|   return user | ||||
|   return user, sid | ||||
| end | ||||
|  | ||||
| def create_response(user_id, operation, key, db, expire = 6.hours) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user