Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions src/predefinitions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -979,13 +979,27 @@ pub async fn initialize_predefined_configurations(database_pool: &deadpool_postg
default_text_value: Some("^[a-zA-Z0-9._-]+$".to_string()),
..Default::default()
},
InitialConfigurationProperties {
name: "fields.allowedDisplayNameRegex".to_string(),
description: Some("A regular expression that field display names must match in order to be allowed.".to_string()),
value_type: ConfigurationValueType::Text,
default_text_value: Some("^.+$".to_string()),
..Default::default()
},
InitialConfigurationProperties {
name: "fields.maximumNameLength".to_string(),
description: Some("The maximum length of field names in characters. Slashstep Group recommends keeping this value at a reasonable length to maintain performance.".to_string()),
value_type: ConfigurationValueType::Number,
default_number_value: Some(Decimal::from(256 as i64)),
..Default::default()
},
InitialConfigurationProperties {
name: "fields.maximumDescriptionLength".to_string(),
description: Some("The maximum length of field descriptions in characters. Slashstep Group recommends keeping this value at a reasonable length to maintain performance.".to_string()),
value_type: ConfigurationValueType::Number,
default_number_value: Some(Decimal::from(1024 as i64)),
..Default::default()
},
InitialConfigurationProperties {
name: "fields.maximumDisplayNameLength".to_string(),
description: Some("The maximum length of field display names in characters. Slashstep Group recommends keeping this value at a reasonable length to maintain performance.".to_string()),
Expand Down
18 changes: 13 additions & 5 deletions src/routes/actions/{action_id}/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use crate::{
}, action_log_entry::{ActionLogEntry, ActionLogEntryActorType, ActionLogEntryTargetResourceType, InitialActionLogEntryProperties}, app::App, app_authorization::AppAuthorization, http_transaction::HTTPTransaction, server_log_entry::ServerLogEntry, user::User
},
utilities::{reusable_route_handlers::delete_resource, route_handler_utilities::{
AuthenticatedPrincipal, get_action_by_id, get_action_by_name, get_action_log_entry_expiration_timestamp, get_authenticated_principal, get_request_body_without_json_rejection, get_resource_hierarchy, get_uuid_from_string, validate_action_display_name, validate_action_name, validate_resource_display_name_length, validate_resource_name_length, verify_delegate_permissions, verify_principal_permissions
AuthenticatedPrincipal, get_action_by_id, get_action_by_name, get_action_log_entry_expiration_timestamp, get_authenticated_principal, get_request_body_without_json_rejection, get_resource_hierarchy, get_uuid_from_string, validate_field_length, validate_resource_display_name, validate_resource_name, verify_delegate_permissions, verify_principal_permissions
}}
};

