1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192

//! rocket_auth provides a ready-to-use  backend agnostic API for authentication management.
//! It supports connections for SQLite and Postgresql. It lets you create, delete, and authenticate users.
//! The available features are:
//! * `sqlite-db`: for interacting with a SQLite database. 
//! * `postgres-db`: for interacting with a Postgresql database.
//! * `redis-session`: for storing sessions on a redis server. 
//! 
//! By default this crate stores sessions on a concurrent hashmap. 
//! As a result, sessions will only be stored as long as the rocket application runs uninterrupted. 
//! In order to store persistent sessions, it is recommended to connect the [`Users`](`Users::open_redis`) instance to a [redis server](https://redis.io/) .
//! This requires the `redis-session` feature to be enabled. 
//! 
//! `rocket_auth` uses private cookies to store session data. 
//! This means that in order for cookies to be properly decrypted between launches, a `secret_key` must be set.
//! For more information visit rocket's [configuration guide](https://rocket.rs/v0.4/guide/configuration/).
//! 
//! 
//! 
//! 
//! 
//! To use `rocket_auth` include it as a dependency in your Cargo.toml file: 
//! ```ini
//! [dependencies.rocket_auth]
//! version = "0.3.0"
//! features = ["sqlite-db"]
//! ```
//! # Quick overview
//! This crate provides two guards:
//! * [`Auth`]: manages authentication.
//! * [`Session`]: retrieves session data from client cookies.
//! * [`User`]: It restricts content, so it can be viewed by authenticated clients only.
//! 
//! It also includes two structs to be parsed from forms and json data: 
//! * [`Signup`]: used to create new users.
//! * [`Login`]: used to authenticate users.
//! 
//! Finally it has two structures for queries: 
//! * [`Users`]: it allows to query users to the database.
//! * [`User`]: it is the response of a query.
//! 

//! The [`Auth`] guard allows to log in, log out, sign up, modify, and delete the currently (un)authenticated user. 
//! For more information see [`Auth`]. Because of rust's ownership rules, you may not retrieve both `rocket::http::Cookies` and the [`Auth`] guard
//! simultaneously. However, retrieveng cookies is not needed since `Auth` stores them in the public field [`Auth::cookies`].
//!  A working example: 
//! ```rust,no_run
//! #![feature(decl_macro)]
//! use rocket::{get, post, request::Form, routes};
//! use rocket_auth::{Users, Error, Auth, Signup, Login};
//! 
//! #[post("/signup", data="<form>")] 
//! fn signup(form: Form<Signup>, mut auth: Auth) {
//!     auth.signup(&form);
//!     auth.login(&form.into());
//! }
//! 
//! #[post("/login", data="<form>")] 
//! fn login(form: Form<Login>, mut auth: Auth) {
//!     auth.login(&form);
//! }
//! 
//! #[get("/logout")] 
//! fn logout(mut auth: Auth) {
//!     auth.logout();
//! }
//! 
//! fn main() -> Result<(), Error>{
//!     let users = Users::open_sqlite("mydb.db")?;
//! 
//!     rocket::ignite()
//!         .mount("/", routes![signup, login, logout])
//!         .manage(users)
//!         .launch();
//!     Ok(())
//! }
//! ```
//! 
//! ## Users struct
//! The [`Users`] struct administers interactions with the database. 
//! It lets you query, create, modify and delete users.
//! Unlike the [`Auth`] guard, a [`Users`] instance can manage any user in the database.
//! Note that the [`Auth`] guards includes a `Users` instance stored on the public `users` field.
//! So it is not necesary to retrieve Users when using `Auth`.
//! A simple example of how to query a user with the [`Users`] struct:
//! 
//! ```rust 
//! # #![feature(decl_macro)]
//! # use rocket::{get, State};
//! # use serde_json::json;
//! use rocket_auth::Users;
//! 
//! #[get("/see-user/<id>")]
//! fn see_user(id: i32, users: State<Users>) -> String {
//!     let user = users.get_by_id(id).unwrap();
//!     format!("{}", json!(user))
//! }
//! # fn main() {}
//! ```
//! 
//! A [`Users`] instance can be constructed by connecting it to the database with the methods [`open_sqlite`](Users::open_sqlite),
//! [`open_postgres`](Users::open_postgres). Furthermore, it can be constructed from a working connection. 
//! 
//! 
//! ## User guard
//! The `User` guard can be used to restrict content so it can only be viewed by authenticated users. 
//! Additionally, yo can use it to render special content if the client is authenticated or not. 
//! ```rust
//! #[get("/private-content")]
//! fn private_content(user: User) -> &'static str {
//!     "If you can see this, you are logged in."
//! } 
//! 
//! #[get("/special-content")]
//! fn special_content(option: Option<User>) -> String {
//!     if let Some(user) = option {
//!         format!("hello, {}.", user.email)
//!     } else {
//!         "hello, anonymous user".into()
//!     }
//! } 
//! ```
//! 



mod cookies;
mod db;
mod error;
mod forms;
mod prelude;
mod session;
mod user;
mod language;


#[cfg(test)]
mod tests;


use prelude::*;
use rocket::FromForm;

pub use language::Language;
pub use cookies::Session;
pub use error::Error;
pub use crate::user::auth::Auth;



/// The `User` guard can be used to restrict content so it can only be viewed by authenticated users. 
/// ```rust
/// # #![feature(decl_macro)]
/// # use rocket::{get};
/// # use rocket_auth::User;
/// #[get("/private-content")]
/// fn private_content(user: User) -> &'static str {
///     "If you can see this, you are logged in."
/// }
/// # fn main() {}
/// ```
#[derive(Serialize, Deserialize, PartialEq, Eq, Clone)]
pub struct User {
    id: i32,
    email: String,
    #[serde(skip_serializing)]
    password: String,
    pub is_admin: bool,
}


/// The `Users` struct is used to query users from the database, as well as to create, modify and delete them.
pub struct Users {
    conn: Box<dyn DBConnection>,
    sess: Box<dyn SessionManager>,
}

/// The `Login` form is used along with the [`Auth`] guard to authenticate users. 
#[derive(FromForm, Deserialize, Debug, Clone)]
pub struct Login {
    pub email: String,
    password: String,
}


/// The `Signup` form is used along with the [`Auth`] guard to create new users. 

#[derive(FromForm, Deserialize, Debug, Clone)]
pub struct Signup {
    pub email: String,
    password: String,
}