lrau/lib.rs
1//! # LrAU
2//!
3//! LrAU is an authentication and permission management system for rust. It uses Argon2id to hash passwords to prevent against rainbow table and brute-forcing.
4//!
5//! ## Note for migrators
6//!
7//! Since version 3.0, instead of paths being strings they are now slices. This will cause issues with legacy code, preventing it to compile, and preventing serde information from being read.
8//!
9//!
10//! ## Example
11//!
12//! ```rust
13//! #[test]
14//! fn generic() {
15//! // Load from a toml file.
16//! let permissions: lrau::Permissions =
17//! toml::from_str(include_str!("./generic.toml")).unwrap();
18//!
19//! // Create a password typical of someone who thinks their being clever.
20//! let mut user = lrau::User::new(
21//! String::from("john_t"),
22//! String::from("1234"),
23//! permissions,
24//! );
25//!
26//!
27//! // Valid their password
28//! assert!(user.validate("1234"));
29//! // Invalid their password
30//! assert!(!user.validate("12345"));
31//!
32//! // Permissions
33//!
34//! // See if we have permissions to access contacts without
35//! // mutable access.
36//! assert!(user.get_permission(&["contacts", "name"], false));
37//!
38//! // See if we can change users passwords with mut access.
39//! assert!(user.get_permission(&["admin", "passwords"], true));
40//!
41//! // Nonexisting paths inherit from paths further up the tree
42//! assert!(user.get_permission(&["admin", "passwords", "reset"], true));
43//!
44//! // Or are nothing if they are completely irrelevant.
45//! assert!(!user.get_permission(&["notathing"], false));
46//!
47//! // Checks if we have logged in (we haven't)
48//! assert!(!user.check_login());
49//! assert!(!user.check_valid_login());
50//!
51//! // User Login
52//! user.log_in("1234", std::time::Duration::from_secs(1));
53//!
54//! // Checks for logins
55//! assert!(user.check_login());
56//! assert!(user.check_valid_login());
57//!
58//! // Timeouts
59//! std::thread::sleep(std::time::Duration::from_secs(1));
60//!
61//! // We are still logged in...
62//! assert!(user.check_login());
63//!
64//! // But not validly.
65//! assert!(!user.check_valid_login());
66//!
67//! // And so getting vaild permissions does not work.
68//! assert_eq!(
69//! user.get_valid_permissions(&["admin", "passwords", "reset"], true),
70//! Err(lrau::user::SessionExpired {}),
71//! );
72//! }
73//! ```
74//!
75//! ## Serde
76//!
77//! Serde is supported through the `serde` feature. If you configure in toml, you can get something like this:
78//!
79//! ```toml
80//! [[permissions]]
81//! path = ["contacts"]
82//! auth = false
83//!
84//! [[permissions]]
85//! path = ["contacts", "name"]
86//! auth = true
87//!
88//! [[permissions]]
89//! path = ["contacts", "name", "middle"]
90//! auth = false
91//!
92//! [[permissions]]
93//! path = ["contacts", "name", "last"]
94//! auth = true
95//!
96//! [[permissions]]
97//! path = ["admin"]
98//! auth = false
99//!
100//! [[permissions]]
101//! path = ["admin", "passwords"]
102//! auth = true
103//! mut = true
104//! ```
105//!
106//! `mut`, be default, is assumed to be `false`, so you only need to write it if you are enabling it.
107//!
108//! ## Features
109//!
110//! * Serde `serde`.
111//! * Diesel `diesel-support`.
112//! * Sqlx `sqlx-support`
113#![warn(clippy::pedantic)]
114#![allow(clippy::doc_markdown, clippy::missing_errors_doc)]
115
116pub mod permission;
117pub mod user;
118
119pub use permission::Permission;
120pub use permission::Permissions;
121pub use user::User;
122
123use rand::Rng;
124#[cfg(feature = "diesel-support")]
125#[macro_use]
126extern crate diesel;
127
128#[cfg(feature = "diesel-support")]
129#[macro_use]
130extern crate diesel_migrations;
131
132#[cfg(feature = "diesel-support")]
133pub mod schema;
134
135#[cfg(feature = "sql")]
136pub mod sql_support;
137
138/// Generates a random salt, this is automatically done when
139/// creating a user.
140#[must_use]
141pub fn salt() -> String {
142 // Base64 characters
143 let chars = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ\
144 abcdefghijklmnopqrstuvwxyz\
145 0123456789+/";
146
147 // Salt variable
148 let mut salt = String::new();
149
150 for _ in 0..128 {
151 // Random Number
152 let num: usize = rand::thread_rng().gen::<usize>() % chars.len();
153
154 salt.push(chars[num].into());
155 }
156
157 salt
158}