Configured Rustfmt

pull/36/head
Jef Roosens 2021-08-22 16:45:01 +02:00
parent b13b760e2f
commit 16ddc9aecd
Signed by: Jef Roosens
GPG Key ID: 955C0660072F691F
12 changed files with 169 additions and 63 deletions

69
rustfmt.toml 100644
View File

@ -0,0 +1,69 @@
binop_separator = "Front"
blank_lines_lower_bound = 0
blank_lines_upper_bound = 1
# Trying something new
brace_style = "AlwaysNextLine"
color = "Auto"
combine_control_expr = false
comment_width = 80
condense_wildcard_suffixes = false
control_brace_style = "AlwaysSameLine"
disable_all_formatting = false
edition = "2018"
emit_mode = "Files"
empty_item_single_line = true
enum_discrim_align_threshold = 0
error_on_line_overflow = false
error_on_unformatted = false
fn_args_layout = "Tall"
fn_single_line = false
force_explicit_abi = true
force_multiline_blocks = false
format_code_in_doc_comments = false
format_macro_bodies = true
format_macro_matchers = false
format_strings = false
group_imports = "StdExternalCrate"
hard_tabs = false
hide_parse_errors = false
ignore = []
imports_granularity = "Crate"
imports_indent = "Block"
imports_layout = "Mixed"
indent_style = "Block"
inline_attribute_width = 0
license_template_path = ""
make_backup = false
match_arm_blocks = true
match_arm_leading_pipes = "Never"
match_block_trailing_comma = false
max_width = 100
merge_derives = true
newline_style = "Auto"
normalize_comments = false
normalize_doc_attributes = false
overflow_delimited_expr = false
remove_nested_parens = true
reorder_impl_items = false
reorder_imports = true
reorder_modules = true
report_fixme = "Always"
report_todo = "Always"
required_version = "1.4.36"
skip_children = false
space_after_colon = true
space_before_colon = false
spaces_around_ranges = false
struct_field_align_threshold = 0
struct_lit_single_line = true
tab_spaces = 4
trailing_comma = "Vertical"
trailing_semicolon = true
type_punctuation_density = "Wide"
unstable_features = false
use_field_init_shorthand = false
use_small_heuristics = "Default"
use_try_shorthand = false
version = "One"
where_single_line = false
wrap_comments = false

View File

