feat: usr_session
This commit is contained in:
parent
0b9c597ca4
commit
0502154f4d
0
client_min_messages
Normal file
0
client_min_messages
Normal file
@ -7,7 +7,7 @@ services:
|
|||||||
ports:
|
ports:
|
||||||
- "5433:5432"
|
- "5433:5432"
|
||||||
volumes:
|
volumes:
|
||||||
- "./data/base:/var/lib/postgres/data"
|
- "./data/base:/var/lib/postgresql/data"
|
||||||
env_file:
|
env_file:
|
||||||
- "./.env.schema"
|
- "./.env.schema"
|
||||||
head:
|
head:
|
||||||
@ -17,6 +17,6 @@ services:
|
|||||||
ports:
|
ports:
|
||||||
- "5432:5432"
|
- "5432:5432"
|
||||||
volumes:
|
volumes:
|
||||||
- "./data/head:/var/lib/postgres/data"
|
- "./data/head:/var/lib/postgresql/data"
|
||||||
env_file:
|
env_file:
|
||||||
- "./.env.schema"
|
- "./.env.schema"
|
||||||
|
@ -1,5 +1,33 @@
|
|||||||
select create_newtype_text('public.usr_tag');
|
select create_newtype_text('public.usr_tag');
|
||||||
|
|
||||||
|
select create_newtype_text('public.usr_tag_or_email');
|
||||||
|
|
||||||
|
create function usr_tag_or_email_to_email(toe public.usr_tag_or_email)
|
||||||
|
returns public.email
|
||||||
|
language plpgsql
|
||||||
|
immutable as $$
|
||||||
|
begin
|
||||||
|
if position('@' in usr_tag_or_email_to_string(toe)) > 0 then
|
||||||
|
return email_of_string(usr_tag_or_email_to_string(toe));
|
||||||
|
else
|
||||||
|
return null;
|
||||||
|
end if;
|
||||||
|
end;
|
||||||
|
$$;
|
||||||
|
|
||||||
|
create function usr_tag_or_email_to_tag(toe public.usr_tag_or_email)
|
||||||
|
returns public.usr_tag
|
||||||
|
language plpgsql
|
||||||
|
immutable as $$
|
||||||
|
begin
|
||||||
|
if usr_tag_or_email_to_email(toe) is null then
|
||||||
|
return usr_tag_of_string(usr_tag_or_email_to_string(toe));
|
||||||
|
else
|
||||||
|
return null;
|
||||||
|
end if;
|
||||||
|
end;
|
||||||
|
$$;
|
||||||
|
|
||||||
create table public.usr
|
create table public.usr
|
||||||
( id int not null primary key generated always as identity
|
( id int not null primary key generated always as identity
|
||||||
, uid uuid not null default gen_random_uuid()
|
, uid uuid not null default gen_random_uuid()
|
||||||
@ -10,7 +38,6 @@ create table public.usr
|
|||||||
);
|
);
|
||||||
|
|
||||||
insert into public.usr (tag, password, email)
|
insert into public.usr (tag, password, email)
|
||||||
overriding system value
|
|
||||||
values (usr_tag_of_string('system'), hashed_text_of_string(''), email_of_string(''));
|
values (usr_tag_of_string('system'), hashed_text_of_string(''), email_of_string(''));
|
||||||
|
|
||||||
select audit( 'public'
|
select audit( 'public'
|
||||||
|
@ -118,4 +118,3 @@ select immutable( 'public'
|
|||||||
, 'usr'
|
, 'usr'
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
118
schema/021_user.sql
Normal file
118
schema/021_user.sql
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
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 default usr_session_key_gen()
|
||||||
|
, 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;
|
||||||
|
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
|
||||||
|
(expires_at, usr, location, device, ip)
|
||||||
|
values
|
||||||
|
(expires_at, usr.id, location, device, ip)
|
||||||
|
returning usr_session.key
|
||||||
|
into key;
|
||||||
|
|
||||||
|
return key;
|
||||||
|
end;
|
||||||
|
$$;
|
Loading…
Reference in New Issue
Block a user