Upload and download attachments, and added License file

This commit is contained in:
Daniel García
2018-02-15 00:40:34 +01:00
parent 5cd40c63ed
commit b54684b677
20 changed files with 1147 additions and 199 deletions

View File

@@ -0,0 +1,93 @@
use serde_json::Value as JsonValue;
use super::Cipher;
use CONFIG;
#[derive(Debug, Identifiable, Queryable, Insertable, Associations)]
#[table_name = "attachments"]
#[belongs_to(Cipher, foreign_key = "cipher_uuid")]
#[primary_key(id)]
pub struct Attachment {
pub id: String,
pub cipher_uuid: String,
pub file_name: String,
pub file_size: i32,
}
/// Local methods
impl Attachment {
pub fn new(id: String, cipher_uuid: String, file_name: String, file_size: i32) -> Self {
Self {
id,
cipher_uuid,
file_name,
file_size,
}
}
pub fn get_file_path(&self) -> String {
format!("{}/{}/{}", CONFIG.attachments_folder, self.cipher_uuid, self.id)
}
pub fn to_json(&self) -> JsonValue {
use util::get_display_size;
use CONFIG;
// TODO: Change all references to localhost (maybe put it in .env?)
let host = "http://localhost:8000";
let web_path = format!("{}/attachments/{}/{}", host, self.cipher_uuid, self.id);
let file_path = self.get_file_path();
let display_size = get_display_size(self.file_size);
json!({
"Id": self.id,
"Url": web_path,
"FileName": self.file_name,
"Size": self.file_size.to_string(),
"SizeName": display_size,
"Object": "attachment"
})
}
}
use diesel;
use diesel::prelude::*;
use db::DbConn;
use db::schema::attachments;
/// Database methods
impl Attachment {
pub fn save(&self, conn: &DbConn) -> bool {
// TODO: Update modified date
match diesel::replace_into(attachments::table)
.values(self)
.execute(&**conn) {
Ok(1) => true, // One row inserted
_ => false,
}
}
pub fn delete(self, conn: &DbConn) -> bool {
match diesel::delete(attachments::table.filter(
attachments::id.eq(self.id)))
.execute(&**conn) {
Ok(1) => true, // One row deleted
_ => false,
}
}
pub fn find_by_id(id: &str, conn: &DbConn) -> Option<Self> {
attachments::table
.filter(attachments::id.eq(id))
.first::<Self>(&**conn).ok()
}
pub fn find_by_cipher(cipher_uuid: &str, conn: &DbConn) -> Vec<Self> {
attachments::table
.filter(attachments::cipher_uuid.eq(cipher_uuid))
.load::<Self>(&**conn).expect("Error loading attachments")
}
}

View File