Expand Down Expand Up @@ -85,10 +85,18 @@ async fn handle_patch_action_request(

let http_transaction = http_transaction.clone();
let updated_action_properties = get_request_body_without_json_rejection(body, &http_transaction, &state.database_pool).await?;
if let Some(updated_action_name) = &updated_action_properties.name { validate_resource_name_length(updated_action_name, "actions.maximumNameLength", "Action", &http_transaction, &state.database_pool).await?; };
if let Some(updated_action_display_name) = &updated_action_properties.display_name { validate_resource_display_name_length(updated_action_display_name, "actions.maximumDisplayNameLength", "Action", &http_transaction, &state.database_pool).await?; };
if let Some(updated_action_name) = &updated_action_properties.name { validate_action_name(updated_action_name, &http_transaction, &state.database_pool).await?; };
if let Some(updated_action_display_name) = &updated_action_properties.display_name { validate_action_display_name(updated_action_display_name, &http_transaction, &state.database_pool).await?; }
if let Some(updated_action_name) = &updated_action_properties.name {

validate_field_length(updated_action_name, "actions.maximumNameLength", "name", &http_transaction, &state.database_pool).await?;
validate_resource_name(updated_action_name, "actions.allowedNameRegex", "Action", &http_transaction, &state.database_pool).await?;

};
if let Some(updated_action_display_name) = &updated_action_properties.display_name {

validate_field_length(updated_action_display_name, "actions.maximumDisplayNameLength", "name", &http_transaction, &state.database_pool).await?;
validate_resource_display_name(updated_action_display_name, "actions.allowedDisplayNameRegex", "Action", &http_transaction, &state.database_pool).await?;

};
let original_target_action = get_action_by_id(&action_id, &http_transaction, &state.database_pool).await?;
let resource_hierarchy = get_resource_hierarchy(&original_target_action, &AccessPolicyResourceType::Action, &original_target_action.id, &http_transaction, &state.database_pool).await?;
let update_access_policy_action = get_action_by_name("actions.update", &http_transaction, &state.database_pool).await?;
Expand Down
9 changes: 4 additions & 5 deletions src/routes/apps/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,11 @@ use std::sync::Arc;
use argon2::{Argon2, PasswordHasher, password_hash::{SaltString, rand_core::{OsRng, le}}};
use axum::{Extension, Json, Router, extract::{Query, State, rejection::JsonRejection}};
use axum_extra::response::ErasedJson;
use rand::{Rng, RngExt, distr::Alphanumeric};
use rand::{RngExt, distr::Alphanumeric};
use reqwest::StatusCode;
use rust_decimal::prelude::ToPrimitive;
use serde::{Deserialize, Serialize};
use uuid::Uuid;
use crate::{AppState, HTTPError, middleware::{authentication_middleware, http_request_middleware}, resources::{ResourceError, access_policy::{AccessPolicyResourceType, ActionPermissionLevel, ResourceHierarchy}, action_log_entry::{ActionLogEntry, ActionLogEntryActorType, ActionLogEntryTargetResourceType, InitialActionLogEntryProperties}, app::{App, AppClientType, AppParentResourceType, DEFAULT_MAXIMUM_APP_LIST_LIMIT, InitialAppProperties}, app_authorization::AppAuthorization, configuration::Configuration, http_transaction::HTTPTransaction, server_log_entry::ServerLogEntry, user::User}, utilities::{reusable_route_handlers::{ResourceListQueryParameters, list_resources}, route_handler_utilities::{AuthenticatedPrincipal, get_action_by_id, get_action_by_name, get_action_log_entry_expiration_timestamp, get_authenticated_principal, get_configuration_by_name, get_request_body_without_json_rejection, validate_resource_display_name_length, validate_resource_name_length, verify_delegate_permissions, verify_principal_permissions}}};
use crate::{AppState, HTTPError, middleware::{authentication_middleware, http_request_middleware}, resources::{access_policy::{AccessPolicyResourceType, ActionPermissionLevel, ResourceHierarchy}, action_log_entry::{ActionLogEntry, ActionLogEntryActorType, ActionLogEntryTargetResourceType, InitialActionLogEntryProperties}, app::{App, AppClientType, AppParentResourceType, DEFAULT_MAXIMUM_APP_LIST_LIMIT, InitialAppProperties}, app_authorization::AppAuthorization, http_transaction::HTTPTransaction, server_log_entry::ServerLogEntry, user::User}, utilities::{reusable_route_handlers::{ResourceListQueryParameters, list_resources}, route_handler_utilities::{AuthenticatedPrincipal, get_action_by_name, get_action_log_entry_expiration_timestamp, get_authenticated_principal, get_configuration_by_name, get_request_body_without_json_rejection, validate_field_length, verify_delegate_permissions, verify_principal_permissions}}};

#[derive(Debug, Serialize, Deserialize, Default)]
pub struct InitialAppPropertiesWithoutClientSecretHash {
Expand Down Expand Up @@ -189,9 +188,9 @@ async fn handle_create_app_request(
let http_transaction = http_transaction.clone();
let app_properties_json = get_request_body_without_json_rejection(body, &http_transaction, &state.database_pool).await?;
validate_app_name(&app_properties_json.name, &http_transaction, &state.database_pool).await?;
validate_resource_name_length(&app_properties_json.name, "apps.maximumNameLength", "App", &http_transaction, &state.database_pool).await?;
validate_field_length(&app_properties_json.name, "apps.maximumNameLength", "name", &http_transaction, &state.database_pool).await?;
validate_app_display_name(&app_properties_json.display_name, &http_transaction, &state.database_pool).await?;
validate_resource_display_name_length(&app_properties_json.display_name, "apps.maximumDisplayNameLength", "App", &http_transaction, &state.database_pool).await?;
validate_field_length(&app_properties_json.display_name, "apps.maximumDisplayNameLength", "display_name", &http_transaction, &state.database_pool).await?;

// Make sure the authenticated_user can create apps for the target action log entry.
let resource_hierarchy: ResourceHierarchy = vec![(AccessPolicyResourceType::Server, None)];
Expand Down
24 changes: 12 additions & 12 deletions src/routes/apps/{app_id}/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use crate::{
resources::{
access_policy::{AccessPolicyResourceType, ActionPermissionLevel}, action_log_entry::{ActionLogEntry, ActionLogEntryActorType, ActionLogEntryTargetResourceType, InitialActionLogEntryProperties}, app::{App, EditableAppProperties}, app_authorization::AppAuthorization, http_transaction::HTTPTransaction, server_log_entry::ServerLogEntry, user::User
},
utilities::{reusable_route_handlers::delete_resource, route_handler_utilities::{AuthenticatedPrincipal, get_action_by_name, get_action_log_entry_expiration_timestamp, get_app_by_id, get_authenticated_principal, get_request_body_without_json_rejection, get_resource_hierarchy, get_uuid_from_string, validate_resource_display_name_length, validate_resource_name_length, verify_delegate_permissions, verify_principal_permissions}}
utilities::{reusable_route_handlers::delete_resource, route_handler_utilities::{AuthenticatedPrincipal, get_action_by_name, get_action_log_entry_expiration_timestamp, get_app_by_id, get_authenticated_principal, get_request_body_without_json_rejection, get_resource_hierarchy, get_uuid_from_string, validate_field_length, verify_delegate_permissions, verify_principal_permissions}}
};

#[path = "./access-policies/mod.rs"]
Expand Down Expand Up @@ -119,12 +119,12 @@ async fn handle_patch_app_request(
let updated_app_properties = get_request_body_without_json_rejection(body, &http_transaction, &state.database_pool).await?;
if let Some(updated_app_name) = &updated_app_properties.name {

validate_resource_name_length(updated_app_name, "apps.maximumNameLength", "App", &http_transaction, &state.database_pool).await?;
validate_field_length(updated_app_name, "apps.maximumNameLength", "name", &http_transaction, &state.database_pool).await?;

};
if let Some(updated_app_display_name) = &updated_app_properties.display_name {

validate_resource_display_name_length(updated_app_display_name, "apps.maximumDisplayNameLength", "App", &http_transaction, &state.database_pool).await?;
validate_field_length(updated_app_display_name, "apps.maximumDisplayNameLength", "display_name", &http_transaction, &state.database_pool).await?;

};

Expand All @@ -136,9 +136,9 @@ async fn handle_patch_app_request(
verify_principal_permissions(&authenticated_principal, &update_access_policy_action, &resource_hierarchy, &http_transaction, &ActionPermissionLevel::User, &state.database_pool).await?;

ServerLogEntry::trace(&format!("Updating authenticated_app {}...", original_target_app.id), Some(&http_transaction.id), &state.database_pool).await.ok();
let updated_target_action = match original_target_app.update(&updated_app_properties, &state.database_pool).await {
let updated_target_app = match original_target_app.update(&updated_app_properties, &state.database_pool).await {

Ok(updated_target_action) => updated_target_action,
Ok(updated_target_app) => updated_target_app,

Err(error) => {

Expand All @@ -158,22 +158,22 @@ async fn handle_patch_app_request(
actor_type: if let AuthenticatedPrincipal::User(_) = &authenticated_principal { ActionLogEntryActorType::User } else { ActionLogEntryActorType::App },
actor_user_id: if let AuthenticatedPrincipal::User(authenticated_user) = &authenticated_principal { Some(authenticated_user.id.clone()) } else { None },
actor_app_id: if let AuthenticatedPrincipal::App(authenticated_app) = &authenticated_principal { Some(authenticated_app.id.clone()) } else { None },
target_resource_type: ActionLogEntryTargetResourceType::Action,
target_action_id: Some(updated_target_action.id),
target_resource_type: ActionLogEntryTargetResourceType::App,
target_app_id: Some(updated_target_app.id),
..Default::default()
}, &state.database_pool).await.ok();
ServerLogEntry::success(&format!("Successfully updated action {}.", updated_target_action.id), Some(&http_transaction.id), &state.database_pool).await.ok();
ServerLogEntry::success(&format!("Successfully updated app {}.", updated_target_app.id), Some(&http_transaction.id), &state.database_pool).await.ok();

return Ok(Json(updated_target_action));
return Ok(Json(updated_target_app));

}

pub fn get_router(state: AppState) -> Router<AppState> {

let router = Router::<AppState>::new()
.route("/apps/{action_id}", axum::routing::get(handle_get_app_request))
.route("/apps/{action_id}", axum::routing::delete(handle_delete_app_request))
.route("/apps/{action_id}", axum::routing::patch(handle_patch_app_request))
.route("/apps/{app_id}", axum::routing::get(handle_get_app_request))
.route("/apps/{app_id}", axum::routing::delete(handle_delete_app_request))
.route("/apps/{app_id}", axum::routing::patch(handle_patch_app_request))
.layer(axum::middleware::from_fn_with_state(state.clone(), authentication_middleware::authenticate_user))
.layer(axum::middleware::from_fn_with_state(state.clone(), authentication_middleware::authenticate_app))
.layer(axum::middleware::from_fn_with_state(state.clone(), http_request_middleware::create_http_request))
Expand Down
10 changes: 6 additions & 4 deletions src/routes/fields/{field_id}/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ use crate::{
resources::{
access_policy::{AccessPolicyResourceType, ActionPermissionLevel}, action_log_entry::{ActionLogEntry, ActionLogEntryActorType, ActionLogEntryTargetResourceType, InitialActionLogEntryProperties}, app::App, app_authorization::AppAuthorization, field::{EditableFieldProperties, Field}, http_transaction::HTTPTransaction, server_log_entry::ServerLogEntry, user::User
},
utilities::{reusable_route_handlers::delete_resource, route_handler_utilities::{AuthenticatedPrincipal, get_action_by_name, get_action_log_entry_expiration_timestamp, get_authenticated_principal, get_field_by_id, get_request_body_without_json_rejection, get_resource_hierarchy, get_uuid_from_string, validate_field_name, validate_resource_display_name_length, validate_resource_name_length, verify_delegate_permissions, verify_principal_permissions}}
utilities::{reusable_route_handlers::delete_resource, route_handler_utilities::{AuthenticatedPrincipal, get_action_by_name, get_action_log_entry_expiration_timestamp, get_authenticated_principal, get_field_by_id, get_request_body_without_json_rejection, get_resource_hierarchy, get_uuid_from_string, validate_field_length, validate_resource_display_name, validate_resource_name, verify_delegate_permissions, verify_principal_permissions}}
};

/// GET /fields/{field_id}
Expand Down Expand Up @@ -119,15 +119,17 @@ async fn handle_patch_field_request(
let updated_field_properties = get_request_body_without_json_rejection(body, &http_transaction, &state.database_pool).await?;
if let Some(field_name) = &updated_field_properties.name {

validate_field_name(field_name, &http_transaction, &state.database_pool).await?;
validate_resource_name_length(field_name, "fields.maximumNameLength", "Field", &http_transaction, &state.database_pool).await?;
validate_field_length(field_name, "fields.maximumNameLength", "name", &http_transaction, &state.database_pool).await?;
validate_resource_name(field_name, "fields.allowedNameRegex", "Field", &http_transaction, &state.database_pool).await?;

};
if let Some(field_display_name) = &updated_field_properties.display_name {

validate_resource_display_name_length(field_display_name, "fields.maximumDisplayNameLength", "Field", &http_transaction, &state.database_pool).await?;
validate_field_length(field_display_name, "fields.maximumDisplayNameLength", "display_name", &http_transaction, &state.database_pool).await?;
validate_resource_display_name(field_display_name, "fields.allowedDisplayNameRegex", "Field", &http_transaction, &state.database_pool).await?;

};
if let Some(field_description) = &updated_field_properties.description { validate_field_length(field_description, "fields.maximumDescriptionLength", "description", &http_transaction, &state.database_pool).await?; };
let field_id = get_uuid_from_string(&field_id, "field", &http_transaction, &state.database_pool).await?;
let original_target_field = get_field_by_id(&field_id, &http_transaction, &state.database_pool).await?;
let resource_hierarchy = get_resource_hierarchy(&original_target_field, &AccessPolicyResourceType::Field, &original_target_field.id, &http_transaction, &state.database_pool).await?;
Expand Down
4 changes: 2 additions & 2 deletions src/routes/fields/{field_id}/tests.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/**
*
* Any test cases for /fields/{app_id} should be handled here.
* Any test cases for /fields/{field_id} should be handled here.
*
* Programmers:
* - Christian Toney (https://christiantoney.com)
Expand All @@ -23,7 +23,7 @@ use crate::{
}, resources::{
ResourceError, access_policy::{
AccessPolicy, AccessPolicyPrincipalType, AccessPolicyResourceType, ActionPermissionLevel, InitialAccessPolicyProperties
}, app::App, configuration::{Configuration, EditableConfigurationProperties}, field::{EditableFieldProperties, Field, InitialFieldProperties}
}, app::App, configuration::{Configuration, EditableConfigurationProperties}, field::{EditableFieldProperties, Field}
}, tests::{TestEnvironment, TestSlashstepServerError}
};

Expand Down
Loading