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
|
use std::path::{PathBuf};
use std::fs;
use std::env;
use std::io::ErrorKind;
use serde_json;
use serde::{Serialize, Deserialize};
use sha2::{Sha256, Digest};
use base64::decode;
use crate::{
PlayerId,
errors::AnyError,
util::write_file_safe
};
pub enum LoaderError {
MissingResource(AnyError),
InvalidResource(AnyError)
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum UserRole {
Player,
Bridge
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct User {
pub name: String,
pub pass_token: String,
pub role: UserRole
}
impl User {
pub fn validate_token(&self, token: &str) -> bool {
if let (Ok(saved), Ok(given)) = (decode(&self.pass_token), decode(token)) {
let hashed: Vec<u8> = Sha256::digest(&given)[..].to_vec();
hashed == saved
} else {
false
}
}
}
macro_rules! inv {
($code:expr) => {($code).map_err(|err| LoaderError::InvalidResource(Box::new(err)))}
}
pub trait UserRegistry {
fn load_user(&self, id: &PlayerId) -> Result<User, LoaderError>;
fn register_user(&self, id: &PlayerId, user: &User) -> Result<(), AnyError>;
fn user_exists(&self, id: &PlayerId) -> bool {
match self.load_user(id) {
Ok(_) => true,
Err(LoaderError::InvalidResource(_)) => true,
Err(LoaderError::MissingResource(_)) => false
}
}
}
pub struct FileRegister {
directory: PathBuf
}
impl FileRegister {
pub fn new(path: PathBuf) -> Self {
Self {
directory: path
}
}
pub fn default_register_dir() -> Option<PathBuf> {
if let Some(pathname) = env::var_os("XDG_DATA_HOME") {
let mut path = PathBuf::from(pathname);
path.push("asciifarm");
path.push("users");
Some(path)
} else if let Some(pathname) = env::var_os("HOME") {
let mut path = PathBuf::from(pathname);
path.push(".asciifarm");
path.push("users");
Some(path)
} else {
None
}
}
}
impl UserRegistry for FileRegister {
fn load_user(&self, id: &PlayerId) -> Result<User, LoaderError> {
let mut path = self.directory.clone();
let fname = id.to_string() + ".auth.json";
path.push(fname);
let text = fs::read_to_string(path).map_err(|err| {
if err.kind() == ErrorKind::NotFound {
LoaderError::MissingResource(Box::new(err))
} else {
LoaderError::InvalidResource(Box::new(err))
}
})?;
let user: User = inv!(serde_json::from_str(&text))?;
Ok(user)
}
fn register_user(&self, id: &PlayerId, user: &User) -> Result<(), AnyError> {
let mut path = self.directory.clone();
fs::create_dir_all(&path)?;
let fname = id.to_string() + ".auth.json";
path.push(fname);
let text = serde_json::to_string(user)?;
write_file_safe(path, text)?;
Ok(())
}
}
|