Move DB queries related to session tokens in a separate module
This commit is contained in:
parent
c021b93b5c
commit
92eea3b18b
8 changed files with 140 additions and 22 deletions
|
@ -247,7 +247,7 @@ before_all do |env|
|
|||
|
||||
# Invidious users only have SID
|
||||
if !env.request.cookies.has_key? "SSID"
|
||||
if email = PG_DB.query_one?("SELECT email FROM session_ids WHERE id = $1", sid, as: String)
|
||||
if email = Invidious::Database::SessionIDs.select_email(sid)
|
||||
user = PG_DB.query_one("SELECT * FROM users WHERE email = $1", email, as: User)
|
||||
csrf_token = generate_response(sid, {
|
||||
":authorize_token",
|
||||
|
@ -633,6 +633,7 @@ get "/subscription_manager" do |env|
|
|||
end
|
||||
|
||||
user = user.as(User)
|
||||
sid = sid.as(String)
|
||||
|
||||
if !user.password
|
||||
# Refresh account
|
||||
|
@ -1008,7 +1009,7 @@ post "/delete_account" do |env|
|
|||
|
||||
view_name = "subscriptions_#{sha256(user.email)}"
|
||||
PG_DB.exec("DELETE FROM users * WHERE email = $1", user.email)
|
||||
PG_DB.exec("DELETE FROM session_ids * WHERE email = $1", user.email)
|
||||
Invidious::Database::SessionIDs.delete(email: user.email)
|
||||
PG_DB.exec("DROP MATERIALIZED VIEW #{view_name}")
|
||||
|
||||
env.request.cookies.each do |cookie|
|
||||
|
@ -1150,8 +1151,7 @@ get "/token_manager" do |env|
|
|||
end
|
||||
|
||||
user = user.as(User)
|
||||
|
||||
tokens = PG_DB.query_all("SELECT id, issued FROM session_ids WHERE email = $1 ORDER BY issued DESC", user.email, as: {session: String, issued: Time})
|
||||
tokens = Invidious::Database::SessionIDs.select_all(user.email)
|
||||
|
||||
templated "token_manager"
|
||||
end
|
||||
|
@ -1200,7 +1200,7 @@ post "/token_ajax" do |env|
|
|||
|
||||
case action
|
||||
when .starts_with? "action_revoke_token"
|
||||
PG_DB.exec("DELETE FROM session_ids * WHERE id = $1 AND email = $2", session, user.email)
|
||||
Invidious::Database::SessionIDs.delete(sid: session, email: user.email)
|
||||
else
|
||||
next error_json(400, "Unsupported action #{action}")
|
||||
end
|
||||
|
|
46
src/invidious/database/nonces.cr
Normal file
46
src/invidious/database/nonces.cr
Normal file
|
@ -0,0 +1,46 @@
|
|||
require "./base.cr"
|
||||
|
||||
module Invidious::Database::Nonces
|
||||
extend self
|
||||
|
||||
# -------------------
|
||||
# Insert
|
||||
# -------------------
|
||||
|
||||
def insert(nonce : String, expire : Time)
|
||||
request = <<-SQL
|
||||
INSERT INTO nonces
|
||||
VALUES ($1, $2)
|
||||
ON CONFLICT DO NOTHING
|
||||
SQL
|
||||
|
||||
PG_DB.exec(request, nonce, expire)
|
||||
end
|
||||
|
||||
# -------------------
|
||||
# Update
|
||||
# -------------------
|
||||
|
||||
def update_set_expired(nonce : String)
|
||||
request = <<-SQL
|
||||
UPDATE nonces
|
||||
SET expire = $1
|
||||
WHERE nonce = $2
|
||||
SQL
|
||||
|
||||
PG_DB.exec(request, Time.utc(1990, 1, 1), nonce)
|
||||
end
|
||||
|
||||
# -------------------
|
||||
# Select
|
||||
# -------------------
|
||||
|
||||
def select(nonce : String) : Tuple(String, Time)?
|
||||
request = <<-SQL
|
||||
SELECT * FROM nonces
|
||||
WHERE nonce = $1
|
||||
SQL
|
||||
|
||||
return PG_DB.query_one?(request, nonce, as: {String, Time})
|
||||
end
|
||||
end
|
74
src/invidious/database/sessions.cr
Normal file
74
src/invidious/database/sessions.cr
Normal file
|
@ -0,0 +1,74 @@
|
|||
require "./base.cr"
|
||||
|
||||
module Invidious::Database::SessionIDs
|
||||
extend self
|
||||
|
||||
# -------------------
|
||||
# Insert
|
||||
# -------------------
|
||||
|
||||
def insert(sid : String, email : String, handle_conflicts : Bool = false)
|
||||
request = <<-SQL
|
||||
INSERT INTO session_ids
|
||||
VALUES ($1, $2, $3)
|
||||
SQL
|
||||
|
||||
request += " ON CONFLICT (id) DO NOTHING" if handle_conflicts
|
||||
|
||||
PG_DB.exec(request, sid, email, Time.utc)
|
||||
end
|
||||
|
||||
# -------------------
|
||||
# Delete
|
||||
# -------------------
|
||||
|
||||
def delete(*, sid : String)
|
||||
request = <<-SQL
|
||||
DELETE FROM session_ids *
|
||||
WHERE id = $1
|
||||
SQL
|
||||
|
||||
PG_DB.exec(request, sid)
|
||||
end
|
||||
|
||||
def delete(*, email : String)
|
||||
request = <<-SQL
|
||||
DELETE FROM session_ids *
|
||||
WHERE email = $1
|
||||
SQL
|
||||
|
||||
PG_DB.exec(request, email)
|
||||
end
|
||||
|
||||
def delete(*, sid : String, email : String)
|
||||
request = <<-SQL
|
||||
DELETE FROM session_ids *
|
||||
WHERE id = $1 AND email = $2
|
||||
SQL
|
||||
|
||||
PG_DB.exec(request, sid, email)
|
||||
end
|
||||
|
||||
# -------------------
|
||||
# Select
|
||||
# -------------------
|
||||
|
||||
def select_email(sid : String) : String?
|
||||
request = <<-SQL
|
||||
SELECT email FROM session_ids
|
||||
WHERE id = $1
|
||||
SQL
|
||||
|
||||
PG_DB.query_one?(request, sid, as: String)
|
||||
end
|
||||
|
||||
def select_all(email : String) : Array({session: String, issued: Time})
|
||||
request = <<-SQL
|
||||
SELECT id, issued FROM session_ids
|
||||
WHERE email = $1
|
||||
ORDER BY issued DESC
|
||||
SQL
|
||||
|
||||
PG_DB.query_all(request, email, as: {session: String, issued: Time})
|
||||
end
|
||||
end
|
|
@ -99,7 +99,7 @@ class AuthHandler < Kemal::Handler
|
|||
session = URI.decode_www_form(token["session"].as_s)
|
||||
scopes, expire, signature = validate_request(token, session, env.request, HMAC_KEY, PG_DB, nil)
|
||||
|
||||
if email = PG_DB.query_one?("SELECT email FROM session_ids WHERE id = $1", session, as: String)
|
||||
if email = Invidious::Database::SessionIDs.select_email(session)
|
||||
user = PG_DB.query_one("SELECT * FROM users WHERE email = $1", email, as: User)
|
||||
end
|
||||
elsif sid = env.request.cookies["SID"]?.try &.value
|
||||
|
@ -107,7 +107,7 @@ class AuthHandler < Kemal::Handler
|
|||
raise "Cannot use token as SID"
|
||||
end
|
||||
|
||||
if email = PG_DB.query_one?("SELECT email FROM session_ids WHERE id = $1", sid, as: String)
|
||||
if email = Invidious::Database::SessionIDs.select_email(sid)
|
||||
user = PG_DB.query_one("SELECT * FROM users WHERE email = $1", email, as: User)
|
||||
end
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ require "crypto/subtle"
|
|||
|
||||
def generate_token(email, scopes, expire, key, db)
|
||||
session = "v1:#{Base64.urlsafe_encode(Random::Secure.random_bytes(32))}"
|
||||
PG_DB.exec("INSERT INTO session_ids VALUES ($1, $2, $3)", session, email, Time.utc)
|
||||
Invidious::Database::SessionIDs.insert(session, email)
|
||||
|
||||
token = {
|
||||
"session" => session,
|
||||
|
@ -30,7 +30,7 @@ def generate_response(session, scopes, key, db, expire = 6.hours, use_nonce = fa
|
|||
|
||||
if use_nonce
|
||||
nonce = Random::Secure.hex(16)
|
||||
db.exec("INSERT INTO nonces VALUES ($1, $2) ON CONFLICT DO NOTHING", nonce, expire)
|
||||
Invidious::Database::Nonces.insert(nonce, expire)
|
||||
token["nonce"] = nonce
|
||||
end
|
||||
|
||||
|
@ -92,9 +92,9 @@ def validate_request(token, session, request, key, db, locale = nil)
|
|||
raise InfoException.new("Invalid signature")
|
||||
end
|
||||
|
||||
if token["nonce"]? && (nonce = db.query_one?("SELECT * FROM nonces WHERE nonce = $1", token["nonce"], as: {String, Time}))
|
||||
if token["nonce"]? && (nonce = Invidious::Database::Nonces.select(token["nonce"].as_s))
|
||||
if nonce[1] > Time.utc
|
||||
db.exec("UPDATE nonces SET expire = $1 WHERE nonce = $2", Time.utc(1990, 1, 1), nonce[0])
|
||||
Invidious::Database::Nonces.update_set_expired(nonce[0])
|
||||
else
|
||||
raise InfoException.new("Erroneous token")
|
||||
end
|
||||
|
|
|
@ -312,7 +312,7 @@ module Invidious::Routes::API::V1::Authenticated
|
|||
user = env.get("user").as(User)
|
||||
scopes = env.get("scopes").as(Array(String))
|
||||
|
||||
tokens = PG_DB.query_all("SELECT id, issued FROM session_ids WHERE email = $1", user.email, as: {session: String, issued: Time})
|
||||
tokens = Invidious::Database::SessionIDs.select_all(user.email)
|
||||
|
||||
JSON.build do |json|
|
||||
json.array do
|
||||
|
@ -400,9 +400,9 @@ module Invidious::Routes::API::V1::Authenticated
|
|||
|
||||
# Allow tokens to revoke other tokens with correct scope
|
||||
if session == env.get("session").as(String)
|
||||
PG_DB.exec("DELETE FROM session_ids * WHERE id = $1", session)
|
||||
Invidious::Database::SessionIDs.delete(sid: session)
|
||||
elsif scopes_include_scope(scopes, "GET:tokens")
|
||||
PG_DB.exec("DELETE FROM session_ids * WHERE id = $1", session)
|
||||
Invidious::Database::SessionIDs.delete(sid: session)
|
||||
else
|
||||
return error_json(400, "Cannot revoke session #{session}")
|
||||
end
|
||||
|
|
|
@ -336,7 +336,7 @@ module Invidious::Routes::Login
|
|||
|
||||
if Crypto::Bcrypt::Password.new(user.password.not_nil!).verify(password.byte_slice(0, 55))
|
||||
sid = Base64.urlsafe_encode(Random::Secure.random_bytes(32))
|
||||
PG_DB.exec("INSERT INTO session_ids VALUES ($1, $2, $3)", sid, email, Time.utc)
|
||||
Invidious::Database::SessionIDs.insert(sid, email)
|
||||
|
||||
if Kemal.config.ssl || CONFIG.https_only
|
||||
secure = true
|
||||
|
@ -455,7 +455,7 @@ module Invidious::Routes::Login
|
|||
args = arg_array(user_array)
|
||||
|
||||
PG_DB.exec("INSERT INTO users VALUES (#{args})", args: user_array)
|
||||
PG_DB.exec("INSERT INTO session_ids VALUES ($1, $2, $3)", sid, email, Time.utc)
|
||||
Invidious::Database::SessionIDs.insert(sid, email)
|
||||
|
||||
view_name = "subscriptions_#{sha256(user.email)}"
|
||||
PG_DB.exec("CREATE MATERIALIZED VIEW #{view_name} AS #{MATERIALIZED_VIEW_SQL.call(user.email)}")
|
||||
|
@ -511,7 +511,7 @@ module Invidious::Routes::Login
|
|||
return error_template(400, ex)
|
||||
end
|
||||
|
||||
PG_DB.exec("DELETE FROM session_ids * WHERE id = $1", sid)
|
||||
Invidious::Database::SessionIDs.delete(sid: sid)
|
||||
|
||||
env.request.cookies.each do |cookie|
|
||||
cookie.expires = Time.utc(1990, 1, 1)
|
||||
|
|
|
@ -30,7 +30,7 @@ struct User
|
|||
end
|
||||
|
||||
def get_user(sid, headers, db, refresh = true)
|
||||
if email = db.query_one?("SELECT email FROM session_ids WHERE id = $1", sid, as: String)
|
||||
if email = Invidious::Database::SessionIDs.select_email(sid)
|
||||
user = db.query_one("SELECT * FROM users WHERE email = $1", email, as: User)
|
||||
|
||||
if refresh && Time.utc - user.updated > 1.minute
|
||||
|
@ -42,8 +42,7 @@ def get_user(sid, headers, db, refresh = true)
|
|||
db.exec("INSERT INTO users VALUES (#{args}) \
|
||||
ON CONFLICT (email) DO UPDATE SET updated = $1, subscriptions = $3", args: user_array)
|
||||
|
||||
db.exec("INSERT INTO session_ids VALUES ($1,$2,$3) \
|
||||
ON CONFLICT (id) DO NOTHING", sid, user.email, Time.utc)
|
||||
Invidious::Database::SessionIDs.insert(sid, user.email, handle_conflicts: true)
|
||||
|
||||
begin
|
||||
view_name = "subscriptions_#{sha256(user.email)}"
|
||||
|
@ -60,8 +59,7 @@ def get_user(sid, headers, db, refresh = true)
|
|||
db.exec("INSERT INTO users VALUES (#{args}) \
|
||||
ON CONFLICT (email) DO UPDATE SET updated = $1, subscriptions = $3", args: user_array)
|
||||
|
||||
db.exec("INSERT INTO session_ids VALUES ($1,$2,$3) \
|
||||
ON CONFLICT (id) DO NOTHING", sid, user.email, Time.utc)
|
||||
Invidious::Database::SessionIDs.insert(sid, user.email, handle_conflicts: true)
|
||||
|
||||
begin
|
||||
view_name = "subscriptions_#{sha256(user.email)}"
|
||||
|
|
Loading…
Reference in a new issue