dusa_common/
shared.rs

1pub mod prefix;
2
3use std::{fs, os::unix::fs::PermissionsExt, path::PathBuf, time::Duration};
4
5use nix::unistd::{chown, Gid, Uid};
6use simple_pretty::halt;
7use serde::{Deserialize, Serialize};
8use dusa_collection_utils::{
9    errors::{
10        ErrorArray, ErrorArrayItem, Errors as SE, OkWarning, UnifiedResult as uf, WarningArray,
11        WarningArrayItem, Warnings,
12    },
13    functions::del_file,
14    types::PathType,
15};
16use users::{Groups, Users, UsersCache};
17
18/// Current version of the protocol, derived from the package version.
19pub const VERSION: &str = env!("CARGO_PKG_VERSION");
20/// Time to live in seconds for file that are decrypted.
21pub const TTL: u64 = 30;
22
23/// Getting the current uid
24pub fn get_id() -> (Uid, Gid) {
25    let user_cache: UsersCache = UsersCache::new();
26    let dusa_uid = user_cache.get_user_by_name("dusa").unwrap().uid();
27    let dusa_gid = user_cache.get_group_by_name("dusa").unwrap().gid();
28
29    (Uid::from_raw(dusa_uid), Gid::from_raw(dusa_gid))
30}
31
32/// Struct representing a write request.
33#[derive(Serialize, Deserialize, Debug)]
34pub struct RequestRecsWrite {
35    pub path: PathType,
36    pub owner: String,
37    pub name: String,
38    pub uid: u32,
39}
40
41/// Struct representing a plain text request.
42#[derive(Serialize, Deserialize, Debug)]
43pub struct RequestRecsPlainText {
44    pub command: Commands,
45    pub data: String,
46    pub uid: u32,
47}
48
49/// Struct representing a simple request.
50#[derive(Serialize, Deserialize, Debug)]
51pub struct RequestRecsSimple {
52    pub command: Commands,
53    pub owner: String,
54    pub name: String,
55    pub uid: u32,
56}
57
58/// Struct representing a response.
59#[derive(Serialize, Deserialize, Debug)]
60pub struct ResponseData {
61    pub status: String,
62    pub detail: String,
63}
64
65#[derive(Serialize, Deserialize, Debug, Clone)]
66pub struct DecryptResponseData{
67    pub temp_p: PathType,
68    pub orig_p: PathType,
69    pub ttl: Duration,
70}
71
72/// Enum representing different request payloads.
73#[derive(Serialize, Deserialize, Debug)]
74pub enum RequestPayload {
75    Write(RequestRecsWrite),
76    PlainText(RequestRecsPlainText),
77    Simple(RequestRecsSimple),
78}
79
80/// enums for commands 
81#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
82pub enum Commands {
83    EncryptRawText,
84    DecryptRawText,
85    DecryptFile,
86    RemoveFile,
87    PingFile,
88}
89
90/// Generic message struct used for communication.
91#[derive(Serialize, Deserialize, Debug)]
92pub struct Message<T> {
93    pub version: String,
94    pub msg_type: MessageType,
95    pub payload: T,
96    pub error: Option<DusaError>,
97}
98
99/// Enum representing different message types.
100#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
101pub enum MessageType {
102    Request,
103    Response,
104    ErrorResponse,
105    Simple,
106    Acknowledge,
107    Test,
108    // Add more custom message types as needed
109}
110
111/// Enum representing different error codes.
112#[derive(Serialize, Deserialize, Debug)]
113pub enum ErrorCode {
114    UnknownMessageType,
115    InvalidPayload,
116    InvalidVersion,
117    InternalError,
118    InvalidPermissions,
119    // Add more standardized error codes as needed
120}
121
122impl std::fmt::Display for ErrorCode {
123    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
124        match self {
125            ErrorCode::UnknownMessageType => write!(f, "Unknown message type"),
126            ErrorCode::InvalidPayload => write!(f, "Invalid payload"),
127            ErrorCode::InternalError => write!(f, "Internal error"),
128            ErrorCode::InvalidVersion => write!(f, "We aren't speaking the same language"),
129            ErrorCode::InvalidPermissions => write!(f, "You have no authority here"),
130            // Add more standardized error codes as needed
131        }
132    }
133}
134
135impl std::fmt::Display for Commands {
136    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
137        match self {
138            Commands::EncryptRawText => write!(f, "et"),
139            Commands::DecryptRawText => write!(f, "dt"),
140            Commands::DecryptFile => write!(f, "df"),
141            Commands::RemoveFile => write!(f, "rf"),
142            Commands::PingFile => write!(f, "pf"),
143        }
144    }
145}
146
147/// Struct representing an error message.
148#[derive(Serialize, Deserialize, Debug)]
149pub struct DusaError {
150    pub code: ErrorCode,
151    pub message: String,
152}
153
154pub fn check_version(incoming_version: &str) -> bool {
155    // Split the version strings into major, minor, and patch parts
156    let parse_version = |v: &str| -> Option<(u32, u32)> {
157        let parts: Vec<&str> = v.split('.').collect();
158        if parts.len() != 3 {
159            return None;
160        }
161        let major = parts[0].parse::<u32>().ok()?;
162        let minor = parts[1].parse::<u32>().ok()?;
163        let _patch: u32 = parts[2].parse::<u32>().ok()?;
164        Some((major, minor))
165    };
166
167    if let (Some((inc_major, inc_minor)), Some((ver_major, ver_minor))) =
168        (parse_version(incoming_version), parse_version(VERSION))
169    {
170        inc_major == ver_major && inc_minor == ver_minor
171    } else {
172        false
173    }
174}
175
176
177/// Returns the path to the socket.
178///
179/// # Arguments
180/// * `int` - A boolean indicating if initialization is needed.
181/// * `errors` - An array of errors to be populated if any occur.
182/// * `warnings` - An array of warnings to be populated if any occur.
183///
184/// # Returns
185/// A unified result containing the path type or errors/warnings.
186#[allow(nonstandard_style)]
187pub fn SOCKET_PATH(
188    int: bool,
189    mut errors: ErrorArray,
190    mut warnings: WarningArray,
191) -> uf<OkWarning<PathType>> {
192    let socket_file = PathType::Content(String::from("/var/run/dusa/dusa.sock"));
193    // let socket_file = PathType::Content(String::from("/home/dwhitfield/Developer/RUST/Dev/server/s.socket"));
194    let _socket_dir = match socket_file.ancestors().next() {
195        Some(d) => PathType::PathBuf(d.to_path_buf()),
196        None => {
197            errors.push(ErrorArrayItem::new(
198                SE::InvalidFile,
199                "Socket file not found".to_string(),
200            ));
201            return uf::new(Err(errors));
202        }
203    };
204
205    if int {
206        // Create the dir and the sock file
207        if socket_file.exists() {
208            match del_file(socket_file.clone(), errors.clone(), warnings.clone()).uf_unwrap() {
209                Ok(_) => {
210                    return uf::new(Ok(OkWarning {
211                        data: socket_file,
212                        warning: warnings,
213                    }));
214                }
215                Err(_) => {
216                    warnings.push(WarningArrayItem::new(Warnings::OutdatedVersion));
217                }
218            }
219        }
220    }
221
222    uf::new(Ok(OkWarning {
223        data: socket_file,
224        warning: warnings,
225    }))
226}
227
228pub fn set_file_ownership(path: &PathBuf, uid: Uid, gid: Gid, mut errors: ErrorArray) -> uf<()> {
229    match chown(path, Some(uid), Some(gid)) {
230        Ok(_) => uf::new(Ok(())),
231        Err(_) => {
232            errors.push(ErrorArrayItem::new(
233                dusa_collection_utils::errors::Errors::Unauthorized,
234                String::from("chown failed"),
235            ));
236            uf::new(Err(errors))
237        }
238    }
239}
240
241pub fn set_socket_permission(socket_path: PathType) {
242    // Changing the permissions the socket
243    let socket_metadata = match fs::metadata(socket_path.clone()) {
244        Ok(d) => d,
245        Err(e) => {
246            halt(&format!(
247                "Couldn't read meta data of the socket: {}",
248                &e.to_string()
249            ));
250            unreachable!()
251        }
252    };
253    let mut permissions = socket_metadata.permissions();
254    permissions.set_mode(0o660); // Set desired permissions
255
256    match fs::set_permissions(socket_path.clone(), permissions) {
257        Ok(()) => (),
258        Err(e) => halt(&format!(
259            "We own the socket but we can't change its permissions, all i know is '{}'",
260            &e.to_string()
261        )),
262    };
263}
264
265impl std::fmt::Display for MessageType {
266    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
267        match self {
268            MessageType::Request => write!(f, "Request"),
269            MessageType::Response => write!(f, "Response"),
270            MessageType::ErrorResponse => write!(f, "Error"),
271            MessageType::Simple => write!(f, "Simple Message"),
272            MessageType::Acknowledge => write!(f, "Understood"),
273            MessageType::Test => write!(f, "Test message"),
274            // Add more custom message types as needed
275        }
276    }
277}
278