db/schema/021_usr_session.sql

117 lines
3.3 KiB
MySQL
Raw Normal View History

2023-07-02 20:57:28 +00:00
select create_newtype_text('public.usr_session_key');
create function usr_session_key_gen()
returns public.usr_session_key
volatile
language sql as $$
select usr_session_key_of_string(
md5(extract(epoch from now()) || gen_random_bytes(32) :: text)
);
$$;
create type usr_session_device as enum
( 'linux'
, 'macos'
, 'win'
, 'android'
, 'ios'
, 'other'
);
create table public.usr_session
( id int not null primary key generated always as identity
, key public.usr_session_key not null unique
2023-07-02 20:57:28 +00:00
, expired boolean not null default false
, expires_at timestamp not null
, usr int not null references public.usr (id)
, location text null
, device usr_session_device null
, ip inet null
);
select immutable( 'public'
, 'usr_session'
, array[ 'id'
, 'key'
, 'expires_at'
, 'usr'
, 'location'
, 'device'
, 'ip'
]
);
create function public.usr_session_login_validate
( tag_or_email public.usr_tag_or_email
, password text
)
returns public.usr
language plpgsql
stable
as $$
declare
usr_email public.email := public.usr_tag_or_email_to_email(tag_or_email);
usr_tag public.usr_tag := public.usr_tag_or_email_to_tag(tag_or_email);
usr public.usr;
begin
select *
from public.usr as u
where u.email = usr_email
or u.tag = usr_tag
into usr;
if usr.id = 1 or usr.tag = usr_tag_of_string('system') then
raise notice 'system user may not be logged into';
raise exception 'incorrect password for user %', usr_tag_or_email_to_string(tag_or_email);
end if;
if usr is null then
-- prevent email guess bruteforces by raising the same exception
-- for invalid password and user not found
raise notice 'user % not found', usr_tag_or_email_to_string(tag_or_email);
raise exception 'incorrect password for user %', usr_tag_or_email_to_string(tag_or_email);
end if;
if not hashed_text_matches(password, usr.password) then
raise notice 'password does not match for user %', usr_tag_or_email_to_string(tag_or_email);
raise exception 'incorrect password for user %', usr_tag_or_email_to_string(tag_or_email);
end if;
return usr;
end;
$$;
create function public.usr_session_login
( tag_or_email public.usr_tag_or_email
, password text
, remember boolean default false
, location text default null
, device public.usr_session_device default null
, ip inet default null
)
returns public.usr_session_key
language plpgsql
volatile
as $$
declare
usr public.usr;
key public.usr_session_key := usr_session_key_gen();
2023-07-02 20:57:28 +00:00
expires_at timestamp;
begin
usr := public.usr_session_login_validate(tag_or_email, password);
if remember then
expires_at := now() + interval '1 week';
else
expires_at := now() + interval '1 hour';
end if;
insert into public.usr_session
(key, expires_at, usr, location, device, ip)
2023-07-02 20:57:28 +00:00
values
(key, expires_at, usr.id, location, device, ip);
2023-07-02 20:57:28 +00:00
return key;
end;
$$;