-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
rework codebase to use sea_orm instead
move entities rework polar rules buncha other changes rework rules and endpoint logic fix role assn remove unused imports fix oso query, result might be error update deps super thicc diff too many changes to document, but basically reworking to use SeaORM WIP dumb mistake WIP bloop don't actually need the extra ref more WIP don't program when tired seriously, DONT PROGRAM WHEN TIRED fix remove custom-derive, use fieldfilter WIP adjust rules to work with new pclasses impl update_user handler finish user handlers rewrite finish rework whoops
- Loading branch information
1 parent
e2f20c0
commit 0434463
Showing
24 changed files
with
758 additions
and
506 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
[tasks.format] | ||
install_crate = "rustfmt" | ||
command = "cargo" | ||
args = ["fmt", "--", "--emit=files"] | ||
|
||
[tasks.clean] | ||
command = "cargo" | ||
args = ["clean"] | ||
|
||
[tasks.build] | ||
command = "cargo" | ||
args = ["build"] | ||
dependencies = ["clean"] | ||
|
||
[tasks.test] | ||
command = "cargo" | ||
args = ["test"] | ||
dependencies = ["clean"] | ||
|
||
[tasks.create-db] | ||
command = "sqlx" | ||
args = ["database", "create"] | ||
workspace = false | ||
|
||
[tasks.drop-db] | ||
command = "sqlx" | ||
args = ["database", "drop"] | ||
workspace = false | ||
|
||
[tasks.generate-entities] | ||
command = "sea-orm-cli" | ||
args = ["generate", "entity", "-o", "entity/src", "--with-serde", "both"] | ||
workspace = false |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
|
||
[package] | ||
name = "entity" | ||
version = "0.1.0" | ||
edition = "2021" | ||
publish = false | ||
|
||
[lib] | ||
name = "entity" | ||
path = "src/mod.rs" | ||
|
||
[dependencies] | ||
bincode = "1.3.3" | ||
oso = { git = "https://github.com/fairingrey/oso", branch = "rust-addl-interface", features = [ | ||
"uuid-07", | ||
] } | ||
redis = { version = "0.21.5", features = [ | ||
"aio", | ||
"tokio-comp", | ||
"connection-manager", | ||
], default-features = false } | ||
sea-orm = { version = "0.6.0", features = [ | ||
"macros", | ||
"debug-print", | ||
"runtime-tokio-native-tls", | ||
"sqlx-postgres", | ||
], default-features = false } | ||
serde = { version = "1.0.136", features = ["derive"] } |
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
//! SeaORM Entity. Generated by sea-orm-codegen 0.6.0 | ||
pub mod macros; | ||
pub mod prelude; | ||
|
||
pub mod sea_orm_active_enums; | ||
pub mod user_account; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
//! SeaORM Entity. Generated by sea-orm-codegen 0.6.0 | ||
pub use super::user_account::Entity as UserAccount; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
//! SeaORM Entity. Generated by sea-orm-codegen 0.6.0 | ||
use oso::PolarClass; | ||
use sea_orm::entity::prelude::*; | ||
use serde::{Deserialize, Serialize}; | ||
|
||
#[derive( | ||
Debug, Clone, PartialEq, EnumIter, DeriveActiveEnum, Serialize, Deserialize, PolarClass, | ||
)] | ||
#[sea_orm(rs_type = "String", db_type = "Enum", enum_name = "user_role")] | ||
pub enum UserRole { | ||
#[sea_orm(string_value = "admin")] | ||
Admin, | ||
#[sea_orm(string_value = "contributor")] | ||
Contributor, | ||
#[sea_orm(string_value = "creator")] | ||
Creator, | ||
#[sea_orm(string_value = "maintainer")] | ||
Maintainer, | ||
#[sea_orm(string_value = "member")] | ||
Member, | ||
#[sea_orm(string_value = "moderator")] | ||
Moderator, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
//! SeaORM Entity. Generated by sea-orm-codegen 0.6.0 | ||
use super::sea_orm_active_enums::UserRole; | ||
use oso::PolarClass; | ||
use sea_orm::entity::prelude::*; | ||
use serde::{Deserialize, Serialize}; | ||
|
||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize, Deserialize, PolarClass)] | ||
#[sea_orm(table_name = "user_account")] | ||
#[polar(class_name = "User")] | ||
pub struct Model { | ||
#[sea_orm(primary_key, auto_increment = false)] | ||
#[polar(attribute)] | ||
pub id: Uuid, | ||
pub created_at: DateTimeWithTimeZone, | ||
pub updated_at: DateTimeWithTimeZone, | ||
#[sea_orm(column_type = "Text")] | ||
#[polar(attribute)] | ||
pub name: String, | ||
#[polar(attribute)] | ||
pub email: String, | ||
#[polar(attribute)] | ||
pub role: UserRole, | ||
#[sea_orm(column_type = "Text")] | ||
pub password: String, | ||
#[polar(attribute)] | ||
pub verified: bool, | ||
} | ||
|
||
#[derive(Copy, Clone, Debug, EnumIter)] | ||
pub enum Relation {} | ||
|
||
impl RelationTrait for Relation { | ||
fn def(&self) -> RelationDef { | ||
panic!("No RelationDef") | ||
} | ||
} | ||
|
||
impl ActiveModelBehavior for ActiveModel {} | ||
|
||
crate::impl_redis_rv!(Model); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
-- Add down migration script here | ||
DROP TABLE IF EXISTS user_account; | ||
|
||
DROP TYPE IF EXISTS user_role; |
8 changes: 4 additions & 4 deletions
8
...ations/20220211233308_create_users.up.sql → ...20220211233308_create_user_account.up.sql
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,16 +1,16 @@ | ||
-- Add up migration script here | ||
CREATE TYPE role AS ENUM ('admin', 'moderator', 'maintainer', 'creator', 'contributor', 'member'); | ||
CREATE TYPE user_role AS ENUM ('admin', 'moderator', 'maintainer', 'creator', 'contributor', 'member'); | ||
|
||
CREATE TABLE users ( | ||
CREATE TABLE user_account ( | ||
id UUID PRIMARY KEY NOT NULL, | ||
created_at TIMESTAMPTZ NOT NULL DEFAULT current_timestamp, | ||
updated_at TIMESTAMPTZ NOT NULL DEFAULT current_timestamp, | ||
name TEXT NOT NULL, | ||
email VARCHAR(254) NOT NULL, | ||
UNIQUE (name, email), | ||
role role NOT NULL DEFAULT 'member', | ||
role user_role NOT NULL DEFAULT 'member', | ||
password TEXT NOT NULL, | ||
verified BOOLEAN NOT NULL DEFAULT FALSE | ||
); | ||
|
||
SELECT manage_updated_at('users'); | ||
SELECT manage_updated_at('user_account'); |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,55 +1,46 @@ | ||
# User rules | ||
|
||
## admins and mods can read all of a user's fields except passwords | ||
allow_field(user: User, "READ", _other_user: User, field) if | ||
allow_field(user: User, _: Read, _other_user: User, field) if | ||
user.role in [Role::Admin, Role::Moderator] and | ||
field in ["name", "created_at", "updated_at", "role", "email"]; | ||
field in ["created_at", "updated_at", "name", "email", "role"]; | ||
|
||
## users can read all of their own fields except passwords | ||
allow_field(user: User, "READ", other_user: User, field) if | ||
allow_field(user: User, _: Read, other_user: User, field) if | ||
user.id == other_user.id and | ||
field in ["name", "created_at", "updated_at", "role", "email"]; | ||
field in ["created_at", "updated_at", "name", "email", "role"]; | ||
|
||
## anyone can read ids, names, created_at, and role of other users | ||
allow_field(_, "READ", _other_user: User, field: String) if | ||
field in ["name", "created_at", "role"]; | ||
## anyone can read names, created_at, and role of other users | ||
allow_field(_, _: Read, _other_user: User, field: String) if | ||
field in ["created_at", "name", "role"]; | ||
|
||
## admins can change user names or emails | ||
allow_field(user: User, "UPDATE", _other_user: User, field: String) if | ||
## admins can change everything for a user except the password | ||
allow(user: User, update: UpdateUser, _other_user: User) if | ||
user.role = Role::Admin and | ||
field in ["name", "email"]; | ||
update.password = nil; | ||
|
||
## moderators can do the same but only to other users of role below them | ||
allow_field(user: User, "UPDATE", other_user: User, field: String) if | ||
## they cannot assign roles higher than or equal to themselves | ||
allow(user: User, update: UpdateUser, other_user: User) if | ||
user.role = Role::Moderator and | ||
other_user.role in [Role::Maintainer, Role::Creator, Role::Contributor, Role::Member] and | ||
field in ["name", "email"]; | ||
update.role in [Role::Maintainer, Role::Creator, Role::Contributor, Role::Member, nil] and | ||
update.password = nil; | ||
|
||
## users can update themselves but not their role | ||
allow(user: User, update: UpdateUser, other_user: User) if | ||
user.id = other_user.id and | ||
changes.role = nil; | ||
|
||
## admins can delete other users | ||
allow(user: User, "DELETE", _other_user: User) if | ||
allow(user: User, _: Delete, _other_user: User) if | ||
user.role = Role::Admin; | ||
|
||
## moderators can also, but again only to other users of role below them | ||
allow(user: User, "DELETE", other_user: User) if | ||
allow(user: User, _: Delete, other_user: User) if | ||
user.role = Role::Moderator and | ||
other_user.role in [Role::Maintainer, Role::Creator, Role::Contributor, Role::Member]; | ||
|
||
# role specific stuff | ||
|
||
## admins can assign any role | ||
allow_assign_role(user: User, _role: Role) if | ||
user.role = Role::Admin; | ||
|
||
## Moderators can only assign roles below them | ||
allow_assign_role(user: User, role: Role) if | ||
user.role = Role::Moderator and | ||
role in [Role::Maintainer, Role::Creator, Role::Contributor, Role::Member]; | ||
|
||
## users can update themselves but only on certain fields | ||
allow_field(user: User, "UPDATE", other_user: User, field) if | ||
field in ["name", "email", "password"] and | ||
user.id = other_user.id; | ||
|
||
## users can delete themselves | ||
allow(user: User, "DELETE", other_user: User) if | ||
allow(user: User, _: Delete, other_user: User) if | ||
user.id = other_user.id; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
//! CRUD action-like resources | ||
use anyhow::Result; | ||
use entity::sea_orm_active_enums::UserRole; | ||
use oso::{Oso, PolarClass}; | ||
use serde::Deserialize; | ||
use validator::Validate; | ||
|
||
use crate::constants::RE_USERNAME; | ||
|
||
/// The "READ" action. Because there is no data pertinent to this action it is a unit struct. | ||
#[derive(Debug, Clone, Copy, PolarClass)] | ||
pub(crate) struct Read; | ||
|
||
/// The "DELETE" action. Because there is no data pertinent to this action it is a unit struct. | ||
#[derive(Debug, Clone, Copy, PolarClass)] | ||
pub(crate) struct Delete; | ||
|
||
/// The action by which a user is updated. Can be understood as a sort of changeset. | ||
/// | ||
/// This struct in particular doubles up for multiple use cases. It's used for PUT `/user/:id` form responses, | ||
/// in authorization rules, and also for updates to the ORM. | ||
#[derive(Debug, Clone, Validate, Deserialize, PolarClass)] | ||
pub(crate) struct UpdateUser { | ||
#[validate( | ||
length( | ||
min = 5, | ||
max = 32, | ||
message = "Minimum length is 5 characters, maximum is 32" | ||
), | ||
regex( | ||
path = "RE_USERNAME", | ||
message = "Can only contain letters, numbers, dashes (-), periods (.), and underscores (_)" | ||
) | ||
)] | ||
#[polar(attribute)] | ||
pub(crate) name: Option<String>, | ||
#[validate(email(message = "Must be a valid email address."))] | ||
#[polar(attribute)] | ||
pub(crate) email: Option<String>, | ||
#[polar(attribute)] | ||
pub(crate) role: Option<UserRole>, | ||
} | ||
|
||
/// Attempt to create a new oso instance for managing authorization schemes. | ||
pub(crate) fn try_register_oso() -> Result<Oso> { | ||
let mut oso = Oso::new(); | ||
|
||
// NOTE: load classes here | ||
oso.register_class(entity::user_account::Model::get_polar_class())?; | ||
oso.register_class(UserRole::get_polar_class())?; | ||
|
||
// action classes in this module should be loaded here too | ||
oso.register_class(Read::get_polar_class())?; | ||
oso.register_class(Delete::get_polar_class())?; | ||
oso.register_class(UpdateUser::get_polar_class())?; | ||
|
||
// NOTE: load oso rule files here | ||
oso.load_files(vec!["polar/users.polar"])?; | ||
|
||
Ok(oso) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.