@@ -4,8 +4,11 @@ use serde_json::Value as JsonValue;
use uuid::Uuid;
#[derive(Queryable, Insertable, Identifiable)]
use super::User;
#[derive(Debug, Identifiable, Queryable, Insertable, Associations)]
#[table_name = "ciphers"]
#[belongs_to(User, foreign_key = "user_uuid")]
#[primary_key(uuid)]
pub struct Cipher {
pub uuid: String,
@@ -24,15 +27,14 @@ pub struct Cipher {
pub data: String,
pub favorite: bool,
pub attachments: Option<Vec<u8>>,
}
/// Local methods
impl Cipher {
pub fn new(user_uuid: String, type_: i32, favorite: bool) -> Cipher {
pub fn new(user_uuid: String, type_: i32, favorite: bool) -> Self {
let now = Utc::now().naive_utc();
Cipher {
Self {
uuid: Uuid::new_v4().to_string(),
created_at: now,
updated_at: now,
@@ -45,30 +47,8 @@ impl Cipher {
favorite,
data: String::new(),
attachments: None,
}
}
pub fn to_json(&self) -> JsonValue {
use serde_json;
use util::format_date;
let data: JsonValue = serde_json::from_str(&self.data).unwrap();
json!({
"Id": self.uuid,
"Type": self.type_,
"RevisionDate": format_date(&self.updated_at),
"FolderId": self.folder_uuid,
"Favorite": self.favorite,
"OrganizationId": "",
"Attachments": self.attachments,
"OrganizationUseTotp": false,
"Data": data,
"Object": "cipher",
"Edit": true,
})
}
}
use diesel;
@@ -78,6 +58,31 @@ use db::schema::ciphers;
/// Database methods
impl Cipher {
pub fn to_json(&self, conn: &DbConn) -> JsonValue {
use serde_json;
use util::format_date;
use super::Attachment;
let data_json: JsonValue = serde_json::from_str(&self.data).unwrap();
let attachments = Attachment::find_by_cipher(&self.uuid, conn);
let attachments_json: Vec<JsonValue> = attachments.iter().map(|c| c.to_json()).collect();
json!({
"Id": self.uuid,
"Type": self.type_,
"RevisionDate": format_date(&self.updated_at),
"FolderId": self.folder_uuid,
"Favorite": self.favorite,
"OrganizationId": "",
"Attachments": attachments_json,
"OrganizationUseTotp": false,
"Data": data_json,
"Object": "cipher",
"Edit": true,
})
}
pub fn save(&self, conn: &DbConn) -> bool {
// TODO: Update modified date
@@ -98,15 +103,15 @@ impl Cipher {
}
}
pub fn find_by_uuid(uuid: &str, conn: &DbConn) -> Option<Cipher> {
pub fn find_by_uuid(uuid: &str, conn: &DbConn) -> Option<Self> {
ciphers::table
.filter(ciphers::uuid.eq(uuid))
.first::<Cipher>(&**conn).ok()
.first::<Self>(&**conn).ok()
}
pub fn find_by_user(user_uuid: &str, conn: &DbConn) -> Vec<Cipher> {
pub fn find_by_user(user_uuid: &str, conn: &DbConn) -> Vec<Self> {
ciphers::table
.filter(ciphers::user_uuid.eq(user_uuid))
.load::<Cipher>(&**conn).expect("Error loading ciphers")
.load::<Self>(&**conn).expect("Error loading ciphers")
}
}

View File

@@ -4,8 +4,11 @@ use serde_json::Value as JsonValue;
use uuid::Uuid;
#[derive(Queryable, Insertable, Identifiable)]
use super::User;
#[derive(Debug, Identifiable, Queryable, Insertable, Associations)]
#[table_name = "devices"]
#[belongs_to(User, foreign_key = "user_uuid")]
#[primary_key(uuid)]
pub struct Device {
pub uuid: String,
@@ -24,10 +27,10 @@ pub struct Device {
/// Local methods
impl Device {
pub fn new(uuid: String, user_uuid: String, name: String, type_: i32) -> Device {
pub fn new(uuid: String, user_uuid: String, name: String, type_: i32) -> Self {
let now = Utc::now().naive_utc();
Device {
Self {
uuid,
created_at: now,
updated_at: now,
@@ -103,15 +106,15 @@ impl Device {
}
}
pub fn find_by_uuid(uuid: &str, conn: &DbConn) -> Option<Device> {
pub fn find_by_uuid(uuid: &str, conn: &DbConn) -> Option<Self> {
devices::table
.filter(devices::uuid.eq(uuid))
.first::<Device>(&**conn).ok()
.first::<Self>(&**conn).ok()
}
pub fn find_by_refresh_token(refresh_token: &str, conn: &DbConn) -> Option<Device> {
pub fn find_by_refresh_token(refresh_token: &str, conn: &DbConn) -> Option<Self> {
devices::table
.filter(devices::refresh_token.eq(refresh_token))
.first::<Device>(&**conn).ok()
.first::<Self>(&**conn).ok()
}
}

View File

@@ -4,8 +4,11 @@ use serde_json::Value as JsonValue;
use uuid::Uuid;
#[derive(Queryable, Insertable, Identifiable)]
use super::User;
#[derive(Debug, Identifiable, Queryable, Insertable, Associations)]
#[table_name = "folders"]
#[belongs_to(User, foreign_key = "user_uuid")]
#[primary_key(uuid)]
pub struct Folder {
pub uuid: String,
@@ -17,10 +20,10 @@ pub struct Folder {
/// Local methods
impl Folder {
pub fn new(user_uuid: String, name: String) -> Folder {
pub fn new(user_uuid: String, name: String) -> Self {
let now = Utc::now().naive_utc();
Folder {
Self {
uuid: Uuid::new_v4().to_string(),
created_at: now,
updated_at: now,
@@ -69,15 +72,15 @@ impl Folder {
}
}
pub fn find_by_uuid(uuid: &str, conn: &DbConn) -> Option<Folder> {
pub fn find_by_uuid(uuid: &str, conn: &DbConn) -> Option<Self> {
folders::table
.filter(folders::uuid.eq(uuid))
.first::<Folder>(&**conn).ok()
.first::<Self>(&**conn).ok()
}
pub fn find_by_user(user_uuid: &str, conn: &DbConn) -> Vec<Folder> {
pub fn find_by_user(user_uuid: &str, conn: &DbConn) -> Vec<Self> {
folders::table
.filter(folders::user_uuid.eq(user_uuid))
.load::<Folder>(&**conn).expect("Error loading folders")
.load::<Self>(&**conn).expect("Error loading folders")
}
}

View File

@@ -1,8 +1,10 @@
mod attachment;
mod cipher;
mod device;
mod folder;
mod user;
pub use self::attachment::Attachment;
pub use self::cipher::Cipher;
pub use self::device::Device;
pub use self::folder::Folder;

View File

@@ -6,7 +6,7 @@ use uuid::Uuid;
use CONFIG;
#[derive(Queryable, Insertable, Identifiable)]
#[derive(Debug, Identifiable, Queryable, Insertable)]
#[table_name = "users"]
#[primary_key(uuid)]
pub struct User {
@@ -28,11 +28,14 @@ pub struct User {
pub totp_secret: Option<String>,
pub totp_recover: Option<String>,
pub security_stamp: String,
pub equivalent_domains: String,
pub excluded_globals: String,
}
/// Local methods
impl User {
pub fn new(mail: String, key: String, password: String) -> User {
pub fn new(mail: String, key: String, password: String) -> Self {
let now = Utc::now().naive_utc();
let email = mail.to_lowercase();
@@ -42,7 +45,7 @@ impl User {
let salt = crypto::get_random_64();
let password_hash = crypto::hash_password(password.as_bytes(), &salt, iterations as u32);
User {
Self {
uuid: Uuid::new_v4().to_string(),
created_at: now,
updated_at: now,
@@ -61,6 +64,9 @@ impl User {
public_key: None,
totp_secret: None,
totp_recover: None,
equivalent_domains: "[]".to_string(),
excluded_globals: "[]".to_string(),
}
}
@@ -144,16 +150,16 @@ impl User {
}
}
pub fn find_by_mail(mail: &str, conn: &DbConn) -> Option<User> {
pub fn find_by_mail(mail: &str, conn: &DbConn) -> Option<Self> {
let lower_mail = mail.to_lowercase();
users::table
.filter(users::email.eq(lower_mail))
.first::<User>(&**conn).ok()
.first::<Self>(&**conn).ok()
}
pub fn find_by_uuid(uuid: &str, conn: &DbConn) -> Option<User> {
pub fn find_by_uuid(uuid: &str, conn: &DbConn) -> Option<Self> {
users::table
.filter(users::uuid.eq(uuid))
.first::<User>(&**conn).ok()
.first::<Self>(&**conn).ok()
}
}

View File

@@ -1,3 +1,12 @@
table! {
attachments (id) {
id -> Text,
cipher_uuid -> Text,
file_name -> Text,
file_size -> Integer,
}
}
table! {
ciphers (uuid) {
uuid -> Text,
@@ -10,7 +19,6 @@ table! {
type_ -> Integer,
data -> Text,
favorite -> Bool,
attachments -> Nullable<Binary>,
}
}
@@ -55,15 +63,19 @@ table! {
totp_secret -> Nullable<Text>,
totp_recover -> Nullable<Text>,
security_stamp -> Text,
equivalent_domains -> Text,
excluded_globals -> Text,
}
}
joinable!(attachments -> ciphers (cipher_uuid));
joinable!(ciphers -> folders (folder_uuid));
joinable!(ciphers -> users (user_uuid));
joinable!(devices -> users (user_uuid));
joinable!(folders -> users (user_uuid));
allow_tables_to_appear_in_same_query!(
attachments,
ciphers,
devices,
folders,