@ -1,21 +1,23 @@
use crate::errors::RBError;
use crate::db::{
users::{User, NewUser},
tokens::{RefreshToken, NewRefreshToken}
};
use crate::schema::refresh_tokens::dsl as refresh_tokens;
use crate::schema::users::dsl as users;
use argon2::verify_encoded;
use chrono::Utc;
use diesel::prelude::*;
use diesel::{insert_into, PgConnection};
use diesel::{insert_into, prelude::*, PgConnection};
use hmac::{Hmac, NewMac};
use jwt::SignWithKey;
use rand::{thread_rng, Rng};
use serde::{Deserialize, Serialize};
use sha2::Sha256;
pub fn verify_user(conn: &PgConnection, username: &str, password: &str) -> crate::Result<User> {
use crate::{
db::{
tokens::{NewRefreshToken, RefreshToken},
users::{NewUser, User},
},
errors::RBError,
schema::{refresh_tokens::dsl as refresh_tokens, users::dsl as users},
};
pub fn verify_user(conn: &PgConnection, username: &str, password: &str) -> crate::Result<User>
{
// TODO handle non-"NotFound" Diesel errors accordingely
let user = users::users
.filter(users::username.eq(username))
@ -35,20 +37,23 @@ pub fn verify_user(conn: &PgConnection, username: &str, password: &str) -> crate
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub struct JWTResponse {
pub struct JWTResponse
{
token: String,
refresh_token: String,
}
#[derive(Serialize, Deserialize)]
pub struct Claims {
pub struct Claims
{
pub id: uuid::Uuid,
pub username: String,
pub admin: bool,
pub exp: i64,
}
pub fn generate_jwt_token(conn: &PgConnection, user: &User) -> crate::Result<JWTResponse> {
pub fn generate_jwt_token(conn: &PgConnection, user: &User) -> crate::Result<JWTResponse>
{
let secret = std::env::var("JWT_KEY").map_err(|_| RBError::MissingJWTKey)?;
let key: Hmac<Sha256> =
Hmac::new_from_slice(secret.as_bytes()).map_err(|_| RBError::JWTCreationError)?;
@ -92,7 +97,8 @@ pub fn generate_jwt_token(conn: &PgConnection, user: &User) -> crate::Result<JWT
})
}
pub fn hash_password(password: &str) -> crate::Result<String> {
pub fn hash_password(password: &str) -> crate::Result<String>
{
// Generate a random salt
let mut salt = [0u8; 64];
thread_rng().fill(&mut salt[..]);
@ -102,11 +108,9 @@ pub fn hash_password(password: &str) -> crate::Result<String> {
argon2::hash_encoded(password.as_bytes(), &salt, &config).map_err(|_| RBError::PWSaltError)
}
pub fn create_admin_user(
conn: &PgConnection,
username: &str,
password: &str,
) -> crate::Result<bool> {
pub fn create_admin_user(conn: &PgConnection, username: &str, password: &str)
-> crate::Result<bool>
{
let pass_hashed = hash_password(password)?;
let new_user = NewUser {
username: username.to_string(),
@ -125,7 +129,8 @@ pub fn create_admin_user(
Ok(true)
}
pub fn refresh_token(conn: &PgConnection, refresh_token: &str) -> crate::Result<JWTResponse> {
pub fn refresh_token(conn: &PgConnection, refresh_token: &str) -> crate::Result<JWTResponse>
{
let token_bytes = base64::decode(refresh_token).map_err(|_| RBError::InvalidRefreshToken)?;
// First, we request the token from the database to see if it's really a valid token

View File

@ -1,2 +1,2 @@
pub mod users;
pub mod tokens;
pub mod users;

View File

@ -1,10 +1,11 @@
use diesel::{Insertable, Queryable};
use uuid::Uuid;
use diesel::{Queryable, Insertable};
use crate::schema::refresh_tokens;
#[derive(Queryable)]
pub struct RefreshToken {
pub struct RefreshToken
{
pub token: Vec<u8>,
pub user_id: Uuid,
pub expires_at: chrono::NaiveDateTime,
@ -13,7 +14,8 @@ pub struct RefreshToken {
#[derive(Insertable)]
#[table_name = "refresh_tokens"]
pub struct NewRefreshToken {
pub struct NewRefreshToken
{
pub token: Vec<u8>,
pub user_id: Uuid,
pub expires_at: chrono::NaiveDateTime,

View File

@ -1,12 +1,15 @@
use crate::schema::users;
use diesel::{AsChangeset, Insertable, Queryable, prelude::*};
use diesel::{prelude::*, AsChangeset, Insertable, Queryable};
use serde::Serialize;
use uuid::Uuid;
use crate::schema::users::dsl::*;
use crate::errors::RBError;
use crate::{
errors::RBError,
schema::{users, users::dsl::*},
};
#[derive(Queryable, Serialize)]
pub struct User {
pub struct User
{
pub id: Uuid,
pub username: String,
#[serde(skip_serializing)]
@ -18,12 +21,14 @@ pub struct User {
#[derive(Insertable, AsChangeset)]
#[table_name = "users"]
pub struct NewUser {
pub struct NewUser
{
pub username: String,
pub password: String,
pub admin: bool,
}
pub fn all(conn: &PgConnection) -> crate::Result<Vec<User>> {
pub fn all(conn: &PgConnection) -> crate::Result<Vec<User>>
{
users.load::<User>(conn).map_err(|_| RBError::DBError)
}

View File

@ -1,10 +1,14 @@
use rocket::http::Status;
use rocket::request::Request;
use rocket::response::{self, Responder, Response};
use std::io;
use rocket::{
http::Status,
request::Request,
response::{self, Responder, Response},
};
#[derive(Debug)]
pub enum RBError {
pub enum RBError
{
/// When the login requests an unknown user
UnknownUser,
BlockedUser,
@ -26,8 +30,10 @@ pub enum RBError {
DBError,
}
impl<'r> Responder<'r, 'static> for RBError {
fn respond_to(self, _: &'r Request<'_>) -> response::Result<'static> {
impl<'r> Responder<'r, 'static> for RBError
{
fn respond_to(self, _: &'r Request<'_>) -> response::Result<'static>
{
let (status, message): (Status, &str) = match self {
RBError::UnknownUser => (Status::NotFound, "Unknown user"),
RBError::BlockedUser => (Status::Unauthorized, "This user is blocked"),

View File

@ -12,10 +12,12 @@ use sha2::Sha256;
pub struct Bearer(String);
#[rocket::async_trait]
impl<'r> FromRequest<'r> for Bearer {
impl<'r> FromRequest<'r> for Bearer
{
type Error = rb::errors::RBError;
async fn from_request(req: &'r Request<'_>) -> Outcome<Self, Self::Error> {
async fn from_request(req: &'r Request<'_>) -> Outcome<Self, Self::Error>
{
// If the header isn't present, just forward to the next route
let header = match req.headers().get_one("Authorization") {
None => return Outcome::Forward(()),
@ -40,10 +42,12 @@ impl<'r> FromRequest<'r> for Bearer {
pub struct JWT(Claims);
#[rocket::async_trait]
impl<'r> FromRequest<'r> for JWT {
impl<'r> FromRequest<'r> for JWT
{
type Error = rb::errors::RBError;
async fn from_request(req: &'r Request<'_>) -> Outcome<Self, Self::Error> {
async fn from_request(req: &'r Request<'_>) -> Outcome<Self, Self::Error>
{
let bearer = try_outcome!(req.guard::<Bearer>().await).0;
// Get secret & key
@ -73,10 +77,12 @@ impl<'r> FromRequest<'r> for JWT {
pub struct User(Claims);
#[rocket::async_trait]
impl<'r> FromRequest<'r> for User {
impl<'r> FromRequest<'r> for User
{
type Error = rb::errors::RBError;
async fn from_request(req: &'r Request<'_>) -> Outcome<Self, Self::Error> {
async fn from_request(req: &'r Request<'_>) -> Outcome<Self, Self::Error>
{
let claims = try_outcome!(req.guard::<JWT>().await).0;
// Verify key hasn't yet expired
@ -92,10 +98,12 @@ impl<'r> FromRequest<'r> for User {
pub struct Admin(Claims);
#[rocket::async_trait]
impl<'r> FromRequest<'r> for Admin {
impl<'r> FromRequest<'r> for Admin
{
type Error = rb::errors::RBError;
async fn from_request(req: &'r Request<'_>) -> Outcome<Self, Self::Error> {
async fn from_request(req: &'r Request<'_>) -> Outcome<Self, Self::Error>
{
let user = try_outcome!(req.guard::<User>().await);
if user.0.admin {
Outcome::Success(Self(user.0))

View File

@ -1,8 +1,8 @@
#[macro_use]
extern crate diesel;
pub mod db;
pub mod auth;
pub mod db;
pub mod errors;
pub(crate) mod schema;

View File

@ -18,7 +18,8 @@ embed_migrations!();
#[database("postgres_rb")]
pub struct RbDbConn(diesel::PgConnection);
async fn run_db_migrations(rocket: Rocket<Build>) -> Result<Rocket<Build>, Rocket<Build>> {
async fn run_db_migrations(rocket: Rocket<Build>) -> Result<Rocket<Build>, Rocket<Build>>
{
let conn = RbDbConn::get_one(&rocket)
.await
.expect("database connection");
@ -29,7 +30,8 @@ async fn run_db_migrations(rocket: Rocket<Build>) -> Result<Rocket<Build>, Rocke
.await
}
async fn create_admin_user(rocket: Rocket<Build>) -> Result<Rocket<Build>, Rocket<Build>> {
async fn create_admin_user(rocket: Rocket<Build>) -> Result<Rocket<Build>, Rocket<Build>>
{
let admin_user = std::env::var("ADMIN_USER").unwrap_or(String::from("admin"));
let admin_password = std::env::var("ADMIN_PASSWORD").unwrap_or(String::from("password"));
@ -46,7 +48,8 @@ async fn create_admin_user(rocket: Rocket<Build>) -> Result<Rocket<Build>, Rocke
}
#[launch]
fn rocket() -> _ {
fn rocket() -> _
{
rocket::build()
.attach(RbDbConn::fairing())
.attach(AdHoc::try_on_ignite(

View File

@ -1,13 +1,15 @@
use crate::guards::Admin;
use crate::RbDbConn;
use rb::db::users::User;
use rocket::serde::json::Json;
pub fn routes() -> Vec<rocket::Route> {
use crate::{guards::Admin, RbDbConn};
pub fn routes() -> Vec<rocket::Route>
{
routes![get_users]
}
#[get("/users")]
async fn get_users(admin: Admin, conn: RbDbConn) -> rb::Result<Json<Vec<User>>> {
async fn get_users(admin: Admin, conn: RbDbConn) -> rb::Result<Json<Vec<User>>>
{
Ok(Json(conn.run(|c| rb::db::users::all(c)).await?))
}

View File

@ -1,26 +1,30 @@
use crate::guards::User;
use crate::RbDbConn;
use rb::auth::{generate_jwt_token, verify_user, JWTResponse};
use rocket::serde::json::Json;
use serde::Deserialize;
pub(crate) fn routes() -> Vec<rocket::Route> {
use crate::{guards::User, RbDbConn};
pub(crate) fn routes() -> Vec<rocket::Route>
{
routes![login, already_logged_in, refresh_token]
}
#[derive(Deserialize)]
struct Credentials {
struct Credentials
{
username: String,
password: String,
}
#[post("/login")]
async fn already_logged_in(_user: User) -> String {
async fn already_logged_in(_user: User) -> String
{
String::from("You're already logged in!")
}
#[post("/login", data = "<credentials>", rank = 2)]
async fn login(conn: RbDbConn, credentials: Json<Credentials>) -> rb::Result<Json<JWTResponse>> {
async fn login(conn: RbDbConn, credentials: Json<Credentials>) -> rb::Result<Json<JWTResponse>>
{
let credentials = credentials.into_inner();
// Get the user, if credentials are valid
@ -33,7 +37,8 @@ async fn login(conn: RbDbConn, credentials: Json<Credentials>) -> rb::Result<Jso
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
struct RefreshTokenRequest {
struct RefreshTokenRequest
{
pub refresh_token: String,
}
@ -41,7 +46,8 @@ struct RefreshTokenRequest {
async fn refresh_token(
conn: RbDbConn,
refresh_token_request: Json<RefreshTokenRequest>,
) -> rb::Result<Json<JWTResponse>> {
) -> rb::Result<Json<JWTResponse>>
{
let refresh_token = refresh_token_request.into_inner().refresh_token;
Ok(Json(

View File

@ -1,2 +1,2 @@
pub mod auth;
pub mod admin;
pub mod auth;