From 7999239ccfd7cdcccdb23c877bd18de06491b1bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Espino=20Garc=C3=ADa?= Date: Thu, 27 Mar 2025 13:13:20 +0100 Subject: [PATCH] Add system console settings for mobile security (#30456) * Add config settings for additional security features on mobile * Add system console settings for mobile security * Update svg and link * Fix strings * Add test for the discovery feature * Fix tests * Add permission migrations * Add relevant e2e tests * Fix key alignment * fix tests * Fix lint * Mock new migration * Fix playwright prettier * Add new section to delegated permissions * Update snapshots * Fix flakyness in playwright test --------- Co-authored-by: Elias Nahum Co-authored-by: Mattermost Build --- e2e-tests/cypress/tests/support/api/role.js | 6 +- .../playwright/support/ui/components/index.ts | 4 + .../system_users/feature_discovery.ts | 25 + .../sections/system_users/mobile_security.ts | 81 + .../support/ui/pages/system_console.ts | 8 + .../system_console/mobile_security.spec.ts | 126 ++ server/channels/app/permissions_migrations.go | 20 + server/channels/testlib/store.go | 1 + server/public/model/migration.go | 1 + server/public/model/permission.go | 17 + .../schema_admin_settings.test.tsx.snap | 1 + .../admin_console/admin_definition.tsx | 56 + .../__snapshots__/admin_sidebar.test.tsx.snap | 2011 +++++++++++++++++ .../admin_sidebar/admin_sidebar.test.tsx | 128 ++ .../custom_plugin_settings.test.tsx.snap | 3 + .../feature_discovery/feature_discovery.tsx | 5 +- .../features/images/mobile_security_svg.tsx | 360 +++ .../feature_discovery/features/index.ts | 2 + .../features/mobile_security.test.tsx | 68 + .../features/mobile_security.tsx | 36 + .../admin_console/schema_admin_settings.tsx | 5 +- .../system_role_permissions.test.tsx.snap | 3 + .../system_roles/system_role/strings.tsx | 6 + .../system_role/system_role_permissions.tsx | 1 + .../product_menu_list.test.tsx.snap | 3 + webapp/channels/src/i18n/en.json | 11 + .../src/constants/permissions.ts | 4 + .../src/constants/permissions_sysconsole.ts | 2 + .../src/sass/routes/_admin-console.scss | 1 + 29 files changed, 2990 insertions(+), 5 deletions(-) create mode 100644 e2e-tests/playwright/support/ui/components/system_console/sections/system_users/feature_discovery.ts create mode 100644 e2e-tests/playwright/support/ui/components/system_console/sections/system_users/mobile_security.ts create mode 100644 e2e-tests/playwright/tests/functional/system_console/mobile_security.spec.ts create mode 100644 webapp/channels/src/components/admin_console/feature_discovery/features/images/mobile_security_svg.tsx create mode 100644 webapp/channels/src/components/admin_console/feature_discovery/features/mobile_security.test.tsx create mode 100644 webapp/channels/src/components/admin_console/feature_discovery/features/mobile_security.tsx diff --git a/e2e-tests/cypress/tests/support/api/role.js b/e2e-tests/cypress/tests/support/api/role.js index 9d6e047a99c..4180581d36f 100644 --- a/e2e-tests/cypress/tests/support/api/role.js +++ b/e2e-tests/cypress/tests/support/api/role.js @@ -17,13 +17,13 @@ export const defaultRolesPermissions = { playbook_member: 'playbook_public_view playbook_public_manage_members playbook_public_manage_properties playbook_private_view playbook_private_manage_members playbook_private_manage_properties run_create', run_admin: 'run_manage_properties run_manage_members', run_member: 'run_view', - system_admin: 'sysconsole_write_environment_elasticsearch playbook_public_manage_properties sysconsole_write_authentication_ldap run_view manage_jobs manage_roles playbook_public_create manage_public_channel_properties sysconsole_read_plugins delete_post purge_elasticsearch_indexes sysconsole_read_integrations_bot_accounts read_data_retention_job manage_private_channel_members create_elasticsearch_post_indexing_job manage_elasticsearch_post_indexing_job sysconsole_read_authentication_guest_access create_elasticsearch_post_aggregation_job manage_elasticsearch_post_aggregation_job join_public_teams sysconsole_read_site_public_links add_saml_idp_cert sysconsole_write_site_announcement_banner sysconsole_write_site_notices sysconsole_read_experimental_feature_flags sysconsole_read_site_users_and_teams manage_slash_commands sysconsole_read_authentication_ldap read_channel read_channel_content sysconsole_write_authentication_password list_users_without_team sysconsole_read_authentication_email add_saml_public_cert playbook_private_create promote_guest sysconsole_read_user_management_system_roles manage_public_channel_members create_data_retention_job manage_data_retention_job add_saml_private_cert sysconsole_write_user_management_users sysconsole_read_compliance_compliance_monitoring playbook_public_manage_members sysconsole_write_environment_database sysconsole_write_user_management_teams playbook_private_manage_roles read_public_channel sysconsole_write_plugins sysconsole_read_authentication_openid sysconsole_write_user_management_groups sysconsole_write_site_file_sharing_and_downloads playbook_private_manage_properties sysconsole_read_site_customization join_public_channels add_user_to_team restore_custom_group download_compliance_export_result sysconsole_write_user_management_system_roles sysconsole_write_environment_session_lengths create_custom_group manage_private_channel_properties create_post_public remove_ldap_private_cert sysconsole_write_site_public_links import_team sysconsole_read_environment_developer sysconsole_read_environment_database sysconsole_read_environment_web_server use_channel_mentions view_team remove_others_reactions sysconsole_read_environment_session_lengths sysconsole_write_integrations_bot_accounts playbook_public_view use_group_mentions sysconsole_write_environment_web_server add_ldap_private_cert read_public_channel_groups invite_guest sysconsole_read_environment_smtp create_post sysconsole_read_about_edition_and_license sysconsole_read_authentication_signup sysconsole_read_authentication_saml sysconsole_read_environment_file_storage sysconsole_write_experimental_feature_flags sysconsole_write_site_localization sysconsole_write_environment_rate_limiting sysconsole_read_environment_rate_limiting sysconsole_read_products_boards get_saml_cert_status sysconsole_read_environment_high_availability manage_secure_connections read_compliance_export_job sysconsole_write_compliance_custom_terms_of_service read_user_access_token edit_post sysconsole_write_environment_logging sysconsole_read_environment_push_notification_server sysconsole_write_site_customization read_other_users_teams read_elasticsearch_post_aggregation_job sysconsole_write_compliance_data_retention_policy sysconsole_read_user_management_permissions sysconsole_read_site_emoji sysconsole_read_compliance_data_retention_policy read_license_information sysconsole_read_experimental_features read_deleted_posts sysconsole_read_environment_logging sysconsole_read_reporting_site_statistics test_elasticsearch sysconsole_read_site_posts add_reaction sysconsole_write_authentication_signup manage_outgoing_webhooks create_post_ephemeral sysconsole_read_environment_image_proxy invite_user manage_others_outgoing_webhooks create_user_access_token sysconsole_write_environment_image_proxy sysconsole_write_products_boards read_elasticsearch_post_indexing_job purge_bleve_indexes sysconsole_write_environment_performance_monitoring sysconsole_write_authentication_guest_access sysconsole_read_compliance_custom_terms_of_service edit_others_posts sysconsole_write_billing get_saml_metadata_from_idp sysconsole_write_authentication_saml create_post_bleve_indexes_job manage_post_bleve_indexes_job invalidate_caches sysconsole_write_experimental_bleve view_members manage_others_bots run_create join_private_teams convert_private_channel_to_public read_audits assign_bot read_jobs remove_user_from_team revoke_user_access_token manage_team sysconsole_read_reporting_server_logs get_public_link manage_others_slash_commands manage_system delete_public_channel read_private_channel_groups sysconsole_read_authentication_mfa delete_emojis list_private_teams create_emojis sysconsole_read_billing sysconsole_write_site_emoji invalidate_email_invite sysconsole_write_environment_file_storage sysconsole_write_compliance_compliance_monitoring remove_saml_public_cert sysconsole_read_compliance_compliance_export sysconsole_read_site_localization manage_team_roles list_public_teams get_logs sysconsole_write_integrations_integration_management sysconsole_read_integrations_cors manage_oauth manage_outgoing_oauth_connections delete_others_emojis sysconsole_write_integrations_gif manage_incoming_webhooks sysconsole_write_authentication_email create_private_channel playbook_private_make_public manage_bots add_ldap_public_cert remove_ldap_public_cert sysconsole_write_site_notifications sysconsole_write_environment_developer playbook_private_manage_members sysconsole_read_user_management_teams edit_custom_group remove_reaction playbook_public_manage_roles sysconsole_write_reporting_server_logs read_others_bots sysconsole_write_site_posts sysconsole_read_site_notifications sysconsole_read_authentication_password playbook_private_view manage_system_wide_oauth get_analytics list_team_channels sysconsole_write_user_management_channels delete_private_channel manage_custom_group_members test_s3 create_ldap_sync_job manage_ldap_sync_job sysconsole_read_integrations_integration_management test_site_url recycle_database_connections sysconsole_read_site_announcement_banner test_email manage_shared_channels read_bots sysconsole_write_environment_smtp sysconsole_read_experimental_bleve sysconsole_write_environment_push_notification_server sysconsole_write_user_management_permissions sysconsole_read_environment_elasticsearch sysconsole_write_reporting_site_statistics sysconsole_write_site_users_and_teams demote_to_guest create_team test_ldap remove_saml_idp_cert delete_others_posts edit_other_users sysconsole_write_reporting_team_statistics sysconsole_read_integrations_gif sysconsole_read_site_notices sysconsole_write_about_edition_and_license manage_others_incoming_webhooks run_manage_members create_bot sysconsole_write_authentication_mfa sysconsole_read_user_management_users assign_system_admin_role sysconsole_write_experimental_features edit_brand create_group_channel sysconsole_write_authentication_openid create_direct_channel manage_license_information reload_config manage_channel_roles sysconsole_read_user_management_groups create_compliance_export_job manage_compliance_export_job read_ldap_sync_job upload_file sysconsole_read_site_file_sharing_and_downloads delete_custom_group sysconsole_read_user_management_channels sysconsole_write_compliance_compliance_export remove_saml_private_cert sysconsole_read_environment_performance_monitoring create_public_channel sysconsole_write_integrations_cors sysconsole_write_environment_high_availability playbook_public_make_private run_manage_properties sysconsole_read_reporting_team_statistics convert_public_channel_to_private add_bookmark_public_channel edit_bookmark_public_channel delete_bookmark_public_channel order_bookmark_public_channel add_bookmark_private_channel edit_bookmark_private_channel delete_bookmark_private_channel order_bookmark_private_channel', + system_admin: 'sysconsole_write_environment_elasticsearch playbook_public_manage_properties sysconsole_write_authentication_ldap run_view manage_jobs manage_roles playbook_public_create manage_public_channel_properties sysconsole_read_plugins delete_post purge_elasticsearch_indexes sysconsole_read_integrations_bot_accounts read_data_retention_job manage_private_channel_members create_elasticsearch_post_indexing_job manage_elasticsearch_post_indexing_job sysconsole_read_authentication_guest_access create_elasticsearch_post_aggregation_job manage_elasticsearch_post_aggregation_job join_public_teams sysconsole_read_site_public_links add_saml_idp_cert sysconsole_write_site_announcement_banner sysconsole_write_site_notices sysconsole_read_experimental_feature_flags sysconsole_read_site_users_and_teams manage_slash_commands sysconsole_read_authentication_ldap read_channel read_channel_content sysconsole_write_authentication_password list_users_without_team sysconsole_read_authentication_email add_saml_public_cert playbook_private_create promote_guest sysconsole_read_user_management_system_roles manage_public_channel_members create_data_retention_job manage_data_retention_job add_saml_private_cert sysconsole_write_user_management_users sysconsole_read_compliance_compliance_monitoring playbook_public_manage_members sysconsole_write_environment_database sysconsole_write_user_management_teams playbook_private_manage_roles read_public_channel sysconsole_write_plugins sysconsole_read_authentication_openid sysconsole_write_user_management_groups sysconsole_write_site_file_sharing_and_downloads playbook_private_manage_properties sysconsole_read_site_customization join_public_channels add_user_to_team restore_custom_group download_compliance_export_result sysconsole_write_user_management_system_roles sysconsole_write_environment_session_lengths create_custom_group manage_private_channel_properties create_post_public remove_ldap_private_cert sysconsole_write_site_public_links import_team sysconsole_read_environment_developer sysconsole_read_environment_database sysconsole_read_environment_web_server sysconsole_read_environment_mobile_security sysconsole_write_environment_mobile_security use_channel_mentions view_team remove_others_reactions sysconsole_read_environment_session_lengths sysconsole_write_integrations_bot_accounts playbook_public_view use_group_mentions sysconsole_write_environment_web_server add_ldap_private_cert read_public_channel_groups invite_guest sysconsole_read_environment_smtp create_post sysconsole_read_about_edition_and_license sysconsole_read_authentication_signup sysconsole_read_authentication_saml sysconsole_read_environment_file_storage sysconsole_write_experimental_feature_flags sysconsole_write_site_localization sysconsole_write_environment_rate_limiting sysconsole_read_environment_rate_limiting sysconsole_read_products_boards get_saml_cert_status sysconsole_read_environment_high_availability manage_secure_connections read_compliance_export_job sysconsole_write_compliance_custom_terms_of_service read_user_access_token edit_post sysconsole_write_environment_logging sysconsole_read_environment_push_notification_server sysconsole_write_site_customization read_other_users_teams read_elasticsearch_post_aggregation_job sysconsole_write_compliance_data_retention_policy sysconsole_read_user_management_permissions sysconsole_read_site_emoji sysconsole_read_compliance_data_retention_policy read_license_information sysconsole_read_experimental_features read_deleted_posts sysconsole_read_environment_logging sysconsole_read_reporting_site_statistics test_elasticsearch sysconsole_read_site_posts add_reaction sysconsole_write_authentication_signup manage_outgoing_webhooks create_post_ephemeral sysconsole_read_environment_image_proxy invite_user manage_others_outgoing_webhooks create_user_access_token sysconsole_write_environment_image_proxy sysconsole_write_products_boards read_elasticsearch_post_indexing_job purge_bleve_indexes sysconsole_write_environment_performance_monitoring sysconsole_write_authentication_guest_access sysconsole_read_compliance_custom_terms_of_service edit_others_posts sysconsole_write_billing get_saml_metadata_from_idp sysconsole_write_authentication_saml create_post_bleve_indexes_job manage_post_bleve_indexes_job invalidate_caches sysconsole_write_experimental_bleve view_members manage_others_bots run_create join_private_teams convert_private_channel_to_public read_audits assign_bot read_jobs remove_user_from_team revoke_user_access_token manage_team sysconsole_read_reporting_server_logs get_public_link manage_others_slash_commands manage_system delete_public_channel read_private_channel_groups sysconsole_read_authentication_mfa delete_emojis list_private_teams create_emojis sysconsole_read_billing sysconsole_write_site_emoji invalidate_email_invite sysconsole_write_environment_file_storage sysconsole_write_compliance_compliance_monitoring remove_saml_public_cert sysconsole_read_compliance_compliance_export sysconsole_read_site_localization manage_team_roles list_public_teams get_logs sysconsole_write_integrations_integration_management sysconsole_read_integrations_cors manage_oauth manage_outgoing_oauth_connections delete_others_emojis sysconsole_write_integrations_gif manage_incoming_webhooks sysconsole_write_authentication_email create_private_channel playbook_private_make_public manage_bots add_ldap_public_cert remove_ldap_public_cert sysconsole_write_site_notifications sysconsole_write_environment_developer playbook_private_manage_members sysconsole_read_user_management_teams edit_custom_group remove_reaction playbook_public_manage_roles sysconsole_write_reporting_server_logs read_others_bots sysconsole_write_site_posts sysconsole_read_site_notifications sysconsole_read_authentication_password playbook_private_view manage_system_wide_oauth get_analytics list_team_channels sysconsole_write_user_management_channels delete_private_channel manage_custom_group_members test_s3 create_ldap_sync_job manage_ldap_sync_job sysconsole_read_integrations_integration_management test_site_url recycle_database_connections sysconsole_read_site_announcement_banner test_email manage_shared_channels read_bots sysconsole_write_environment_smtp sysconsole_read_experimental_bleve sysconsole_write_environment_push_notification_server sysconsole_write_user_management_permissions sysconsole_read_environment_elasticsearch sysconsole_write_reporting_site_statistics sysconsole_write_site_users_and_teams demote_to_guest create_team test_ldap remove_saml_idp_cert delete_others_posts edit_other_users sysconsole_write_reporting_team_statistics sysconsole_read_integrations_gif sysconsole_read_site_notices sysconsole_write_about_edition_and_license manage_others_incoming_webhooks run_manage_members create_bot sysconsole_write_authentication_mfa sysconsole_read_user_management_users assign_system_admin_role sysconsole_write_experimental_features edit_brand create_group_channel sysconsole_write_authentication_openid create_direct_channel manage_license_information reload_config manage_channel_roles sysconsole_read_user_management_groups create_compliance_export_job manage_compliance_export_job read_ldap_sync_job upload_file sysconsole_read_site_file_sharing_and_downloads delete_custom_group sysconsole_read_user_management_channels sysconsole_write_compliance_compliance_export remove_saml_private_cert sysconsole_read_environment_performance_monitoring create_public_channel sysconsole_write_integrations_cors sysconsole_write_environment_high_availability playbook_public_make_private run_manage_properties sysconsole_read_reporting_team_statistics convert_public_channel_to_private add_bookmark_public_channel edit_bookmark_public_channel delete_bookmark_public_channel order_bookmark_public_channel add_bookmark_private_channel edit_bookmark_private_channel delete_bookmark_private_channel order_bookmark_private_channel', system_custom_group_admin: 'create_custom_group edit_custom_group delete_custom_group restore_custom_group manage_custom_group_members', system_guest: 'create_group_channel create_direct_channel', - system_manager: 'sysconsole_read_site_announcement_banner manage_private_channel_properties edit_brand read_private_channel_groups manage_private_channel_members manage_team_roles sysconsole_write_environment_session_lengths sysconsole_read_site_emoji sysconsole_write_environment_developer sysconsole_read_user_management_groups sysconsole_write_user_management_groups sysconsole_write_environment_rate_limiting delete_private_channel sysconsole_read_environment_performance_monitoring sysconsole_read_environment_rate_limiting sysconsole_write_user_management_teams sysconsole_write_integrations_integration_management sysconsole_write_site_public_links sysconsole_read_authentication_ldap sysconsole_write_integrations_cors reload_config sysconsole_write_user_management_channels sysconsole_read_environment_high_availability sysconsole_read_site_users_and_teams sysconsole_read_user_management_teams sysconsole_write_site_users_and_teams sysconsole_read_site_customization sysconsole_write_environment_high_availability sysconsole_read_integrations_bot_accounts sysconsole_read_authentication_guest_access sysconsole_read_site_public_links read_elasticsearch_post_indexing_job sysconsole_read_user_management_channels sysconsole_read_reporting_team_statistics invalidate_caches sysconsole_read_authentication_signup read_elasticsearch_post_aggregation_job sysconsole_write_environment_smtp manage_public_channel_members list_public_teams add_user_to_team sysconsole_read_environment_web_server sysconsole_read_site_localization get_logs sysconsole_write_site_posts sysconsole_write_integrations_bot_accounts sysconsole_write_user_management_permissions sysconsole_read_environment_elasticsearch sysconsole_read_environment_smtp list_private_teams read_public_channel_groups sysconsole_write_environment_file_storage sysconsole_write_integrations_gif manage_public_channel_properties sysconsole_write_environment_performance_monitoring sysconsole_write_site_notifications sysconsole_read_site_notifications sysconsole_read_environment_image_proxy sysconsole_write_site_announcement_banner sysconsole_write_site_emoji test_site_url sysconsole_read_integrations_gif sysconsole_write_environment_logging convert_public_channel_to_private get_analytics sysconsole_read_user_management_permissions sysconsole_write_environment_image_proxy test_elasticsearch recycle_database_connections sysconsole_write_site_localization sysconsole_read_reporting_server_logs create_elasticsearch_post_indexing_job manage_elasticsearch_post_indexing_job sysconsole_read_reporting_site_statistics test_ldap delete_public_channel sysconsole_write_environment_push_notification_server read_license_information sysconsole_write_products_boards sysconsole_read_about_edition_and_license convert_private_channel_to_public sysconsole_read_integrations_integration_management create_elasticsearch_post_aggregation_job manage_elasticsearch_post_aggregation_job purge_elasticsearch_indexes sysconsole_read_environment_database join_public_teams sysconsole_read_authentication_email sysconsole_read_environment_push_notification_server view_team read_channel sysconsole_read_authentication_password read_ldap_sync_job sysconsole_read_integrations_cors sysconsole_read_environment_logging manage_team sysconsole_read_authentication_openid read_public_channel sysconsole_write_environment_elasticsearch sysconsole_read_plugins manage_channel_roles remove_user_from_team test_email sysconsole_write_site_file_sharing_and_downloads test_s3 sysconsole_read_site_file_sharing_and_downloads sysconsole_read_site_notices sysconsole_read_environment_file_storage join_private_teams sysconsole_read_products_boards sysconsole_read_environment_session_lengths sysconsole_write_environment_database sysconsole_read_authentication_saml sysconsole_read_authentication_mfa sysconsole_write_site_notices sysconsole_write_environment_web_server sysconsole_read_site_posts sysconsole_read_environment_developer sysconsole_write_site_customization manage_outgoing_oauth_connections', + system_manager: 'sysconsole_read_site_announcement_banner manage_private_channel_properties edit_brand read_private_channel_groups manage_private_channel_members manage_team_roles sysconsole_write_environment_session_lengths sysconsole_read_site_emoji sysconsole_write_environment_developer sysconsole_read_user_management_groups sysconsole_write_user_management_groups sysconsole_write_environment_rate_limiting delete_private_channel sysconsole_read_environment_performance_monitoring sysconsole_read_environment_rate_limiting sysconsole_write_user_management_teams sysconsole_write_integrations_integration_management sysconsole_write_site_public_links sysconsole_read_authentication_ldap sysconsole_write_integrations_cors reload_config sysconsole_write_user_management_channels sysconsole_read_environment_high_availability sysconsole_read_site_users_and_teams sysconsole_read_user_management_teams sysconsole_write_site_users_and_teams sysconsole_read_site_customization sysconsole_write_environment_high_availability sysconsole_read_integrations_bot_accounts sysconsole_read_authentication_guest_access sysconsole_read_site_public_links read_elasticsearch_post_indexing_job sysconsole_read_user_management_channels sysconsole_read_reporting_team_statistics invalidate_caches sysconsole_read_authentication_signup read_elasticsearch_post_aggregation_job sysconsole_write_environment_smtp manage_public_channel_members list_public_teams add_user_to_team sysconsole_read_environment_web_server sysconsole_read_site_localization get_logs sysconsole_write_site_posts sysconsole_write_integrations_bot_accounts sysconsole_write_user_management_permissions sysconsole_read_environment_elasticsearch sysconsole_read_environment_smtp list_private_teams read_public_channel_groups sysconsole_write_environment_file_storage sysconsole_write_integrations_gif manage_public_channel_properties sysconsole_write_environment_performance_monitoring sysconsole_write_site_notifications sysconsole_read_site_notifications sysconsole_read_environment_image_proxy sysconsole_write_site_announcement_banner sysconsole_write_site_emoji test_site_url sysconsole_read_integrations_gif sysconsole_write_environment_logging convert_public_channel_to_private get_analytics sysconsole_read_user_management_permissions sysconsole_write_environment_image_proxy test_elasticsearch recycle_database_connections sysconsole_write_site_localization sysconsole_read_reporting_server_logs create_elasticsearch_post_indexing_job manage_elasticsearch_post_indexing_job sysconsole_read_reporting_site_statistics test_ldap delete_public_channel sysconsole_write_environment_push_notification_server read_license_information sysconsole_write_products_boards sysconsole_read_about_edition_and_license convert_private_channel_to_public sysconsole_read_integrations_integration_management create_elasticsearch_post_aggregation_job manage_elasticsearch_post_aggregation_job purge_elasticsearch_indexes sysconsole_read_environment_database join_public_teams sysconsole_read_authentication_email sysconsole_read_environment_push_notification_server view_team read_channel sysconsole_read_authentication_password read_ldap_sync_job sysconsole_read_integrations_cors sysconsole_read_environment_logging manage_team sysconsole_read_authentication_openid read_public_channel sysconsole_write_environment_elasticsearch sysconsole_read_plugins manage_channel_roles remove_user_from_team test_email sysconsole_write_site_file_sharing_and_downloads test_s3 sysconsole_read_site_file_sharing_and_downloads sysconsole_read_site_notices sysconsole_read_environment_file_storage join_private_teams sysconsole_read_products_boards sysconsole_read_environment_session_lengths sysconsole_write_environment_database sysconsole_read_authentication_saml sysconsole_read_authentication_mfa sysconsole_write_site_notices sysconsole_write_environment_web_server sysconsole_read_site_posts sysconsole_read_environment_developer sysconsole_write_site_customization sysconsole_read_environment_mobile_security sysconsole_write_environment_mobile_security manage_outgoing_oauth_connections', system_post_all: 'use_group_mentions use_channel_mentions create_post', system_post_all_public: 'use_group_mentions use_channel_mentions create_post_public', - system_read_only_admin: 'sysconsole_read_authentication_guest_access download_compliance_export_result sysconsole_read_compliance_data_retention_policy get_logs sysconsole_read_environment_file_storage read_channel sysconsole_read_integrations_integration_management sysconsole_read_compliance_custom_terms_of_service sysconsole_read_site_notices sysconsole_read_environment_rate_limiting sysconsole_read_about_edition_and_license read_public_channel sysconsole_read_experimental_features test_ldap sysconsole_read_user_management_permissions read_elasticsearch_post_aggregation_job sysconsole_read_environment_image_proxy sysconsole_read_compliance_compliance_export sysconsole_read_integrations_bot_accounts sysconsole_read_authentication_openid sysconsole_read_site_posts sysconsole_read_user_management_users sysconsole_read_experimental_feature_flags sysconsole_read_reporting_team_statistics sysconsole_read_site_localization read_private_channel_groups sysconsole_read_site_file_sharing_and_downloads sysconsole_read_user_management_channels sysconsole_read_authentication_email read_data_retention_job read_audits sysconsole_read_plugins view_team get_analytics sysconsole_read_user_management_groups sysconsole_read_experimental_bleve sysconsole_read_products_boards read_compliance_export_job sysconsole_read_environment_logging sysconsole_read_authentication_signup sysconsole_read_environment_smtp sysconsole_read_environment_session_lengths sysconsole_read_environment_developer sysconsole_read_environment_high_availability read_ldap_sync_job sysconsole_read_environment_performance_monitoring sysconsole_read_authentication_saml read_public_channel_groups sysconsole_read_integrations_gif sysconsole_read_authentication_mfa list_public_teams sysconsole_read_environment_database list_private_teams sysconsole_read_authentication_ldap sysconsole_read_compliance_compliance_monitoring sysconsole_read_site_notifications sysconsole_read_site_announcement_banner read_other_users_teams sysconsole_read_authentication_password sysconsole_read_environment_push_notification_server sysconsole_read_site_users_and_teams sysconsole_read_site_public_links sysconsole_read_site_emoji sysconsole_read_environment_elasticsearch read_license_information sysconsole_read_integrations_cors sysconsole_read_user_management_teams sysconsole_read_reporting_server_logs sysconsole_read_site_customization sysconsole_read_reporting_site_statistics sysconsole_read_environment_web_server read_elasticsearch_post_indexing_job', + system_read_only_admin: 'sysconsole_read_authentication_guest_access download_compliance_export_result sysconsole_read_compliance_data_retention_policy get_logs sysconsole_read_environment_file_storage read_channel sysconsole_read_integrations_integration_management sysconsole_read_compliance_custom_terms_of_service sysconsole_read_site_notices sysconsole_read_environment_rate_limiting sysconsole_read_about_edition_and_license read_public_channel sysconsole_read_experimental_features test_ldap sysconsole_read_user_management_permissions read_elasticsearch_post_aggregation_job sysconsole_read_environment_image_proxy sysconsole_read_compliance_compliance_export sysconsole_read_integrations_bot_accounts sysconsole_read_authentication_openid sysconsole_read_site_posts sysconsole_read_user_management_users sysconsole_read_experimental_feature_flags sysconsole_read_reporting_team_statistics sysconsole_read_site_localization read_private_channel_groups sysconsole_read_site_file_sharing_and_downloads sysconsole_read_user_management_channels sysconsole_read_authentication_email read_data_retention_job read_audits sysconsole_read_plugins view_team get_analytics sysconsole_read_user_management_groups sysconsole_read_experimental_bleve sysconsole_read_products_boards read_compliance_export_job sysconsole_read_environment_logging sysconsole_read_authentication_signup sysconsole_read_environment_smtp sysconsole_read_environment_session_lengths sysconsole_read_environment_developer sysconsole_read_environment_high_availability sysconsole_read_environment_mobile_security read_ldap_sync_job sysconsole_read_environment_performance_monitoring sysconsole_read_authentication_saml read_public_channel_groups sysconsole_read_integrations_gif sysconsole_read_authentication_mfa list_public_teams sysconsole_read_environment_database list_private_teams sysconsole_read_authentication_ldap sysconsole_read_compliance_compliance_monitoring sysconsole_read_site_notifications sysconsole_read_site_announcement_banner read_other_users_teams sysconsole_read_authentication_password sysconsole_read_environment_push_notification_server sysconsole_read_site_users_and_teams sysconsole_read_site_public_links sysconsole_read_site_emoji sysconsole_read_environment_elasticsearch read_license_information sysconsole_read_integrations_cors sysconsole_read_user_management_teams sysconsole_read_reporting_server_logs sysconsole_read_site_customization sysconsole_read_reporting_site_statistics sysconsole_read_environment_web_server read_elasticsearch_post_indexing_job', system_user: 'delete_custom_group create_emojis edit_custom_group create_direct_channel view_members join_public_teams restore_custom_group create_custom_group manage_custom_group_members delete_emojis list_public_teams create_team create_group_channel', system_user_access_token: 'create_user_access_token read_user_access_token revoke_user_access_token', system_user_manager: 'sysconsole_read_authentication_password sysconsole_read_authentication_openid sysconsole_write_user_management_groups list_private_teams sysconsole_read_user_management_groups sysconsole_read_authentication_email manage_public_channel_properties delete_private_channel sysconsole_read_authentication_signup read_private_channel_groups sysconsole_read_user_management_teams test_ldap read_channel view_team manage_team sysconsole_write_user_management_teams manage_channel_roles sysconsole_read_authentication_saml sysconsole_read_authentication_guest_access convert_private_channel_to_public sysconsole_read_user_management_permissions join_public_teams sysconsole_write_user_management_channels read_public_channel_groups sysconsole_read_user_management_channels list_public_teams manage_team_roles join_private_teams manage_public_channel_members convert_public_channel_to_private remove_user_from_team sysconsole_read_authentication_ldap manage_private_channel_properties delete_public_channel manage_private_channel_members read_public_channel add_user_to_team sysconsole_read_authentication_mfa read_ldap_sync_job', diff --git a/e2e-tests/playwright/support/ui/components/index.ts b/e2e-tests/playwright/support/ui/components/index.ts index 18ec9adce24..8fcde8e3680 100644 --- a/e2e-tests/playwright/support/ui/components/index.ts +++ b/e2e-tests/playwright/support/ui/components/index.ts @@ -36,6 +36,8 @@ import {SystemUsersColumnToggleMenu} from './system_console/sections/system_user import ChannelsPostEdit from '@e2e-support/ui/components/channels/post_edit'; import DeletePostConfirmationDialog from '@e2e-support/ui/components/channels/delete_post_confirmation_dialog'; import RestorePostConfirmationDialog from '@e2e-support/ui/components/channels/restore_post_confirmation_dialog'; +import MobileSecurity from './system_console/sections/system_users/mobile_security'; +import FeatureDiscovery from './system_console/sections/system_users/feature_discovery'; const components = { GlobalHeader, @@ -71,6 +73,8 @@ const components = { UserProfilePopover, DeletePostConfirmationDialog, RestorePostConfirmationDialog, + MobileSecurity, + FeatureDiscovery, }; export { diff --git a/e2e-tests/playwright/support/ui/components/system_console/sections/system_users/feature_discovery.ts b/e2e-tests/playwright/support/ui/components/system_console/sections/system_users/feature_discovery.ts new file mode 100644 index 00000000000..2a4ba637ea4 --- /dev/null +++ b/e2e-tests/playwright/support/ui/components/system_console/sections/system_users/feature_discovery.ts @@ -0,0 +1,25 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import {expect, Locator} from '@playwright/test'; + +/** + * System Console -> Feature Discovery + */ +export default class FeatureDiscovery { + readonly container: Locator; + + constructor(container: Locator) { + this.container = container; + } + + async toBeVisible() { + await expect(this.container).toBeVisible(); + } + + async toHaveTitle(title: string) { + await expect(this.container.getByTestId('featureDiscovery_title')).toHaveText(title); + } +} + +export {FeatureDiscovery}; diff --git a/e2e-tests/playwright/support/ui/components/system_console/sections/system_users/mobile_security.ts b/e2e-tests/playwright/support/ui/components/system_console/sections/system_users/mobile_security.ts new file mode 100644 index 00000000000..18f5e91ab1d --- /dev/null +++ b/e2e-tests/playwright/support/ui/components/system_console/sections/system_users/mobile_security.ts @@ -0,0 +1,81 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import {expect, Locator} from '@playwright/test'; + +/** + * System Console -> Environment -> Mobile Security + */ +export default class MobileSecurity { + readonly container: Locator; + + readonly enableBiometricAuthenticationToggleTrue: Locator; + readonly enableBiometricAuthenticationToggleFalse: Locator; + readonly preventScreenCaptureToggleTrue: Locator; + readonly preventScreenCaptureToggleFalse: Locator; + readonly jailbreakProtectionToggleTrue: Locator; + readonly jailbreakProtectionToggleFalse: Locator; + + readonly saveButton: Locator; + + constructor(container: Locator) { + this.container = container; + + this.enableBiometricAuthenticationToggleTrue = this.container.getByTestId( + 'NativeAppSettings.MobileEnableBiometricstrue', + ); + this.enableBiometricAuthenticationToggleFalse = this.container.getByTestId( + 'NativeAppSettings.MobileEnableBiometricsfalse', + ); + + this.preventScreenCaptureToggleTrue = this.container.getByTestId( + 'NativeAppSettings.MobilePreventScreenCapturetrue', + ); + this.preventScreenCaptureToggleFalse = this.container.getByTestId( + 'NativeAppSettings.MobilePreventScreenCapturefalse', + ); + + this.jailbreakProtectionToggleTrue = this.container.getByTestId( + 'NativeAppSettings.MobileJailbreakProtectiontrue', + ); + this.jailbreakProtectionToggleFalse = this.container.getByTestId( + 'NativeAppSettings.MobileJailbreakProtectionfalse', + ); + + this.saveButton = this.container.getByRole('button', {name: 'Save'}); + } + + async toBeVisible() { + await expect(this.container).toBeVisible(); + } + + async clickEnableBiometricAuthenticationToggleTrue() { + await this.enableBiometricAuthenticationToggleTrue.click(); + } + + async clickEnableBiometricAuthenticationToggleFalse() { + await this.enableBiometricAuthenticationToggleFalse.click(); + } + + async clickPreventScreenCaptureToggleTrue() { + await this.preventScreenCaptureToggleTrue.click(); + } + + async clickPreventScreenCaptureToggleFalse() { + await this.preventScreenCaptureToggleFalse.click(); + } + + async clickJailbreakProtectionToggleTrue() { + await this.jailbreakProtectionToggleTrue.click(); + } + + async clickJailbreakProtectionToggleFalse() { + await this.jailbreakProtectionToggleFalse.click(); + } + + async clickSaveButton() { + await this.saveButton.click(); + } +} + +export {MobileSecurity}; diff --git a/e2e-tests/playwright/support/ui/pages/system_console.ts b/e2e-tests/playwright/support/ui/pages/system_console.ts index 21786828c9f..f15dd882517 100644 --- a/e2e-tests/playwright/support/ui/pages/system_console.ts +++ b/e2e-tests/playwright/support/ui/pages/system_console.ts @@ -21,6 +21,10 @@ class SystemConsolePage { readonly systemUsersColumnToggleMenu; readonly systemUsersActionMenus; + readonly mobileSecurity; + + readonly featureDiscovery; + // modal readonly confirmModal; readonly exportModal; @@ -35,6 +39,10 @@ class SystemConsolePage { // Sections and sub-sections this.systemUsers = new components.SystemUsers(page.getByTestId('systemUsersSection')); + this.mobileSecurity = new components.MobileSecurity( + page.getByTestId('sysconsole_section_MobileSecuritySettings'), + ); + this.featureDiscovery = new components.FeatureDiscovery(page.getByTestId('featureDiscovery')); // Menus & Popovers this.systemUsersFilterPopover = new components.SystemUsersFilterPopover( diff --git a/e2e-tests/playwright/tests/functional/system_console/mobile_security.spec.ts b/e2e-tests/playwright/tests/functional/system_console/mobile_security.spec.ts new file mode 100644 index 00000000000..72da3bd0124 --- /dev/null +++ b/e2e-tests/playwright/tests/functional/system_console/mobile_security.spec.ts @@ -0,0 +1,126 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import {waitUntil} from '@e2e-support/test_action'; +import {expect, test} from '@e2e-support/test_fixture'; + +test('should be able to enable mobile security settings when licensed', async ({pw}) => { + const {adminUser, adminClient} = await pw.initSetup(); + + const license = await adminClient.getClientLicenseOld(); + + test.skip(license.SkuShortName !== 'enterprise', 'Skipping test - server has no enterprise license'); + + if (!adminUser) { + throw new Error('Failed to create admin user'); + } + + // # Log in as admin + const {systemConsolePage} = await pw.testBrowser.login(adminUser); + + // # Visit system console + await systemConsolePage.goto(); + await systemConsolePage.toBeVisible(); + + // # Go to Mobile Security section + await systemConsolePage.sidebar.goToItem('Mobile Security'); + await systemConsolePage.mobileSecurity.toBeVisible(); + + // # Enable Biometric Authentication + await systemConsolePage.mobileSecurity.clickEnableBiometricAuthenticationToggleTrue(); + + // * Verify only Biometric Authentication is enabled + expect(await systemConsolePage.mobileSecurity.enableBiometricAuthenticationToggleTrue.isChecked()).toBe(true); + expect(await systemConsolePage.mobileSecurity.preventScreenCaptureToggleTrue.isChecked()).toBe(false); + expect(await systemConsolePage.mobileSecurity.jailbreakProtectionToggleTrue.isChecked()).toBe(false); + + // # Save settings + await systemConsolePage.mobileSecurity.clickSaveButton(); + // # Wait until the save button has settled + await waitUntil(async () => (await systemConsolePage.mobileSecurity.saveButton.textContent()) === 'Save'); + + // # Go to any other section and come back to Mobile Security + await systemConsolePage.sidebar.goToItem('Users'); + await systemConsolePage.systemUsers.toBeVisible(); + + await systemConsolePage.sidebar.goToItem('Mobile Security'); + + // * Verify Biometric Authentication is still enabled + expect(await systemConsolePage.mobileSecurity.enableBiometricAuthenticationToggleTrue.isChecked()).toBe(true); + expect(await systemConsolePage.mobileSecurity.preventScreenCaptureToggleTrue.isChecked()).toBe(false); + expect(await systemConsolePage.mobileSecurity.jailbreakProtectionToggleTrue.isChecked()).toBe(false); + + // # Enable Prevent Screen Capture + await systemConsolePage.mobileSecurity.clickPreventScreenCaptureToggleTrue(); + + // * Verify only Biometric Authentication and Prevent Screen Capture are enabled + expect(await systemConsolePage.mobileSecurity.enableBiometricAuthenticationToggleTrue.isChecked()).toBe(true); + expect(await systemConsolePage.mobileSecurity.preventScreenCaptureToggleTrue.isChecked()).toBe(true); + expect(await systemConsolePage.mobileSecurity.jailbreakProtectionToggleTrue.isChecked()).toBe(false); + + // # Save settings + await systemConsolePage.mobileSecurity.clickSaveButton(); + // # Wait until the save button has settled + await waitUntil(async () => (await systemConsolePage.mobileSecurity.saveButton.textContent()) === 'Save'); + + // # Go to any other section and come back to Mobile Security + await systemConsolePage.sidebar.goToItem('Users'); + await systemConsolePage.systemUsers.toBeVisible(); + + await systemConsolePage.sidebar.goToItem('Mobile Security'); + + // * Verify Biometric Authentication and Prevent Screen Capture are still enabled + expect(await systemConsolePage.mobileSecurity.enableBiometricAuthenticationToggleTrue.isChecked()).toBe(true); + expect(await systemConsolePage.mobileSecurity.preventScreenCaptureToggleTrue.isChecked()).toBe(true); + expect(await systemConsolePage.mobileSecurity.jailbreakProtectionToggleTrue.isChecked()).toBe(false); + + // # Enable Jailbreak Protection + await systemConsolePage.mobileSecurity.clickJailbreakProtectionToggleTrue(); + + // * Verify all toggles are enabled + expect(await systemConsolePage.mobileSecurity.enableBiometricAuthenticationToggleTrue.isChecked()).toBe(true); + expect(await systemConsolePage.mobileSecurity.preventScreenCaptureToggleTrue.isChecked()).toBe(true); + expect(await systemConsolePage.mobileSecurity.jailbreakProtectionToggleTrue.isChecked()).toBe(true); + + // # Save settings + await systemConsolePage.mobileSecurity.clickSaveButton(); + // # Wait until the save button has settled + await waitUntil(async () => (await systemConsolePage.mobileSecurity.saveButton.textContent()) === 'Save'); + + // # Go to any other section and come back to Mobile Security + await systemConsolePage.sidebar.goToItem('Users'); + await systemConsolePage.systemUsers.toBeVisible(); + + await systemConsolePage.sidebar.goToItem('Mobile Security'); + + // * Verify all toggles are still enabled + expect(await systemConsolePage.mobileSecurity.enableBiometricAuthenticationToggleTrue.isChecked()).toBe(true); + expect(await systemConsolePage.mobileSecurity.preventScreenCaptureToggleTrue.isChecked()).toBe(true); + expect(await systemConsolePage.mobileSecurity.jailbreakProtectionToggleTrue.isChecked()).toBe(true); +}); + +test('should show mobile security upsell when not licensed', async ({pw}) => { + const {adminUser, adminClient} = await pw.initSetup(); + + const license = await adminClient.getClientLicenseOld(); + + test.skip(license.SkuShortName === 'enterprise', 'Skipping test - server has enterprise license'); + + if (!adminUser) { + throw new Error('Failed to create admin user'); + } + + // # Log in as admin + const {systemConsolePage} = await pw.testBrowser.login(adminUser); + + // # Visit system console + await systemConsolePage.goto(); + await systemConsolePage.toBeVisible(); + + // # Go to Mobile Security section + await systemConsolePage.sidebar.goToItem('Mobile Security'); + await systemConsolePage.featureDiscovery.toBeVisible(); + + // * Verify title is correct + await systemConsolePage.featureDiscovery.toHaveTitle('Enhance mobile app security with Mattermost Enterprise'); +}); diff --git a/server/channels/app/permissions_migrations.go b/server/channels/app/permissions_migrations.go index 28dc8564237..9532aaa0f9a 100644 --- a/server/channels/app/permissions_migrations.go +++ b/server/channels/app/permissions_migrations.go @@ -1154,6 +1154,25 @@ func (a *App) removeGetAnalyticsPermissionMigration() (permissionsMap, error) { return transformations, nil } +func (a *App) addSysConsoleMobileSecurityPermission() (permissionsMap, error) { + transformations := []permissionTransformation{} + + transformations = append(transformations, permissionTransformation{ + On: isExactRole(model.SystemAdminRoleId), + Add: []string{model.PermissionSysconsoleWriteEnvironmentMobileSecurity.Id}, + }) + + transformations = append(transformations, permissionTransformation{ + On: permissionOr( + isExactRole(model.SystemAdminRoleId), + isExactRole(model.SystemReadOnlyAdminRoleId), + ), + Add: []string{model.PermissionSysconsoleReadEnvironmentMobileSecurity.Id}, + }) + + return transformations, nil +} + // Only sysadmins, team admins, and users with channels and groups managements have access to "convert channel to public" func (a *App) getRestrictAcessToChannelConversionToPublic() (permissionsMap, error) { return []permissionTransformation{ @@ -1223,6 +1242,7 @@ func (s *Server) doPermissionsMigrations() error { {Key: model.RestrictAccessToChannelConversionToPublic, Migration: a.getRestrictAcessToChannelConversionToPublic}, {Key: model.MigrationKeyFixReadAuditsPermission, Migration: a.getFixReadAuditsPermissionMigration}, {Key: model.MigrationRemoveGetAnalyticsPermission, Migration: a.removeGetAnalyticsPermissionMigration}, + {Key: model.MigrationAddSysconsoleMobileSecurityPermission, Migration: a.addSysConsoleMobileSecurityPermission}, } roles, err := s.Store().Role().GetAll() diff --git a/server/channels/testlib/store.go b/server/channels/testlib/store.go index 8f2a7de1cf7..0482a10da1b 100644 --- a/server/channels/testlib/store.go +++ b/server/channels/testlib/store.go @@ -85,6 +85,7 @@ func GetMockStoreForSetupFunctions() *mocks.Store { systemStore.On("GetByName", "CustomGroupAdminRoleCreationMigrationComplete").Return(&model.System{Name: model.MigrationKeyAddPlayboosksManageRolesPermissions, Value: "true"}, nil) systemStore.On("GetByName", "products_boards").Return(&model.System{Name: "products_boards", Value: "true"}, nil) systemStore.On("GetByName", "elasticsearch_fix_channel_index_migration").Return(&model.System{Name: "elasticsearch_fix_channel_index_migration", Value: "true"}, nil) + systemStore.On("GetByName", model.MigrationAddSysconsoleMobileSecurityPermission).Return(&model.System{Name: model.MigrationAddSysconsoleMobileSecurityPermission, Value: "true"}, nil) systemStore.On("InsertIfExists", mock.AnythingOfType("*model.System")).Return(&model.System{}, nil).Once() systemStore.On("Save", mock.AnythingOfType("*model.System")).Return(nil) diff --git a/server/public/model/migration.go b/server/public/model/migration.go index 3857b48784d..a561c735c4f 100644 --- a/server/public/model/migration.go +++ b/server/public/model/migration.go @@ -53,4 +53,5 @@ const ( RestrictAccessToChannelConversionToPublic = "restrict_access_to_channel_conversion_to_public_permissions" MigrationKeyFixReadAuditsPermission = "fix_read_audits_permission" MigrationRemoveGetAnalyticsPermission = "remove_get_analytics_permission" + MigrationAddSysconsoleMobileSecurityPermission = "add_sysconsole_mobile_security_permission" ) diff --git a/server/public/model/permission.go b/server/public/model/permission.go index 744964c4c3f..38411660435 100644 --- a/server/public/model/permission.go +++ b/server/public/model/permission.go @@ -252,6 +252,9 @@ var PermissionSysconsoleWriteEnvironmentPerformanceMonitoring *Permission var PermissionSysconsoleReadEnvironmentDeveloper *Permission var PermissionSysconsoleWriteEnvironmentDeveloper *Permission +var PermissionSysconsoleReadEnvironmentMobileSecurity *Permission +var PermissionSysconsoleWriteEnvironmentMobileSecurity *Permission + var PermissionSysconsoleReadSite *Permission var PermissionSysconsoleWriteSite *Permission @@ -1622,6 +1625,18 @@ func initializePermissions() { "", PermissionScopeSystem, } + PermissionSysconsoleReadEnvironmentMobileSecurity = &Permission{ + "sysconsole_read_environment_mobile_security", + "", + "", + PermissionScopeSystem, + } + PermissionSysconsoleWriteEnvironmentMobileSecurity = &Permission{ + "sysconsole_write_environment_mobile_security", + "", + "", + PermissionScopeSystem, + } // DEPRECATED PermissionSysconsoleReadSite = &Permission{ "sysconsole_read_site", @@ -2262,6 +2277,7 @@ func initializePermissions() { PermissionSysconsoleReadEnvironmentSessionLengths, PermissionSysconsoleReadEnvironmentPerformanceMonitoring, PermissionSysconsoleReadEnvironmentDeveloper, + PermissionSysconsoleReadEnvironmentMobileSecurity, PermissionSysconsoleReadSiteCustomization, PermissionSysconsoleReadSiteLocalization, PermissionSysconsoleReadSiteUsersAndTeams, @@ -2321,6 +2337,7 @@ func initializePermissions() { PermissionSysconsoleWriteEnvironmentSessionLengths, PermissionSysconsoleWriteEnvironmentPerformanceMonitoring, PermissionSysconsoleWriteEnvironmentDeveloper, + PermissionSysconsoleWriteEnvironmentMobileSecurity, PermissionSysconsoleWriteSiteCustomization, PermissionSysconsoleWriteSiteLocalization, PermissionSysconsoleWriteSiteUsersAndTeams, diff --git a/webapp/channels/src/components/admin_console/__snapshots__/schema_admin_settings.test.tsx.snap b/webapp/channels/src/components/admin_console/__snapshots__/schema_admin_settings.test.tsx.snap index 97bd0e04b2e..39df57b7a41 100644 --- a/webapp/channels/src/components/admin_console/__snapshots__/schema_admin_settings.test.tsx.snap +++ b/webapp/channels/src/components/admin_console/__snapshots__/schema_admin_settings.test.tsx.snap @@ -91,6 +91,7 @@ exports[`components/admin_console/SchemaAdminSettings should match snapshot with exports[`components/admin_console/SchemaAdminSettings should match snapshot with settings and plugin 1`] = `
config diff --git a/webapp/channels/src/components/admin_console/admin_definition.tsx b/webapp/channels/src/components/admin_console/admin_definition.tsx index 5f8866b9277..14890f118c9 100644 --- a/webapp/channels/src/components/admin_console/admin_definition.tsx +++ b/webapp/channels/src/components/admin_console/admin_definition.tsx @@ -73,6 +73,7 @@ import { GuestAccessFeatureDiscovery, SystemRolesFeatureDiscovery, GroupsFeatureDiscovery, + MobileSecurityFeatureDiscovery, } from './feature_discovery/features'; import FeatureFlags, {messages as featureFlagsMessages} from './feature_flags'; import GroupDetails from './group_settings/group_details'; @@ -2039,6 +2040,61 @@ const AdminDefinition: AdminDefinitionType = { ], }, }, + mobile_security: { + url: 'environment/mobile_security', + title: defineMessage({id: 'admin.sidebar.mobileSecurity', defaultMessage: 'Mobile Security'}), + isHidden: it.any( + it.not(it.userHasReadPermissionOnResource(RESOURCE_KEYS.ENVIRONMENT.MOBILE_SECURITY)), + it.not(it.licensedForSku(LicenseSkus.Enterprise)), + ), + schema: { + id: 'MobileSecuritySettings', + name: defineMessage({id: 'admin.mobileSecurity.title', defaultMessage: 'Mobile Security'}), + settings: [ + { + type: 'bool', + key: 'NativeAppSettings.MobileEnableBiometrics', + label: defineMessage({id: 'admin.mobileSecurity.biometricsTitle', defaultMessage: 'Enable Biometric Authentication:'}), + help_text: defineMessage({id: 'admin.mobileSecurity.biometricsDescription', defaultMessage: 'Enforces biometric authentication (with PIN/passcode fallback) before accessing the app. Users will be prompted based on session activity and server switching rules.'}), + }, + { + type: 'bool', + key: 'NativeAppSettings.MobilePreventScreenCapture', + label: defineMessage({id: 'admin.mobileSecurity.screenCaptureTitle', defaultMessage: 'Prevent Screen Capture:'}), + help_text: defineMessage({id: 'admin.mobileSecurity.screenCaptureDescription', defaultMessage: 'Blocks screenshots and screen recordings when using the mobile app. Screenshots will appear blank, and screen recordings will blur (iOS) or show a black screen (Android). Also applies when switching apps.'}), + }, + { + type: 'bool', + key: 'NativeAppSettings.MobileJailbreakProtection', + label: defineMessage({id: 'admin.mobileSecurity.jailbreakTitle', defaultMessage: 'Enable Jailbreak/Root Protection:'}), + help_text: defineMessage({id: 'admin.mobileSecurity.jailbreakDescription', defaultMessage: 'Prevents access to the app on devices detected as jailbroken or rooted. If a device fails the security check, users will be denied access or prompted to switch to a compliant server.'}), + }, + ], + }, + }, + mobile_security_feature_discovery: { + url: 'environment/mobile_security_feature_discovery', + isDiscovery: true, + title: defineMessage({id: 'admin.sidebar.mobileSecurity', defaultMessage: 'Mobile Security'}), + isHidden: it.any( + it.not(it.userHasReadPermissionOnResource(RESOURCE_KEYS.ENVIRONMENT.MOBILE_SECURITY)), + it.licensedForSku(LicenseSkus.Enterprise), + it.not(it.enterpriseReady), + ), + schema: { + id: 'MobileSecurityFeatureDiscoverySettings', + name: defineMessage({id: 'admin.mobileSecurity.title', defaultMessage: 'Mobile Security'}), + settings: [ + { + type: 'custom', + component: MobileSecurityFeatureDiscovery, + key: 'MobileSecurityFeatureDiscovery', + isDisabled: it.not(it.userHasWritePermissionOnResource(RESOURCE_KEYS.ABOUT.EDITION_AND_LICENSE)), + }, + ], + }, + restrictedIndicator: getRestrictedIndicator(true), + }, }, }, site: { diff --git a/webapp/channels/src/components/admin_console/admin_sidebar/__snapshots__/admin_sidebar.test.tsx.snap b/webapp/channels/src/components/admin_console/admin_sidebar/__snapshots__/admin_sidebar.test.tsx.snap index 961d99e17fe..1053a5a94d7 100644 --- a/webapp/channels/src/components/admin_console/admin_sidebar/__snapshots__/admin_sidebar.test.tsx.snap +++ b/webapp/channels/src/components/admin_console/admin_sidebar/__snapshots__/admin_sidebar.test.tsx.snap @@ -1192,6 +1192,1969 @@ exports[`components/AdminSidebar should match snapshot 1`] = `
`; +exports[`components/AdminSidebar should match snapshot with license with enterprise SKU 1`] = ` +
+ +
+
+ +
+ +
    + + } + key="about" + parentLink="/admin_console" + sectionClass="" + title={ + + } + > + + } + /> + + + } + key="reporting" + parentLink="/admin_console" + sectionClass="" + title={ + + } + > + + } + /> + + } + /> + + } + /> + + } + /> + + + } + key="user_management" + parentLink="/admin_console" + sectionClass="" + title={ + + } + > + + } + /> + + } + title={ + + } + /> + + } + /> + + } + /> + + } + /> + + } + title={ + + } + /> + + + } + key="environment" + parentLink="/admin_console" + sectionClass="" + title={ + + } + > + + } + /> + + } + /> + + } + /> + + } + /> + + } + /> + + } + /> + + } + /> + + } + /> + + } + /> + + } + /> + + } + /> + + } + /> + + + } + key="site" + parentLink="/admin_console" + sectionClass="" + title={ + + } + > + + } + /> + + } + /> + + } + /> + + } + /> + + } + title={ + + } + /> + + } + /> + + } + /> + + } + /> + + } + /> + + } + /> + + + } + key="authentication" + parentLink="/admin_console" + sectionClass="" + title={ + + } + > + + } + /> + + } + /> + + } + /> + + } + /> + + } + title={ + + } + /> + + } + title={ + + } + /> + + } + /> + + } + title={ + + } + /> + + } + title={ + + } + /> + + + } + key="plugins" + parentLink="/admin_console" + sectionClass="" + title={ + + } + > + + } + /> + + + + } + key="integrations" + parentLink="/admin_console" + sectionClass="" + title={ + + } + > + + } + /> + + } + /> + + } + /> + + } + /> + + } + /> + + + } + key="compliance" + parentLink="/admin_console" + sectionClass="" + title={ + + } + > + + } + title={ + + } + /> + + } + title={ + + } + /> + + } + title={ + + } + /> + + + } + key="experimental" + parentLink="/admin_console" + sectionClass="" + title={ + + } + > + + } + /> + + } + /> + + } + /> + +
+
+
+
+
+`; + +exports[`components/AdminSidebar should match snapshot with license with professional SKU 1`] = ` +
+ +
+
+ +
+ +
    + + } + key="about" + parentLink="/admin_console" + sectionClass="" + title={ + + } + > + + } + /> + + + } + key="reporting" + parentLink="/admin_console" + sectionClass="" + title={ + + } + > + + } + /> + + } + /> + + } + /> + + } + /> + + + } + key="user_management" + parentLink="/admin_console" + sectionClass="" + title={ + + } + > + + } + /> + + } + title={ + + } + /> + + } + /> + + } + /> + + } + /> + + } + title={ + + } + /> + + + } + key="environment" + parentLink="/admin_console" + sectionClass="" + title={ + + } + > + + } + /> + + } + /> + + } + /> + + } + /> + + } + /> + + } + /> + + } + /> + + } + /> + + } + /> + + } + /> + + } + /> + + } + title={ + + } + /> + + + } + key="site" + parentLink="/admin_console" + sectionClass="" + title={ + + } + > + + } + /> + + } + /> + + } + /> + + } + /> + + } + title={ + + } + /> + + } + /> + + } + /> + + } + /> + + } + /> + + } + /> + + + } + key="authentication" + parentLink="/admin_console" + sectionClass="" + title={ + + } + > + + } + /> + + } + /> + + } + /> + + } + /> + + } + title={ + + } + /> + + } + title={ + + } + /> + + } + /> + + } + title={ + + } + /> + + } + title={ + + } + /> + + + } + key="plugins" + parentLink="/admin_console" + sectionClass="" + title={ + + } + > + + } + /> + + + + } + key="integrations" + parentLink="/admin_console" + sectionClass="" + title={ + + } + > + + } + /> + + } + /> + + } + /> + + } + /> + + } + /> + + + } + key="compliance" + parentLink="/admin_console" + sectionClass="" + title={ + + } + > + + } + title={ + + } + /> + + } + title={ + + } + /> + + } + title={ + + } + /> + + + } + key="experimental" + parentLink="/admin_console" + sectionClass="" + title={ + + } + > + + } + /> + + } + /> + + } + /> + +
+
+
+
+
+`; + exports[`components/AdminSidebar should match snapshot with workspace optimization dashboard enabled 1`] = `
} /> + + } + title={ + + } + /> } /> + + } + title={ + + } + /> { expect(wrapper).toMatchSnapshot(); }); + test('should match snapshot with license with enterprise SKU', () => { + const props: Props = { + license: { + IsLicensed: 'true', + SkuShortName: 'enterprise', + }, + config: { + ...defaultProps.config, + ExperimentalSettings: { + RestrictSystemAdmin: false, + } as ExperimentalSettings, + PluginSettings: { + Enable: true, + EnableUploads: true, + } as PluginSettings, + GoogleSettings: { + Id: 'googleID', + Secret: 'googleSecret', + Scope: 'scope', + } as SSOSettings, + GitLabSettings: { + Id: 'gitlabID', + Secret: 'gitlabSecret', + Scope: 'scope', + } as SSOSettings, + Office365Settings: { + Id: 'office365ID', + Secret: 'office365Secret', + Scope: 'scope', + } as Office365Settings, + }, + adminDefinition: AdminDefinition, + buildEnterpriseReady: true, + navigationBlocked: false, + siteName: 'test snap', + subscriptionProduct: undefined, + plugins: { + plugin_0: { + active: false, + description: 'The plugin 0.', + id: 'plugin_0', + name: 'Plugin 0', + version: '0.1.0', + settings_schema: { + footer: '', + header: '', + settings: [], + }, + webapp: {bundle_path: 'webapp/dist/main.js'}, + }, + }, + onSearchChange: jest.fn(), + actions: { + getPlugins: jest.fn(), + }, + consoleAccess: {...defaultProps.consoleAccess}, + cloud: {...defaultProps.cloud}, + showTaskList: false, + }; + + const wrapper = shallowWithIntl(); + expect(wrapper).toMatchSnapshot(); + }); + + test('should match snapshot with license with professional SKU', () => { + const props: Props = { + license: { + IsLicensed: 'true', + SkuShortName: 'professional', + }, + config: { + ...defaultProps.config, + ExperimentalSettings: { + RestrictSystemAdmin: false, + } as ExperimentalSettings, + PluginSettings: { + Enable: true, + EnableUploads: true, + } as PluginSettings, + GoogleSettings: { + Id: 'googleID', + Secret: 'googleSecret', + Scope: 'scope', + } as SSOSettings, + GitLabSettings: { + Id: 'gitlabID', + Secret: 'gitlabSecret', + Scope: 'scope', + } as SSOSettings, + Office365Settings: { + Id: 'office365ID', + Secret: 'office365Secret', + Scope: 'scope', + } as Office365Settings, + }, + adminDefinition: AdminDefinition, + buildEnterpriseReady: true, + navigationBlocked: false, + siteName: 'test snap', + subscriptionProduct: undefined, + plugins: { + plugin_0: { + active: false, + description: 'The plugin 0.', + id: 'plugin_0', + name: 'Plugin 0', + version: '0.1.0', + settings_schema: { + footer: '', + header: '', + settings: [], + }, + webapp: {bundle_path: 'webapp/dist/main.js'}, + }, + }, + onSearchChange: jest.fn(), + actions: { + getPlugins: jest.fn(), + }, + consoleAccess: {...defaultProps.consoleAccess}, + cloud: {...defaultProps.cloud}, + showTaskList: false, + }; + + const wrapper = shallowWithIntl(); + expect(wrapper).toMatchSnapshot(); + }); + describe('generateIndex', () => { const props: Props = { license: {}, diff --git a/webapp/channels/src/components/admin_console/custom_plugin_settings/__snapshots__/custom_plugin_settings.test.tsx.snap b/webapp/channels/src/components/admin_console/custom_plugin_settings/__snapshots__/custom_plugin_settings.test.tsx.snap index d924330ec2a..ea4f168f915 100644 --- a/webapp/channels/src/components/admin_console/custom_plugin_settings/__snapshots__/custom_plugin_settings.test.tsx.snap +++ b/webapp/channels/src/components/admin_console/custom_plugin_settings/__snapshots__/custom_plugin_settings.test.tsx.snap @@ -3,6 +3,7 @@ exports[`components/admin_console/CustomPluginSettings should match snapshot with no settings and plugin 1`] = `
testplugin @@ -203,6 +204,7 @@ exports[`components/admin_console/CustomPluginSettings should match snapshot wit exports[`components/admin_console/CustomPluginSettings should match snapshot with settings and no plugin 1`] = `
testplugin @@ -253,6 +255,7 @@ exports[`components/admin_console/CustomPluginSettings should match snapshot wit exports[`components/admin_console/CustomPluginSettings should match snapshot with settings and plugin 1`] = `
testplugin diff --git a/webapp/channels/src/components/admin_console/feature_discovery/feature_discovery.tsx b/webapp/channels/src/components/admin_console/feature_discovery/feature_discovery.tsx index 59247a2b675..cac6c4c3e4d 100644 --- a/webapp/channels/src/components/admin_console/feature_discovery/feature_discovery.tsx +++ b/webapp/channels/src/components/admin_console/feature_discovery/feature_discovery.tsx @@ -294,7 +294,10 @@ export default class FeatureDiscovery extends React.PureComponent } return ( -
+
( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +); + +export default MobileSecuritySVG; diff --git a/webapp/channels/src/components/admin_console/feature_discovery/features/index.ts b/webapp/channels/src/components/admin_console/feature_discovery/features/index.ts index ee24864d754..fc8d875ef7c 100644 --- a/webapp/channels/src/components/admin_console/feature_discovery/features/index.ts +++ b/webapp/channels/src/components/admin_console/feature_discovery/features/index.ts @@ -8,6 +8,7 @@ import DataRetentionFeatureDiscovery from './data_retention'; import GroupsFeatureDiscovery from './groups'; import GuestAccessFeatureDiscovery from './guest_access'; import LDAPFeatureDiscovery from './ldap'; +import MobileSecurityFeatureDiscovery from './mobile_security'; import OpenIDFeatureDiscovery from './openid'; import OpenIDCustomFeatureDiscovery from './openid_custom'; import SAMLFeatureDiscovery from './saml'; @@ -25,4 +26,5 @@ export { GuestAccessFeatureDiscovery, SystemRolesFeatureDiscovery, GroupsFeatureDiscovery, + MobileSecurityFeatureDiscovery, }; diff --git a/webapp/channels/src/components/admin_console/feature_discovery/features/mobile_security.test.tsx b/webapp/channels/src/components/admin_console/feature_discovery/features/mobile_security.test.tsx new file mode 100644 index 00000000000..7eb07460d62 --- /dev/null +++ b/webapp/channels/src/components/admin_console/feature_discovery/features/mobile_security.test.tsx @@ -0,0 +1,68 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import React from 'react'; + +import {renderWithContext, screen} from 'tests/react_testing_utils'; +import {LicenseSkus} from 'utils/constants'; + +import MobileSecurityFeatureDiscovery from './mobile_security'; + +// Mock the FeatureDiscovery component +jest.mock('../index', () => ({ + __esModule: true, + default: jest.fn((props) => { + // Render a simple div with key props for testing + return ( +
+
{props.featureName}
+
{props.minimumSKURequiredForFeature}
+
{props.title.defaultMessage}
+
{props.copy.defaultMessage}
+
{props.learnMoreURL}
+
{props.featureDiscoveryImage}
+
+ ); + }), +})); + +// Mock the SVG component +jest.mock('./images/mobile_security_svg', () => ({ + __esModule: true, + default: jest.fn((props) => ( +
+
{props.width}
+
{props.height}
+
+ )), +})); + +describe('components/admin_console/feature_discovery/features/MobileSecurityFeatureDiscovery', () => { + it('renders correctly with expected props', () => { + renderWithContext(); + + // Verify feature name + expect(screen.getByTestId('feature-name')).toHaveTextContent('mobile_security'); + + // Verify minimum SKU + expect(screen.getByTestId('minimum-sku')).toHaveTextContent(LicenseSkus.Enterprise); + + // Verify title + expect(screen.getByTestId('title')).toHaveTextContent('Enhance mobile app security with Mattermost Enterprise'); + + // Verify copy text + expect(screen.getByTestId('copy')).toHaveTextContent( + 'Enable advanced security features like biometric authentication, screen capture prevention, and jailbreak/root detection for your mobile users.', + ); + + // Verify learn more URL + expect(screen.getByTestId('learn-more-url')).toHaveTextContent( + 'https://docs.mattermost.com/configure/environment-configuration-settings.html#mobile-security', + ); + + // Verify SVG is rendered + expect(screen.getByTestId('mobile-security-svg')).toBeInTheDocument(); + expect(screen.getByTestId('mobile-security-svg-width')).toHaveTextContent('294'); + expect(screen.getByTestId('mobile-security-svg-height')).toHaveTextContent('170'); + }); +}); diff --git a/webapp/channels/src/components/admin_console/feature_discovery/features/mobile_security.tsx b/webapp/channels/src/components/admin_console/feature_discovery/features/mobile_security.tsx new file mode 100644 index 00000000000..96981b30727 --- /dev/null +++ b/webapp/channels/src/components/admin_console/feature_discovery/features/mobile_security.tsx @@ -0,0 +1,36 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import React from 'react'; +import {defineMessage} from 'react-intl'; + +import {LicenseSkus} from 'utils/constants'; + +import MobileSecuritySVG from './images/mobile_security_svg'; + +import FeatureDiscovery from '../index'; + +const MobileSecurityFeatureDiscovery = () => { + return ( + } + /> + ); +}; + +export default MobileSecurityFeatureDiscovery; diff --git a/webapp/channels/src/components/admin_console/schema_admin_settings.tsx b/webapp/channels/src/components/admin_console/schema_admin_settings.tsx index 81986559061..998a0d3a97a 100644 --- a/webapp/channels/src/components/admin_console/schema_admin_settings.tsx +++ b/webapp/channels/src/components/admin_console/schema_admin_settings.tsx @@ -1328,7 +1328,10 @@ export class SchemaAdminSettings extends React.PureComponent { } return ( -
+
{this.renderTitle()}
diff --git a/webapp/channels/src/components/admin_console/system_roles/system_role/__snapshots__/system_role_permissions.test.tsx.snap b/webapp/channels/src/components/admin_console/system_roles/system_role/__snapshots__/system_role_permissions.test.tsx.snap index aff4505ac8c..e3428b3994c 100644 --- a/webapp/channels/src/components/admin_console/system_roles/system_role/__snapshots__/system_role_permissions.test.tsx.snap +++ b/webapp/channels/src/components/admin_console/system_roles/system_role/__snapshots__/system_role_permissions.test.tsx.snap @@ -172,6 +172,9 @@ exports[`admin_console/system_role_permissions should match snapshot 1`] = ` Object { "name": "environment_developer", }, + Object { + "name": "environment_mobile_security", + }, ], } } diff --git a/webapp/channels/src/components/admin_console/system_roles/system_role/strings.tsx b/webapp/channels/src/components/admin_console/system_roles/system_role/strings.tsx index b5631ef8186..c26fd44f9ed 100644 --- a/webapp/channels/src/components/admin_console/system_roles/system_role/strings.tsx +++ b/webapp/channels/src/components/admin_console/system_roles/system_role/strings.tsx @@ -200,6 +200,12 @@ export const sectionStrings: Record> = defaultMessage: 'Developer', }, }), + environment_mobile_security: defineMessages({ + name: { + id: 'admin.permissions.sysconsole_section_environment_mobile_security.name', + defaultMessage: 'Mobile Security', + }, + }), site: defineMessages({ name: { id: 'admin.permissions.sysconsole_section_site.name', diff --git a/webapp/channels/src/components/admin_console/system_roles/system_role/system_role_permissions.tsx b/webapp/channels/src/components/admin_console/system_roles/system_role/system_role_permissions.tsx index 85f13c6c02d..79b9717fe1f 100644 --- a/webapp/channels/src/components/admin_console/system_roles/system_role/system_role_permissions.tsx +++ b/webapp/channels/src/components/admin_console/system_roles/system_role/system_role_permissions.tsx @@ -82,6 +82,7 @@ const sectionsList: SystemSection[] = [ {name: 'environment_session_lengths'}, {name: 'environment_performance_monitoring'}, {name: 'environment_developer'}, + {name: 'environment_mobile_security'}, ], }, { diff --git a/webapp/channels/src/components/global_header/left_controls/product_menu/product_menu_list/__snapshots__/product_menu_list.test.tsx.snap b/webapp/channels/src/components/global_header/left_controls/product_menu/product_menu_list/__snapshots__/product_menu_list.test.tsx.snap index 2f0c45285f2..48f9cbaa2f4 100644 --- a/webapp/channels/src/components/global_header/left_controls/product_menu/product_menu_list/__snapshots__/product_menu_list.test.tsx.snap +++ b/webapp/channels/src/components/global_header/left_controls/product_menu/product_menu_list/__snapshots__/product_menu_list.test.tsx.snap @@ -47,6 +47,7 @@ exports[`components/global/product_switcher_menu should match snapshot with id 1 "sysconsole_read_environment_session_lengths", "sysconsole_read_environment_performance_monitoring", "sysconsole_read_environment_developer", + "sysconsole_read_environment_mobile_security", "sysconsole_read_authentication_signup", "sysconsole_read_authentication_email", "sysconsole_read_authentication_password", @@ -234,6 +235,7 @@ exports[`components/global/product_switcher_menu should match snapshot with most "sysconsole_read_environment_session_lengths", "sysconsole_read_environment_performance_monitoring", "sysconsole_read_environment_developer", + "sysconsole_read_environment_mobile_security", "sysconsole_read_authentication_signup", "sysconsole_read_authentication_email", "sysconsole_read_authentication_password", @@ -548,6 +550,7 @@ exports[`components/global/product_switcher_menu should show integrations should "sysconsole_read_environment_session_lengths", "sysconsole_read_environment_performance_monitoring", "sysconsole_read_environment_developer", + "sysconsole_read_environment_mobile_security", "sysconsole_read_authentication_signup", "sysconsole_read_authentication_email", "sysconsole_read_authentication_password", diff --git a/webapp/channels/src/i18n/en.json b/webapp/channels/src/i18n/en.json index 3de70e740f3..97f694f7e10 100644 --- a/webapp/channels/src/i18n/en.json +++ b/webapp/channels/src/i18n/en.json @@ -1531,6 +1531,15 @@ "admin.metrics.listenAddressEx": "E.g.: \":8067\"", "admin.metrics.listenAddressTitle": "Listen Address:", "admin.mfa.bannerDesc": "Multi-factor authentication is available for accounts with AD/LDAP or email login. If other login methods are used, MFA should be configured with the authentication provider.", + "admin.mobile_security_feature_discovery.copy": "Enable advanced security features like biometric authentication, screen capture prevention, and jailbreak/root detection for your mobile users.", + "admin.mobile_security_feature_discovery.title": "Enhance mobile app security with Mattermost Enterprise", + "admin.mobileSecurity.biometricsDescription": "Enforces biometric authentication (with PIN/passcode fallback) before accessing the app. Users will be prompted based on session activity and server switching rules.", + "admin.mobileSecurity.biometricsTitle": "Enable Biometric Authentication:", + "admin.mobileSecurity.jailbreakDescription": "Prevents access to the app on devices detected as jailbroken or rooted. If a device fails the security check, users will be denied access or prompted to switch to a compliant server.", + "admin.mobileSecurity.jailbreakTitle": "Enable Jailbreak/Root Protection:", + "admin.mobileSecurity.screenCaptureDescription": "Blocks screenshots and screen recordings when using the mobile app. Screenshots will appear blank, and screen recordings will blur (iOS) or show a black screen (Android). Also applies when switching apps.", + "admin.mobileSecurity.screenCaptureTitle": "Prevent Screen Capture:", + "admin.mobileSecurity.title": "Mobile Security", "admin.nav.administratorsGuide": "Administrator's Guide", "admin.nav.commercialSupport": "Commercial Support", "admin.nav.menuAriaLabel": "Admin Console Menu", @@ -1846,6 +1855,7 @@ "admin.permissions.sysconsole_section_environment_high_availability.name": "High Availability", "admin.permissions.sysconsole_section_environment_image_proxy.name": "Image Proxy", "admin.permissions.sysconsole_section_environment_logging.name": "Logging", + "admin.permissions.sysconsole_section_environment_mobile_security.name": "Mobile Security", "admin.permissions.sysconsole_section_environment_performance_monitoring.name": "Performance Monitoring", "admin.permissions.sysconsole_section_environment_push_notification_server.name": "Push Notification Server", "admin.permissions.sysconsole_section_environment_rate_limiting.name": "Rate Limiting", @@ -2471,6 +2481,7 @@ "admin.sidebar.logs": "Server Logs", "admin.sidebar.metrics": "Performance Monitoring", "admin.sidebar.mfa": "MFA", + "admin.sidebar.mobileSecurity": "Mobile Security", "admin.sidebar.move_thread": "Move thread (Beta)", "admin.sidebar.notices": "Notices", "admin.sidebar.notifications": "Notifications", diff --git a/webapp/channels/src/packages/mattermost-redux/src/constants/permissions.ts b/webapp/channels/src/packages/mattermost-redux/src/constants/permissions.ts index 7ffa6502348..73791213946 100644 --- a/webapp/channels/src/packages/mattermost-redux/src/constants/permissions.ts +++ b/webapp/channels/src/packages/mattermost-redux/src/constants/permissions.ts @@ -181,6 +181,8 @@ const values = { SYSCONSOLE_WRITE_ENVIRONMENT_PERFORMANCE_MONITORING: 'sysconsole_write_environment_performance_monitoring', SYSCONSOLE_READ_ENVIRONMENT_DEVELOPER: 'sysconsole_read_environment_developer', SYSCONSOLE_WRITE_ENVIRONMENT_DEVELOPER: 'sysconsole_write_environment_developer', + SYSCONSOLE_READ_ENVIRONMENT_MOBILE_SECURITY: 'sysconsole_read_environment_mobile_security', + SYSCONSOLE_WRITE_ENVIRONMENT_MOBILE_SECURITY: 'sysconsole_write_environment_mobile_security', SYSCONSOLE_READ_AUTHENTICATION_SIGNUP: 'sysconsole_read_authentication_signup', SYSCONSOLE_WRITE_AUTHENTICATION_SIGNUP: 'sysconsole_write_authentication_signup', SYSCONSOLE_READ_AUTHENTICATION_EMAIL: 'sysconsole_read_authentication_email', @@ -306,6 +308,7 @@ values.SYSCONSOLE_READ_PERMISSIONS = [ values.SYSCONSOLE_READ_ENVIRONMENT_SESSION_LENGTHS, values.SYSCONSOLE_READ_ENVIRONMENT_PERFORMANCE_MONITORING, values.SYSCONSOLE_READ_ENVIRONMENT_DEVELOPER, + values.SYSCONSOLE_READ_ENVIRONMENT_MOBILE_SECURITY, values.SYSCONSOLE_READ_AUTHENTICATION_SIGNUP, values.SYSCONSOLE_READ_AUTHENTICATION_EMAIL, values.SYSCONSOLE_READ_AUTHENTICATION_PASSWORD, @@ -363,6 +366,7 @@ values.SYSCONSOLE_WRITE_PERMISSIONS = [ values.SYSCONSOLE_WRITE_ENVIRONMENT_SESSION_LENGTHS, values.SYSCONSOLE_WRITE_ENVIRONMENT_PERFORMANCE_MONITORING, values.SYSCONSOLE_WRITE_ENVIRONMENT_DEVELOPER, + values.SYSCONSOLE_WRITE_ENVIRONMENT_MOBILE_SECURITY, values.SYSCONSOLE_WRITE_AUTHENTICATION_SIGNUP, values.SYSCONSOLE_WRITE_AUTHENTICATION_EMAIL, values.SYSCONSOLE_WRITE_AUTHENTICATION_PASSWORD, diff --git a/webapp/channels/src/packages/mattermost-redux/src/constants/permissions_sysconsole.ts b/webapp/channels/src/packages/mattermost-redux/src/constants/permissions_sysconsole.ts index af24bf1ac28..d544560fd9e 100644 --- a/webapp/channels/src/packages/mattermost-redux/src/constants/permissions_sysconsole.ts +++ b/webapp/channels/src/packages/mattermost-redux/src/constants/permissions_sysconsole.ts @@ -77,6 +77,7 @@ export const RESOURCE_KEYS = { SESSION_LENGTHS: 'environment.session_lengths', PERFORMANCE_MONITORING: 'environment.performance_monitoring', DEVELOPER: 'environment.developer', + MOBILE_SECURITY: 'environment.mobile_security', }, }; @@ -116,6 +117,7 @@ export const ResourceToSysConsolePermissionsTable: Record = { [RESOURCE_KEYS.ENVIRONMENT.SESSION_LENGTHS]: [Permissions.SYSCONSOLE_READ_ENVIRONMENT_SESSION_LENGTHS, Permissions.SYSCONSOLE_WRITE_ENVIRONMENT_SESSION_LENGTHS], [RESOURCE_KEYS.ENVIRONMENT.PERFORMANCE_MONITORING]: [Permissions.SYSCONSOLE_READ_ENVIRONMENT_PERFORMANCE_MONITORING, Permissions.SYSCONSOLE_WRITE_ENVIRONMENT_PERFORMANCE_MONITORING], [RESOURCE_KEYS.ENVIRONMENT.DEVELOPER]: [Permissions.SYSCONSOLE_READ_ENVIRONMENT_DEVELOPER, Permissions.SYSCONSOLE_WRITE_ENVIRONMENT_DEVELOPER], + [RESOURCE_KEYS.ENVIRONMENT.MOBILE_SECURITY]: [Permissions.SYSCONSOLE_READ_ENVIRONMENT_MOBILE_SECURITY, Permissions.SYSCONSOLE_WRITE_ENVIRONMENT_MOBILE_SECURITY], [RESOURCE_KEYS.AUTHENTICATION.SIGNUP]: [Permissions.SYSCONSOLE_READ_AUTHENTICATION_SIGNUP, Permissions.SYSCONSOLE_WRITE_AUTHENTICATION_SIGNUP], [RESOURCE_KEYS.AUTHENTICATION.EMAIL]: [Permissions.SYSCONSOLE_READ_AUTHENTICATION_EMAIL, Permissions.SYSCONSOLE_WRITE_AUTHENTICATION_EMAIL], [RESOURCE_KEYS.AUTHENTICATION.PASSWORD]: [Permissions.SYSCONSOLE_READ_AUTHENTICATION_PASSWORD, Permissions.SYSCONSOLE_WRITE_AUTHENTICATION_PASSWORD], diff --git a/webapp/channels/src/sass/routes/_admin-console.scss b/webapp/channels/src/sass/routes/_admin-console.scss index 765c3053d25..0e7e5ede19d 100644 --- a/webapp/channels/src/sass/routes/_admin-console.scss +++ b/webapp/channels/src/sass/routes/_admin-console.scss @@ -784,6 +784,7 @@ position: absolute; top: 0; right: 0; + display: flex; height: 100%; i {