Skip to content

Commit

Permalink
Merge pull request #24 from curieo-org/rust-server-users-and-login
Browse files Browse the repository at this point in the history
Rust server users and basic login with sessions
  • Loading branch information
ivarflakstad authored Apr 1, 2024
2 parents 495a662 + 7f456b5 commit 4607ba3
Show file tree
Hide file tree
Showing 28 changed files with 3,096 additions and 106 deletions.
1,834 changes: 1,774 additions & 60 deletions server/Cargo.lock

Large diffs are not rendered by default.

24 changes: 22 additions & 2 deletions server/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,39 @@ name = "server"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[lib]
path = "src/lib.rs"

[[bin]]
name = "server"
path = "src/main.rs"

[dependencies]
anyhow = { version = "1.0.81", features = ["backtrace"] }
async-trait = "0.1.78"
axum = { version = "0.7.4", features = ["macros"] }
axum-login = "0.15.0"
chrono = { version = "0.4.35", features = ["serde"] }
color-eyre = "0.6.3"
config = { version = "0.14.0", features = ["toml"] }
dotenvy = "0.15.7"
hyper = { version = "1.2.0", features = ["full"] }
oauth2 = "4.4.2"
once_cell = "1.19.0"
secrecy = { version = "0.8.0", features = ["serde"] }
password-auth = "1.0.0"
reqwest = { version = "0.12.1", features = ["json"] }
serde = "1.0.197"
serde_json = "1.0.114"
serde_urlencoded = "0.7.1"
sqlx = { version = "0.7.4", features = ["postgres", "runtime-tokio", "tls-rustls", "migrate", "uuid", "time"] }
thiserror = "1.0.58"
tokio = { version = "1.36.0", features = ["full"] }
tower-http = { version = "0.5.2", features = ["trace", "cors"] }
tracing = "0.1.40"
tower = "0.4.13"
tracing-error = "0.2.0"
tracing-log = "0.2.0"
tracing-logfmt = "0.3.4"
tracing-subscriber = { version = "0.3.18", features = ["json", "registry", "env-filter"] }
uuid = { version = "1.8.0", features = ["serde"] }
log = "0.4.21"
5 changes: 5 additions & 0 deletions server/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// generated by `sqlx migrate build-script`
fn main() {
// trigger recompilation when a new migration is added
println!("cargo:rerun-if-changed=migrations");
}
2 changes: 2 additions & 0 deletions server/config/dev.toml
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
db = "postgresql://postgres:postgres@localhost/curieo"

[log]
level = "info"
format = "json"
47 changes: 47 additions & 0 deletions server/migrations/20240321195639_setup.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
-- As a style choice, we prefer not to write SQL in all uppercase as lowercase feels friendlier to the eyes.
-- It's nicer to read WHEN THE CODE ISN'T YELLING AT YOU ALL DAY.
-- It perhaps made sense back when code highlighting was not the norm and case was used to differentiate keywords
-- from non-keywords, but at this point it's purely from inertia.
-- The language itself is not case-sensitive except for quoted identifiers.
-- Whichever style you use, however, consistency should still be maintained.

-- This extension gives us `uuid_generate_v1mc()` which generates UUIDs that cluster better than `gen_random_uuid()`
-- while still being difficult to predict and enumerate.
-- Also, while unlikely, `gen_random_uuid()` can in theory produce collisions which can trigger spurious errors on
-- insertion, whereas it's much less likely with `uuid_generate_v1mc()`.
create extension if not exists "uuid-ossp";

-- We try to ensure every table has `created_at` and `updated_at` columns, which can help immensely with debugging
-- and auditing.
--
-- While `created_at` can just be `default now()`, setting `updated_at` on update requires a trigger which
-- is a lot of boilerplate. These two functions save us from writing that every time as instead we can just do
--
-- select trigger_updated_at('<table name>');
--
-- after a `CREATE TABLE`.
create or replace function set_updated_at()
returns trigger as
$$
begin
NEW.updated_at = now();
return NEW;
end;
$$ language plpgsql;

create or replace function trigger_updated_at(tablename regclass)
returns void as
$$
begin
execute format('CREATE TRIGGER set_updated_at
BEFORE UPDATE
ON %s
FOR EACH ROW
WHEN (OLD is distinct from NEW)
EXECUTE FUNCTION set_updated_at();', tablename);
end;
$$ language plpgsql;

-- Finally, this is a text collation that sorts text case-insensitively, useful for `UNIQUE` indexes
-- over things like usernames and emails, without needing to remember to do case-conversion.
create collation case_insensitive (provider = icu, locale = 'und-u-ks-level2', deterministic = false);
19 changes: 19 additions & 0 deletions server/migrations/20240321210310_users.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
create table users (
-- Having the table name as part of the primary key column makes it nicer to write joins, e.g.:
--
-- select * from users
-- inner join article using (user_id)
--
-- as opposed to `inner join article on article.user_id = user.id`, and makes it easier to keep track of primary
-- keys as opposed to having all PK columns named "id"
user_id uuid primary key default uuid_generate_v1mc(),
username text collate "case_insensitive" unique not null,
email text collate "case_insensitive" unique not null,
password_hash text,
access_token text,
created_at timestamptz not null default now(),
updated_at timestamptz
);

-- And applying our `updated_at` trigger is as easy as this.
SELECT trigger_updated_at('users');
7 changes: 7 additions & 0 deletions server/src/auth/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
pub use models::*;
pub use routes::*;
pub use services::*;
pub mod models;
pub mod routes;
pub mod services;
mod utils;
Loading

0 comments on commit 4607ba3

Please sign in to comment.