Skip to content

Commit

Permalink
refactor(tokens)!: DangerousUser -> User & use token table.
Browse files Browse the repository at this point in the history
I refactore & renamed the DangerousUser struct.
The sessions table has been replaced with tokens table in the db.
& The tokens table is now being used for token storage
BREAKING CHANGE: `user.sessions` column replaced by table `tokens` in db.
  • Loading branch information
5-pebbles committed Mar 11, 2024
1 parent 51beb2e commit 5345175
Show file tree
Hide file tree
Showing 13 changed files with 123 additions and 120 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
CREATE TABLE IF NOT EXISTS sessions (id TEXT PRIMARY KEY
CREATE TABLE IF NOT EXISTS tokens (id TEXT PRIMARY KEY
, username TEXT NOT NULL
, FOREIGN KEY (username) REFERENCES users(username)
)
1 change: 0 additions & 1 deletion migrations/U5__users.sql
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
CREATE TABLE IF NOT EXISTS users (username TEXT PRIMARY KEY
, permissions TEXT NOT NULL DEFAULT ''
, hash TEXT NOT NULL
, sessions TEXT NOT NULL DEFAULT ''
)
14 changes: 7 additions & 7 deletions src/api/music/albums.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@ use rocket_sync_db_pools::rusqlite::{params, Error::QueryReturnedNoRows, ToSql};

use crate::{
api::errors::ApiError,
database::{albums::Album, database::Database, permissions::Permission, users::DangerousUser},
database::{albums::Album, database::Database, permissions::Permission, users::User},
};

type Result<T> = std::result::Result<T, ApiError>;

#[post("/album", data = "<album>")]
async fn album_write(db: Database, user: DangerousUser, album: Json<Album>) -> Result<Json<Album>> {
if !user.has_permissions(&[Permission::AlbumWrite]) {
async fn album_write(db: Database, user: User, album: Json<Album>) -> Result<Json<Album>> {
if !user.permissions.contains(&Permission::AlbumWrite) {
Err(Status::Forbidden)?
}

Expand Down Expand Up @@ -55,7 +55,7 @@ async fn album_write(db: Database, user: DangerousUser, album: Json<Album>) -> R
#[get("/album?<id>&<name>&<maxrelease>&<minrelease>&<genres>&<maxcount>&<mincount>&<limit>")]
async fn album_get(
db: Database,
user: DangerousUser,
user: User,
id: Option<String>,
name: Option<String>,
maxrelease: Option<u16>,
Expand All @@ -65,7 +65,7 @@ async fn album_get(
mincount: Option<u16>,
limit: Option<u16>,
) -> Result<Json<Vec<Album>>> {
if !user.has_permissions(&[Permission::AlbumRead]) {
if !user.permissions.contains(&Permission::AlbumRead) {
Err(Status::Forbidden)?
}

Expand Down Expand Up @@ -154,8 +154,8 @@ async fn album_get(
}

#[delete("/album/<id>")]
async fn album_delete(db: Database, user: DangerousUser, id: String) -> Result<()> {
if !user.has_permissions(&[Permission::AlbumDelete]) {
async fn album_delete(db: Database, user: User, id: String) -> Result<()> {
if !user.permissions.contains(&Permission::AlbumDelete) {
Err(Status::Forbidden)?
}

Expand Down
14 changes: 7 additions & 7 deletions src/api/music/artists.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use rocket_sync_db_pools::rusqlite::{params, Error::QueryReturnedNoRows, ToSql};
use crate::{
api::errors::ApiError,
database::{
artists::Artist, database::Database, permissions::Permission, users::DangerousUser,
artists::Artist, database::Database, permissions::Permission, users::User,
},
};

Expand All @@ -13,10 +13,10 @@ type Result<T> = std::result::Result<T, ApiError>;
#[post("/artist", data = "<artist>")]
async fn artist_write(
db: Database,
user: DangerousUser,
user: User,
artist: Json<Artist>,
) -> Result<Json<Artist>> {
if !user.has_permissions(&[Permission::ArtistWrite]) {
if !user.permissions.contains(&Permission::ArtistWrite) {
Err(Status::Forbidden)?
}

Expand Down Expand Up @@ -59,13 +59,13 @@ async fn artist_write(
#[get("/artist?<id>&<name>&<genres>&<limit>")]
async fn artist_get(
db: Database,
user: DangerousUser,
user: User,
id: Option<String>,
name: Option<String>,
genres: Option<Json<Vec<String>>>,
limit: Option<u16>,
) -> Result<Json<Vec<Artist>>> {
if !user.has_permissions(&[Permission::ArtistRead]) {
if !user.permissions.contains(&Permission::ArtistRead) {
Err(Status::Forbidden)?
}

Expand Down Expand Up @@ -116,8 +116,8 @@ async fn artist_get(
}

#[delete("/artist/<id>")]
async fn artist_delete(db: Database, user: DangerousUser, id: String) -> Result<()> {
if !user.has_permissions(&[Permission::ArtistDelete]) {
async fn artist_delete(db: Database, user: User, id: String) -> Result<()> {
if !user.permissions.contains(&Permission::ArtistDelete) {
Err(Status::Forbidden)?
}

Expand Down
14 changes: 7 additions & 7 deletions src/api/music/genres.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
use crate::{
api::errors::ApiError,
database::{database::Database, permissions::Permission, users::DangerousUser},
database::{database::Database, permissions::Permission, users::User},
};
use rocket::{fairing::AdHoc, http::Status, serde::json::Json};
use rocket_sync_db_pools::rusqlite::{params, Error::QueryReturnedNoRows, ToSql};

type Result<T> = std::result::Result<T, ApiError>;

#[post("/genre/<genre>")]
async fn genre_write(db: Database, user: DangerousUser, genre: String) -> Result<Json<String>> {
if !user.has_permissions(&[Permission::GenreWrite]) {
async fn genre_write(db: Database, user: User, genre: String) -> Result<Json<String>> {
if !user.permissions.contains(&Permission::GenreWrite) {
Err(Status::Forbidden)?
}
db.run(move |conn| -> Result<Json<String>> {
Expand All @@ -23,11 +23,11 @@ async fn genre_write(db: Database, user: DangerousUser, genre: String) -> Result
#[get("/genre?<genre>&<limit>")]
async fn genre_get(
db: Database,
user: DangerousUser,
user: User,
genre: Option<String>,
limit: Option<u16>,
) -> Result<Json<Vec<String>>> {
if !user.has_permissions(&[Permission::GenreRead]) {
if !user.permissions.contains(&Permission::GenreRead) {
Err(Status::Forbidden)?
}

Expand Down Expand Up @@ -56,8 +56,8 @@ async fn genre_get(
}

#[delete("/genre/<genre>")]
async fn genre_delete(db: Database, user: DangerousUser, genre: String) -> Result<()> {
if !user.has_permissions(&[Permission::GenreDelete]) {
async fn genre_delete(db: Database, user: User, genre: String) -> Result<()> {
if !user.permissions.contains(&Permission::GenreDelete) {
Err(Status::Forbidden)?
}

Expand Down
14 changes: 7 additions & 7 deletions src/api/music/tracks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@ use rocket_sync_db_pools::rusqlite::{params, Error::QueryReturnedNoRows, ToSql};

use crate::{
api::errors::ApiError,
database::{database::Database, permissions::Permission, tracks::Track, users::DangerousUser},
database::{database::Database, permissions::Permission, tracks::Track, users::User},
};

type Result<T> = std::result::Result<T, ApiError>;

#[post("/track", data = "<track>")]
async fn track_write(db: Database, user: DangerousUser, track: Json<Track>) -> Result<Json<Track>> {
if !user.has_permissions(&[Permission::TrackWrite]) {
async fn track_write(db: Database, user: User, track: Json<Track>) -> Result<Json<Track>> {
if !user.permissions.contains(&Permission::TrackWrite) {
Err(Status::Forbidden)?
}

Expand Down Expand Up @@ -56,7 +56,7 @@ async fn track_write(db: Database, user: DangerousUser, track: Json<Track>) -> R
#[get("/track?<id>&<name>&<maxrelease>&<minrelease>&<genres>&<albums>&<artists>&<lyrics>&<limit>")]
async fn track_get(
db: Database,
user: DangerousUser,
user: User,
id: Option<String>,
name: Option<String>,
maxrelease: Option<u16>,
Expand All @@ -67,7 +67,7 @@ async fn track_get(
lyrics: Option<String>,
limit: Option<u16>,
) -> Result<Json<Vec<Track>>> {
if !user.has_permissions(&[Permission::TrackRead]) {
if !user.permissions.contains(&Permission::TrackRead) {
Err(Status::Forbidden)?
}
db.run(move |conn| -> Result<Json<Vec<Track>>> {
Expand Down Expand Up @@ -164,8 +164,8 @@ async fn track_get(
}

#[delete("/track/<id>")]
async fn track_delete(db: Database, user: DangerousUser, id: String) -> Result<()> {
if !user.has_permissions(&[Permission::TrackDelete]) {
async fn track_delete(db: Database, user: User, id: String) -> Result<()> {
if !user.permissions.contains(&Permission::TrackDelete) {
Err(Status::Forbidden)?
}

Expand Down
25 changes: 12 additions & 13 deletions src/api/user/invites.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use crate::{
database::Database,
invites::Invite,
permissions::Permission,
users::{DangerousLogin, DangerousUser},
users::{DangerousLogin, User},
},
};

Expand All @@ -33,12 +33,11 @@ async fn invite_use(db: Database, code: String, login: Json<DangerousLogin>) ->
.map_err(|e| ApiError::from(e))?;

tx.execute(
"INSERT INTO users (username, permissions, hash, sessions) VALUES (?1, ?2, ?3, ?4)",
"INSERT INTO users (username, permissions, hash) VALUES (?1, ?2, ?3)",
params![
login.username,
permissions,
hash(login.password, DEFAULT_COST)?,
""
],
)?;

Expand All @@ -57,15 +56,15 @@ async fn invite_use(db: Database, code: String, login: Json<DangerousLogin>) ->
}

#[post("/invite", data = "<invite>")]
async fn invite_write(
db: Database,
user: DangerousUser,
invite: Json<Invite>,
) -> Result<Json<Invite>> {
async fn invite_write(db: Database, user: User, invite: Json<Invite>) -> Result<Json<Invite>> {
let mut invite = invite.into_inner();
let mut required_permissions = invite.permissions.inner().to_owned();
required_permissions.push(Permission::InviteWrite);
if !user.has_permissions(&required_permissions) {

if !required_permissions
.iter()
.all(|permission| user.permissions.contains(permission))
{
Err(Status::Forbidden)?
}

Expand Down Expand Up @@ -96,15 +95,15 @@ async fn invite_write(
#[get("/invite?<code>&<permissions>&<maxremaining>&<minremaining>&<creator>&<limit>")]
async fn invite_get(
db: Database,
user: DangerousUser,
user: User,
code: Option<String>,
permissions: Option<Json<Vec<Permission>>>,
maxremaining: Option<u16>,
minremaining: Option<u16>,
creator: Option<String>,
limit: Option<u16>,
) -> Result<Json<Vec<Invite>>> {
if !user.has_permissions(&[Permission::InviteRead]) {
if !user.permissions.contains(&Permission::InviteRead) {
return Err(Status::Forbidden)?;
}

Expand Down Expand Up @@ -154,8 +153,8 @@ async fn invite_get(
}

#[delete("/invite/<code>")]
async fn invite_delete(db: Database, user: DangerousUser, code: String) -> Result<()> {
if !user.has_permissions(&[Permission::InviteDelete]) {
async fn invite_delete(db: Database, user: User, code: String) -> Result<()> {
if !user.permissions.contains(&Permission::InviteDelete) {
return Err(Status::Forbidden)?;
}

Expand Down
16 changes: 11 additions & 5 deletions src/api/user/permissions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,26 @@ use sqlvec::SqlVec;

use crate::{
api::errors::ApiError,
database::{database::Database, permissions::Permission, users::DangerousUser},
database::{database::Database, permissions::Permission, users::User},
};

type Result<T> = std::result::Result<T, ApiError>;

#[post("/permissions/<username>", data = "<permissions_to_add>")]
async fn permissions_add(
db: Database,
user: DangerousUser,
user: User,
username: String,
permissions_to_add: Json<Vec<Permission>>,
) -> Result<()> {
let permissions_to_add = permissions_to_add.into_inner();

let mut required_permissions = permissions_to_add.clone();
required_permissions.push(Permission::PermissionAdd);
if !user.has_permissions(&required_permissions) {
if !required_permissions
.iter()
.all(|permission| user.permissions.contains(permission))
{
Err(Status::Forbidden)?
}

Expand Down Expand Up @@ -53,7 +56,7 @@ async fn permissions_add(
#[delete("/permissions/<username>", data = "<permissions_to_delete>")]
async fn permissions_delete(
db: Database,
user: DangerousUser,
user: User,
username: String,
permissions_to_delete: Json<Vec<Permission>>,
) -> Result<()> {
Expand All @@ -72,7 +75,10 @@ async fn permissions_delete(

let mut required_permissions = current_permissions.clone();
required_permissions.push(Permission::PermissionDelete);
if !user.has_permissions(&required_permissions) {
if !required_permissions
.iter()
.all(|permission| user.permissions.contains(permission))
{
Err(Status::Forbidden)?
}

Expand Down
32 changes: 10 additions & 22 deletions src/api/user/tokens.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,14 @@ use rocket::{
serde::json::Json,
};
use rocket_sync_db_pools::rusqlite::params;
use sqlvec::SqlVec;
use uuid::Uuid;

use crate::{
api::errors::ApiError,
database::{
database::Database,
permissions::Permission,
users::{DangerousLogin, DangerousUser},
users::{DangerousLogin, User},
},
};

Expand All @@ -30,27 +29,21 @@ async fn token_write(
.run(move |conn| -> Result<String> {
let tx = conn.transaction()?;

let (hash, mut tokens): (String, Vec<String>) = tx.query_row(
"SELECT hash, sessions FROM users WHERE username = ?",
let hash: String = tx.query_row(
"SELECT hash FROM users WHERE username = ?",
params![&login.username],
|row| {
Ok((
row.get(0)?,
row.get::<usize, SqlVec<String>>(1)?.into_inner(),
))
},
|row| row.get("hash"),
)?;

if !verify(login.password, &hash)? {
Err(Status::Forbidden)?
}

let token: String = Uuid::new_v4().to_string();
tokens.push(token.clone());

tx.execute(
"UPDATE users SET sessions = ? WHERE username = ?",
params![SqlVec::new(tokens), login.username],
"INSERT INTO tokens (id, username) VALUES (?1, ?2)",
params![token, login.username],
)?;

tx.commit()?;
Expand All @@ -63,18 +56,13 @@ async fn token_write(
}

#[delete("/token/<username>")]
async fn token_delete(db: Database, user: DangerousUser, username: String) -> Result<()> {
if username != user.username && !user.has_permissions(&[Permission::TokenDelete]) {
async fn token_delete(db: Database, user: User, username: String) -> Result<()> {
if username != user.username && !user.permissions.contains(&Permission::TokenDelete) {
Err(Status::Forbidden)?
}

db.run(move |conn| {
conn.execute(
"UPDATE users SET sessions = '' WHERE username = ?",
params![username],
)
})
.await?;
db.run(move |conn| conn.execute("DELETE FROM tokens WHERE username = ?", params![username]))
.await?;
Ok(())
}

Expand Down
Loading

0 comments on commit 5345175

Please sign in to comment.