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
18pub const VERSION: &str = env!("CARGO_PKG_VERSION");
20pub const TTL: u64 = 30;
22
23pub 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#[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#[derive(Serialize, Deserialize, Debug)]
43pub struct RequestRecsPlainText {
44 pub command: Commands,
45 pub data: String,
46 pub uid: u32,
47}
48
49#[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#[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#[derive(Serialize, Deserialize, Debug)]
74pub enum RequestPayload {
75 Write(RequestRecsWrite),
76 PlainText(RequestRecsPlainText),
77 Simple(RequestRecsSimple),
78}
79
80#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
82pub enum Commands {
83 EncryptRawText,
84 DecryptRawText,
85 DecryptFile,
86 RemoveFile,
87 PingFile,
88}
89
90#[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#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
101pub enum MessageType {
102 Request,
103 Response,
104 ErrorResponse,
105 Simple,
106 Acknowledge,
107 Test,
108 }
110
111#[derive(Serialize, Deserialize, Debug)]
113pub enum ErrorCode {
114 UnknownMessageType,
115 InvalidPayload,
116 InvalidVersion,
117 InternalError,
118 InvalidPermissions,
119 }
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 }
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#[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 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#[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_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 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 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); 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 }
276 }
277}
278