1mod models;
2mod schema;
3
4use diesel::prelude::*;
5use diesel_migrations::embed_migrations;
6use libloading::Library;
7use ipfs_api_backend_hyper::{IpfsApi, IpfsClient};
8use futures::executor::block_on;
9use sha2::{Sha512,Sha256, Digest};
10
11use std::io::{Write,Cursor};
12use std::process::{Command,Stdio};
13use std::time::{SystemTime,UNIX_EPOCH};
14use std::str;
15use std::fs::File;
16use std::fs;
17use std::error::Error;
18
19use self::models::{EntryTag,NewEntryTag,NewEntry, Entry, NewDirTag, DirTag, Tag, NewTag, Dir, NewDir,NewUser,User};
20use crate::ic_types::{IcError,IcLoginDetails,IcPacket,IcExecute,IcConnection};
21use crate::IcModule;
22use futures::TryStreamExt;
23use tar::Archive;
24
25
26embed_migrations!("migrations/");
27
28pub fn delete_sql(username: &str,password: &str) -> Result<(),Box<dyn Error>>{
29 let p = format!("--password={}",password);
31 let echo =
32 Command::new("echo")
33 .arg("DROP DATABASE IntelCache;DROP USER 'intelcache'@'localhost'")
35 .stdout(Stdio::piped())
36 .stderr(Stdio::piped())
37 .spawn()?;
38
39 Command::new("mysql")
47 .args(["-u",username])
48 .arg(p)
49 .stdin(echo.stdout.unwrap())
50 .stdout(Stdio::piped())
51 .stderr(Stdio::piped()).spawn()?.wait()?;
52 Ok(())
53}
54
55pub fn delete_testing_sql(username: &str,password: &str) -> Result<(),Box<dyn Error>>{
56 let p = format!("--password={}",password);
58 let echo =
59 Command::new("echo")
60 .arg("DROP DATABASE IntelCache_testing;DROP USER 'intelcache_tester'@'localhost'")
62 .stdout(Stdio::piped())
63 .stderr(Stdio::piped())
64 .spawn()?;
65
66 Command::new("mysql")
68 .args(["-u",username])
69 .arg(p)
70 .stdin(echo.stdout.unwrap())
71 .stdout(Stdio::piped())
72 .stderr(Stdio::piped()).spawn()?.wait()?;
73 Ok(())
74}
75
76pub fn build_sql(username: &str,password: &str) -> Result<(),Box<dyn Error>>{
77 let p = format!("--password={}",password);
79 let echo =
80 Command::new("echo")
81 .arg("CREATE DATABASE IntelCache;CREATE USER IF NOT EXISTS 'intelcache'@'localhost' IDENTIFIED BY 'intelcache';GRANT ALL ON `IntelCache`.* TO 'intelcache'@'localhost' IDENTIFIED BY 'intelcache';")
83 .stdout(Stdio::piped())
84 .stderr(Stdio::piped())
85 .spawn()?;
86
87 Command::new("mysql")
89 .args(["-u",username])
90 .arg(p)
91 .stdin(echo.stdout.unwrap())
92 .stdout(Stdio::piped())
93 .stderr(Stdio::piped())
94 .spawn()?.wait()?;
95
96 let con = establish_connection()?;
97 embedded_migrations::run(&con)?;
98 Ok(())
99}
100pub fn build_testing_sql(username: &str,password: &str) -> Result<(),Box<dyn Error>>{
101 let p = format!("--password={}",password);
103 let echo =
104 Command::new("echo")
105 .arg("CREATE DATABASE IntelCache_testing;CREATE USER IF NOT EXISTS 'intelcache_tester'@'localhost' IDENTIFIED BY 'intelcache';GRANT ALL ON `IntelCache_testing`.* TO 'intelcache_tester'@'localhost' IDENTIFIED BY 'intelcache';")
107 .stdout(Stdio::piped())
108 .stderr(Stdio::piped())
109 .spawn()?;
110
111 Command::new("mysql")
113 .args(["-u",username])
114 .arg(p)
115 .stdin(echo.stdout.unwrap())
116 .stdout(Stdio::piped())
117 .stderr(Stdio::piped())
118 .spawn()?.wait()?;
119
120 let con = establish_testing_connection()?;
121 embedded_migrations::run(&con)?;
122 Ok(())
123}
124
125pub fn export_sql(username: &str,password: &str,filename: &str) -> Result<(),Box<dyn Error>>{
126 let p = format!("--password={}",password);
128
129 Command::new("mysqldump")
131 .args(["-u",username])
132 .arg(p)
133 .arg("IntelCache")
134 .stdout(File::create(filename)?)
135 .spawn()?.wait()?;
136 Ok(())
137}
138pub fn export_testing_sql(username: &str,password: &str,filename: &str) -> Result<(),Box<dyn Error>>{
139 let p = format!("--password={}",password);
141
142 Command::new("mysqldump")
144 .args(["-u",username])
145 .arg(p)
146 .arg("IntelCache_testing")
147 .stdout(File::create(filename)?)
148 .spawn()?.wait()?;
149 Ok(())
150}
151
152pub fn import_sql(username: &str,password: &str,filename: &str) -> Result<(),Box<dyn Error>>{
153 let p = format!("--password={}",password);
155 let mut mysqlcreate =
156 Command::new("mysql")
157 .args(["-u",username])
158 .arg(&p)
159 .stdin(Stdio::piped())
160 .stdout(Stdio::piped())
161 .stderr(Stdio::piped())
162 .spawn()?;
163 mysqlcreate.stdin.as_mut().unwrap().write(b"CREATE DATABASE IntelCache;CREATE USER IF NOT EXISTS 'intelcache'@'localhost' IDENTIFIED BY 'intelcache';GRANT ALL ON `IntelCache`.* TO 'intelcache'@'localhost' IDENTIFIED BY 'intelcache';")?;
164 mysqlcreate.wait()?;
165
166 Command::new("mysql")
168 .args(["-u",username])
169 .arg(&p)
170 .arg("IntelCache")
171 .stdin(File::open(filename)?)
172 .stdout(Stdio::piped())
173 .stderr(Stdio::piped())
174 .spawn()?.wait()?;
175 Ok(())
176}
177
178pub fn import_testing_sql(username: &str,password: &str,filename: &str) -> Result<(),Box<dyn Error>>{
179 let p = format!("--password={}",password);
181 let mut mysqlcreate =
182 Command::new("mysql")
183 .args(["-u",username])
184 .arg(&p)
185 .stdin(Stdio::piped())
186 .stdout(Stdio::piped())
187 .stderr(Stdio::piped())
188 .spawn()?;
189 mysqlcreate.stdin.as_mut().unwrap().write(b"CREATE DATABASE IntelCache_testing;CREATE USER IF NOT EXISTS 'intelcache_tester'@'localhost' IDENTIFIED BY 'intelcache';GRANT ALL ON `IntelCache_testing`.* TO 'intelcache_tester'@'localhost' IDENTIFIED BY 'intelcache';")?;
190 mysqlcreate.wait()?;
191
192 Command::new("mysql")
194 .args(["-u",username])
195 .arg(&p)
196 .arg("IntelCache_testing")
197 .stdin(File::open(filename)?)
198 .stdout(Stdio::piped())
199 .stderr(Stdio::piped())
200 .spawn()?.wait()?;
201
202 Ok(())
203}
204
205pub fn establish_connection() -> Result<MysqlConnection,Box<dyn Error>> {
206 let u = "mysql://intelcache:intelcache@localhost/IntelCache";
207 let ret: MysqlConnection;
208 match MysqlConnection::establish(&u) {
209 Ok(v) => ret = v,
210 Err(e) => panic!("{:?}",e),
211 }
212 Ok(ret)
213}
214
215pub fn establish_testing_connection() -> Result<MysqlConnection,Box<dyn Error>> {
216 let u = "mysql://intelcache_tester:intelcache@localhost/IntelCache_testing";
217 let ret: MysqlConnection;
218 match MysqlConnection::establish(&u) {
219 Ok(v) => ret = v,
220 Err(e) => panic!("{:?}",e),
221 }
222 Ok(ret)
223}
224
225pub fn create_dir(conn: &MysqlConnection, name: &str, loc: Option<i32>, public: bool,id: &String) -> Result<Dir,IcError> {
226 use schema::dir;
227
228 let l: Option<i32>;
229 if loc != None {
230 l = if loc.unwrap() == 0 {None} else {Some(loc.unwrap())};
231 } else {l = None}
232 let new_dir = NewDir { name,loc: l,visibility: public,owner: id.to_string() };
233
234 match diesel::insert_into(dir::table).values(&new_dir).execute(conn) {
235 Ok(_v) => (),
236 Err(_err) => panic!("{:?}",_err),}
238
239 Ok(dir::table.order(dir::id.desc()).first(conn).unwrap())
240}
241
242pub fn delete_dir(conn: &MysqlConnection,dirid: i32) -> Result<(),IcError>{
243 use self::schema::dir::dsl::*;
244 let rv = match validate_dir(conn,dirid) {
245 Some(_v) => dirid,
246 None => {return Err(IcError("Error deleting directory.".to_string()))}
247 };
248 diesel::delete(dir.filter(id.eq(rv))).execute(conn).unwrap();
249 Ok(())
250}
251pub fn update_dir(conn: &MysqlConnection,dirid: i32,iddest: Option<i32>,new_name: Option<&str>) -> Result<(),IcError>{
252 use schema::dir;
253 if new_name == None {
254 if iddest != None {
255 let rv = diesel::update(dir::table.filter(dir::id.eq(dirid))).set(dir::loc.eq(&iddest)).execute(conn);
256 match rv {
257 Ok(_v) => return Ok(()),
258 Err(_err) => return Err(IcError("Failed to update directory.".to_string())),
259 };
260 } else {return Err(IcError("Failed to update directory.".to_string()))}
261 } else {
262 if iddest != None {
263 let rv = diesel::update(dir::table.filter(dir::id.eq(dirid))).set((dir::loc.eq(&iddest),dir::name.eq(&new_name.unwrap()))).execute(conn);
264 match rv {
265 Ok(_v) => return Ok(()),
266 Err(_err) => return Err(IcError("Failed to update directory.".to_string())),
267 };
268 } else {
269 let rv = diesel::update(dir::table.filter(dir::id.eq(dirid))).set(dir::name.eq(&new_name.unwrap())).execute(conn);
270 match rv {
271 Ok(_v) => return Ok(()),
272 Err(_err) => return Err(IcError("Failed to update directory.".to_string())),
273 };
274 }
275 }
276}
277
278pub fn show_dirs(conn: &MysqlConnection,by_id: Option<i32>,o: &String,owned_only: bool) -> String{
279 use self::schema::dir::dsl::*;
280 use schema::dir;
281 let results: Vec<Dir>;
282 if by_id != None {
283 if by_id.unwrap() != 0 {
284 results = dir.filter(dir::loc.eq(by_id.unwrap()).and(dir::owner.eq(o))).load::<Dir>(conn).expect("Error loading dirs");
285 } else {
286 results = dir.filter(dir::loc.is_null().and(dir::owner.eq(o))).load::<Dir>(conn).expect("Error loading dirs");
287 }
288 } else { results = dir.filter(dir::owner.eq(o)).load::<Dir>(conn).expect("Error loading dirs");
290 }
291 let mut retstr = String::new();
292
293 for d in results {
294 let location = if d.loc.unwrap_or(-1) == -1 {"ROOT".to_string()} else {dir::table.filter(dir::id.eq(d.loc.unwrap())).select(dir::name).get_result::<String>(conn).unwrap()};
295 let tags = get_dir_tags(conn,d.id);
296 retstr.push_str(format!("{} {} ({}) {}\n",d.id,d.name, location, tags).as_str())
297 }
298 if ! owned_only {
299 let public_results = dir.filter(dir::visibility.eq(true)).load::<Dir>(conn).expect("Error loading dirs");
300 for d in public_results {
301 let location = if d.loc.unwrap_or(-1) == -1 {"ROOT".to_string()} else {dir::table.filter(dir::id.eq(d.loc.unwrap())).select(dir::name).get_result::<String>(conn).unwrap()};
302 let tags = get_dir_tags(conn,d.id);
303 retstr.push_str(format!("{} {} ({}) {} -> {} {}\n",d.id,d.name, location, tags,d.owner,if d.visibility {"PUBLIC"} else {"PRIVATE"}).as_str())
304 }
305 }
306 retstr
307}
308
309pub fn show_tags(conn: &MysqlConnection, _display: Option<bool>) -> String {
310 use self::schema::tag::dsl::*;
311 let results = tag.load::<Tag>(conn).expect("Error loading tags");
312 let mut retstr = String::new();
313 for d in results {
314 retstr.push_str(&format!("{} {}\n",d.id,&d.name));
315 }
316 retstr
317}
318
319pub fn rename_tag(conn: &IcConnection,tagid: i32, tagname: &str) -> Result<(),Box<dyn Error>> {
320 use schema::tag;
321 match diesel::update(tag::table.filter(tag::id.eq(tagid))).set(tag::name.eq(tagname)).execute(&conn.backend_con) {
322 Ok(_v) => return Ok(()),
323 Err(e) => return Err(Box::new(e)),
324 }
325}
326
327pub fn create_tag(conn: &IcConnection, name: &str,public: bool) -> Tag {
328 use schema::tag;
329
330 let new_tag = NewTag { name,visibility: public,owner: &conn.login.as_ref().unwrap().id };
331
332 diesel::insert_into(tag::table)
333 .values(&new_tag).execute(&conn.backend_con).expect("Error saving draft");
334
335 tag::table.order(tag::id.desc()).first(&conn.backend_con).unwrap()
336}
337
338pub fn delete_tag(conn: &MysqlConnection,tagid: i32) -> Result<(),IcError>{
339 use self::schema::tag::dsl::*;
340 let rv = match validate_tag(conn,tagid) {
341 Some(_v) => tagid,
342 None => {return Err(IcError("Error deleting tag.".to_string()))}
343 };
344 diesel::delete(tag.filter(id.eq(rv))).execute(conn).unwrap();
345 Ok(())
346}
347
348pub fn tag_dir(conn: &MysqlConnection, dir_id: i32,tag_id: i32) -> Result<DirTag ,IcError>{
349 use schema::dir_tags;
350
351 let new_dir_tag = NewDirTag { dirid: dir_id,tagid: tag_id };
352
353 let res = diesel::insert_into(dir_tags::table).values(&new_dir_tag).execute(conn);
354 match res {
355 Ok(_e) => (),
356 Err(_e) => {return Err(IcError("Invalid dir id or tag id.".to_string()))},
357 }
358
359 Ok(dir_tags::table.filter(dir_tags::tagid.eq(tag_id)).filter(dir_tags::dirid.eq(dir_id)).limit(1).get_result::<DirTag>(conn).unwrap())
360}
361
362pub fn untag_dir(conn: &MysqlConnection,dir_id: i32, tag_id: i32) {
363 use schema::dir_tags;
364
365 diesel::delete(dir_tags::table.filter(dir_tags::dirid.eq(dir_id)).filter(dir_tags::tagid.eq(tag_id))).execute(conn).expect("Error untaging directory.");
366}
367
368pub fn get_dir_tags(conn: &MysqlConnection, dir_id: i32) -> String {
369 use schema::dir_tags;
370 use schema::tag;
371 use schema::dir;
372 use self::schema::dir::dsl::*;
373 let results = dir.left_join(dir_tags::table).left_join(tag::table.on(dir_tags::tagid.eq(tag::id))).filter(dir::id.eq(dir_id)).select(tag::name.nullable()).load::<Option<String>>(conn).unwrap();
374 let mut retstr = String::new();
375 retstr.push_str(if results.len() <= 1 && results[0].as_ref().unwrap_or(&"NONE".to_string()) == &"NONE".to_string() {""} else {"["});
376 let rl = results.len();
377 let mut rlv = String::new();
378 rlv.push_str(&results[0].as_ref().unwrap_or(&"NONE".to_string()));
379 if rlv != "NONE".to_string() {
380 let mut c = 0;
381 for t in results {
382 c += 1;
383 let p = t.unwrap_or("".to_string());
384 retstr.push_str(&p);
385 retstr.push_str(if p == "".to_string() || (p != "".to_string() && c == rl) {""} else {", "});
386 }
387 }
388 retstr.push_str(if rl <= 1 && rlv == "NONE".to_string() {""} else {"]"});
389 retstr
390}
391
392pub fn show_entries(conn: &MysqlConnection, _display: Option<bool>, shortened: Option<bool>, under_id: Option<i32>,o: &String,owned_only: bool) -> String {
393 use self::schema::entry::dsl::*;
394 use schema::entry;
395 let results: Vec<Entry>;
396 if under_id != None && under_id.unwrap() == 0 { results = entry.filter(entry::loc.is_null().and(entry::owner.eq(o))).load::<Entry>(conn).expect("Error loading entries");
398 } else if under_id == None { results = entry.filter(entry::owner.eq(o)).load::<Entry>(conn).expect("Error loading entries");
400 } else { results = entry.filter(entry::loc.eq(under_id.unwrap()).and(entry::owner.eq(o))).load::<Entry>(conn).expect("Error loading entries");
402 }
403
404 let mut retstr = String::new();
405 if ! shortened.unwrap_or(false) {
406 for e in results {
407 if e.owner == *o || (owned_only && e.visibility){
408 let tags = get_entry_tags(conn,e.id);
409 let text = match str::from_utf8(&e.data) {
410 Ok(v) => v,
411 Err(e) => panic!("Invalid UTF-8 sequence: {}", e),
412 };
413 retstr.push_str(format!("{} {} ({}) {} [{}]\n{}\n",e.id,e.name,e.type_,e.loc.unwrap_or(0),tags,text).as_str());
414 }
415 }
416 } else {
417 for e in results {
418 if e.owner == *o || (owned_only && e.visibility){
419 let tags = get_entry_tags(conn,e.id);
420 retstr.push_str(format!("{} {} ({}) {} {}\n",e.id,e.name,e.type_,e.loc.unwrap_or(0),tags).as_str());
421 }
422 }
423 }
424 retstr
425}
426
427#[tokio::main]
428pub async fn delete_entry(conn: &MysqlConnection,entryid: i32) -> Result<(),IcError>{
429 use self::schema::entry::dsl::*;
430 if get_entry_by_id(conn,entryid) != None {
431 let e = get_entry_by_id(conn,entryid).unwrap();
432 if e.type_ == "ipfs_file" {
433 let ipfsclient = IpfsClient::default();
434 block_on(ipfsclient.pin_rm(str::from_utf8(&e.data).unwrap(),true)).unwrap();
435 }
436 diesel::delete(entry.filter(id.eq(entryid))).execute(conn).unwrap();
437 return Ok(());
438 } else { return Err(IcError("Entry id not found".to_string())) }
439}
440
441#[tokio::main]
442pub async fn get_entry(conn: &mut IcConnection,id: i32,name: &str) -> IcPacket{
443 let e = get_entry_by_id(&conn.backend_con,id).unwrap();
444
445 if e.type_ == "ipfs_file" {
446 let client = IpfsClient::default();
447 match block_on(client
449 .get(str::from_utf8(&e.data).unwrap())
450 .map_ok(|chunk| chunk.to_vec())
451 .try_concat())
452 {
453 Ok(res) => {
454 fs::write(name,res).unwrap();
455
456 }
457 Err(e) => return IcPacket::new(Some(format!("ERR: error getting file: {}", e)),None)
458 }
459 let mut archive = Archive::new(File::open(name).unwrap());
460 archive.unpack(".").unwrap();
461 fs::rename(str::from_utf8(&e.data).unwrap(),name).unwrap();
462 let p = IcPacket::new_cached(Some("OK!".to_string()),Some(name.as_bytes().to_vec()));
463 println!("RETURNING PACKET TO SEND: {} ({:?})",&p.header.as_ref().unwrap(),&p.body.as_ref().unwrap());
464 return p;
465 }else if e.type_ == "text" {
466 return IcPacket::new(Some("OK!".to_string()),Some(e.data));
467 } else { return IcPacket::new(Some("ERR: Type unknown".to_string()),None) }
468}
469
470pub fn tag_entry(conn: &MysqlConnection, entry_id: i32,tag_id: i32) -> Result<EntryTag,IcError>{
471 use schema::entry_tags;
472
473 let new_entry_tag = NewEntryTag { entryid: entry_id,tagid: tag_id };
474
475 let res = diesel::insert_into(entry_tags::table).values(&new_entry_tag).execute(conn);
476 match res {
477 Ok(_e) => (),
478 Err(_err) => {return Err(IcError("Error tagging entry.".to_string()))}
479 };
480 Ok(entry_tags::table.filter(entry_tags::tagid.eq(tag_id)).filter(entry_tags::entryid.eq(entry_id)).limit(1).get_result::<EntryTag>(conn).unwrap())
481}
482
483pub fn untag_entry(conn: &MysqlConnection,entry_id: i32, tag_id: i32) {
484 use schema::entry_tags;
485
486 diesel::delete(entry_tags::table.filter(entry_tags::entryid.eq(entry_id)).filter(entry_tags::tagid.eq(tag_id))).execute(conn).expect("Error saving draft");
487}
488
489pub fn get_entry_tags(conn: &MysqlConnection, entry_id: i32) -> String {
490 use schema::entry_tags;
491 use schema::tag;
492 use schema::entry;
493 use self::schema::entry::dsl::*;
494 let results = entry.left_join(entry_tags::table).left_join(tag::table.on(entry_tags::tagid.eq(tag::id))).filter(entry::id.eq(entry_id)).select(tag::name.nullable()).load::<Option<String>>(conn).unwrap();
495 let mut retstr = String::new();
496 retstr.push_str(if results.len() <= 1 && results[0].as_ref().unwrap_or(&"NONE".to_string()) == &"NONE".to_string() {""} else {"["});
497 let rl = results.len();
498 let mut rlv = String::new();
499 rlv.push_str(&results[0].as_ref().unwrap_or(&"NONE".to_string()));
500 if rlv != "NONE".to_string() {
501 let mut c = 0;
502 for t in results {
503 c += 1;
504 let p = t.unwrap_or("".to_string());
505 retstr.push_str(&p);
506 retstr.push_str(if p == "".to_string() || (p != "".to_string() && c == rl) {""} else {", "});
507 }
508 }
509 retstr.push_str(if rl <= 1 && rlv == "NONE".to_string() {""} else {"]"});
510 retstr
511}
512
513#[tokio::main]
514pub async fn make_file_entry(conn: &IcConnection,name: &str,dt: Vec<u8>,location: Option<i32>,lbl: Option<&str>,public: bool,cached: bool) -> Result<Entry,IcError> {
515 use schema::entry;
516
517 let ipfsclient = IpfsClient::default();
518 let l = if (location != None && location.unwrap() <= 0) || location == None {None} else {Some(location.unwrap())};
519 if ! cached {
520 if dt.len() < 65535 {
521 let new_entry = NewEntry { name: name,data: &dt,type_: "text",loc: l,label: lbl, visibility: public,owner: &conn.login.as_ref().unwrap().id };
522
523 let query = diesel::insert_into(entry::table).values(&new_entry);
524 let res = query.execute(&conn.backend_con);
528 match res {
529 Ok(_e) => (),
530 Err(_err) => panic!("{}",_err),}
532 } else {
533 let hash: String;
534 match block_on(ipfsclient.add(Cursor::new(dt))) {
535 Ok(res) => hash = res.hash,
536 Err(_e) => return Err(IcError("Error inserting file in IPFS.".to_string())),
537 }
538 let new_entry = NewEntry { name: name,data: hash.as_bytes(),type_: "ipfs_file",loc: l,label: lbl, visibility: public, owner: &conn.login.as_ref().unwrap().id };
539
540 let res = diesel::insert_into(entry::table).values(&new_entry).execute(&conn.backend_con);
541 match res {
542 Ok(_e) => (),
543 Err(_err) => return Err(IcError("Error making new IPFS entry in the IntelCache.".to_string())),
544 }
545
546 }
547 Ok(entry::table.order(entry::id.desc()).first(&conn.backend_con).unwrap())
548 } else {
549 let b = match str::from_utf8(&dt) {
550 Ok(v) => v,
551 Err(e) => panic!("Invalid UTF-8 sequence: {}", e),
552 };
553 let f = match File::open(b) {
554 Ok(v) => v,
555 Err(e) => panic!("Invalid File: {}", e),
556 };
557
558 let hash: String;
559 match block_on(ipfsclient.add(f)) {
560 Ok(res) => hash = res.hash,
561 Err(_e) => return Err(IcError("Error inserting file in IPFS.".to_string())),
562 }
563 let new_entry = NewEntry { name: name,data: hash.as_bytes(),type_: "ipfs_file",loc: l,label: lbl, visibility: public, owner: &conn.login.as_ref().unwrap().id };
564
565 let res = diesel::insert_into(entry::table).values(&new_entry).execute(&conn.backend_con);
566 match res {
567 Ok(_e) => (),
568 Err(_err) => return Err(IcError("Error making new IPFS entry in the IntelCache.".to_string())),
569 }
570
571 Ok(entry::table.order(entry::id.desc()).first(&conn.backend_con).unwrap())
572 }
573}
574
575pub async fn update_entry(conn: &MysqlConnection,uid: i32,dt: Option<Vec<u8>>,n: Option<&str>,l: Option<i32>,_lbl: Option<&str>) -> Result<(),IcError>{
576 use schema::entry;
577
578 let ipfsclient = IpfsClient::default();
579 if get_entry_by_id(conn,uid) != None {
580 let e = get_entry_by_id(conn,uid).unwrap();
582 if l == None {
583 println!("L IS NONE");
584 if dt != None {
585 println!("DT IS NOT NONE");
586 if dt.as_ref().unwrap().len() < 65535 {
587 diesel::update(entry::table.filter(entry::id.eq(uid))).set((entry::data.eq(&dt.unwrap()),entry::type_.eq("text"),entry::name.eq(n.unwrap_or(&e.name)))).execute(conn).expect("Error updating entry.");
588 Ok(())
589 } else {
590 let hash;
591 match block_on(ipfsclient.add(Cursor::new(dt.unwrap()))) {
592 Ok(res) => hash = res.hash,
593 Err(_e) => return Err(IcError("Error adding updated entry data.".to_string())),
594 };
595 diesel::update(entry::table.filter(entry::id.eq(uid))).set((entry::data.eq(hash.as_bytes()),entry::type_.eq("text"),entry::name.eq(n.unwrap_or(&e.name)))).execute(conn).expect("Error updating entry.");
596 Ok(())
597 }
598 } else {
599 println!("DT IS NONE");
600 diesel::update(entry::table.filter(entry::id.eq(uid))).set(entry::name.eq(n.unwrap_or(&e.name))).execute(conn).expect("Error updating entry.");
601 Ok(())
602 }
603 } else {
604 println!("L IS NOT NONE");
605 let nl: Option<i32> = if l.unwrap() == 0 {None} else {Some(l.unwrap())};
606
607 if dt != None {
608 println!("DT IS NOT NONE");
609 if dt.as_ref().unwrap().len() < 65535 {
610 diesel::update(entry::table.filter(entry::id.eq(uid))).set((entry::data.eq(&dt.unwrap()),entry::type_.eq("text"),entry::name.eq(n.unwrap_or(&e.name)),entry::loc.eq(nl))).execute(conn).expect("Error updating entry.");
611 Ok(())
612 } else {
613 let hash;
614 match block_on(ipfsclient.add(Cursor::new(dt.unwrap()))) {
615 Ok(res) => hash = res.hash,
616 Err(_e) => return Err(IcError("Error adding updated entry data.".to_string())),
617 };
618 diesel::update(entry::table.filter(entry::id.eq(uid))).set((entry::data.eq(hash.as_bytes()),entry::type_.eq("text"),entry::name.eq(n.unwrap_or(&e.name)),entry::loc.eq(nl))).execute(conn).expect("Error updating entry.");
619 Ok(())
620 }
621 } else {
622 println!("DT IS NONE");
623 diesel::update(entry::table.filter(entry::id.eq(uid))).set((entry::name.eq(n.unwrap_or(&e.name)),entry::loc.eq(nl))).execute(conn).expect("Error updating entry.");
624 Ok(())
625 }
626 }
627 } else {return Err(IcError("Error getting entry for update".to_string()))}
628}
629
630#[tokio::main]
631pub async fn get_pip() -> Option<String> {
632 match block_on(public_ip::addr()) {
633 Some(ip) => return Some(format!("{:?}", ip)),
634 None => return None,
635 }
636}
637
638pub fn get_entry_by_id(conn: &MysqlConnection,entryid: i32) -> Option<Entry> {
639 use schema::entry;
640
641 let r = entry::table.filter(entry::id.eq(entryid)).get_result::<Entry>(conn);
642 return match r {
643 Ok(entry) => Some(entry),
644 Err(_e) => None,
645 }
646}
647
648pub fn validate_dir(conn: &MysqlConnection,dirid: i32) -> Option<String> {
649 use schema::dir;
650 let d: Result<Vec<String>,diesel::result::Error>;
651 if dirid > 0 {
652 d = dir::table.filter(dir::id.eq(dirid)).select(dir::name).load::<String>(conn);
653 } else if dirid == 0 {
654 d = Ok(vec!("ROOT".to_string()));
655 } else { return None };
656
657 match d {
658 Ok(n) => return if n.len() as i32 >= 0 {Some(n[0].clone())} else {None},
659 Err(_e) => return None,
660 }
661}
662pub fn validate_tag(conn: &MysqlConnection,tagid: i32) -> Option<String> {
663 use schema::tag;
664 let d = tag::table.filter(tag::id.eq(tagid)).select(tag::name).load::<String>(conn);
665 match d {
666 Ok(n) => return if n.len() > 0 {Some(n[0].clone())} else {None},
667 Err(_e) => return None,
668 }
669}
670
671pub fn register(conn: &MysqlConnection,username: String,password: String,id: String) -> Result<(),IcError> {
672 use schema::user;
673 let user = NewUser{ global_id: id, username: username, password: password };
674 let res = diesel::insert_into(user::table).values(&user).execute(conn);
675
676 match res {
677 Ok(_e) => (),
678 Err(_err) => return Err(IcError("Error making new user.".to_string())),
679 }
680
681 Ok(())
682}
683
684pub fn login(conn: &MysqlConnection,login: &mut Option<IcLoginDetails>,id: String,password: String) -> Result<String,IcError> {
685 use schema::user;
686 let d = user::table.filter(user::global_id.eq(&id)).load::<User>(conn);
687 match d {
688 Ok(n) => {
689 if n.len() == 0 || n[0].password != password {
690 return Err(IcError("Error: wrong user/password.".to_string()));
691 } else {
692 let start = SystemTime::now();
694 let since_the_epoch = start
695 .duration_since(UNIX_EPOCH)
696 .expect("Time went backwards")
697 .as_secs().to_string();
698 let mut hasher = Sha256::new();
699 let gid = (&id).to_string()+&password+&since_the_epoch;
700 hasher.update(&gid);
701 let cookie = format!("{:x}",hasher.finalize());
702 if *login == None {
703 *login = Some(IcLoginDetails{username: n[0].username.clone(),id: id.clone(),cookie: cookie.clone()});
704 return Ok(cookie);
705 } else { return Ok(cookie); }
706 }
707 }
708 Err(_e) => return Err(IcError("Error getting user.".to_string())),
709 }
710}
711
712pub fn parse_ic_packet(packet: IcPacket,modules: &(Vec<Library>,Vec<Box<dyn IcModule>>)) -> Result<(Vec::<String>,Box<dyn IcExecute<Connection = IcConnection>>),IcError> {
713 let mut cmd = packet.parse_header();
714 if cmd.len() == 0 {
715 cmd = Vec::new();
716 cmd.push("CORE".to_string());
717 cmd.push("NULL".to_string());
718 }
719 for m in &modules.1 {
720 if m.icm_get_name() == cmd[0] {
721 match m.icm_get_command(cmd[1..].to_vec()) {
722 Ok(v) => return Ok((cmd[1..].to_vec(),v)),
723 Err(e) => return Err(e),
724 }
725 }
726
727 }
728 Err(IcError("NOT IMPLEMENTED".to_string()))
729}
730
731pub fn fetch_users(conn: &MysqlConnection,username: String) -> Vec<String> {
732 use schema::user;
733 let mut ret = Vec::<String>::new();
734 let d = user::table.filter(user::username.eq(&username)).load::<User>(conn);
735 match d {
736 Ok(v) => {
737 for user in v {
738 ret.push(user.global_id);
739 }
740 },
741 Err(_e) => (),
742 }
743 return ret
744}
745
746pub fn rename_account(conn: &mut IcConnection,new_name: &str) -> Result<String,Box<dyn Error>> {
747 use schema::user;
748 match diesel::update(user::table.filter(user::global_id.eq(&conn.login.as_ref().unwrap().id))).set(user::username.eq(new_name)).execute(&conn.backend_con) {
749 Ok(_v) => {
750 conn.login.as_mut().unwrap().username = new_name.to_string();
751 return Ok("OK!".to_string())
752 },
753 Err(e) => return Err(Box::new(e)),
754 }
755}
756
757pub fn change_password(conn: &mut IcConnection,password: &str) -> Result<String,Box<dyn Error>> {
758 use schema::user;
759 let mut hasher = Sha512::new();
761 hasher.update(password);
762 let hp = format!("{:x}",hasher.finalize());
763 match diesel::update(user::table.filter(user::global_id.eq(&conn.login.as_ref().unwrap().id))).set(user::password.eq(hp)).execute(&conn.backend_con) {
764 Ok(_v) => {
765 return Ok("OK!".to_string())
766 },
767 Err(e) => return Err(Box::new(e)),
768 }
769}
770
771pub fn logout(conn: &mut IcConnection) -> Result<String,Box<dyn Error>> {
772 conn.login = None;
773 Ok("OK!".to_string())
774}
775
776pub fn validate_user(conn: &mut IcConnection,cookie: &str) -> Result<String,Box<dyn Error>> {
777 match &conn.login {
778 Some(l) => if l.cookie == cookie { return Ok(l.username.clone()) }
779 else { return Err(Box::new(IcError("WRONG COOKIE".to_string()))) },
780 None => return Err(Box::new(IcError("NO LOGIN.".to_string()))),
781 };
782}