Store session_ids in separate table
This commit is contained in:
parent
8bbf351d04
commit
3646395f1d
4 changed files with 58 additions and 25 deletions
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
|
CREATE TABLE public.users
|
||||||
(
|
(
|
||||||
id text[] NOT NULL,
|
|
||||||
updated timestamp with time zone,
|
updated timestamp with time zone,
|
||||||
notifications text[],
|
notifications text[],
|
||||||
subscriptions text[],
|
subscriptions text[],
|
||||||
|
|
|
@ -163,9 +163,10 @@ before_all do |env|
|
||||||
|
|
||||||
# Invidious users only have SID
|
# Invidious users only have SID
|
||||||
if !env.request.cookies.has_key? "SSID"
|
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)
|
challenge, token = create_response(user.email, "sign_out", HMAC_KEY, PG_DB, 1.week)
|
||||||
|
|
||||||
env.set "challenge", challenge
|
env.set "challenge", challenge
|
||||||
|
@ -177,7 +178,7 @@ before_all do |env|
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
begin
|
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)
|
challenge, token = create_response(user.email, "sign_out", HMAC_KEY, PG_DB, 1.week)
|
||||||
env.set "challenge", challenge
|
env.set "challenge", challenge
|
||||||
|
@ -312,7 +313,7 @@ get "/watch" do |env|
|
||||||
end
|
end
|
||||||
|
|
||||||
if watched && !watched.includes? id
|
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
|
end
|
||||||
|
|
||||||
if nojs
|
if nojs
|
||||||
|
@ -880,7 +881,7 @@ post "/login" do |env|
|
||||||
|
|
||||||
sid = login.cookies["SID"].value
|
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
|
# We are now logged in
|
||||||
|
|
||||||
|
@ -986,7 +987,7 @@ post "/login" do |env|
|
||||||
|
|
||||||
if Crypto::Bcrypt::Password.new(user.password.not_nil!) == password
|
if Crypto::Bcrypt::Password.new(user.password.not_nil!) == password
|
||||||
sid = Base64.urlsafe_encode(Random::Secure.random_bytes(32))
|
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
|
if Kemal.config.ssl || CONFIG.https_only
|
||||||
secure = true
|
secure = true
|
||||||
|
@ -1024,13 +1025,14 @@ post "/login" do |env|
|
||||||
end
|
end
|
||||||
|
|
||||||
sid = Base64.urlsafe_encode(Random::Secure.random_bytes(32))
|
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 = user.to_a
|
||||||
|
|
||||||
user_array[5] = user_array[5].to_json
|
user_array[5] = user_array[5].to_json
|
||||||
args = arg_array(user_array)
|
args = arg_array(user_array)
|
||||||
|
|
||||||
PG_DB.exec("INSERT INTO users VALUES (#{args})", 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]}"
|
view_name = "subscriptions_#{sha256(user.email)[0..7]}"
|
||||||
PG_DB.exec("CREATE MATERIALIZED VIEW #{view_name} AS \
|
PG_DB.exec("CREATE MATERIALIZED VIEW #{view_name} AS \
|
||||||
|
@ -1078,7 +1080,7 @@ get "/signout" do |env|
|
||||||
|
|
||||||
user = env.get("user").as(User)
|
user = env.get("user").as(User)
|
||||||
sid = env.get("sid").as(String)
|
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|
|
env.request.cookies.each do |cookie|
|
||||||
cookie.expires = Time.new(1990, 1, 1)
|
cookie.expires = Time.new(1990, 1, 1)
|
||||||
|
@ -1252,7 +1254,7 @@ get "/mark_watched" do |env|
|
||||||
if user
|
if user
|
||||||
user = user.as(User)
|
user = user.as(User)
|
||||||
if !user.watched.includes? id
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1347,9 +1349,10 @@ get "/subscription_manager" do |env|
|
||||||
locale = LOCALES[env.get("locale").as(String)]?
|
locale = LOCALES[env.get("locale").as(String)]?
|
||||||
|
|
||||||
user = env.get? "user"
|
user = env.get? "user"
|
||||||
|
sid = env.get? "sid"
|
||||||
referer = get_referer(env, "/")
|
referer = get_referer(env, "/")
|
||||||
|
|
||||||
if !user
|
if !user && !sid
|
||||||
next env.redirect referer
|
next env.redirect referer
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1360,7 +1363,7 @@ get "/subscription_manager" do |env|
|
||||||
headers = HTTP::Headers.new
|
headers = HTTP::Headers.new
|
||||||
headers["Cookie"] = env.request.headers["Cookie"]
|
headers["Cookie"] = env.request.headers["Cookie"]
|
||||||
|
|
||||||
user = get_user(user.id[0], headers, PG_DB)
|
user, sid = get_user(sid, headers, PG_DB)
|
||||||
end
|
end
|
||||||
|
|
||||||
action_takeout = env.params.query["action_takeout"]?.try &.to_i?
|
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)]?
|
locale = LOCALES[env.get("locale").as(String)]?
|
||||||
|
|
||||||
user = env.get? "user"
|
user = env.get? "user"
|
||||||
|
sid = env.get? "sid"
|
||||||
referer = get_referer(env)
|
referer = get_referer(env)
|
||||||
|
|
||||||
if user
|
if user
|
||||||
user = user.as(User)
|
user = user.as(User)
|
||||||
|
sid = sid.as(String)
|
||||||
preferences = user.preferences
|
preferences = user.preferences
|
||||||
|
|
||||||
if preferences.unseen_only
|
if preferences.unseen_only
|
||||||
|
@ -1771,7 +1776,7 @@ get "/feed/subscriptions" do |env|
|
||||||
headers["Cookie"] = env.request.headers["Cookie"]
|
headers["Cookie"] = env.request.headers["Cookie"]
|
||||||
|
|
||||||
if !user.password
|
if !user.password
|
||||||
user = get_user(user.id[0], headers, PG_DB)
|
user, sid = get_user(sid, headers, PG_DB)
|
||||||
end
|
end
|
||||||
|
|
||||||
max_results = preferences.max_results
|
max_results = preferences.max_results
|
||||||
|
|
|
@ -12,7 +12,6 @@ class User
|
||||||
end
|
end
|
||||||
|
|
||||||
add_mapping({
|
add_mapping({
|
||||||
id: Array(String),
|
|
||||||
updated: Time,
|
updated: Time,
|
||||||
notifications: Array(String),
|
notifications: Array(String),
|
||||||
subscriptions: Array(String),
|
subscriptions: Array(String),
|
||||||
|
@ -126,18 +125,21 @@ class Preferences
|
||||||
end
|
end
|
||||||
|
|
||||||
def get_user(sid, headers, db, refresh = true)
|
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)
|
if email = db.query_one?("SELECT email FROM session_ids WHERE id = $1", sid, as: String)
|
||||||
user = db.query_one("SELECT * FROM users WHERE $1 = ANY(id)", sid, as: User)
|
user = db.query_one("SELECT * FROM users WHERE email = $1", email, as: User)
|
||||||
|
|
||||||
if refresh && Time.now - user.updated > 1.minute
|
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 = user.to_a
|
||||||
|
|
||||||
user_array[5] = user_array[5].to_json
|
user_array[5] = user_array[5].to_json
|
||||||
args = arg_array(user_array)
|
args = arg_array(user_array)
|
||||||
|
|
||||||
db.exec("INSERT INTO users VALUES (#{args}) \
|
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
|
begin
|
||||||
view_name = "subscriptions_#{sha256(user.email)[0..7]}"
|
view_name = "subscriptions_#{sha256(user.email)[0..7]}"
|
||||||
|
@ -149,14 +151,17 @@ def get_user(sid, headers, db, refresh = true)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
user = fetch_user(sid, headers, db)
|
user, sid = fetch_user(sid, headers, db)
|
||||||
user_array = user.to_a
|
user_array = user.to_a
|
||||||
|
|
||||||
user_array[5] = user_array[5].to_json
|
user_array[5] = user_array[5].to_json
|
||||||
args = arg_array(user.to_a)
|
args = arg_array(user.to_a)
|
||||||
|
|
||||||
db.exec("INSERT INTO users VALUES (#{args}) \
|
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
|
begin
|
||||||
view_name = "subscriptions_#{sha256(user.email)[0..7]}"
|
view_name = "subscriptions_#{sha256(user.email)[0..7]}"
|
||||||
|
@ -168,7 +173,7 @@ def get_user(sid, headers, db, refresh = true)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return user
|
return user, sid
|
||||||
end
|
end
|
||||||
|
|
||||||
def fetch_user(sid, headers, db)
|
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))
|
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(Time.now, [] of String, channels, email, DEFAULT_USER_PREFERENCES, nil, token, [] of String)
|
||||||
return user
|
return user, sid
|
||||||
end
|
end
|
||||||
|
|
||||||
def create_user(sid, email, password)
|
def create_user(sid, email, password)
|
||||||
password = Crypto::Bcrypt::Password.create(password, cost: 10)
|
password = Crypto::Bcrypt::Password.create(password, cost: 10)
|
||||||
token = Base64.urlsafe_encode(Random::Secure.random_bytes(32))
|
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
|
end
|
||||||
|
|
||||||
def create_response(user_id, operation, key, db, expire = 6.hours)
|
def create_response(user_id, operation, key, db, expire = 6.hours)
|
||||||
|
|
Loading…
Reference in a new issue