mirror of
https://github.com/dani-garcia/vaultwarden.git
synced 2025-06-16 15:50:08 +00:00
Allow col managers to import
This commit adds functionality to allow users with manage access to a collection, or managers with all access to import into an organization. Fixes #5592 Signed-off-by: BlackDex <black.dex@gmail.com>
This commit is contained in:
parent
e330f0fe95
commit
b0bff90b9e
5 changed files with 124 additions and 33 deletions
23
Cargo.lock
generated
23
Cargo.lock
generated
|
@ -490,9 +490,9 @@ checksum = "ade8366b8bd5ba243f0a58f036cc0ca8a2f069cff1a2351ef1cac6b083e16fc0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.2.23"
|
version = "1.2.24"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5f4ac86a9e5bc1e2b3449ab9d7d3a6a405e3d1bb28d7b9be8614f55846ae3766"
|
checksum = "16595d3be041c03b09d08d0858631facccee9221e579704070e6e9e4915d3bc7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"shlex",
|
"shlex",
|
||||||
]
|
]
|
||||||
|
@ -1640,11 +1640,10 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hyper-rustls"
|
name = "hyper-rustls"
|
||||||
version = "0.27.5"
|
version = "0.27.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2d191583f3da1305256f22463b9bb0471acad48a4e534a5218b9963e9c1f59b2"
|
checksum = "03a01595e11bdcec50946522c32dde3fc6914743000a68b93000965f2f02406d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures-util",
|
|
||||||
"http 1.3.1",
|
"http 1.3.1",
|
||||||
"hyper 1.6.0",
|
"hyper 1.6.0",
|
||||||
"hyper-util",
|
"hyper-util",
|
||||||
|
@ -1673,9 +1672,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hyper-util"
|
name = "hyper-util"
|
||||||
version = "0.1.11"
|
version = "0.1.12"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "497bbc33a26fdd4af9ed9c70d63f61cf56a938375fbb32df34db9b1cd6d643f2"
|
checksum = "cf9f1e950e0d9d1d3c47184416723cf29c0d1f93bd8cccf37e4beb6b44f31710"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"futures-channel",
|
"futures-channel",
|
||||||
|
@ -3282,9 +3281,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustversion"
|
name = "rustversion"
|
||||||
version = "1.0.20"
|
version = "1.0.21"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2"
|
checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ryu"
|
name = "ryu"
|
||||||
|
@ -4145,11 +4144,13 @@ checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uuid"
|
name = "uuid"
|
||||||
version = "1.16.0"
|
version = "1.17.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "458f7a779bf54acc9f347480ac654f68407d3aab21269a6e3c9f922acd9e2da9"
|
checksum = "3cf4199d1e5d15ddd86a694e4d0dffa9c323ce759fea589f00fef9d81cc1931d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"getrandom 0.3.3",
|
"getrandom 0.3.3",
|
||||||
|
"js-sys",
|
||||||
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
|
@ -95,7 +95,7 @@ ring = "0.17.14"
|
||||||
subtle = "2.6.1"
|
subtle = "2.6.1"
|
||||||
|
|
||||||
# UUID generation
|
# UUID generation
|
||||||
uuid = { version = "1.16.0", features = ["v4"] }
|
uuid = { version = "1.17.0", features = ["v4"] }
|
||||||
|
|
||||||
# Date and time libraries
|
# Date and time libraries
|
||||||
chrono = { version = "0.4.41", features = ["clock", "serde"], default-features = false }
|
chrono = { version = "0.4.41", features = ["clock", "serde"], default-features = false }
|
||||||
|
|
|
@ -697,6 +697,9 @@ async fn _delete_organization_collection(
|
||||||
headers: &ManagerHeaders,
|
headers: &ManagerHeaders,
|
||||||
conn: &mut DbConn,
|
conn: &mut DbConn,
|
||||||
) -> EmptyResult {
|
) -> EmptyResult {
|
||||||
|
if org_id != &headers.org_id {
|
||||||
|
err!("Organization not found", "Organization id's do not match");
|
||||||
|
}
|
||||||
let Some(collection) = Collection::find_by_uuid_and_org(col_id, org_id, conn).await else {
|
let Some(collection) = Collection::find_by_uuid_and_org(col_id, org_id, conn).await else {
|
||||||
err!("Collection not found", "Collection does not exist or does not belong to this organization")
|
err!("Collection not found", "Collection does not exist or does not belong to this organization")
|
||||||
};
|
};
|
||||||
|
@ -909,7 +912,7 @@ struct OrgIdData {
|
||||||
|
|
||||||
#[get("/ciphers/organization-details?<data..>")]
|
#[get("/ciphers/organization-details?<data..>")]
|
||||||
async fn get_org_details(data: OrgIdData, headers: OrgMemberHeaders, mut conn: DbConn) -> JsonResult {
|
async fn get_org_details(data: OrgIdData, headers: OrgMemberHeaders, mut conn: DbConn) -> JsonResult {
|
||||||
if data.organization_id != headers.org_id {
|
if data.organization_id != headers.membership.org_uuid {
|
||||||
err_code!("Resource not found.", "Organization id's do not match", rocket::http::Status::NotFound.code);
|
err_code!("Resource not found.", "Organization id's do not match", rocket::http::Status::NotFound.code);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1196,6 +1199,9 @@ async fn reinvite_member(
|
||||||
headers: AdminHeaders,
|
headers: AdminHeaders,
|
||||||
mut conn: DbConn,
|
mut conn: DbConn,
|
||||||
) -> EmptyResult {
|
) -> EmptyResult {
|
||||||
|
if org_id != headers.org_id {
|
||||||
|
err!("Organization not found", "Organization id's do not match");
|
||||||
|
}
|
||||||
_reinvite_member(&org_id, &member_id, &headers.user.email, &mut conn).await
|
_reinvite_member(&org_id, &member_id, &headers.user.email, &mut conn).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1413,6 +1419,9 @@ async fn _confirm_invite(
|
||||||
conn: &mut DbConn,
|
conn: &mut DbConn,
|
||||||
nt: &Notify<'_>,
|
nt: &Notify<'_>,
|
||||||
) -> EmptyResult {
|
) -> EmptyResult {
|
||||||
|
if org_id != &headers.org_id {
|
||||||
|
err!("Organization not found", "Organization id's do not match");
|
||||||
|
}
|
||||||
if key.is_empty() || member_id.is_empty() {
|
if key.is_empty() || member_id.is_empty() {
|
||||||
err!("Key or UserId is not set, unable to process request");
|
err!("Key or UserId is not set, unable to process request");
|
||||||
}
|
}
|
||||||
|
@ -1735,6 +1744,9 @@ async fn _delete_member(
|
||||||
conn: &mut DbConn,
|
conn: &mut DbConn,
|
||||||
nt: &Notify<'_>,
|
nt: &Notify<'_>,
|
||||||
) -> EmptyResult {
|
) -> EmptyResult {
|
||||||
|
if org_id != &headers.org_id {
|
||||||
|
err!("Organization not found", "Organization id's do not match");
|
||||||
|
}
|
||||||
let Some(member_to_delete) = Membership::find_by_uuid_and_org(member_id, org_id, conn).await else {
|
let Some(member_to_delete) = Membership::find_by_uuid_and_org(member_id, org_id, conn).await else {
|
||||||
err!("User to delete isn't member of the organization")
|
err!("User to delete isn't member of the organization")
|
||||||
};
|
};
|
||||||
|
@ -1829,16 +1841,20 @@ struct RelationsData {
|
||||||
value: usize,
|
value: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// https://github.com/bitwarden/server/blob/9ebe16587175b1c0e9208f84397bb75d0d595510/src/Api/Tools/Controllers/ImportCiphersController.cs#L62
|
||||||
#[post("/ciphers/import-organization?<query..>", data = "<data>")]
|
#[post("/ciphers/import-organization?<query..>", data = "<data>")]
|
||||||
async fn post_org_import(
|
async fn post_org_import(
|
||||||
query: OrgIdData,
|
query: OrgIdData,
|
||||||
data: Json<ImportData>,
|
data: Json<ImportData>,
|
||||||
headers: AdminHeaders,
|
headers: OrgMemberHeaders,
|
||||||
mut conn: DbConn,
|
mut conn: DbConn,
|
||||||
nt: Notify<'_>,
|
nt: Notify<'_>,
|
||||||
) -> EmptyResult {
|
) -> EmptyResult {
|
||||||
let data: ImportData = data.into_inner();
|
|
||||||
let org_id = query.organization_id;
|
let org_id = query.organization_id;
|
||||||
|
if org_id != headers.membership.org_uuid {
|
||||||
|
err!("Organization not found", "Organization id's do not match");
|
||||||
|
}
|
||||||
|
let data: ImportData = data.into_inner();
|
||||||
|
|
||||||
// Validate the import before continuing
|
// Validate the import before continuing
|
||||||
// Bitwarden does not process the import if there is one item invalid.
|
// Bitwarden does not process the import if there is one item invalid.
|
||||||
|
@ -1851,8 +1867,20 @@ async fn post_org_import(
|
||||||
let mut collections: Vec<CollectionId> = Vec::with_capacity(data.collections.len());
|
let mut collections: Vec<CollectionId> = Vec::with_capacity(data.collections.len());
|
||||||
for col in data.collections {
|
for col in data.collections {
|
||||||
let collection_uuid = if existing_collections.contains(&col.id) {
|
let collection_uuid = if existing_collections.contains(&col.id) {
|
||||||
col.id.unwrap()
|
let col_id = col.id.unwrap();
|
||||||
|
// When not an Owner or Admin, check if the member is allowed to access the collection.
|
||||||
|
if headers.membership.atype < MembershipType::Admin
|
||||||
|
&& !Collection::can_access_collection(&headers.membership, &col_id, &mut conn).await
|
||||||
|
{
|
||||||
|
err!(Small, "The current user isn't allowed to manage this collection")
|
||||||
|
}
|
||||||
|
col_id
|
||||||
} else {
|
} else {
|
||||||
|
// We do not allow users or managers which can not manage all collections to create new collections
|
||||||
|
// If there is any collection other than an existing import collection, abort the import.
|
||||||
|
if headers.membership.atype <= MembershipType::Manager && !headers.membership.has_full_access() {
|
||||||
|
err!(Small, "The current user isn't allowed to create new collections")
|
||||||
|
}
|
||||||
let new_collection = Collection::new(org_id.clone(), col.name, col.external_id);
|
let new_collection = Collection::new(org_id.clone(), col.name, col.external_id);
|
||||||
new_collection.save(&mut conn).await?;
|
new_collection.save(&mut conn).await?;
|
||||||
new_collection.uuid
|
new_collection.uuid
|
||||||
|
@ -1875,7 +1903,17 @@ async fn post_org_import(
|
||||||
// Always clear folder_id's via an organization import
|
// Always clear folder_id's via an organization import
|
||||||
cipher_data.folder_id = None;
|
cipher_data.folder_id = None;
|
||||||
let mut cipher = Cipher::new(cipher_data.r#type, cipher_data.name.clone());
|
let mut cipher = Cipher::new(cipher_data.r#type, cipher_data.name.clone());
|
||||||
update_cipher_from_data(&mut cipher, cipher_data, &headers, None, &mut conn, &nt, UpdateType::None).await.ok();
|
update_cipher_from_data(
|
||||||
|
&mut cipher,
|
||||||
|
cipher_data,
|
||||||
|
&headers,
|
||||||
|
Some(collections.clone()),
|
||||||
|
&mut conn,
|
||||||
|
&nt,
|
||||||
|
UpdateType::None,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.ok();
|
||||||
ciphers.push(cipher.uuid);
|
ciphers.push(cipher.uuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2420,6 +2458,9 @@ async fn _revoke_member(
|
||||||
headers: &AdminHeaders,
|
headers: &AdminHeaders,
|
||||||
conn: &mut DbConn,
|
conn: &mut DbConn,
|
||||||
) -> EmptyResult {
|
) -> EmptyResult {
|
||||||
|
if org_id != &headers.org_id {
|
||||||
|
err!("Organization not found", "Organization id's do not match");
|
||||||
|
}
|
||||||
match Membership::find_by_uuid_and_org(member_id, org_id, conn).await {
|
match Membership::find_by_uuid_and_org(member_id, org_id, conn).await {
|
||||||
Some(mut member) if member.status > MembershipStatus::Revoked as i32 => {
|
Some(mut member) if member.status > MembershipStatus::Revoked as i32 => {
|
||||||
if member.user_uuid == headers.user.uuid {
|
if member.user_uuid == headers.user.uuid {
|
||||||
|
@ -2527,6 +2568,9 @@ async fn _restore_member(
|
||||||
headers: &AdminHeaders,
|
headers: &AdminHeaders,
|
||||||
conn: &mut DbConn,
|
conn: &mut DbConn,
|
||||||
) -> EmptyResult {
|
) -> EmptyResult {
|
||||||
|
if org_id != &headers.org_id {
|
||||||
|
err!("Organization not found", "Organization id's do not match");
|
||||||
|
}
|
||||||
match Membership::find_by_uuid_and_org(member_id, org_id, conn).await {
|
match Membership::find_by_uuid_and_org(member_id, org_id, conn).await {
|
||||||
Some(mut member) if member.status < MembershipStatus::Accepted as i32 => {
|
Some(mut member) if member.status < MembershipStatus::Accepted as i32 => {
|
||||||
if member.user_uuid == headers.user.uuid {
|
if member.user_uuid == headers.user.uuid {
|
||||||
|
@ -2679,6 +2723,9 @@ async fn post_groups(
|
||||||
data: Json<GroupRequest>,
|
data: Json<GroupRequest>,
|
||||||
mut conn: DbConn,
|
mut conn: DbConn,
|
||||||
) -> JsonResult {
|
) -> JsonResult {
|
||||||
|
if org_id != headers.org_id {
|
||||||
|
err!("Organization not found", "Organization id's do not match");
|
||||||
|
}
|
||||||
if !CONFIG.org_groups_enabled() {
|
if !CONFIG.org_groups_enabled() {
|
||||||
err!("Group support is disabled");
|
err!("Group support is disabled");
|
||||||
}
|
}
|
||||||
|
@ -2708,6 +2755,9 @@ async fn put_group(
|
||||||
headers: AdminHeaders,
|
headers: AdminHeaders,
|
||||||
mut conn: DbConn,
|
mut conn: DbConn,
|
||||||
) -> JsonResult {
|
) -> JsonResult {
|
||||||
|
if org_id != headers.org_id {
|
||||||
|
err!("Organization not found", "Organization id's do not match");
|
||||||
|
}
|
||||||
if !CONFIG.org_groups_enabled() {
|
if !CONFIG.org_groups_enabled() {
|
||||||
err!("Group support is disabled");
|
err!("Group support is disabled");
|
||||||
}
|
}
|
||||||
|
@ -2824,6 +2874,9 @@ async fn _delete_group(
|
||||||
headers: &AdminHeaders,
|
headers: &AdminHeaders,
|
||||||
conn: &mut DbConn,
|
conn: &mut DbConn,
|
||||||
) -> EmptyResult {
|
) -> EmptyResult {
|
||||||
|
if org_id != &headers.org_id {
|
||||||
|
err!("Organization not found", "Organization id's do not match");
|
||||||
|
}
|
||||||
if !CONFIG.org_groups_enabled() {
|
if !CONFIG.org_groups_enabled() {
|
||||||
err!("Group support is disabled");
|
err!("Group support is disabled");
|
||||||
}
|
}
|
||||||
|
@ -2853,6 +2906,9 @@ async fn bulk_delete_groups(
|
||||||
headers: AdminHeaders,
|
headers: AdminHeaders,
|
||||||
mut conn: DbConn,
|
mut conn: DbConn,
|
||||||
) -> EmptyResult {
|
) -> EmptyResult {
|
||||||
|
if org_id != headers.org_id {
|
||||||
|
err!("Organization not found", "Organization id's do not match");
|
||||||
|
}
|
||||||
if !CONFIG.org_groups_enabled() {
|
if !CONFIG.org_groups_enabled() {
|
||||||
err!("Group support is disabled");
|
err!("Group support is disabled");
|
||||||
}
|
}
|
||||||
|
@ -2916,6 +2972,9 @@ async fn put_group_members(
|
||||||
data: Json<Vec<MembershipId>>,
|
data: Json<Vec<MembershipId>>,
|
||||||
mut conn: DbConn,
|
mut conn: DbConn,
|
||||||
) -> EmptyResult {
|
) -> EmptyResult {
|
||||||
|
if org_id != headers.org_id {
|
||||||
|
err!("Organization not found", "Organization id's do not match");
|
||||||
|
}
|
||||||
if !CONFIG.org_groups_enabled() {
|
if !CONFIG.org_groups_enabled() {
|
||||||
err!("Group support is disabled");
|
err!("Group support is disabled");
|
||||||
}
|
}
|
||||||
|
@ -3100,7 +3159,7 @@ async fn get_organization_public_key(
|
||||||
headers: OrgMemberHeaders,
|
headers: OrgMemberHeaders,
|
||||||
mut conn: DbConn,
|
mut conn: DbConn,
|
||||||
) -> JsonResult {
|
) -> JsonResult {
|
||||||
if org_id != headers.org_id {
|
if org_id != headers.membership.org_uuid {
|
||||||
err!("Organization not found", "Organization id's do not match");
|
err!("Organization not found", "Organization id's do not match");
|
||||||
}
|
}
|
||||||
let Some(org) = Organization::find_by_uuid(&org_id, &mut conn).await else {
|
let Some(org) = Organization::find_by_uuid(&org_id, &mut conn).await else {
|
||||||
|
@ -3324,6 +3383,9 @@ async fn _api_key(
|
||||||
headers: AdminHeaders,
|
headers: AdminHeaders,
|
||||||
mut conn: DbConn,
|
mut conn: DbConn,
|
||||||
) -> JsonResult {
|
) -> JsonResult {
|
||||||
|
if org_id != &headers.org_id {
|
||||||
|
err!("Organization not found", "Organization id's do not match");
|
||||||
|
}
|
||||||
let data: PasswordOrOtpData = data.into_inner();
|
let data: PasswordOrOtpData = data.into_inner();
|
||||||
let user = headers.user;
|
let user = headers.user;
|
||||||
|
|
||||||
|
|
30
src/auth.rs
30
src/auth.rs
|
@ -694,17 +694,6 @@ impl<'r> FromRequest<'r> for AdminHeaders {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<AdminHeaders> for Headers {
|
|
||||||
fn from(h: AdminHeaders) -> Headers {
|
|
||||||
Headers {
|
|
||||||
host: h.host,
|
|
||||||
device: h.device,
|
|
||||||
user: h.user,
|
|
||||||
ip: h.ip,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// col_id is usually the fourth path param ("/organizations/<org_id>/collections/<col_id>"),
|
// col_id is usually the fourth path param ("/organizations/<org_id>/collections/<col_id>"),
|
||||||
// but there could be cases where it is a query value.
|
// but there could be cases where it is a query value.
|
||||||
// First check the path, if this is not a valid uuid, try the query values.
|
// First check the path, if this is not a valid uuid, try the query values.
|
||||||
|
@ -874,8 +863,10 @@ impl<'r> FromRequest<'r> for OwnerHeaders {
|
||||||
|
|
||||||
pub struct OrgMemberHeaders {
|
pub struct OrgMemberHeaders {
|
||||||
pub host: String,
|
pub host: String,
|
||||||
|
pub device: Device,
|
||||||
pub user: User,
|
pub user: User,
|
||||||
pub org_id: OrganizationId,
|
pub membership: Membership,
|
||||||
|
pub ip: ClientIp,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rocket::async_trait]
|
#[rocket::async_trait]
|
||||||
|
@ -887,8 +878,10 @@ impl<'r> FromRequest<'r> for OrgMemberHeaders {
|
||||||
if headers.is_member() {
|
if headers.is_member() {
|
||||||
Outcome::Success(Self {
|
Outcome::Success(Self {
|
||||||
host: headers.host,
|
host: headers.host,
|
||||||
|
device: headers.device,
|
||||||
user: headers.user,
|
user: headers.user,
|
||||||
org_id: headers.membership.org_uuid,
|
membership: headers.membership,
|
||||||
|
ip: headers.ip,
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
err_handler!("You need to be a Member of the Organization to call this endpoint")
|
err_handler!("You need to be a Member of the Organization to call this endpoint")
|
||||||
|
@ -896,6 +889,17 @@ impl<'r> FromRequest<'r> for OrgMemberHeaders {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<OrgMemberHeaders> for Headers {
|
||||||
|
fn from(h: OrgMemberHeaders) -> Headers {
|
||||||
|
Headers {
|
||||||
|
host: h.host,
|
||||||
|
device: h.device,
|
||||||
|
user: h.user,
|
||||||
|
ip: h.ip,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Client IP address detection
|
// Client IP address detection
|
||||||
//
|
//
|
||||||
|
|
28
src/error.rs
28
src/error.rs
|
@ -59,6 +59,8 @@ use yubico::yubicoerror::YubicoError as YubiErr;
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
pub struct Empty {}
|
pub struct Empty {}
|
||||||
|
|
||||||
|
pub struct Small {}
|
||||||
|
|
||||||
// Error struct
|
// Error struct
|
||||||
// Contains a String error message, meant for the user and an enum variant, with an error of different types.
|
// Contains a String error message, meant for the user and an enum variant, with an error of different types.
|
||||||
//
|
//
|
||||||
|
@ -69,6 +71,7 @@ make_error! {
|
||||||
Empty(Empty): _no_source, _serialize,
|
Empty(Empty): _no_source, _serialize,
|
||||||
// Used to represent err! calls
|
// Used to represent err! calls
|
||||||
Simple(String): _no_source, _api_error,
|
Simple(String): _no_source, _api_error,
|
||||||
|
Small(Small): _no_source, _api_error_small,
|
||||||
|
|
||||||
// Used in our custom http client to handle non-global IPs and blocked domains
|
// Used in our custom http client to handle non-global IPs and blocked domains
|
||||||
CustomHttpClient(CustomHttpClientError): _has_source, _api_error,
|
CustomHttpClient(CustomHttpClientError): _has_source, _api_error,
|
||||||
|
@ -132,6 +135,12 @@ impl Error {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn with_kind(mut self, kind: ErrorKind) -> Self {
|
||||||
|
self.error = kind;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn with_code(mut self, code: u16) -> Self {
|
pub const fn with_code(mut self, code: u16) -> Self {
|
||||||
self.error_code = code;
|
self.error_code = code;
|
||||||
|
@ -200,6 +209,18 @@ fn _api_error(_: &impl std::any::Any, msg: &str) -> String {
|
||||||
_serialize(&json, "")
|
_serialize(&json, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn _api_error_small(_: &impl std::any::Any, msg: &str) -> String {
|
||||||
|
let json = json!({
|
||||||
|
"message": msg,
|
||||||
|
"validationErrors": null,
|
||||||
|
"exceptionMessage": null,
|
||||||
|
"exceptionStackTrace": null,
|
||||||
|
"innerExceptionMessage": null,
|
||||||
|
"object": "error"
|
||||||
|
});
|
||||||
|
_serialize(&json, "")
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Rocket responder impl
|
// Rocket responder impl
|
||||||
//
|
//
|
||||||
|
@ -212,8 +233,7 @@ use rocket::response::{self, Responder, Response};
|
||||||
impl Responder<'_, 'static> for Error {
|
impl Responder<'_, 'static> for Error {
|
||||||
fn respond_to(self, _: &Request<'_>) -> response::Result<'static> {
|
fn respond_to(self, _: &Request<'_>) -> response::Result<'static> {
|
||||||
match self.error {
|
match self.error {
|
||||||
ErrorKind::Empty(_) => {} // Don't print the error in this situation
|
ErrorKind::Empty(_) | ErrorKind::Simple(_) | ErrorKind::Small(_) => {} // Don't print the error in this situation
|
||||||
ErrorKind::Simple(_) => {} // Don't print the error in this situation
|
|
||||||
_ => error!(target: "error", "{self:#?}"),
|
_ => error!(target: "error", "{self:#?}"),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -228,6 +248,10 @@ impl Responder<'_, 'static> for Error {
|
||||||
//
|
//
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! err {
|
macro_rules! err {
|
||||||
|
($kind:ident, $msg:expr) => {{
|
||||||
|
error!("{}", $msg);
|
||||||
|
return Err($crate::error::Error::new($msg, $msg).with_kind($crate::error::ErrorKind::$kind($crate::error::$kind {})));
|
||||||
|
}};
|
||||||
($msg:expr) => {{
|
($msg:expr) => {{
|
||||||
error!("{}", $msg);
|
error!("{}", $msg);
|
||||||
return Err($crate::error::Error::new($msg, $msg));
|
return Err($crate::error::Error::new($msg, $msg));
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue