From ea4c887c09bc79d3cbcb559901e5feadb1f08ab7 Mon Sep 17 00:00:00 2001 From: rvdwegen Date: Sun, 21 Jul 2024 19:24:03 +0200 Subject: [PATCH 001/130] Add bulk options to device list --- src/views/endpoint/intune/Devices.jsx | 38 +++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/views/endpoint/intune/Devices.jsx b/src/views/endpoint/intune/Devices.jsx index 85111eab9967..01ab8dd14071 100644 --- a/src/views/endpoint/intune/Devices.jsx +++ b/src/views/endpoint/intune/Devices.jsx @@ -283,6 +283,44 @@ const DevicesList = () => { path: '/api/ListDevices', reportName: `${tenant?.defaultDomainName}-Device-List`, params: { TenantFilter: tenant?.defaultDomainName }, + tableProps: { + keyField: 'id', + selectableRows: true, + actionsList: [ + { + label: 'Sync Device', + modal: true, + modalUrl: `/api/ExecDeviceAction?TenantFilter=${tenant.defaultDomainName}&GUID=!id&Action=syncDevice`, + modalMessage: 'Are you sure you want to Sync these device(s)?', + }, + { + label: 'Reboot Device(s)', + modal: true, + modalUrl: `/api/ExecDeviceAction?TenantFilter=${tenant.defaultDomainName}&GUID=!id&Action=rebootNow`, + modalMessage: 'Are you sure you want to reboot these device(s)?', + }, + { + label: 'Update Windows Defender', + modal: true, + modalUrl: `/api/ExecDeviceAction?TenantFilter=${tenant.defaultDomainName}&GUID=!id&Action=windowsDefenderUpdateSignatures`, + modalMessage: + 'Are you sure you want to update the Windows Defender signatures for these device(s)?', + }, + { + label: 'Rotate Local Admin Password', + modal: true, + modalUrl: `/api/ExecDeviceAction?TenantFilter=${tenant.defaultDomainName}&GUID=!id&Action=RotateLocalAdminPassword`, + modalMessage: 'Are you sure you want to rotate the password for these devices(s)?', + }, + { + label: 'Rotate Bitlocker Keys', + modal: true, + modalUrl: `/api/ExecDeviceAction?TenantFilter=${tenant.defaultDomainName}&GUID=!id&Action=rotateBitLockerKeys`, + modalMessage: + 'Are you sure you want to rotate the Bitlocker Keys for these device(s)?', + }, + ], + }, }} /> ) From 68c6af9c818fbb1e6a9281dda0e44933048abd27 Mon Sep 17 00:00:00 2001 From: Esco Date: Mon, 22 Jul 2024 14:25:39 +0200 Subject: [PATCH 002/130] Risk report quickfix * Added NoPagination true * Added $top 500 --- .../identity/administration/RiskyUsers.jsx | 20 +++---------------- src/views/identity/reports/RiskDetections.jsx | 4 +++- 2 files changed, 6 insertions(+), 18 deletions(-) diff --git a/src/views/identity/administration/RiskyUsers.jsx b/src/views/identity/administration/RiskyUsers.jsx index 727ee8dd896d..d51a899bef85 100644 --- a/src/views/identity/administration/RiskyUsers.jsx +++ b/src/views/identity/administration/RiskyUsers.jsx @@ -77,15 +77,6 @@ const RiskyUsers = () => { modalMessage: 'Are you sure you want to dismiss this users risk?', icon: , }, - /* TODO Add action for Compromised - { - label: 'Confirm Compromised', - color: 'info', - modal: true, - modalUrl: `/api/ExecBECRemediate?TenantFilter=${tenant.defaultDomainName}&userid=${row.id}`, - modalMessage: 'Are you sure you want to confirm this user as compromised?', - icon: , - },*/ ]} placement="end" visible={ocVisible} @@ -186,10 +177,12 @@ const RiskyUsers = () => { path: `api/ListGraphRequest`, reportName: `${tenant?.defaultDomainName}-ListRiskyUsers`, params: { - TenantFilter: tenant?.defaultDomainName, + TenantFilter: tenant.defaultDomainName, Endpoint: `identityProtection/riskyUsers`, $count: true, $orderby: 'riskLastUpdatedDateTime desc', + NoPagination: true, + $top: 500, }, tableProps: { selectableRows: true, @@ -200,13 +193,6 @@ const RiskyUsers = () => { model: true, modalUrl: `/api/ExecDismissRiskyUser?TenantFilter=${tenant.defaultDomainName}&userid=!id&userDisplayName=!userDisplayName`, }, - /* TODO Add action for Compromised - { - label: 'Confirm Compromised', - color: 'danger', - model: true, - modalUrl: `/api/ExecBECRemediate?TenantFilter=${tenant.defaultDomainName}&userid=!id`, - },*/ ], }, }} diff --git a/src/views/identity/reports/RiskDetections.jsx b/src/views/identity/reports/RiskDetections.jsx index b139fa058161..b031a9d9fc6b 100644 --- a/src/views/identity/reports/RiskDetections.jsx +++ b/src/views/identity/reports/RiskDetections.jsx @@ -214,10 +214,12 @@ const RiskDetections = () => { path: `api/ListGraphRequest`, reportName: `${tenant?.defaultDomainName}-RiskDetections-Report`, params: { - TenantFilter: tenant?.defaultDomainName, + TenantFilter: tenant.defaultDomainName, Endpoint: `identityProtection/riskDetections`, $count: true, $orderby: 'detectedDateTime desc', + NoPagination: true, + $top: 500, }, }} /> From eb418bf4782820798eaf562fe78470feaf4b49b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Tue, 23 Jul 2024 00:32:38 +0200 Subject: [PATCH 003/130] Added missing docs property --- src/data/standards.json | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/data/standards.json b/src/data/standards.json index c018b25b8a8e..dbcdd1f9a6c9 100644 --- a/src/data/standards.json +++ b/src/data/standards.json @@ -5,11 +5,6 @@ "tag": ["lowimpact"], "helpText": "Defines the email address to receive general updates and information related to M365 subscriptions. Leave a contact field blank if you do not want to update the contact information.", "docsDescription": "", - "disabledFeatures": { - "report": false, - "warn": false, - "remediate": false - }, "addedComponent": [ { "type": "input", @@ -645,7 +640,9 @@ "addedComponent": [], "label": "Disables Voice call as an MFA method", "impact": "High Impact", - "impactColour": "danger" + "impactColour": "danger", + "powershellEquivalent": "Update-MgBetaPolicyAuthenticationMethodPolicyAuthenticationMethodConfiguration", + "recommendedBy": [] }, { "name": "standards.DisableEmail", From 7b973a52c6b6947de480fc9cef3b6f825e9059f6 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Mon, 22 Jul 2024 19:09:15 -0400 Subject: [PATCH 004/130] Add more hudu settings --- src/data/Extensions.json | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/data/Extensions.json b/src/data/Extensions.json index 6d4b8ab242f0..6524c9236657 100644 --- a/src/data/Extensions.json +++ b/src/data/Extensions.json @@ -186,6 +186,11 @@ "label": "Hudu API Key", "placeholder": "Enter your Hudu API Key" }, + { + "type": "checkbox", + "name": "Hudu.Enabled", + "label": "Enable Integration" + }, { "type": "checkbox", "name": "Hudu.CreateMissingUsers", @@ -196,10 +201,20 @@ "name": "Hudu.CreateMissingDevices", "label": "Create missing devices in Hudu" }, + { + "type": "text", + "name": "Hudu.ExcludeSerials", + "label": "Exclude device serials (comma separated)" + }, { "type": "checkbox", - "name": "Hudu.Enabled", - "label": "Enable Integration" + "name": "Hudu.ImportDomains", + "label": "Import domains from M365" + }, + { + "type": "checkbox", + "name": "Hudu.MonitorDomains", + "label": "Monitor domains in Hudu" } ], "mappingRequired": true, From d4e99bac477558e7ffe557e587f5258660b6847e Mon Sep 17 00:00:00 2001 From: John Duprey Date: Tue, 23 Jul 2024 16:28:44 -0400 Subject: [PATCH 005/130] Change placeholder --- src/views/cipp/Setup.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/views/cipp/Setup.jsx b/src/views/cipp/Setup.jsx index bf09e8b04baf..7f18e7c6a661 100644 --- a/src/views/cipp/Setup.jsx +++ b/src/views/cipp/Setup.jsx @@ -286,7 +286,7 @@ const Setup = () => { type="text" name="TenantID" label="Tenant ID" - placeholder="Enter the Tenant ID. e.g. mymsp.onmicrosoft.com. Leave blank to retain a previous key if this exists." + placeholder="Enter the Tenant ID. e.g. 1111-1111-1111-1111-11111. Leave blank to retain a previous key if this exists." /> From d0f3dcde9c62b69896f121719d00b20c772f315c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Wed, 24 Jul 2024 18:59:50 +0200 Subject: [PATCH 006/130] New standard for setting SharePoint sync button state --- src/data/standards.json | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/data/standards.json b/src/data/standards.json index dbcdd1f9a6c9..684111375dc8 100644 --- a/src/data/standards.json +++ b/src/data/standards.json @@ -2091,6 +2091,34 @@ "powershellEquivalent": "Graph API or Portal", "recommendedBy": [] }, + { + "name": "standards.SPSyncButtonState", + "cat": "SharePoint Standards", + "tag": ["mediumimpact"], + "helpText": "If disabled users in the tenant will no longer be able to use the Sync button to sync SharePoint content. However, existing synced content will remain functional on the user's computer.", + "addedComponent": [ + { + "type": "Select", + "label": "SharePoint Sync Button state", + "name": "standards.SPSyncButtonState.state", + "values": [ + { + "label": "Disabled", + "value": "true" + }, + { + "label": "Enabled", + "value": "false" + } + ] + } + ], + "label": "Set SharePoint sync button state", + "impact": "Medium Impact", + "impactColour": "warning", + "powershellEquivalent": "Set-SPOTenant -HideSyncButtonOnTeamSite:$true or $false", + "recommendedBy": [] + }, { "name": "standards.DisableSharePointLegacyAuth", "cat": "SharePoint Standards", From 9cff0cc548f27fdcbc38285e8cb3ead5aa6c2e56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Wed, 24 Jul 2024 21:09:17 +0200 Subject: [PATCH 007/130] Update standard with enable and disable options --- src/data/standards.json | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/src/data/standards.json b/src/data/standards.json index 684111375dc8..fefdf431455b 100644 --- a/src/data/standards.json +++ b/src/data/standards.json @@ -2078,24 +2078,35 @@ "name": "standards.DisableAddShortcutsToOneDrive", "cat": "SharePoint Standards", "tag": ["mediumimpact"], - "helpText": "When the feature is disabled the option Add shortcut to OneDrive will be removed. Any folders that have already been added will remain on the user's computer.", - "disabledFeatures": { - "report": true, - "warn": true, - "remediate": false - }, - "addedComponent": [], - "label": "Disable Add Shortcuts To OneDrive", + "helpText": "If disabled, the button Add shortcut to OneDrive will be removed and users in the tenant will no longer be able to add new shortcuts to their OneDrive. Existing shortcuts will remain functional", + "addedComponent": [ + { + "type": "Select", + "label": "Add Shortcuts To OneDrive button state", + "name": "standards.DisableAddShortcutsToOneDrive.state", + "values": [ + { + "label": "Disabled", + "value": "true" + }, + { + "label": "Enabled", + "value": "false" + } + ] + } + ], + "label": "Set Add Shortcuts To OneDrive button state", "impact": "Medium Impact", "impactColour": "warning", - "powershellEquivalent": "Graph API or Portal", + "powershellEquivalent": "Set-SPOTenant -DisableAddShortcutsToOneDrive $true or $false", "recommendedBy": [] }, { "name": "standards.SPSyncButtonState", "cat": "SharePoint Standards", "tag": ["mediumimpact"], - "helpText": "If disabled users in the tenant will no longer be able to use the Sync button to sync SharePoint content. However, existing synced content will remain functional on the user's computer.", + "helpText": "If disabled, users in the tenant will no longer be able to use the Sync button to sync SharePoint content on all sites. However, existing synced content will remain functional on the user's computer.", "addedComponent": [ { "type": "Select", @@ -2116,7 +2127,7 @@ "label": "Set SharePoint sync button state", "impact": "Medium Impact", "impactColour": "warning", - "powershellEquivalent": "Set-SPOTenant -HideSyncButtonOnTeamSite:$true or $false", + "powershellEquivalent": "Set-SPOTenant -HideSyncButtonOnTeamSite $true or $false", "recommendedBy": [] }, { From 4b12ee52753405687e448b64d11bc66cfe55da23 Mon Sep 17 00:00:00 2001 From: Esco Date: Fri, 19 Jul 2024 13:26:53 +0200 Subject: [PATCH 008/130] Added List Malware Filters --- src/_nav.jsx | 5 + src/importsMap.jsx | 1 + src/routes.json | 6 + .../email-exchange/reports/MalwareFilters.jsx | 207 ++++++++++++++++++ 4 files changed, 219 insertions(+) create mode 100644 src/views/email-exchange/reports/MalwareFilters.jsx diff --git a/src/_nav.jsx b/src/_nav.jsx index a3910a2f0018..aefc705355c0 100644 --- a/src/_nav.jsx +++ b/src/_nav.jsx @@ -793,6 +793,11 @@ const _nav = [ name: 'Phishing Policies', to: '/email/reports/phishing-policies', }, + { + component: CNavItem, + name: 'Malware Filters', + to: '/email/reports/malware-filters', + }, { component: CNavItem, name: 'Shared Mailbox with Enabled Account', diff --git a/src/importsMap.jsx b/src/importsMap.jsx index a8435a662dbd..6af8bac51461 100644 --- a/src/importsMap.jsx +++ b/src/importsMap.jsx @@ -134,6 +134,7 @@ import React from 'react' "/email/reports/message-trace": React.lazy(() => import('./views/email-exchange/reports/MessageTrace')), "/cipp/user-settings": React.lazy(() => import('./views/cipp/UserSettings')), "/email/reports/phishing-policies": React.lazy(() => import('./views/email-exchange/reports/PhishingPoliciesList')), + "/email/reports/malware-filters": React.lazy(() => import('./views/email-exchange/reports/MalwareFilters')), "/security/incidents/list-alerts": React.lazy(() => import('./views/security/incidents/ListAlerts')), "/security/incidents/list-incidents": React.lazy(() => import('./views/security/incidents/ListIncidents')), "/security/reports/list-device-compliance": React.lazy(() => import('./views/security/reports/ListDeviceComplianceReport')), diff --git a/src/routes.json b/src/routes.json index 9817ebc8aabd..5ae6152f0bd7 100644 --- a/src/routes.json +++ b/src/routes.json @@ -895,6 +895,12 @@ "component": "views/email-exchange/reports/PhishingPoliciesList", "allowedRoles": ["admin", "editor", "readonly"] }, + { + "path": "/email/reports/malware-filters", + "name": "Malware Filters", + "component": "views/email-exchange/reports/MalwareFilters", + "allowedRoles": ["admin", "editor", "readonly"] + }, { "name": "Security & Compliance", "path": "/security", diff --git a/src/views/email-exchange/reports/MalwareFilters.jsx b/src/views/email-exchange/reports/MalwareFilters.jsx new file mode 100644 index 000000000000..e77053c5be99 --- /dev/null +++ b/src/views/email-exchange/reports/MalwareFilters.jsx @@ -0,0 +1,207 @@ +import { useSelector } from 'react-redux' +import { CippPageList } from 'src/components/layout' +import { cellDateFormatter, cellBooleanFormatter, CellTip } from 'src/components/tables' +import { cellTableFormatter } from 'src/components/tables/CellTable' + +const ListMalwareFilters = () => { + const tenant = useSelector((state) => state.app.currentTenant) + + const Offcanvas = (row, rowIndex, formatExtraData) => { + const [ocVisible, setOCVisible] = useState(false) + + return ( + <> + setOCVisible(true)}> + + + , + modal: true, + modalUrl: `/api/EditMalwareFilter?State=Enable&TenantFilter=${tenant.defaultDomainName}&RuleName=${row.RuleName}`, + modalMessage: 'Are you sure you want to enable this rule?', + }, + { + label: 'Disable Rule', + color: 'info', + icon: , + modal: true, + modalUrl: `/api/EditMalwareFilter?State=Disable&TenantFilter=${tenant.defaultDomainName}&RuleName=${row.RuleName}`, + modalMessage: 'Are you sure you want to disable this rule?', + }, + /*{ + label: 'Delete Rule', + color: 'danger', + modal: true, + icon: , + modalUrl: `/api/RemoveMalwareFilter?TenantFilter=${tenant.defaultDomainName}&RuleName=${row.RuleName}`, + modalMessage: 'Are you sure you want to delete this rule?', + },*/ + ]} + placement="end" + visible={ocVisible} + id={row.id} + hideFunction={() => setOCVisible(false)} + /> + + ) + } + + const columns = [ + { + name: 'Rule Name', + selector: (row) => row['RuleName'], + sortable: true, + exportSelector: 'RuleName', + }, + { + name: 'Policy Name', + selector: (row) => row['Name'], + sortable: true, + exportSelector: 'Name', + }, + { + name: 'Enabled', + selector: (row) => row['State'], + exportSelector: 'State', + cell: cellBooleanFormatter(), + maxWidth: '40px', + }, + { + name: 'Priority', + selector: (row) => row['Priority'], + sortable: true, + exportSelector: 'Priority', + maxWidth: '40px', + }, + { + name: 'Recipient Domains', + selector: (row) => row['RecipientDomainIs'], + sortable: true, + exportSelector: 'RecipientDomainIs', + cell: cellTableFormatter('RecipientDomainIs'), + }, + { + name: 'File Filter', + selector: (row) => row['EnableFileFilter'], + exportSelector: 'EnableFileFilter', + cell: cellBooleanFormatter(), + maxWidth: '40px', + }, + { + name: 'File Types', + selector: (row) => row['FileTypes'], + sortable: true, + exportSelector: 'FileTypes', + cell: cellTableFormatter('FileTypes'), + }, + { + name: 'File Type Action', + selector: (row) => row['FileTypeAction'], + sortable: true, + exportSelector: 'FileTypeAction', + maxWidth: '200px', + }, + { + name: 'Zap', + selector: (row) => row['ZapEnabled'], + exportSelector: 'ZapEnabled', + cell: cellBooleanFormatter(), + maxWidth: '40px', + }, + { + name: 'Quarantine Tag', + selector: (row) => row['QuarantineTag'], + sortable: true, + exportSelector: 'QuarantineTag', + maxWidth: '200px', + }, + { + name: 'Internal Admin Notifications', + selector: (row) => row['EnableInternalSenderAdminNotifications'], + exportSelector: 'EnableInternalSenderAdminNotifications', + cell: cellBooleanFormatter(), + maxWidth: '40px', + }, + { + name: 'Internal Sender Admin Address', + selector: (row) => row['InternalSenderAdminAddress'], + sortable: true, + exportSelector: 'InternalSenderAdminAddress', + }, + { + name: 'External Admin Notifications', + selector: (row) => row['EnableExternalSenderAdminNotifications'], + exportSelector: 'EnableExternalSenderAdminNotifications', + cell: cellBooleanFormatter(), + maxWidth: '40px', + }, + { + name: 'External Sender Admin Address', + selector: (row) => row['ExternalSenderAdminAddress'], + sortable: true, + exportSelector: 'ExternalSenderAdminAddress', + }, + { + name: 'Creation Date', + selector: (row) => row['WhenCreated'], + sortable: true, + exportSelector: 'WhenCreated', + cell: cellDateFormatter(), + maxWidth: '150px', + }, + { + name: 'Last Modified Date', + selector: (row) => row['WhenChanged'], + sortable: true, + exportSelector: 'WhenChanged', + cell: cellDateFormatter(), + maxWidth: '150px', + }, + ] + + return ( + <> + + + ) +} + +export default ListMalwareFilters From 9b4206e32e6ddd6ae69388c2d7fc2bb0c3cdda75 Mon Sep 17 00:00:00 2001 From: Esco Date: Wed, 24 Jul 2024 14:54:16 +0200 Subject: [PATCH 009/130] Added List SafeLinks Filters --- src/_nav.jsx | 5 + src/importsMap.jsx | 1 + src/routes.json | 6 + .../reports/SafeLinksFilters.jsx | 216 ++++++++++++++++++ 4 files changed, 228 insertions(+) create mode 100644 src/views/email-exchange/reports/SafeLinksFilters.jsx diff --git a/src/_nav.jsx b/src/_nav.jsx index aefc705355c0..5b6e8cb0e6c5 100644 --- a/src/_nav.jsx +++ b/src/_nav.jsx @@ -798,6 +798,11 @@ const _nav = [ name: 'Malware Filters', to: '/email/reports/malware-filters', }, + { + component: CNavItem, + name: 'Safe Links Filters', + to: '/email/reports/safelinks-filters', + }, { component: CNavItem, name: 'Shared Mailbox with Enabled Account', diff --git a/src/importsMap.jsx b/src/importsMap.jsx index 6af8bac51461..3990a1551623 100644 --- a/src/importsMap.jsx +++ b/src/importsMap.jsx @@ -135,6 +135,7 @@ import React from 'react' "/cipp/user-settings": React.lazy(() => import('./views/cipp/UserSettings')), "/email/reports/phishing-policies": React.lazy(() => import('./views/email-exchange/reports/PhishingPoliciesList')), "/email/reports/malware-filters": React.lazy(() => import('./views/email-exchange/reports/MalwareFilters')), + "/email/reports/safelinks-filters": React.lazy(() => import('./views/email-exchange/reports/SafeLinksFilters')), "/security/incidents/list-alerts": React.lazy(() => import('./views/security/incidents/ListAlerts')), "/security/incidents/list-incidents": React.lazy(() => import('./views/security/incidents/ListIncidents')), "/security/reports/list-device-compliance": React.lazy(() => import('./views/security/reports/ListDeviceComplianceReport')), diff --git a/src/routes.json b/src/routes.json index 5ae6152f0bd7..16cfe3e8268c 100644 --- a/src/routes.json +++ b/src/routes.json @@ -901,6 +901,12 @@ "component": "views/email-exchange/reports/MalwareFilters", "allowedRoles": ["admin", "editor", "readonly"] }, + { + "path": "/email/reports/safelinks-filters", + "name": "Safe Links Filters", + "component": "views/email-exchange/reports/SafeLinksFilters", + "allowedRoles": ["admin", "editor", "readonly"] + }, { "name": "Security & Compliance", "path": "/security", diff --git a/src/views/email-exchange/reports/SafeLinksFilters.jsx b/src/views/email-exchange/reports/SafeLinksFilters.jsx new file mode 100644 index 000000000000..122526e52352 --- /dev/null +++ b/src/views/email-exchange/reports/SafeLinksFilters.jsx @@ -0,0 +1,216 @@ +import { useSelector } from 'react-redux' +import { CippPageList } from 'src/components/layout' +import { cellDateFormatter, cellBooleanFormatter, CellTip } from 'src/components/tables' +import { cellTableFormatter } from 'src/components/tables/CellTable' + +const ListSafeLinksFilters = () => { + const tenant = useSelector((state) => state.app.currentTenant) + + const Offcanvas = (row, rowIndex, formatExtraData) => { + const [ocVisible, setOCVisible] = useState(false) + + return ( + <> + setOCVisible(true)}> + + + , + modal: true, + modalUrl: `/api/EditSafeLinksFilter?State=Enable&TenantFilter=${tenant.defaultDomainName}&RuleName=${row.RuleName}`, + modalMessage: 'Are you sure you want to enable this rule?', + }, + { + label: 'Disable Rule', + color: 'info', + icon: , + modal: true, + modalUrl: `/api/EditSafeLinksFilter?State=Disable&TenantFilter=${tenant.defaultDomainName}&RuleName=${row.RuleName}`, + modalMessage: 'Are you sure you want to disable this rule?', + }, + /*{ + label: 'Delete Rule', + color: 'danger', + modal: true, + icon: , + modalUrl: `/api/RemoveSafeLinksFilter?TenantFilter=${tenant.defaultDomainName}&RuleName=${row.RuleName}`, + modalMessage: 'Are you sure you want to delete this rule?', + },*/ + ]} + placement="end" + visible={ocVisible} + id={row.id} + hideFunction={() => setOCVisible(false)} + /> + + ) + } + + const columns = [ + { + name: 'Rule Name', + selector: (row) => row['RuleName'], + sortable: true, + exportSelector: 'RuleName', + }, + { + name: 'Policy Name', + selector: (row) => row['Name'], + sortable: true, + exportSelector: 'Name', + }, + { + name: 'Enabled', + selector: (row) => row['State'], + exportSelector: 'State', + cell: cellBooleanFormatter(), + maxWidth: '40px', + }, + { + name: 'Priority', + selector: (row) => row['Priority'], + sortable: true, + exportSelector: 'Priority', + maxWidth: '40px', + }, + { + name: 'Recipient Domains', + selector: (row) => row['RecipientDomainIs'], + sortable: true, + exportSelector: 'RecipientDomainIs', + cell: cellTableFormatter('RecipientDomainIs'), + }, + { + name: 'SafeLinks For Email', + selector: (row) => row['EnableSafeLinksForEmail'], + exportSelector: 'EnableSafeLinksForEmail', + cell: cellBooleanFormatter(), + maxWidth: '40px', + }, + { + name: 'SafeLinks For Teams', + selector: (row) => row['EnableSafeLinksForTeams'], + exportSelector: 'EnableSafeLinksForTeams', + cell: cellBooleanFormatter(), + maxWidth: '40px', + }, + { + name: 'SafeLinks For Office', + selector: (row) => row['EnableSafeLinksForOffice'], + exportSelector: 'EnableSafeLinksForOffice', + cell: cellBooleanFormatter(), + maxWidth: '40px', + }, + { + name: 'Track Clicks', + selector: (row) => row['TrackClicks'], + exportSelector: 'TrackClicks', + cell: cellBooleanFormatter(), + maxWidth: '40px', + }, + { + name: 'Scan Urls', + selector: (row) => row['ScanUrls'], + exportSelector: 'ScanUrls', + cell: cellBooleanFormatter(), + maxWidth: '40px', + }, + { + name: 'Enable For Internal Senders', + selector: (row) => row['EnableForInternalSenders'], + exportSelector: 'EnableForInternalSenders', + cell: cellBooleanFormatter(), + maxWidth: '40px', + }, + { + name: 'Deliver Message After Scan', + selector: (row) => row['DeliverMessageAfterScan'], + exportSelector: 'DeliverMessageAfterScan', + cell: cellBooleanFormatter(), + maxWidth: '40px', + }, + { + name: 'Allow Click Through', + selector: (row) => row['AllowClickThrough'], + exportSelector: 'AllowClickThrough', + cell: cellBooleanFormatter(), + maxWidth: '40px', + }, + { + name: 'Disable Url Rewrite', + selector: (row) => row['DisableUrlRewrite'], + exportSelector: 'DisableUrlRewrite', + cell: cellBooleanFormatter(), + maxWidth: '40px', + }, + { + name: 'Organization Branding', + selector: (row) => row['EnableOrganizationBranding'], + exportSelector: 'EnableOrganizationBranding', + cell: cellBooleanFormatter(), + maxWidth: '40px', + }, + { + name: 'Creation Date', + selector: (row) => row['WhenCreated'], + sortable: true, + exportSelector: 'WhenCreated', + cell: cellDateFormatter(), + maxWidth: '150px', + }, + { + name: 'Last Modified Date', + selector: (row) => row['WhenChanged'], + sortable: true, + exportSelector: 'WhenChanged', + cell: cellDateFormatter(), + maxWidth: '150px', + }, + ] + + return ( + <> + + + ) +} + +export default ListSafeLinksFilters From 516cc8cb9ce2ad5de103900d4d1269d8ca4f3f2d Mon Sep 17 00:00:00 2001 From: Esco Date: Thu, 25 Jul 2024 09:25:29 +0200 Subject: [PATCH 010/130] Added List SafeAttachment Filters --- src/_nav.jsx | 5 + src/importsMap.jsx | 1 + src/routes.json | 6 + .../reports/SafeAttachmentsFilters.jsx | 171 ++++++++++++++++++ 4 files changed, 183 insertions(+) create mode 100644 src/views/email-exchange/reports/SafeAttachmentsFilters.jsx diff --git a/src/_nav.jsx b/src/_nav.jsx index 5b6e8cb0e6c5..08a5f65d3e7f 100644 --- a/src/_nav.jsx +++ b/src/_nav.jsx @@ -803,6 +803,11 @@ const _nav = [ name: 'Safe Links Filters', to: '/email/reports/safelinks-filters', }, + { + component: CNavItem, + name: 'Safe Attachments Filters', + to: '/email/reports/safeattachments-filters', + }, { component: CNavItem, name: 'Shared Mailbox with Enabled Account', diff --git a/src/importsMap.jsx b/src/importsMap.jsx index 3990a1551623..af1f13be9479 100644 --- a/src/importsMap.jsx +++ b/src/importsMap.jsx @@ -136,6 +136,7 @@ import React from 'react' "/email/reports/phishing-policies": React.lazy(() => import('./views/email-exchange/reports/PhishingPoliciesList')), "/email/reports/malware-filters": React.lazy(() => import('./views/email-exchange/reports/MalwareFilters')), "/email/reports/safelinks-filters": React.lazy(() => import('./views/email-exchange/reports/SafeLinksFilters')), + "/email/reports/safeattachments-filters": React.lazy(() => import('./views/email-exchange/reports/SafeAttachmentsFilters')), "/security/incidents/list-alerts": React.lazy(() => import('./views/security/incidents/ListAlerts')), "/security/incidents/list-incidents": React.lazy(() => import('./views/security/incidents/ListIncidents')), "/security/reports/list-device-compliance": React.lazy(() => import('./views/security/reports/ListDeviceComplianceReport')), diff --git a/src/routes.json b/src/routes.json index 16cfe3e8268c..c814a8bff979 100644 --- a/src/routes.json +++ b/src/routes.json @@ -907,6 +907,12 @@ "component": "views/email-exchange/reports/SafeLinksFilters", "allowedRoles": ["admin", "editor", "readonly"] }, + { + "path": "/email/reports/safeattachments-filters", + "name": "Safe Attachment Filters", + "component": "views/email-exchange/reports/SafeAttachmentsFilters", + "allowedRoles": ["admin", "editor", "readonly"] + }, { "name": "Security & Compliance", "path": "/security", diff --git a/src/views/email-exchange/reports/SafeAttachmentsFilters.jsx b/src/views/email-exchange/reports/SafeAttachmentsFilters.jsx new file mode 100644 index 000000000000..43248aefdf32 --- /dev/null +++ b/src/views/email-exchange/reports/SafeAttachmentsFilters.jsx @@ -0,0 +1,171 @@ +import { useSelector } from 'react-redux' +import { CippPageList } from 'src/components/layout' +import { cellDateFormatter, cellBooleanFormatter, CellTip } from 'src/components/tables' +import { cellTableFormatter } from 'src/components/tables/CellTable' + +const ListSafeAttachmentsFilters = () => { + const tenant = useSelector((state) => state.app.currentTenant) + + const Offcanvas = (row, rowIndex, formatExtraData) => { + const [ocVisible, setOCVisible] = useState(false) + + return ( + <> + setOCVisible(true)}> + + + , + modal: true, + modalUrl: `/api/EditSafeAttachmentsFilter?State=Enable&TenantFilter=${tenant.defaultDomainName}&RuleName=${row.RuleName}`, + modalMessage: 'Are you sure you want to enable this rule?', + }, + { + label: 'Disable Rule', + color: 'info', + icon: , + modal: true, + modalUrl: `/api/EditSafeAttachmentsFilter?State=Disable&TenantFilter=${tenant.defaultDomainName}&RuleName=${row.RuleName}`, + modalMessage: 'Are you sure you want to disable this rule?', + }, + /*{ + label: 'Delete Rule', + color: 'danger', + modal: true, + icon: , + modalUrl: `/api/RemoveSafeAttachmentsFilter?TenantFilter=${tenant.defaultDomainName}&RuleName=${row.RuleName}`, + modalMessage: 'Are you sure you want to delete this rule?', + },*/ + ]} + placement="end" + visible={ocVisible} + id={row.id} + hideFunction={() => setOCVisible(false)} + /> + + ) + } + + const columns = [ + { + name: 'Rule Name', + selector: (row) => row['RuleName'], + sortable: true, + exportSelector: 'RuleName', + }, + { + name: 'Policy Name', + selector: (row) => row['Name'], + sortable: true, + exportSelector: 'Name', + }, + { + name: 'Enabled', + selector: (row) => row['State'], + exportSelector: 'State', + cell: cellBooleanFormatter(), + maxWidth: '40px', + }, + { + name: 'Priority', + selector: (row) => row['Priority'], + sortable: true, + exportSelector: 'Priority', + maxWidth: '40px', + }, + { + name: 'Recipient Domains', + selector: (row) => row['RecipientDomainIs'], + sortable: true, + exportSelector: 'RecipientDomainIs', + cell: cellTableFormatter('RecipientDomainIs'), + }, + { + name: 'Action', + selector: (row) => row['Action'], + sortable: true, + exportSelector: 'Action', + }, + { + name: 'QuarantineTag', + selector: (row) => row['QuarantineTag'], + sortable: true, + exportSelector: 'QuarantineTag', + }, + { + name: 'Redirect', + selector: (row) => row['Redirect'], + exportSelector: 'Redirect', + cell: cellBooleanFormatter(), + maxWidth: '40px', + }, + { + name: 'Redirect Address', + selector: (row) => row['RedirectAddress'], + sortable: true, + exportSelector: 'RedirectAddress', + }, + { + name: 'Creation Date', + selector: (row) => row['WhenCreated'], + sortable: true, + exportSelector: 'WhenCreated', + cell: cellDateFormatter(), + maxWidth: '150px', + }, + { + name: 'Last Modified Date', + selector: (row) => row['WhenChanged'], + sortable: true, + exportSelector: 'WhenChanged', + cell: cellDateFormatter(), + maxWidth: '150px', + }, + ] + + return ( + <> + + + ) +} + +export default ListSafeAttachmentsFilters From 5d0916931bbddcb80f23fcd34f140e285600725f Mon Sep 17 00:00:00 2001 From: Esco Date: Thu, 25 Jul 2024 10:08:57 +0200 Subject: [PATCH 011/130] Updated List AntiPhishing Filters --- src/_nav.jsx | 4 +- src/importsMap.jsx | 2 +- src/routes.json | 6 +- .../reports/AntiPhishingFilters.jsx | 283 ++++++++++++++++++ .../reports/PhishingPoliciesList.jsx | 73 ----- 5 files changed, 289 insertions(+), 79 deletions(-) create mode 100644 src/views/email-exchange/reports/AntiPhishingFilters.jsx delete mode 100644 src/views/email-exchange/reports/PhishingPoliciesList.jsx diff --git a/src/_nav.jsx b/src/_nav.jsx index 08a5f65d3e7f..c0faa91279c0 100644 --- a/src/_nav.jsx +++ b/src/_nav.jsx @@ -790,8 +790,8 @@ const _nav = [ }, { component: CNavItem, - name: 'Phishing Policies', - to: '/email/reports/phishing-policies', + name: 'Anti-Phishing Filters', + to: '/email/reports/antiphishing-filters', }, { component: CNavItem, diff --git a/src/importsMap.jsx b/src/importsMap.jsx index af1f13be9479..eaa260ad4dbd 100644 --- a/src/importsMap.jsx +++ b/src/importsMap.jsx @@ -133,7 +133,7 @@ import React from 'react' "/email/reports/mailbox-cas-settings": React.lazy(() => import('./views/email-exchange/reports/MailboxClientAccessSettingsList')), "/email/reports/message-trace": React.lazy(() => import('./views/email-exchange/reports/MessageTrace')), "/cipp/user-settings": React.lazy(() => import('./views/cipp/UserSettings')), - "/email/reports/phishing-policies": React.lazy(() => import('./views/email-exchange/reports/PhishingPoliciesList')), + "/email/reports/antiphishing-filters": React.lazy(() => import('./views/email-exchange/reports/AntiPhishingFilters')), "/email/reports/malware-filters": React.lazy(() => import('./views/email-exchange/reports/MalwareFilters')), "/email/reports/safelinks-filters": React.lazy(() => import('./views/email-exchange/reports/SafeLinksFilters')), "/email/reports/safeattachments-filters": React.lazy(() => import('./views/email-exchange/reports/SafeAttachmentsFilters')), diff --git a/src/routes.json b/src/routes.json index c814a8bff979..f5b6053359a7 100644 --- a/src/routes.json +++ b/src/routes.json @@ -890,9 +890,9 @@ "allowedRoles": ["admin", "editor", "readonly"] }, { - "name": "Phishing Policies", - "path": "/email/reports/phishing-policies", - "component": "views/email-exchange/reports/PhishingPoliciesList", + "path": "/email/reports/antiphishing-filters", + "name": "Anti Phishing Filters", + "component": "views/email-exchange/reports/AntiPhishingFilters", "allowedRoles": ["admin", "editor", "readonly"] }, { diff --git a/src/views/email-exchange/reports/AntiPhishingFilters.jsx b/src/views/email-exchange/reports/AntiPhishingFilters.jsx new file mode 100644 index 000000000000..b9be79b8d074 --- /dev/null +++ b/src/views/email-exchange/reports/AntiPhishingFilters.jsx @@ -0,0 +1,283 @@ +import { useSelector } from 'react-redux' +import { CippPageList } from 'src/components/layout' +import { cellDateFormatter, cellBooleanFormatter, CellTip } from 'src/components/tables' +import { cellTableFormatter } from 'src/components/tables/CellTable' + +const ListAntiPhishingFilters = () => { + const tenant = useSelector((state) => state.app.currentTenant) + + const Offcanvas = (row, rowIndex, formatExtraData) => { + const [ocVisible, setOCVisible] = useState(false) + + return ( + <> + setOCVisible(true)}> + + + , + modal: true, + modalUrl: `/api/EditAntiPhishingFilter?State=Enable&TenantFilter=${tenant.defaultDomainName}&RuleName=${row.RuleName}`, + modalMessage: 'Are you sure you want to enable this rule?', + }, + { + label: 'Disable Rule', + color: 'info', + icon: , + modal: true, + modalUrl: `/api/EditAntiPhishingFilter?State=Disable&TenantFilter=${tenant.defaultDomainName}&RuleName=${row.RuleName}`, + modalMessage: 'Are you sure you want to disable this rule?', + }, + /*{ + label: 'Delete Rule', + color: 'danger', + modal: true, + icon: , + modalUrl: `/api/RemoveAntiPhishingFilter?TenantFilter=${tenant.defaultDomainName}&RuleName=${row.RuleName}`, + modalMessage: 'Are you sure you want to delete this rule?', + },*/ + ]} + placement="end" + visible={ocVisible} + id={row.id} + hideFunction={() => setOCVisible(false)} + /> + + ) + } + + const columns = [ + { + name: 'Rule Name', + selector: (row) => row['RuleName'], + sortable: true, + exportSelector: 'RuleName', + }, + { + name: 'Policy Name', + selector: (row) => row['Name'], + sortable: true, + exportSelector: 'Name', + }, + { + name: 'Enabled', + selector: (row) => row['State'], + exportSelector: 'State', + cell: cellBooleanFormatter(), + maxWidth: '40px', + }, + { + name: 'Priority', + selector: (row) => row['Priority'], + sortable: true, + exportSelector: 'Priority', + maxWidth: '40px', + }, + { + name: 'Recipient Domains', + selector: (row) => row['RecipientDomainIs'], + sortable: true, + exportSelector: 'RecipientDomainIs', + cell: cellTableFormatter('RecipientDomainIs'), + }, + { + name: 'Excluded Domains', + selector: (row) => row['ExcludedDomains'], + sortable: true, + exportSelector: 'ExcludedDomains', + cell: cellTableFormatter('ExcludedDomains'), + }, + { + name: 'Excluded Senders', + selector: (row) => row['ExcludedSenders'], + sortable: true, + exportSelector: 'ExcludedSenders', + cell: cellTableFormatter('ExcludedSenders'), + }, + { + name: 'PhishThresholdLevel', + selector: (row) => row['PhishThresholdLevel'], + sortable: true, + exportSelector: 'PhishThresholdLevel', + }, + { + name: 'Mailbox Intelligence', + selector: (row) => row['EnableMailboxIntelligence'], + exportSelector: 'EnableMailboxIntelligence', + cell: cellBooleanFormatter(), + maxWidth: '40px', + }, + { + name: 'Mailbox Intelligence Protection', + selector: (row) => row['EnableMailboxIntelligenceProtection'], + exportSelector: 'EnableMailboxIntelligenceProtection', + cell: cellBooleanFormatter(), + maxWidth: '40px', + }, + { + name: 'Spoof Intelligence', + selector: (row) => row['EnableSpoofIntelligence'], + exportSelector: 'EnableSpoofIntelligence', + cell: cellBooleanFormatter(), + maxWidth: '40px', + }, + { + name: 'First Contact Safety Tips', + selector: (row) => row['EnableFirstContactSafetyTips'], + exportSelector: 'EnableFirstContactSafetyTips', + cell: cellBooleanFormatter(), + maxWidth: '40px', + }, + { + name: 'Similar Users Safety Tips', + selector: (row) => row['EnableSimilarUsersSafetyTips'], + exportSelector: 'EnableSimilarUsersSafetyTips', + cell: cellBooleanFormatter(), + maxWidth: '40px', + }, + { + name: 'Similar Domain Safety Tips', + selector: (row) => row['EnableSimilarDomainsSafetyTips'], + exportSelector: 'EnableSimilarDomainsSafetyTips', + cell: cellBooleanFormatter(), + maxWidth: '40px', + }, + { + name: 'Unusual Characters Safety Tips', + selector: (row) => row['EnableUnusualCharactersSafetyTips'], + exportSelector: 'EnableUnusualCharactersSafetyTips', + cell: cellBooleanFormatter(), + maxWidth: '40px', + }, + { + name: 'Unauthenticated Sender', + selector: (row) => row['EnableUnauthenticatedSender'], + exportSelector: 'EnableUnauthenticatedSender', + cell: cellBooleanFormatter(), + maxWidth: '40px', + }, + { + name: 'ViaTag', + selector: (row) => row['EnableViaTag'], + exportSelector: 'EnableViaTag', + cell: cellBooleanFormatter(), + maxWidth: '40px', + }, + { + name: 'Organization Domains Protection', + selector: (row) => row['EnableOrganizationDomainsProtection'], + exportSelector: 'EnableOrganizationDomainsProtection', + cell: cellBooleanFormatter(), + }, + { + name: 'Authentication Fail Action', + selector: (row) => row['AuthenticationFailAction'], + exportSelector: 'AuthenticationFailAction', + maxWidt: '100px', + }, + { + name: 'Spoof Quarantine Tag', + selector: (row) => row['SpoofQuarantineTag'], + exportSelector: 'SpoofQuarantineTag', + maxWidth: '100px', + }, + { + name: 'MailboxIntelligence Protection Action', + selector: (row) => row['MailboxIntelligenceProtectionAction'], + exportSelector: 'MailboxIntelligenceProtectionAction', + maxWidth: '100px', + }, + { + name: 'Mailbox Intelligence Quarantine Tag', + selector: (row) => row['MailboxIntelligenceQuarantineTag'], + exportSelector: 'MailboxIntelligenceQuarantineTag', + maxWidth: '100px', + }, + { + name: 'Targeted UserProtection Action', + selector: (row) => row['TargetedUserProtectionAction'], + exportSelector: 'TargetedUserProtectionAction', + maxWidth: '100px', + }, + { + name: 'Targeted UserQuarantine Tag', + selector: (row) => row['TargetedUserQuarantineTag'], + exportSelector: 'TargetedUserQuarantineTag', + maxWidth: '100px', + }, + { + name: 'Targeted Domain Protection Action', + selector: (row) => row['TargetedDomainProtectionAction'], + exportSelector: 'TargetedDomainProtectionAction', + maxWidth: '100px', + }, + { + name: 'Targeted Domain Quarantine Tag', + selector: (row) => row['TargetedDomainQuarantineTag'], + exportSelector: 'TargetedDomainQuarantineTag', + maxWidth: '100px', + }, + { + name: 'Creation Date', + selector: (row) => row['WhenCreated'], + sortable: true, + exportSelector: 'WhenCreated', + cell: cellDateFormatter(), + maxWidth: '150px', + }, + { + name: 'Last Modified Date', + selector: (row) => row['WhenChanged'], + sortable: true, + exportSelector: 'WhenChanged', + cell: cellDateFormatter(), + maxWidth: '150px', + }, + ] + + return ( + <> + + + ) +} + +export default ListAntiPhishingFilters diff --git a/src/views/email-exchange/reports/PhishingPoliciesList.jsx b/src/views/email-exchange/reports/PhishingPoliciesList.jsx deleted file mode 100644 index b4cd5ba23a01..000000000000 --- a/src/views/email-exchange/reports/PhishingPoliciesList.jsx +++ /dev/null @@ -1,73 +0,0 @@ -import React from 'react' -import { useSelector } from 'react-redux' -import { CippPageList } from 'src/components/layout/CippPage' -import { cellBooleanFormatter, cellDateFormatter } from 'src/components/tables' - -//TODO: Add CellBoolean -const columns = [ - { - selector: (row) => row['Name'], - name: 'Name', - sortable: true, - exportSelector: 'Name', - }, - { - selector: (row) => row['PhishThresholdLevel'], - name: 'Phish Threshold Level', - sortable: true, - exportSelector: 'PhishThresholdLevel', - }, - { - selector: (row) => row['Enabled'], - name: 'Enabled', - sortable: true, - cell: cellBooleanFormatter({ warning: true, colourless: true }), - exportSelector: 'Enabled', - }, - { - selector: (row) => row['ExcludedSenders'], - name: 'Excluded Senders', - sortable: true, - cell: cellBooleanFormatter({ warning: true, colourless: true, noDataIsFalse: true }), - exportSelector: 'ExcludedSenders', - }, - { - selector: (row) => row['ExcludedDomains'], - name: 'Excluded Domains', - sortable: true, - cell: cellBooleanFormatter(), - exportSelector: 'ExcludedDomains', - }, - { - selector: (row) => row['WhenChangedUTC'], - name: 'Last Change Date (Local)', - sortable: true, - cell: cellDateFormatter(), - exportSelector: 'WhenChangedUTC', - }, - { - selector: (row) => row['Priority'], - name: 'Priority', - sortable: true, - exportSelector: 'Priority', - }, -] - -const MailboxList = () => { - const tenant = useSelector((state) => state.app.currentTenant) - - return ( - - ) -} - -export default MailboxList From d4e642c315c39959391367dffc7a71404a627386 Mon Sep 17 00:00:00 2001 From: Esco Date: Thu, 25 Jul 2024 11:17:38 +0200 Subject: [PATCH 012/130] Added Edit Safe AttachmentsFilter --- .../email-exchange/reports/SafeAttachmentsFilters.jsx | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/views/email-exchange/reports/SafeAttachmentsFilters.jsx b/src/views/email-exchange/reports/SafeAttachmentsFilters.jsx index 43248aefdf32..a9257edfd7e4 100644 --- a/src/views/email-exchange/reports/SafeAttachmentsFilters.jsx +++ b/src/views/email-exchange/reports/SafeAttachmentsFilters.jsx @@ -1,3 +1,8 @@ +import { CButton } from '@coreui/react' +import { faBan, faBook, faCheck, faEllipsisV, faTrash } from '@fortawesome/free-solid-svg-icons' +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' +import React, { useState } from 'react' +import { CippActionsOffcanvas } from 'src/components/utilities' import { useSelector } from 'react-redux' import { CippPageList } from 'src/components/layout' import { cellDateFormatter, cellBooleanFormatter, CellTip } from 'src/components/tables' @@ -148,6 +153,11 @@ const ListSafeAttachmentsFilters = () => { cell: cellDateFormatter(), maxWidth: '150px', }, + { + name: 'Actions', + cell: Offcanvas, + maxWidth: '80px', + }, ] return ( From 6f70b2cf8f0617f17cccbed612d86f71ceabe5c1 Mon Sep 17 00:00:00 2001 From: Esco Date: Thu, 25 Jul 2024 12:30:32 +0200 Subject: [PATCH 013/130] Added Edit Anti-Phishing Filter --- .../email-exchange/reports/AntiPhishingFilters.jsx | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/views/email-exchange/reports/AntiPhishingFilters.jsx b/src/views/email-exchange/reports/AntiPhishingFilters.jsx index b9be79b8d074..ed68929c2005 100644 --- a/src/views/email-exchange/reports/AntiPhishingFilters.jsx +++ b/src/views/email-exchange/reports/AntiPhishingFilters.jsx @@ -1,3 +1,8 @@ +import { CButton } from '@coreui/react' +import { faBan, faBook, faCheck, faEllipsisV, faTrash } from '@fortawesome/free-solid-svg-icons' +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' +import React, { useState } from 'react' +import { CippActionsOffcanvas } from 'src/components/utilities' import { useSelector } from 'react-redux' import { CippPageList } from 'src/components/layout' import { cellDateFormatter, cellBooleanFormatter, CellTip } from 'src/components/tables' @@ -260,6 +265,11 @@ const ListAntiPhishingFilters = () => { cell: cellDateFormatter(), maxWidth: '150px', }, + { + name: 'Actions', + cell: Offcanvas, + maxWidth: '80px', + }, ] return ( From b4aa3dddc4b8c8a5cc94622e4d77540c0c13bb5c Mon Sep 17 00:00:00 2001 From: Esco Date: Thu, 25 Jul 2024 12:30:44 +0200 Subject: [PATCH 014/130] Added Edit Malware Filter Update SafeLinksFilters.jsx --- src/views/email-exchange/reports/MalwareFilters.jsx | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/views/email-exchange/reports/MalwareFilters.jsx b/src/views/email-exchange/reports/MalwareFilters.jsx index e77053c5be99..ebd9d5ad354c 100644 --- a/src/views/email-exchange/reports/MalwareFilters.jsx +++ b/src/views/email-exchange/reports/MalwareFilters.jsx @@ -1,3 +1,8 @@ +import { CButton } from '@coreui/react' +import { faBan, faBook, faCheck, faEllipsisV, faTrash } from '@fortawesome/free-solid-svg-icons' +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' +import React, { useState } from 'react' +import { CippActionsOffcanvas } from 'src/components/utilities' import { useSelector } from 'react-redux' import { CippPageList } from 'src/components/layout' import { cellDateFormatter, cellBooleanFormatter, CellTip } from 'src/components/tables' @@ -184,6 +189,11 @@ const ListMalwareFilters = () => { cell: cellDateFormatter(), maxWidth: '150px', }, + { + name: 'Actions', + cell: Offcanvas, + maxWidth: '80px', + }, ] return ( From 9213b34c7fd92c865af801973c092527ecd1f57d Mon Sep 17 00:00:00 2001 From: Esco Date: Thu, 25 Jul 2024 12:30:54 +0200 Subject: [PATCH 015/130] Added Edit SafeLinks Filter --- src/views/email-exchange/reports/SafeLinksFilters.jsx | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/views/email-exchange/reports/SafeLinksFilters.jsx b/src/views/email-exchange/reports/SafeLinksFilters.jsx index 122526e52352..68c9d07305ff 100644 --- a/src/views/email-exchange/reports/SafeLinksFilters.jsx +++ b/src/views/email-exchange/reports/SafeLinksFilters.jsx @@ -1,3 +1,8 @@ +import { CButton } from '@coreui/react' +import { faBan, faBook, faCheck, faEllipsisV, faTrash } from '@fortawesome/free-solid-svg-icons' +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' +import React, { useState } from 'react' +import { CippActionsOffcanvas } from 'src/components/utilities' import { useSelector } from 'react-redux' import { CippPageList } from 'src/components/layout' import { cellDateFormatter, cellBooleanFormatter, CellTip } from 'src/components/tables' @@ -193,6 +198,11 @@ const ListSafeLinksFilters = () => { cell: cellDateFormatter(), maxWidth: '150px', }, + { + name: 'Actions', + cell: Offcanvas, + maxWidth: '80px', + }, ] return ( From 0d4dd6f3fd24d2a8d701bd27a0b1601346d6c500 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Thu, 25 Jul 2024 17:57:55 -0400 Subject: [PATCH 016/130] MFA report update --- src/views/identity/reports/MFAReport.jsx | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/views/identity/reports/MFAReport.jsx b/src/views/identity/reports/MFAReport.jsx index 27f09aecfa3b..7eb6859a3b07 100644 --- a/src/views/identity/reports/MFAReport.jsx +++ b/src/views/identity/reports/MFAReport.jsx @@ -3,6 +3,7 @@ import { useSelector } from 'react-redux' import { cellBooleanFormatter, CellTip } from 'src/components/tables' import { CippPageList } from 'src/components/layout' import { Row } from 'react-bootstrap' +import { cellGenericFormatter } from 'src/components/tables/CellGenericFormat' const columns = [ { @@ -57,9 +58,23 @@ const columns = [ selector: (row) => row['CoveredByCA'], name: 'Enforced via Conditional Access', sortable: true, - cell: (row) => CellTip(row['CoveredByCA']), + cell: cellGenericFormatter(), exportSelector: 'CoveredByCA', }, + { + selector: (row) => row['MFAMethods'], + name: 'MFA Methods', + sortable: true, + cell: cellGenericFormatter(), + exportSelector: 'MFAMethods', + }, + { + selector: (row) => row['CAPolicies'], + name: 'CA Policies', + sortable: true, + cell: cellGenericFormatter(), + exportSelector: 'CAPolicies', + }, ] const Altcolumns = [ From 34a75336f21626b931488cc3de1e5c8130c1d441 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Thu, 25 Jul 2024 18:20:35 -0400 Subject: [PATCH 017/130] Add remove tenant bulk action --- src/views/cipp/app-settings/SettingsTenants.jsx | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/views/cipp/app-settings/SettingsTenants.jsx b/src/views/cipp/app-settings/SettingsTenants.jsx index c425f3c1ae97..bbced7def29a 100644 --- a/src/views/cipp/app-settings/SettingsTenants.jsx +++ b/src/views/cipp/app-settings/SettingsTenants.jsx @@ -7,7 +7,7 @@ import { useLazyGenericGetRequestQuery } from 'src/store/api/app.js' import React, { useEffect, useRef } from 'react' import { ModalService, TenantSelectorMultiple } from 'src/components/utilities/index.js' import { setCurrentTenant } from 'src/store/features/app.js' -import { CAlert, CButton, CCallout, CSpinner, CTooltip } from '@coreui/react' +import { CButton, CSpinner, CTooltip } from '@coreui/react' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import { faCheckCircle, @@ -261,6 +261,16 @@ export function SettingsTenants() { modalMessage: 'Are you sure you want to reset the CPV permissions for these tenants? (This will delete the Service Principal and re-add it.)', }, + { + label: 'Remove Tenant', + modal: true, + modalType: 'POST', + modalUrl: `/api/ExecRemoveTenant`, + modalBody: { + TenantID: '!customerId', + }, + modalMessage: 'Are you sure you want to remove this tenant?', + }, ], }, isModal: true, From d03b70e65725f7d40ca34ab0a9031ef5008e202d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Fri, 26 Jul 2024 00:56:57 +0200 Subject: [PATCH 018/130] Pass userEmail to backend to use in logging --- src/views/identity/administration/UserMailboxRuleList.jsx | 5 +++-- src/views/identity/administration/ViewUser.jsx | 6 +++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/views/identity/administration/UserMailboxRuleList.jsx b/src/views/identity/administration/UserMailboxRuleList.jsx index 4ab999081ee8..ae2592866e85 100644 --- a/src/views/identity/administration/UserMailboxRuleList.jsx +++ b/src/views/identity/administration/UserMailboxRuleList.jsx @@ -10,7 +10,7 @@ const rowStyle = (row, rowIndex) => { return style } -export default function UserMailboxRuleList({ userId, tenantDomain, className = null }) { +export default function UserMailboxRuleList({ userId, userEmail, tenantDomain, className = null }) { const formatter = (cell) => CellBoolean({ cell }) const columns = [ { @@ -79,7 +79,7 @@ export default function UserMailboxRuleList({ userId, tenantDomain, className = datatable={{ reportName: 'ListUserMailboxRules', path: '/api/ListUserMailboxRules', - params: { tenantFilter: tenantDomain, userId }, + params: { tenantFilter: tenantDomain, userId, userEmail }, columns, keyField: 'id', responsive: true, @@ -93,6 +93,7 @@ export default function UserMailboxRuleList({ userId, tenantDomain, className = UserMailboxRuleList.propTypes = { userId: PropTypes.string.isRequired, + userEmail: PropTypes.string, tenantDomain: PropTypes.string.isRequired, className: PropTypes.string, } diff --git a/src/views/identity/administration/ViewUser.jsx b/src/views/identity/administration/ViewUser.jsx index ae0e44510693..72341f5cda9f 100644 --- a/src/views/identity/administration/ViewUser.jsx +++ b/src/views/identity/administration/ViewUser.jsx @@ -91,7 +91,11 @@ const ViewUser = (props) => { - + )} From b55fb5fe6b871d8625650e5f68ae36078cf2e951 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Fri, 26 Jul 2024 09:36:31 +0200 Subject: [PATCH 019/130] Reorder offboarding options --- .../identity/administration/OffboardingWizard.jsx | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/views/identity/administration/OffboardingWizard.jsx b/src/views/identity/administration/OffboardingWizard.jsx index d7008c071724..208190c00ee9 100644 --- a/src/views/identity/administration/OffboardingWizard.jsx +++ b/src/views/identity/administration/OffboardingWizard.jsx @@ -167,17 +167,17 @@ const OffboardingWizard = () => {
- - + + + + + + - - + - - - From 9f0bd38d3df0d2cdcadccd33f716bad4e820b4ba Mon Sep 17 00:00:00 2001 From: Esco Date: Fri, 26 Jul 2024 09:35:13 +0200 Subject: [PATCH 020/130] Added Optional Malware FileTypes --- src/data/standards.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/data/standards.json b/src/data/standards.json index dbcdd1f9a6c9..6c82f88d0fa1 100644 --- a/src/data/standards.json +++ b/src/data/standards.json @@ -1632,6 +1632,11 @@ } ] }, + { + "type": "input", + "name": "standards.MalwareFilterPolicy.OptionalFileTypes", + "label": "Optional File Types, Comma separated" + }, { "type": "Select", "label": "QuarantineTag", From 09481773764255758de794ababf759c0f5d417fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Fri, 26 Jul 2024 10:03:31 +0200 Subject: [PATCH 021/130] Add tags to standards --- src/data/standards.json | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/data/standards.json b/src/data/standards.json index dbcdd1f9a6c9..6866899224a4 100644 --- a/src/data/standards.json +++ b/src/data/standards.json @@ -584,7 +584,7 @@ { "name": "standards.OauthConsentLowSec", "cat": "Entra (AAD) Standards", - "tag": ["mediumimpact"], + "tag": ["mediumimpact", "IntegratedApps"], "helpText": "Sets the default oauth consent level so users can consent to applications that have low risks.", "docsDescription": "Allows users to consent to applications with low assigned risk.", "label": "Allow users to consent to applications with low security risk (Prevent OAuth phishing. Lower impact, less secure)", @@ -1336,7 +1336,8 @@ "mdo_highconfidencephishaction", "mdo_phisspamacation", "mdo_spam_notifications_only_for_admins", - "mdo_antiphishingpolicies" + "mdo_antiphishingpolicies", + "mdo_phishthresholdlevel" ], "helpText": "This creates a Anti-Phishing policy that automatically enables Mailbox Intelligence and spoofing, optional switches for Mailtips.", "addedComponent": [ @@ -2094,7 +2095,7 @@ { "name": "standards.DisableSharePointLegacyAuth", "cat": "SharePoint Standards", - "tag": ["mediumimpact", "CIS"], + "tag": ["mediumimpact", "CIS", "spo_legacy_auth"], "helpText": "Disables the ability to authenticate with SharePoint using legacy authentication methods. Any applications that use legacy authentication will need to be updated to use modern authentication.", "docsDescription": "Disables the ability for users and applications to access SharePoint via legacy basic authentication. This will likely not have any user impact, but will block systems/applications depending on basic auth or the SharePointOnlineCredentials class.", "addedComponent": [], From d98383f457bbbdafaf37d96fe4c612a62016fc3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Fri, 26 Jul 2024 13:23:49 +0200 Subject: [PATCH 022/130] Add missing options in user settings for Offboarding Defaults --- src/views/cipp/UserSettings.jsx | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/src/views/cipp/UserSettings.jsx b/src/views/cipp/UserSettings.jsx index cedc16b9e672..a7fcaa628f3e 100644 --- a/src/views/cipp/UserSettings.jsx +++ b/src/views/cipp/UserSettings.jsx @@ -156,28 +156,36 @@ const UserSettings = () => {

Offboarding Defaults

- - - - + - - - - - - + + + + + + + + + + +
From 0972e11eb8918ea7ad4841bafe1e7d9862e26af7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Fri, 26 Jul 2024 15:11:01 +0200 Subject: [PATCH 023/130] Add DisableAutoForwarding standard --- src/data/standards.json | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/data/standards.json b/src/data/standards.json index dbcdd1f9a6c9..a291df111cb8 100644 --- a/src/data/standards.json +++ b/src/data/standards.json @@ -1278,6 +1278,19 @@ "powershellEquivalent": "Get-Mailbox & Update-MgUser", "recommendedBy": ["CIS"] }, + { + "name": "standards.EXODisableAutoForwarding", + "cat": "Exchange Standards", + "tag": ["highimpact", "CIS", "mdo_autoforwardingmode", "mdo_blockmailforward"], + "helpText": "Disables the ability for users to automatically forward e-mails to external recipients.", + "docsDescription": "Disables the ability for users to automatically forward e-mails to external recipients. This is to prevent data exfiltration. Please check if there are any legitimate use cases for this feature before implementing, like forwarding invoices and such.", + "addedComponent": [], + "label": "Disable automatic forwarding to external recipients", + "impact": "High Impact", + "impactColour": "danger", + "powershellEquivalent": "Set-HostedOutboundSpamFilterPolicy -AutoForwardingMode 'Off'", + "recommendedBy": ["CIS"] + }, { "name": "standards.QuarantineRequestAlert", "cat": "Defender Standards", From e69f33bd55897a27206a035e652d2933932e5178 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Fri, 26 Jul 2024 10:48:43 -0400 Subject: [PATCH 024/130] Log Subscriptoins --- src/views/cipp/app-settings/CIPPSettings.jsx | 28 ++++--- .../SettingsWebhookSubscriptions.jsx | 78 +++++++++++++++++++ 2 files changed, 97 insertions(+), 9 deletions(-) create mode 100644 src/views/cipp/app-settings/SettingsWebhookSubscriptions.jsx diff --git a/src/views/cipp/app-settings/CIPPSettings.jsx b/src/views/cipp/app-settings/CIPPSettings.jsx index 5a610170e49b..b4dd85cba84f 100644 --- a/src/views/cipp/app-settings/CIPPSettings.jsx +++ b/src/views/cipp/app-settings/CIPPSettings.jsx @@ -10,6 +10,7 @@ import { SettingsNotifications } from 'src/views/cipp/app-settings/SettingsNotif import { SettingsLicenses } from 'src/views/cipp/app-settings/SettingsLicenses.jsx' import { SettingsMaintenance } from 'src/views/cipp/app-settings/SettingsMaintenance.jsx' import { SettingsPartner } from 'src/views/cipp/app-settings/SettingsPartner.jsx' +import { SettingsWebhookSubscriptions } from 'src/views/cipp/app-settings/SettingsWebhookSubscriptions.jsx' import useQuery from 'src/hooks/useQuery.jsx' import { SettingsSuperAdmin } from './SettingsSuperAdmin.jsx' import { useLoadClientPrincipalQuery } from 'src/store/api/auth.js' @@ -48,16 +49,19 @@ export default function CIPPSettings() { Notifications setActive(5)} href="#"> - Partner Webhooks + Log Subscriptions setActive(6)} href="#"> - Licenses + Partner Webhooks setActive(7)} href="#"> + Licenses + + setActive(8)} href="#"> Maintenance {superAdmin && ( - setActive(8)} href="#"> + setActive(9)} href="#"> SuperAdmin Settings )} @@ -84,23 +88,29 @@ export default function CIPPSettings() { - + - - - + + - + - + + {superAdmin && ( + + + + + + )} ) diff --git a/src/views/cipp/app-settings/SettingsWebhookSubscriptions.jsx b/src/views/cipp/app-settings/SettingsWebhookSubscriptions.jsx new file mode 100644 index 000000000000..e373644af40e --- /dev/null +++ b/src/views/cipp/app-settings/SettingsWebhookSubscriptions.jsx @@ -0,0 +1,78 @@ +import React from 'react' +import { CippPageList } from 'src/components/layout/index.js' +import { cellGenericFormatter } from 'src/components/tables/CellGenericFormat' +import { cellBadgeFormatter, cellDateFormatter } from 'src/components/tables' + +/** + * SettingsWebhookSubscriptions component is used to manage webhook subscriptions in a settings page. + * + * @returns {JSX.Element} The generated settings page component. + */ +export function SettingsWebhookSubscriptions() { + const columns = [ + { + name: 'Tenant', + selector: (row) => row['PartitionKey'], + exportSelector: 'PartitionKey', + sortable: true, + cell: cellGenericFormatter(), + }, + { + name: 'Resource', + selector: (row) => row['Resource'], + exportSelector: 'Resource', + sortable: true, + cell: cellGenericFormatter(), + }, + { + name: 'Status', + selector: (row) => row['Status'], + exportSelector: 'Status', + sortable: true, + cell: cellBadgeFormatter(), + }, + { + name: 'Last Update', + selector: (row) => row['Timestamp'], + sortable: true, + cell: cellDateFormatter({ format: 'short' }), + exportSelector: 'Timestamp', + }, + ] + return ( + <> + + + ) +} From c8aba868b3775bc3f8346dd634b227892b164222 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Fri, 26 Jul 2024 12:02:20 -0400 Subject: [PATCH 025/130] UI tweaks --- src/views/cipp/ExtensionSync.jsx | 14 +++++++------- .../app-settings/SettingsWebhookSubscriptions.jsx | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/views/cipp/ExtensionSync.jsx b/src/views/cipp/ExtensionSync.jsx index c9937921aa86..f121bf08e513 100644 --- a/src/views/cipp/ExtensionSync.jsx +++ b/src/views/cipp/ExtensionSync.jsx @@ -19,49 +19,49 @@ const ExtensionSync = () => { const columns = [ { name: 'Tenant', - selector: (row) => row['Tenant'], + selector: (row) => row?.Tenant, sortable: true, cell: cellGenericFormatter(), exportSelector: 'Tenants', }, { name: 'Sync Type', - selector: (row) => row['SyncType'], + selector: (row) => row?.SyncType, sortable: true, cell: cellBadgeFormatter({ color: 'info' }), exportSelector: 'SyncType', }, { name: 'Task', - selector: (row) => row['Name'], + selector: (row) => row?.Name, sortable: true, cell: cellGenericFormatter(), exportSelector: 'Name', }, { name: 'Scheduled Time', - selector: (row) => row['ScheduledTime'], + selector: (row) => row?.ScheduledTime, sortable: true, cell: cellDateFormatter({ format: 'short' }), exportSelector: 'ScheduledTime', }, { name: 'Last Run', - selector: (row) => row['ExecutedTime'], + selector: (row) => row?.ExecutedTime, sortable: true, cell: cellDateFormatter({ format: 'short' }), exportSelector: 'ExecutedTime', }, { name: 'Repeats every', - selector: (row) => row['RepeatsEvery'], + selector: (row) => row?.RepeatsEvery, sortable: true, cell: (row) => CellTip(row['RepeatsEvery']), exportSelector: 'RepeatsEvery', }, { name: 'Results', - selector: (row) => row['Results'], + selector: (row) => row?.Results, sortable: true, cell: cellGenericFormatter(), exportSelector: 'Results', diff --git a/src/views/cipp/app-settings/SettingsWebhookSubscriptions.jsx b/src/views/cipp/app-settings/SettingsWebhookSubscriptions.jsx index e373644af40e..965e13b57b90 100644 --- a/src/views/cipp/app-settings/SettingsWebhookSubscriptions.jsx +++ b/src/views/cipp/app-settings/SettingsWebhookSubscriptions.jsx @@ -29,7 +29,7 @@ export function SettingsWebhookSubscriptions() { selector: (row) => row['Status'], exportSelector: 'Status', sortable: true, - cell: cellBadgeFormatter(), + cell: cellBadgeFormatter({ color: 'info' }), }, { name: 'Last Update', From a0eb3ecc93452db449303438e2d7af6abd4e7748 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Fri, 26 Jul 2024 13:01:35 -0400 Subject: [PATCH 026/130] up version --- package.json | 2 +- public/version_latest.txt | 2 +- version_latest.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 0d19ddc025c7..e3b9958fe19e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cipp", - "version": "6.1.0", + "version": "6.1.1", "description": "The CyberDrain Improved Partner Portal is a portal to help manage administration for Microsoft Partners.", "homepage": "https://cipp.app/", "bugs": { diff --git a/public/version_latest.txt b/public/version_latest.txt index dfda3e0b4f01..f3b5af39e430 100644 --- a/public/version_latest.txt +++ b/public/version_latest.txt @@ -1 +1 @@ -6.1.0 +6.1.1 diff --git a/version_latest.txt b/version_latest.txt index dfda3e0b4f01..f3b5af39e430 100644 --- a/version_latest.txt +++ b/version_latest.txt @@ -1 +1 @@ -6.1.0 +6.1.1 From 8c7296f3d0c452cf4698cbd754983df37752449d Mon Sep 17 00:00:00 2001 From: Esco Date: Sat, 27 Jul 2024 16:54:20 +0200 Subject: [PATCH 027/130] Added Teams Global Meeting Policy standard --- src/data/standards.json | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/data/standards.json b/src/data/standards.json index 63f9c47d07a2..f49e96a91139 100644 --- a/src/data/standards.json +++ b/src/data/standards.json @@ -2302,5 +2302,41 @@ "impactColour": "danger", "powershellEquivalent": "Update-MgAdminSharepointSetting", "recommendedBy": [] + }, + { + "name": "standards.TeamsGlobalMeetingPolicy", + "cat": "Teams Standards", + "tag": ["lowimpact"], + "helpText": "Defines the CIS recommended global meeting policy for Teams. This includes AllowAnonymousUsersToJoinMeeting, AllowAnonymousUsersToStartMeeting, AutoAdmittedUsers, AllowPSTNUsersToBypassLobby, MeetingChatEnabledType, DesignatedPresenterRoleMode, AllowExternalParticipantGiveRequestControl", + "addedComponent": [ + { + "type": "Select", + "name": "standards.TeamsGlobalMeetingPolicy.DesignatedPresenterRoleMode", + "label": "Default value of the `Who can present?`", + "values": [ + { + "label": "EveryoneUserOverride", + "value": "EveryoneUserOverride" + }, + { + "label": "EveryoneInCompanyUserOverride", + "value": "EveryoneInCompanyUserOverride" + }, + { + "label": "EveryoneInSameAndFederatedCompanyUserOverride", + "value": "EveryoneInSameAndFederatedCompanyUserOverride" + }, + { + "label": "OrganizerOnlyUserOverride", + "value": "OrganizerOnlyUserOverride" + } + ] + } + ], + "label": "Define Global Meeting Policy for Teams", + "impact": "Low Impact", + "impactColour": "info", + "powershellEquivalent": "Set-CsTeamsMeetingPolicy -AllowAnonymousUsersToJoinMeeting $false -AllowAnonymousUsersToStartMeeting $false -AutoAdmittedUsers EveryoneInCompanyExcludingGuests -AllowPSTNUsersToBypassLobby $false -MeetingChatEnabledType EnabledExceptAnonymous -DesignatedPresenterRoleMode $DesignatedPresenterRoleMode -AllowExternalParticipantGiveRequestControl $false", + "recommendedBy": ["CIS 3.0"] } ] From 9cb5b30a882d18fd30455a811e068bdb88909952 Mon Sep 17 00:00:00 2001 From: Esco Date: Sat, 27 Jul 2024 10:12:34 +0200 Subject: [PATCH 028/130] Added Teams External File Sharing Standard --- src/data/standards.json | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/data/standards.json b/src/data/standards.json index f49e96a91139..51e5cf143234 100644 --- a/src/data/standards.json +++ b/src/data/standards.json @@ -2338,5 +2338,43 @@ "impactColour": "info", "powershellEquivalent": "Set-CsTeamsMeetingPolicy -AllowAnonymousUsersToJoinMeeting $false -AllowAnonymousUsersToStartMeeting $false -AutoAdmittedUsers EveryoneInCompanyExcludingGuests -AllowPSTNUsersToBypassLobby $false -MeetingChatEnabledType EnabledExceptAnonymous -DesignatedPresenterRoleMode $DesignatedPresenterRoleMode -AllowExternalParticipantGiveRequestControl $false", "recommendedBy": ["CIS 3.0"] + }, + { + "name": "standards.TeamsExternalFileSharing", + "cat": "Teams Standards", + "tag": ["lowimpact"], + "helpText": "Ensure external file sharing in Teams is enabled for only approved cloud storage services.", + "addedComponent": [ + { + "type": "boolean", + "name": "standards.TeamsExternalFileSharing.AllowGoogleDrive", + "label": "Allow Google Drive" + }, + { + "type": "boolean", + "name": "standards.TeamsExternalFileSharing.AllowShareFile", + "label": "Allow ShareFile" + }, + { + "type": "boolean", + "name": "standards.TeamsExternalFileSharing.AllowBox", + "label": "Allow Box" + }, + { + "type": "boolean", + "name": "standards.TeamsExternalFileSharing.AllowDropBox", + "label": "Allow Dropbox" + }, + { + "type": "boolean", + "name": "standards.TeamsExternalFileSharing.AllowEgnyte", + "label": "Allow Egnyte" + } + ], + "label": "Define approved cloud storage services for external file sharing in Teams", + "impact": "Low Impact", + "impactColour": "info", + "powershellEquivalent": "Set-CsTeamsClientConfiguration -AllowGoogleDrive $false -AllowShareFile $false -AllowBox $false -AllowDropBox $false -AllowEgnyte $false", + "recommendedBy": ["CIS 3.0"] } ] From 3a8c74e4dac88826569334823958b4eecc246c05 Mon Sep 17 00:00:00 2001 From: cipptesting Date: Mon, 29 Jul 2024 14:09:02 -0400 Subject: [PATCH 029/130] Updated Spam Filter Standard --- src/data/standards.json | 51 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/src/data/standards.json b/src/data/standards.json index 51e5cf143234..1536d4a20a2c 100644 --- a/src/data/standards.json +++ b/src/data/standards.json @@ -1703,6 +1703,12 @@ "tag": ["mediumimpact"], "helpText": "This standard creates a Spam filter policy similar to the default strict policy.", "addedComponent": [ + { + "type": "number", + "label": "Bulk email threshold (Default 7)", + "name": "standards.SpamFilterPolicy.BulkThreshold", + "default": 7 + }, { "type": "Select", "label": "Spam Action", @@ -1737,6 +1743,21 @@ } ] }, + { + "type": "Select", + "label": "High Confidence Spam Action", + "name": "standards.SpamFilterPolicy.HighConfidenceSpamAction", + "values": [ + { + "label": "Quarantine the message", + "value": "Quarantine" + }, + { + "label": "Move message to Junk Email folder", + "value": "MoveToJmf" + } + ] + }, { "type": "Select", "label": "High Confidence Spam Quarantine Tag", @@ -1756,6 +1777,21 @@ } ] }, + { + "type": "Select", + "label": "Bulk Spam Action", + "name": "standards.SpamFilterPolicy.BulkSpamAction", + "values": [ + { + "label": "Move message to Junk Email folder", + "value": "MoveToJmf" + }, + { + "label": "Quarantine the message", + "value": "Quarantine" + } + ] + }, { "type": "Select", "label": "Bulk Quarantine Tag", @@ -1775,6 +1811,21 @@ } ] }, + { + "type": "Select", + "label": "Phish Spam Action", + "name": "standards.SpamFilterPolicy.PhishSpamAction", + "values": [ + { + "label": "Quarantine the message", + "value": "Quarantine" + }, + { + "label": "Move message to Junk Email folder", + "value": "MoveToJmf" + } + ] + }, { "type": "Select", "label": "Phish Quarantine Tag", From e2cbb688cd480fcef6f306a784cc7dd73ac6570d Mon Sep 17 00:00:00 2001 From: cipptesting Date: Mon, 29 Jul 2024 15:37:09 -0400 Subject: [PATCH 030/130] Updated standards.json based on feedback --- src/data/standards.json | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/data/standards.json b/src/data/standards.json index 1536d4a20a2c..310890368c4d 100644 --- a/src/data/standards.json +++ b/src/data/standards.json @@ -1714,13 +1714,13 @@ "label": "Spam Action", "name": "standards.SpamFilterPolicy.SpamAction", "values": [ - { - "label": "Move message to Junk Email folder", - "value": "MoveToJmf" - }, { "label": "Quarantine the message", "value": "Quarantine" + }, + { + "label": "Move message to Junk Email folder", + "value": "MoveToJmf" } ] }, @@ -1782,13 +1782,13 @@ "label": "Bulk Spam Action", "name": "standards.SpamFilterPolicy.BulkSpamAction", "values": [ - { - "label": "Move message to Junk Email folder", - "value": "MoveToJmf" - }, { "label": "Quarantine the message", "value": "Quarantine" + }, + { + "label": "Move message to Junk Email folder", + "value": "MoveToJmf" } ] }, From 2bb4af823c38069b47055766433377cd35905402 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Mon, 29 Jul 2024 17:38:13 -0400 Subject: [PATCH 031/130] Add controlStateUpdates table to Secure Score page --- .../tenant/administration/SecureScore.jsx | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/views/tenant/administration/SecureScore.jsx b/src/views/tenant/administration/SecureScore.jsx index 76c77d584296..be036997339c 100644 --- a/src/views/tenant/administration/SecureScore.jsx +++ b/src/views/tenant/administration/SecureScore.jsx @@ -15,7 +15,7 @@ import { CRow, } from '@coreui/react' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' -import { faCheck, faTimes, faExclamation } from '@fortawesome/free-solid-svg-icons' +import { faCheck, faTimes } from '@fortawesome/free-solid-svg-icons' import { CippTable } from 'src/components/tables' import { CippPage } from 'src/components/layout/CippPage' import { useGenericGetRequestQuery, useLazyGenericPostRequestQuery } from 'src/store/api/app' @@ -27,6 +27,7 @@ import { ModalService } from 'src/components/utilities' import { CellTip, cellGenericFormatter } from 'src/components/tables/CellGenericFormat' import { CippCallout } from 'src/components/layout' import CippPrettyCard from 'src/components/contentcards/CippPrettyCard' +import { TableModalButton } from 'src/components/buttons' const SecureScore = () => { const textRef = useRef() @@ -192,6 +193,11 @@ const SecureScore = () => { cell: cellGenericFormatter(), exportSelector: 'actionUrl', }, + { + name: 'Updates', + selector: (row) => row?.controlStateUpdates, + cell: cellGenericFormatter(), + }, ] return ( @@ -278,7 +284,7 @@ const SecureScore = () => {
- {viewMode && translateData.controlScores.length > 1 && isSuccess && isSuccessTranslation && ( + {viewMode && translateData.controlScores?.length > 1 && isSuccess && isSuccessTranslation && ( Best Practice Report @@ -286,7 +292,7 @@ const SecureScore = () => { { openResolution(info)} className="me-3"> Change Status + + From 68d6e5cec6b03ae9c51fd019347d8c1520223e49 Mon Sep 17 00:00:00 2001 From: Esco Date: Tue, 30 Jul 2024 10:11:56 +0200 Subject: [PATCH 032/130] Added Teams Email Integration standard --- src/data/standards.json | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/data/standards.json b/src/data/standards.json index 51e5cf143234..f4e4e8f28b5f 100644 --- a/src/data/standards.json +++ b/src/data/standards.json @@ -2339,6 +2339,25 @@ "powershellEquivalent": "Set-CsTeamsMeetingPolicy -AllowAnonymousUsersToJoinMeeting $false -AllowAnonymousUsersToStartMeeting $false -AutoAdmittedUsers EveryoneInCompanyExcludingGuests -AllowPSTNUsersToBypassLobby $false -MeetingChatEnabledType EnabledExceptAnonymous -DesignatedPresenterRoleMode $DesignatedPresenterRoleMode -AllowExternalParticipantGiveRequestControl $false", "recommendedBy": ["CIS 3.0"] }, + { + "name": "standards.TeamsEmailIntegration", + "cat": "Teams Standards", + "tag": ["lowimpact"], + "helpText": "Should users be allowed to send emails directly to a channel email addresses?", + "docsDescription": "Teams channel email addresses are an optional feature that allows users to email the Teams channel directly.", + "addedComponent": [ + { + "type": "boolean", + "name": "standards.TeamsEmailIntegration.AllowEmailIntoChannel", + "label": "Allow channel emails" + } + ], + "label": "Disallow emails to be sent to channel email addresses", + "impact": "Low Impact", + "impactColour": "info", + "powershellEquivalent": "Set-CsTeamsClientConfiguration -AllowEmailIntoChannel $false", + "recommendedBy": ["CIS 3.0"] + }, { "name": "standards.TeamsExternalFileSharing", "cat": "Teams Standards", From 562e40f39302f1a625d0fae7fbb8017c76444a11 Mon Sep 17 00:00:00 2001 From: Esco Date: Sat, 27 Jul 2024 23:47:50 +0200 Subject: [PATCH 033/130] Added Teams External Access Policy Standard --- src/data/standards.json | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/data/standards.json b/src/data/standards.json index 51e5cf143234..4850180e2bee 100644 --- a/src/data/standards.json +++ b/src/data/standards.json @@ -2376,5 +2376,34 @@ "impactColour": "info", "powershellEquivalent": "Set-CsTeamsClientConfiguration -AllowGoogleDrive $false -AllowShareFile $false -AllowBox $false -AllowDropBox $false -AllowEgnyte $false", "recommendedBy": ["CIS 3.0"] + }, + { + "name": "standards.TeamsExternalAccessPolicy", + "cat": "Teams Standards", + "tag": ["mediumimpact"], + "helpText": "Sets the properties of the Global external access policy.", + "docsDescription": "Sets the properties of the Global external access policy. External access policies determine whether or not your users can: 1) communicate with users who have Session Initiation Protocol (SIP) accounts with a federated organization; 2) communicate with users who are using custom applications built with Azure Communication Services; 3) access Skype for Business Server over the Internet, without having to log on to your internal network; 4) communicate with users who have SIP accounts with a public instant messaging (IM) provider such as Skype; and, 5) communicate with people who are using Teams with an account that's not managed by an organization.", + "addedComponent": [ + { + "type": "boolean", + "name": "standards.TeamsExternalAccessPolicy.EnableFederationAccess", + "label": "Allow communication from trusted organizations" + }, + { + "type": "boolean", + "name": "standards.TeamsExternalAccessPolicy.EnablePublicCloudAccess", + "label": "Allow user to communicate with Skype users" + }, + { + "type": "boolean", + "name": "standards.TeamsExternalAccessPolicy.EnableTeamsConsumerAccess", + "label": "Allow communication with unmanaged Teams accounts" + } + ], + "label": "External Access Settings for Microsoft Teams", + "impact": "Medium Impact", + "impactColour": "warning", + "powershellEquivalent": "Set-CsExternalAccessPolicy", + "recommendedBy": [] } ] From 4ff96472ac6f94f127c68337506e00e1c1fa931e Mon Sep 17 00:00:00 2001 From: John Duprey Date: Tue, 30 Jul 2024 15:31:04 -0400 Subject: [PATCH 034/130] Add form validation for GDAP invite wizard Remove the ability to have duplicate roleDefinitionIds selected --- .../administration/GDAPInviteWizard.jsx | 28 +++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/src/views/tenant/administration/GDAPInviteWizard.jsx b/src/views/tenant/administration/GDAPInviteWizard.jsx index 5f303a3c827f..e46c6b7180e7 100644 --- a/src/views/tenant/administration/GDAPInviteWizard.jsx +++ b/src/views/tenant/administration/GDAPInviteWizard.jsx @@ -28,7 +28,7 @@ const Error = ({ name }) => ( render={({ meta: { touched, error } }) => touched && error ? ( - + {error} ) : null @@ -40,7 +40,31 @@ Error.propTypes = { name: PropTypes.string.isRequired, } -const requiredArray = (value) => (value && value.length !== 0 ? undefined : 'Required') +const requiredArray = (value) => { + if (value && value.length !== 0) { + /// group each item in value by roleDefinitionId and select Role name where count is greater than 1 + const duplicateRoles = value + .map((item) => item.roleDefinitionId) + .filter((item, index, self) => index !== self.indexOf(item)) + console.log(duplicateRoles) + + if (duplicateRoles.length > 0) { + var duplicates = value.filter((item) => duplicateRoles.includes(item.roleDefinitionId)) + /// get unique list of duplicate roles + duplicates = duplicates + .filter( + (role, index, self) => + index === self.findIndex((t) => t.roleDefinitionId === role.roleDefinitionId), + ) + .map((role) => role.RoleName) + return `Duplicate GDAP Roles selected, remove one of the mapped groups for the listed roles to continue: ${duplicates}` + } else { + return undefined + } + } else { + return 'You must select at least one GDAP Role' + } +} const GDAPInviteWizard = () => { const defaultRolesArray = [ From da771ee9d0414d95c18b6e70313e7e3a246e53be Mon Sep 17 00:00:00 2001 From: John Duprey Date: Tue, 30 Jul 2024 16:22:26 -0400 Subject: [PATCH 035/130] Add GDAP invite page --- src/_nav.jsx | 7 ++- src/importsMap.jsx | 3 +- src/routes.json | 8 ++- .../tenant/administration/ListGDAPInvites.jsx | 63 +++++++++++++++++++ 4 files changed, 78 insertions(+), 3 deletions(-) create mode 100644 src/views/tenant/administration/ListGDAPInvites.jsx diff --git a/src/_nav.jsx b/src/_nav.jsx index c0faa91279c0..c83f7f179148 100644 --- a/src/_nav.jsx +++ b/src/_nav.jsx @@ -326,7 +326,12 @@ const _nav = [ { component: CNavItem, name: 'Invite Wizard', - to: '/tenant/administration/gdap-invite', + to: '/tenant/administration/gdap-invite-wizard', + }, + { + component: CNavItem, + name: 'Invite List', + to: '/tenant/administration/gdap-invites', }, { component: CNavItem, diff --git a/src/importsMap.jsx b/src/importsMap.jsx index eaa260ad4dbd..21174e32a0f2 100644 --- a/src/importsMap.jsx +++ b/src/importsMap.jsx @@ -147,7 +147,8 @@ import React from 'react' "/cipp/setup": React.lazy(() => import('./views/cipp/Setup')), "/tenant/administration/securescore": React.lazy(() => import('./views/tenant/administration/SecureScore')), "/tenant/administration/gdap": React.lazy(() => import('./views/tenant/administration/GDAPWizard')), - "/tenant/administration/gdap-invite": React.lazy(() => import('./views/tenant/administration/GDAPInviteWizard')), + "/tenant/administration/gdap-invite-wizard": React.lazy(() => import('./views/tenant/administration/GDAPInviteWizard')), + "/tenant/administration/gdap-invites": React.lazy(() => import('./views/tenant/administration/ListGDAPInvites')), "/tenant/administration/gdap-role-wizard": React.lazy(() => import('./views/tenant/administration/GDAPRoleWizard')), "/tenant/administration/gdap-roles": React.lazy(() => import('./views/tenant/administration/ListGDAPRoles')), "/tenant/administration/gdap-relationships": React.lazy(() => import('././views/tenant/administration/ListGDAPRelationships')), diff --git a/src/routes.json b/src/routes.json index f5b6053359a7..c0a996610e41 100644 --- a/src/routes.json +++ b/src/routes.json @@ -999,11 +999,17 @@ "allowedRoles": ["admin"] }, { - "path": "/tenant/administration/gdap-invite", + "path": "/tenant/administration/gdap-invite-wizard", "name": "GDAP Invite Wizard", "component": "views/tenant/administration/GDAPInviteWizard", "allowedRoles": ["admin"] }, + { + "path": "/tenant/administration/gdap-invites", + "name": "GDAP Invites", + "component": "views/tenant/administration/ListGDAPInvites", + "allowedRoles": ["admin"] + }, { "path": "/tenant/administration/gdap-role-wizard", "name": "GDAP Role Wizard", diff --git a/src/views/tenant/administration/ListGDAPInvites.jsx b/src/views/tenant/administration/ListGDAPInvites.jsx new file mode 100644 index 000000000000..24a44e6b253f --- /dev/null +++ b/src/views/tenant/administration/ListGDAPInvites.jsx @@ -0,0 +1,63 @@ +import React from 'react' +import { CippPageList } from 'src/components/layout' +import { TitleButton } from 'src/components/buttons' +import { cellGenericFormatter } from 'src/components/tables/CellGenericFormat' +import { cellDateFormatter } from 'src/components/tables' + +const ListGDAPInvites = () => { + const columns = [ + { + name: 'Created', + selector: (row) => row['Timestamp'], + sortable: true, + exportSelector: 'Timestamp', + cell: cellDateFormatter({ format: 'short' }), + }, + { + name: 'Relationship ID', + selector: (row) => row['RowKey'], + sortable: true, + exportSelector: 'RowKey', + cell: cellGenericFormatter(), + }, + { + name: 'Invite URL', + selector: (row) => row['InviteUrl'], + exportSelector: 'InviteUrl', + cell: cellGenericFormatter(), + }, + { + name: 'Onboarding URL', + selector: (row) => row['OnboardingUrl'], + exportSelector: 'OnboardingUrl', + cell: cellGenericFormatter(), + }, + { + name: 'Role Mapping', + selector: (row) => row['RoleMappings'], + exportSelector: 'RoleMappings', + cell: cellGenericFormatter(), + }, + ] + return ( +
+ +
+ ) +} + +export default ListGDAPInvites From 4b18fc4b1d089f6ea9c5bfbe38f66fb5eb9225f1 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Tue, 30 Jul 2024 16:37:15 -0400 Subject: [PATCH 036/130] wording, remove console log --- src/views/tenant/administration/GDAPInviteWizard.jsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/views/tenant/administration/GDAPInviteWizard.jsx b/src/views/tenant/administration/GDAPInviteWizard.jsx index e46c6b7180e7..a3c38dbf7dc6 100644 --- a/src/views/tenant/administration/GDAPInviteWizard.jsx +++ b/src/views/tenant/administration/GDAPInviteWizard.jsx @@ -46,18 +46,20 @@ const requiredArray = (value) => { const duplicateRoles = value .map((item) => item.roleDefinitionId) .filter((item, index, self) => index !== self.indexOf(item)) - console.log(duplicateRoles) if (duplicateRoles.length > 0) { var duplicates = value.filter((item) => duplicateRoles.includes(item.roleDefinitionId)) /// get unique list of duplicate roles + duplicates = duplicates .filter( (role, index, self) => index === self.findIndex((t) => t.roleDefinitionId === role.roleDefinitionId), ) .map((role) => role.RoleName) - return `Duplicate GDAP Roles selected, remove one of the mapped groups for the listed roles to continue: ${duplicates}` + return `Duplicate GDAP Roles selected, ensure there is only one group mapping for the listed roles to continue: ${duplicates.join( + ', ', + )}` } else { return undefined } From a6aa56c511c426b8bd58e2e72466e2f46ce1b91d Mon Sep 17 00:00:00 2001 From: Esco Date: Sun, 28 Jul 2024 00:52:21 +0200 Subject: [PATCH 037/130] Added Teams Federation Configuration Standard --- src/data/standards.json | 52 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/src/data/standards.json b/src/data/standards.json index 9667715a5607..ef14f236cd1a 100644 --- a/src/data/standards.json +++ b/src/data/standards.json @@ -2475,5 +2475,57 @@ "impactColour": "warning", "powershellEquivalent": "Set-CsExternalAccessPolicy", "recommendedBy": [] + }, + { + "name": "standards.TeamsFederationConfiguration", + "cat": "Teams Standards", + "tag": ["mediumimpact"], + "helpText": "Sets the properties of the Global federation configuration.", + "docsDescription": "Sets the properties of the Global federation configuration. Federation configuration settings determine whether or not your users can communicate with users who have SIP accounts with a federated organization.", + "addedComponent": [ + { + "type": "boolean", + "name": "standards.TeamsFederationConfiguration.AllowTeamsConsumer", + "label": "Allow users to communicate with other organizations" + }, + { + "type": "boolean", + "name": "standards.TeamsFederationConfiguration.AllowPublicUsers", + "label": "Allow users to communicate with Skype Users" + }, + { + "type": "Select", + "name": "standards.TeamsFederationConfiguration.DomainControl", + "label": "Communication Mode", + "values": [ + { + "label": "Allow all external domains", + "value": "AllowAllExternal" + }, + { + "label": "Block all external domains", + "value": "BlockAllExternal" + }, + { + "label": "Allow specific external domains", + "value": "AllowSpecificExternal" + }, + { + "label": "Block specific external domains", + "value": "BlockSpecificExternal" + } + ] + }, + { + "type": "input", + "name": "standards.TeamsFederationConfiguration.DomainList", + "label": "Domains, Comma separated" + } + ], + "label": "Federation Configuration for Microsoft Teams", + "impact": "Medium Impact", + "impactColour": "warning", + "powershellEquivalent": "Set-CsTenantFederationConfiguration", + "recommendedBy": [] } ] From b168c995bafc24a891d6d29b5f634f49efed8974 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Wed, 31 Jul 2024 16:18:06 -0400 Subject: [PATCH 038/130] Message Viewer --- package-lock.json | 188 ++++++++++- package.json | 6 +- src/_nav.jsx | 5 + src/components/utilities/CippDropzone.jsx | 78 +++++ src/importsMap.jsx | 1 + src/routes.json | 6 + .../email-exchange/tools/MessageViewer.jsx | 310 ++++++++++++++++++ 7 files changed, 582 insertions(+), 12 deletions(-) create mode 100644 src/components/utilities/CippDropzone.jsx create mode 100644 src/views/email-exchange/tools/MessageViewer.jsx diff --git a/package-lock.json b/package-lock.json index bc2ed9783377..5148294a75a6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "cipp", - "version": "5.8.5", + "version": "6.1.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "cipp", - "version": "5.8.5", + "version": "6.1.1", "license": "AGPL-3.0", "dependencies": { "@coreui/chartjs": "^3.0.0", @@ -32,6 +32,8 @@ "chart.js": "^3.5.1", "classnames": "^2.3.1", "core-js": "^3.18.3", + "dompurify": "^3.1.6", + "eml-parse-js": "^1.1.14", "enzyme": "^3.11.0", "final-form": "^4.20.4", "final-form-arrays": "^3.1.0", @@ -51,11 +53,13 @@ "react-data-table-component": "^7.4.5", "react-datepicker": "^4.10.0", "react-dom": "^18.2.0", + "react-dropzone": "^14.2.3", "react-final-form": "^6.5.9", "react-final-form-arrays": "^3.1.4", "react-final-form-listeners": "^1.0.3", "react-helmet-async": "^1.3.0", "react-hotkeys-hook": "^3.4.4", + "react-html-parser": "^2.0.2", "react-loading-skeleton": "^3.1.0", "react-masonry-component": "^6.3.0", "react-media-hook": "^0.4.9", @@ -70,7 +74,7 @@ "redux-persist": "^6.0.0", "simplebar-react": "^2.3.6", "source-map-loader": "^3.0.0", - "styled-components": "^5.3.3" + "styled-components": "^5.3.11" }, "devDependencies": { "@types/react": "^18.2.39", @@ -1714,6 +1718,11 @@ "win32" ] }, + "node_modules/@sinonjs/text-encoding": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.2.tgz", + "integrity": "sha512-sXXKG+uL9IrKqViTtao2Ws6dy0znu9sOaP1di/jKGW1M6VssO8vlpXCQcpZ+jisQ1tTFAC5Jo/EOzFbggBagFQ==" + }, "node_modules/@types/babel__core": { "version": "7.20.5", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", @@ -2438,6 +2447,14 @@ "node": ">= 4.5.0" } }, + "node_modules/attr-accept": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/attr-accept/-/attr-accept-2.2.2.tgz", + "integrity": "sha512-7prDjvt9HmqiZ0cl5CRjtS84sEyhsHP2coDkaZKRKVfCDo9s7iw7ChVmar78Gu9pC4SoR/28wFu/G5JJhTnqEg==", + "engines": { + "node": ">=4" + } + }, "node_modules/auto-changelog": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/auto-changelog/-/auto-changelog-2.3.0.tgz", @@ -3331,10 +3348,9 @@ } }, "node_modules/dompurify": { - "version": "2.4.7", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.4.7.tgz", - "integrity": "sha512-kxxKlPEDa6Nc5WJi+qRgPbOAbgTpSULL+vI3NUXsZMlkJxTqYI9wg5ZTay2sFrdZRWHPWNi+EdAhcJf81WtoMQ==", - "optional": true + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.1.6.tgz", + "integrity": "sha512-cTOAhc36AalkjtBpfG6O8JimdTMWNXjiePT2xQH/ppBGi/4uIpmj8eKyIkMJErXWARyINV/sB38yf8JCLF5pbQ==" }, "node_modules/domutils": { "version": "3.1.0", @@ -3362,6 +3378,15 @@ "batch-processor": "1.0.0" } }, + "node_modules/eml-parse-js": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/eml-parse-js/-/eml-parse-js-1.1.14.tgz", + "integrity": "sha512-6wUmZQ4k67CHGaQdNTukUMtCQ77e/676pRRsn/ga6CdaIwitzbQwqA/YTq/Wk+l1gghFJTPhbRyQphrAptK/GA==", + "dependencies": { + "@sinonjs/text-encoding": "^0.7.2", + "js-base64": "^3.7.2" + } + }, "node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -4259,6 +4284,17 @@ "node": "^10.12.0 || >=12.0.0" } }, + "node_modules/file-selector": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/file-selector/-/file-selector-0.6.0.tgz", + "integrity": "sha512-QlZ5yJC0VxHxQQsQhXvBaC7VRJ2uaxTf+Tfpu4Z/OcVQJVpZO+DGU0rkoVW5ce2SccxugvpBJoMvUs59iILYdw==", + "dependencies": { + "tslib": "^2.4.0" + }, + "engines": { + "node": ">= 12" + } + }, "node_modules/fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -5031,8 +5067,7 @@ "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "node_modules/ini": { "version": "1.3.8", @@ -5537,6 +5572,11 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, + "node_modules/js-base64": { + "version": "3.7.7", + "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-3.7.7.tgz", + "integrity": "sha512-7rCnleh0z2CkXhH67J8K1Ytz0b2Y+yxTPL+/KOJoa20hfnVQ/3/T6W/KflYI4bRHRagNeXeU2bkNGI3v1oS/lw==" + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -5658,6 +5698,12 @@ "jspdf": "^2.5.1" } }, + "node_modules/jspdf/node_modules/dompurify": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.5.6.tgz", + "integrity": "sha512-zUTaUBO8pY4+iJMPE1B9XlO2tXVYIcEA4SNGtvDELzTSCQO7RzH+j7S180BmhmJId78lqGU2z19vgVx2Sxs/PQ==", + "optional": true + }, "node_modules/jsx-ast-utils": { "version": "3.3.5", "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", @@ -6931,6 +6977,22 @@ "react": "^18.2.0" } }, + "node_modules/react-dropzone": { + "version": "14.2.3", + "resolved": "https://registry.npmjs.org/react-dropzone/-/react-dropzone-14.2.3.tgz", + "integrity": "sha512-O3om8I+PkFKbxCukfIR3QAGftYXDZfOE2N1mr/7qebQJHs7U+/RSL/9xomJNpRg9kM5h9soQSdf0Gc7OHF5Fug==", + "dependencies": { + "attr-accept": "^2.2.2", + "file-selector": "^0.6.0", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">= 10.13" + }, + "peerDependencies": { + "react": ">= 16.8 || 18.0.0" + } + }, "node_modules/react-fast-compare": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.2.tgz", @@ -7008,6 +7070,85 @@ "react-dom": ">=16.8.1" } }, + "node_modules/react-html-parser": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/react-html-parser/-/react-html-parser-2.0.2.tgz", + "integrity": "sha512-XeerLwCVjTs3njZcgCOeDUqLgNIt/t+6Jgi5/qPsO/krUWl76kWKXMeVs2LhY2gwM6X378DkhLjur0zUQdpz0g==", + "dependencies": { + "htmlparser2": "^3.9.0" + }, + "peerDependencies": { + "react": "^0.14.0 || ^15.0.0 || ^16.0.0-0" + } + }, + "node_modules/react-html-parser/node_modules/dom-serializer": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz", + "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==", + "dependencies": { + "domelementtype": "^2.0.1", + "entities": "^2.0.0" + } + }, + "node_modules/react-html-parser/node_modules/dom-serializer/node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, + "node_modules/react-html-parser/node_modules/dom-serializer/node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/react-html-parser/node_modules/domelementtype": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", + "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==" + }, + "node_modules/react-html-parser/node_modules/domhandler": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz", + "integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==", + "dependencies": { + "domelementtype": "1" + } + }, + "node_modules/react-html-parser/node_modules/domutils": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz", + "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==", + "dependencies": { + "dom-serializer": "0", + "domelementtype": "1" + } + }, + "node_modules/react-html-parser/node_modules/entities": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", + "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==" + }, + "node_modules/react-html-parser/node_modules/htmlparser2": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz", + "integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==", + "dependencies": { + "domelementtype": "^1.3.1", + "domhandler": "^2.3.0", + "domutils": "^1.5.1", + "entities": "^1.1.1", + "inherits": "^2.0.1", + "readable-stream": "^3.1.1" + } + }, "node_modules/react-is": { "version": "18.2.0", "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", @@ -7393,6 +7534,19 @@ "node": ">=8" } }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", @@ -7699,8 +7853,7 @@ "type": "consulting", "url": "https://feross.org/support" } - ], - "peer": true + ] }, "node_modules/safe-regex-test": { "version": "1.0.3", @@ -8079,6 +8232,14 @@ "resolved": "https://registry.npmjs.org/state-local/-/state-local-1.0.7.tgz", "integrity": "sha512-HTEHMNieakEnoe33shBYcZ7NX83ACUjCu8c40iOGEZsngj9zRnkqS9j1pqQPXwobB0ZcVTk27REb7COQ0UR59w==" }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, "node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", @@ -8595,6 +8756,11 @@ "json5": "lib/cli.js" } }, + "node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", diff --git a/package.json b/package.json index e3b9958fe19e..169a8fbc8a05 100644 --- a/package.json +++ b/package.json @@ -50,6 +50,8 @@ "chart.js": "^3.5.1", "classnames": "^2.3.1", "core-js": "^3.18.3", + "dompurify": "^3.1.6", + "eml-parse-js": "^1.1.14", "enzyme": "^3.11.0", "final-form": "^4.20.4", "final-form-arrays": "^3.1.0", @@ -69,11 +71,13 @@ "react-data-table-component": "^7.4.5", "react-datepicker": "^4.10.0", "react-dom": "^18.2.0", + "react-dropzone": "^14.2.3", "react-final-form": "^6.5.9", "react-final-form-arrays": "^3.1.4", "react-final-form-listeners": "^1.0.3", "react-helmet-async": "^1.3.0", "react-hotkeys-hook": "^3.4.4", + "react-html-parser": "^2.0.2", "react-loading-skeleton": "^3.1.0", "react-masonry-component": "^6.3.0", "react-media-hook": "^0.4.9", @@ -88,7 +92,7 @@ "redux-persist": "^6.0.0", "simplebar-react": "^2.3.6", "source-map-loader": "^3.0.0", - "styled-components": "^5.3.3" + "styled-components": "^5.3.11" }, "devDependencies": { "@types/react": "^18.2.39", diff --git a/src/_nav.jsx b/src/_nav.jsx index c83f7f179148..59d2980e2ae1 100644 --- a/src/_nav.jsx +++ b/src/_nav.jsx @@ -687,6 +687,11 @@ const _nav = [ name: 'Mail Test', to: '/email/tools/mail-test', }, + { + component: CNavItem, + name: 'Message Viewer', + to: '/email/tools/message-viewer', + }, ], }, { diff --git a/src/components/utilities/CippDropzone.jsx b/src/components/utilities/CippDropzone.jsx new file mode 100644 index 000000000000..e42ab066ae6f --- /dev/null +++ b/src/components/utilities/CippDropzone.jsx @@ -0,0 +1,78 @@ +import React, { useCallback, useMemo, useState } from 'react' +import PropTypes from 'prop-types' +import { CippContentCard } from 'src/components/layout' +import { useDropzone } from 'react-dropzone' +import styled from 'styled-components' +import { useMediaPredicate } from 'react-media-hook' +import { useSelector } from 'react-redux' +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' + +const getColor = (props) => { + if (props.isDragAccept) { + return '#00e676' + } + if (props.isDragReject) { + return '#ff1744' + } + if (props.isFocused) { + return '#2196f3' + } + return '#eeeeee' +} + +const BackgroundColor = () => { + const currentTheme = useSelector((state) => state.app.currentTheme) + const preferredTheme = useMediaPredicate('(prefers-color-scheme: dark)') ? 'impact' : 'cyberdrain' + const isDark = + currentTheme === 'impact' || (currentTheme === 'default' && preferredTheme === 'impact') + + if (isDark) { + return '#333' + } else { + return '#fafafa' + } +} + +const Container = styled.div` + flex: 1; + display: flex; + flex-direction: column; + align-items: center; + padding: 20px; + border-width: 2px; + border-radius: 2px; + border-color: ${(props) => getColor(props)}; + border-style: dashed; + background-color: ${() => BackgroundColor()}; + color: #bdbdbd; + outline: none; + transition: border 0.24s ease-in-out; +` + +const CippDropzone = ({ title, onDrop, dropMessage, accept, maxFiles = 1, ...props }) => { + const { getRootProps, getInputProps, isFocused, isDragAccept, isDragReject } = useDropzone({ + onDrop, + accept: accept, + maxFiles: maxFiles, + }) + return ( + +
+ + + {dropMessage} + +
+
+ ) +} + +CippDropzone.propTypes = { + title: PropTypes.string, + onDrop: PropTypes.func.isRequired, + dropMessage: PropTypes.string, + accept: PropTypes.object, + maxFiles: PropTypes.number, +} + +export default CippDropzone diff --git a/src/importsMap.jsx b/src/importsMap.jsx index 21174e32a0f2..f7c2a6e83234 100644 --- a/src/importsMap.jsx +++ b/src/importsMap.jsx @@ -115,6 +115,7 @@ import React from 'react' "/email/tools/mailbox-restore-wizard": React.lazy(() => import('./views/email-exchange/tools/MailboxRestoreWizard')), "/email/tools/mailbox-restores": React.lazy(() => import('./views/email-exchange/tools/MailboxRestores')), "/email/tools/mail-test": React.lazy(() => import('./views/email-exchange/tools/MailTest')), + "/email/tools/message-viewer": React.lazy(() => import('./views/email-exchange/tools/MessageViewer')), "/email/spamfilter/add-template": React.lazy(() => import('./views/email-exchange/spamfilter/AddSpamfilterTemplate')), "/email/administration/edit-mailbox-permissions": React.lazy(() => import('./views/email-exchange/administration/EditMailboxPermissions')), "/email/administration/add-shared-mailbox": React.lazy(() => import('./views/email-exchange/administration/AddSharedMailbox')), diff --git a/src/routes.json b/src/routes.json index c0a996610e41..be956782af6d 100644 --- a/src/routes.json +++ b/src/routes.json @@ -776,6 +776,12 @@ "component": "views/email-exchange/tools/MailTest", "allowedRoles": ["admin", "editor", "readonly"] }, + { + "path": "/email/tools/message-viewer", + "name": "Message Viewer", + "component": "views/email-exchange/tools/MessageViewer", + "allowedRoles": ["admin", "editor", "readonly"] + }, { "path": "/email/spamfilter/add-template", "name": "Add Spamfilter Template", diff --git a/src/views/email-exchange/tools/MessageViewer.jsx b/src/views/email-exchange/tools/MessageViewer.jsx new file mode 100644 index 000000000000..314762758830 --- /dev/null +++ b/src/views/email-exchange/tools/MessageViewer.jsx @@ -0,0 +1,310 @@ +import React, { useCallback, useEffect, useMemo, useState } from 'react' +import PropTypes from 'prop-types' +import { CippPage, CippMasonry, CippMasonryItem, CippContentCard } from 'src/components/layout' +import { parseEml, readEml, GBKUTF8, decode } from 'eml-parse-js' +import { useMediaPredicate } from 'react-media-hook' +import { useSelector } from 'react-redux' +import { CellDate } from 'src/components/tables' +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' +import { + CButton, + CCard, + CCardBody, + CCol, + CDropdown, + CDropdownMenu, + CDropdownToggle, + CLink, + CRow, +} from '@coreui/react' +import ReactTimeAgo from 'react-time-ago' +import { CippCodeBlock, ModalService } from 'src/components/utilities' +import DOMPurify from 'dompurify' +import ReactHtmlParser from 'react-html-parser' +import CippDropzone from 'src/components/utilities/CippDropzone' + +const MessageViewer = ({ emlFile }) => { + const [emlContent, setEmlContent] = useState(null) + const [emailSource, setEmailSource] = useState(emlFile) + const [emlError, setEmlError] = useState(false) + const [messageHtml, setMessageHtml] = useState('') + + const getAttachmentIcon = (contentType) => { + if (contentType.includes('image')) { + return 'image' + } else if (contentType.includes('audio')) { + return 'volume-up' + } else if (contentType.includes('video')) { + return 'video' + } else if (contentType.includes('text')) { + return 'file-lines' + } else if (contentType.includes('pdf')) { + return 'file-pdf' + } else if ( + contentType.includes('zip') || + contentType.includes('compressed') || + contentType.includes('tar') || + contentType.includes('gzip') + ) { + return 'file-zipper' + } else if (contentType.includes('msword')) { + return 'file-word' + } else if (contentType.includes('spreadsheet')) { + return 'file-excel' + } else if (contentType.includes('presentation')) { + return 'file-powerpoint' + } else if (contentType.includes('json') || contentType.includes('xml')) { + return 'file-code' + } else if (contentType.includes('rfc822')) { + return 'envelope' + } else { + return 'file' + } + } + + const downloadAttachment = (attachment, newTab = false) => { + if (attachment?.data) { + var contentType = attachment?.contentType?.split(';')[0] ?? 'text/plain' + var fileBytes = attachment.data + var fileName = attachment.name + downloadFileBytes(fileName, fileBytes, contentType, newTab) + } else { + downloadFile(attachment.name, attachment.data64) + } + } + + const downloadFile = (fileName, base64Content, newTab) => { + const link = document.createElement('a') + link.href = `data:application/octet-stream;base64,${base64Content}` + link.download = fileName + link.click() + } + + const downloadFileBytes = (fileName, fileBytes, contentType, newTab = false) => { + const blob = new Blob([fileBytes], { type: contentType ?? 'application/octet-stream' }) + const url = URL.createObjectURL(blob) + const link = document.createElement('a') + if (newTab) { + if (contentType.includes('rfc822')) { + var content = fileBytes + const nestedMessage = + ModalService.open({ + body: nestedMessage, + title: fileName, + size: 'lg', + }) + } else { + const newWindow = window.open() + newWindow.location.href = url + } + } else { + link.href = url + link.download = fileName + link.click() + URL.revokeObjectURL(url) + } + } + + function isValidDate(d) { + return d instanceof Date && !isNaN(d) + } + + const showEmailModal = (emailSource) => { + ModalService.open({ + data: emailSource, + componentType: 'codeblock', + title: 'Email Source', + size: 'lg', + }) + } + + const EmailButtons = (emailSource) => { + return ( + showEmailModal(emailSource)}> + + View Source + + ) + } + + useEffect(() => { + readEml(emailSource, (err, ReadEmlJson) => { + if (err) { + setEmlError(true) + setEmlContent(null) + setMessageHtml(null) + } else { + setEmlContent(ReadEmlJson) + setEmlError(false) + if (ReadEmlJson.html) { + var sanitizedHtml = DOMPurify.sanitize(ReadEmlJson.html) + var parsedHtml = ReactHtmlParser(sanitizedHtml) + setMessageHtml(parsedHtml) + } else { + setMessageHtml(null) + } + } + }) + }, [emailSource, setMessageHtml, setEmailSource, setEmlError, setEmlContent]) + + var buttons = EmailButtons(emailSource) + + return ( + <> + {emlError && ( + + Unable to parse the EML file, email source is displayed below. + + + )} + + {emlContent && ( + <> + + <> + + +
+ + {emlContent?.from?.name} <{emlContent?.from?.email}> +
+ {emlContent?.to?.length > 0 && ( +
+ + To:{' '} + {emlContent?.to?.map((to) => to.name + ' <' + to.email + '>').join(', ')} + +
+ )} + {emlContent?.cc?.length > 0 && ( +
+ + CC:{' '} + {emlContent?.cc?.map((cc) => cc.name + ' <' + cc.email + '>').join(', ')} + +
+ )} +
+ +
+ + + {emlContent.date && isValidDate(emlContent.date) + ? emlContent.date.toLocaleDateString() + : 'Invalid Date'} + + {emlContent.date && isValidDate(emlContent.date) && ( + <> + () + + )} + +
+
+
+ + + {emlContent.attachments && emlContent.attachments.length > 0 && ( + + + {emlContent.attachments.map((attachment, index) => ( + + + + {attachment.name ?? 'No name'} + + + downloadAttachment(attachment)} + > + + Download + + {(attachment?.contentType === undefined || + attachment?.contentType?.includes('text') || + attachment?.contentType?.includes('pdf') || + attachment?.contentType?.includes('image') || + attachment?.contentType?.includes('rfc822')) && ( + downloadAttachment(attachment, true)} + > + + View + + )} + + + ))} + + + )} + + {(emlContent?.text || emlContent?.html) && ( + + + {messageHtml ? ( +
{messageHtml}
+ ) : ( +
+ +
+ )} +
+
+ )} +
+ + )} + + ) +} + +MessageViewer.propTypes = { + emlFile: PropTypes.string, +} + +const MessageViewerPage = () => { + const [emlFile, setEmlFile] = useState(null) + const onDrop = useCallback((acceptedFiles) => { + acceptedFiles.forEach((file) => { + const reader = new FileReader() + + reader.onabort = () => console.log('file reading was aborted') + reader.onerror = () => console.log('file reading has failed') + reader.onload = () => { + setEmlFile(reader.result) + } + reader.readAsText(file) + }) + }, []) + + return ( + + + {emlFile && } + + ) +} + +export default MessageViewerPage From 9b51796b206dde86252543a00c4bebaf690d81b1 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Wed, 31 Jul 2024 23:33:12 +0200 Subject: [PATCH 039/130] upgrade user schedulder experience. --- src/views/identity/administration/AddUser.jsx | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/src/views/identity/administration/AddUser.jsx b/src/views/identity/administration/AddUser.jsx index 96186c358ed9..ad772b208d1a 100644 --- a/src/views/identity/administration/AddUser.jsx +++ b/src/views/identity/administration/AddUser.jsx @@ -37,8 +37,12 @@ import useQuery from 'src/hooks/useQuery' import Select from 'react-select' import { useNavigate } from 'react-router-dom' import { OnChange } from 'react-final-form-listeners' +import DatePicker from 'react-datepicker' +import 'react-datepicker/dist/react-datepicker.css' const AddUser = () => { + const currentDate = new Date() + const [startDate, setStartDate] = useState(currentDate) let navigate = useNavigate() const [addedAttributes, setAddedAttribute] = React.useState(0) const tenant = useSelector((state) => state.app.currentTenant) @@ -81,6 +85,8 @@ const AddUser = () => { values.addedAttributes.push({ Key: key, Value: values.defaultAttributes[key].Value }) }) } + const unixTime = Math.floor(startDate.getTime() / 1000) + const shippedValues = { AddedAliases: values.addedAliases ? values.addedAliases : '', BusinessPhone: values.businessPhones, @@ -106,6 +112,10 @@ const AddUser = () => { tenantID: tenantDomain, addedAttributes: values.addedAttributes, setManager: values.setManager, + Scheduled: values.Scheduled?.enabled ? { enabled: true, date: unixTime } : { enabled: false }, + PostExecution: values.Scheduled?.enabled + ? { webhook: values.webhook, psa: values.psa, email: values.email } + : '', ...values.license, } //window.alert(JSON.stringify(shippedValues)) @@ -408,6 +418,33 @@ const AddUser = () => { /> {usersError && Failed to load list of users} + + + + + + + + + setStartDate(date)} + /> + + + + + + + + + + From 3f20d802064b8322a32aa9fad0dfe129c321714a Mon Sep 17 00:00:00 2001 From: John Duprey Date: Wed, 31 Jul 2024 19:42:03 -0400 Subject: [PATCH 040/130] message view bugfixes --- .../email-exchange/tools/MessageViewer.jsx | 66 ++++++++++++------- 1 file changed, 41 insertions(+), 25 deletions(-) diff --git a/src/views/email-exchange/tools/MessageViewer.jsx b/src/views/email-exchange/tools/MessageViewer.jsx index 314762758830..52d7c3b637a4 100644 --- a/src/views/email-exchange/tools/MessageViewer.jsx +++ b/src/views/email-exchange/tools/MessageViewer.jsx @@ -23,9 +23,8 @@ import DOMPurify from 'dompurify' import ReactHtmlParser from 'react-html-parser' import CippDropzone from 'src/components/utilities/CippDropzone' -const MessageViewer = ({ emlFile }) => { +const MessageViewer = ({ emailSource }) => { const [emlContent, setEmlContent] = useState(null) - const [emailSource, setEmailSource] = useState(emlFile) const [emlError, setEmlError] = useState(false) const [messageHtml, setMessageHtml] = useState('') @@ -63,39 +62,57 @@ const MessageViewer = ({ emlFile }) => { } const downloadAttachment = (attachment, newTab = false) => { - if (attachment?.data) { - var contentType = attachment?.contentType?.split(';')[0] ?? 'text/plain' - var fileBytes = attachment.data - var fileName = attachment.name - downloadFileBytes(fileName, fileBytes, contentType, newTab) - } else { - downloadFile(attachment.name, attachment.data64) + var contentType = attachment?.contentType?.split(';')[0] ?? 'text/plain' + var fileBytes = attachment.data + if (fileBytes instanceof Uint8Array && attachment?.data64) { + fileBytes = new Uint8Array( + atob(attachment.data64) + .split('') + .map((c) => c.charCodeAt(0)), + ) } - } - - const downloadFile = (fileName, base64Content, newTab) => { - const link = document.createElement('a') - link.href = `data:application/octet-stream;base64,${base64Content}` - link.download = fileName - link.click() - } - - const downloadFileBytes = (fileName, fileBytes, contentType, newTab = false) => { + var fileName = attachment.name const blob = new Blob([fileBytes], { type: contentType ?? 'application/octet-stream' }) const url = URL.createObjectURL(blob) const link = document.createElement('a') if (newTab) { if (contentType.includes('rfc822')) { var content = fileBytes - const nestedMessage = + const nestedMessage = ModalService.open({ body: nestedMessage, title: fileName, size: 'lg', }) + } else if (contentType.includes('pdf')) { + const embeddedPdf = + ModalService.open({ + body: embeddedPdf, + title: fileName, + size: 'lg', + }) + } else if (contentType.includes('image')) { + const embeddedImage = {fileName} + ModalService.open({ + body: embeddedImage, + title: fileName, + size: 'lg', + }) + } else if (contentType.includes('text')) { + const textContent = fileBytes + ModalService.open({ + data: textContent, + componentType: 'codeblock', + title: fileName, + size: 'lg', + }) + setTimeout(() => { + URL.revokeObjectURL(url) + }, 1000) } else { const newWindow = window.open() newWindow.location.href = url + URL.revokeObjectURL(url) } } else { link.href = url @@ -145,7 +162,7 @@ const MessageViewer = ({ emlFile }) => { } } }) - }, [emailSource, setMessageHtml, setEmailSource, setEmlError, setEmlContent]) + }, [emailSource, setMessageHtml, setEmlError, setEmlContent]) var buttons = EmailButtons(emailSource) @@ -238,7 +255,7 @@ const MessageViewer = ({ emlFile }) => { className="dropdown-item" onClick={() => downloadAttachment(attachment, true)} > - + View )} @@ -274,7 +291,7 @@ const MessageViewer = ({ emlFile }) => { } MessageViewer.propTypes = { - emlFile: PropTypes.string, + emailSource: PropTypes.string, } const MessageViewerPage = () => { @@ -282,7 +299,6 @@ const MessageViewerPage = () => { const onDrop = useCallback((acceptedFiles) => { acceptedFiles.forEach((file) => { const reader = new FileReader() - reader.onabort = () => console.log('file reading was aborted') reader.onerror = () => console.log('file reading has failed') reader.onload = () => { @@ -302,7 +318,7 @@ const MessageViewerPage = () => { dropMessage="Drag an EML file or click to add" maxFiles={1} /> - {emlFile && } + {emlFile && } ) } From cff54a8fbd26c98f154a9cade3af684cba243d10 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Wed, 31 Jul 2024 20:00:02 -0400 Subject: [PATCH 041/130] add blob: to content-security-policy --- staticwebapp.config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/staticwebapp.config.json b/staticwebapp.config.json index 8a0fafca07d4..74988468595b 100644 --- a/staticwebapp.config.json +++ b/staticwebapp.config.json @@ -103,7 +103,7 @@ } }, "globalHeaders": { - "content-security-policy": "default-src https: 'unsafe-eval' 'unsafe-inline'; object-src 'none'; img-src 'self' data: *" + "content-security-policy": "default-src https: 'unsafe-eval' 'unsafe-inline'; object-src 'self' blob:; img-src 'self' blob: data: *" }, "mimeTypes": { ".json": "text/json" From ff56eef918f8e04122c6983bc67c51680185845a Mon Sep 17 00:00:00 2001 From: John Duprey Date: Wed, 31 Jul 2024 20:05:33 -0400 Subject: [PATCH 042/130] add blob to default-src --- staticwebapp.config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/staticwebapp.config.json b/staticwebapp.config.json index 74988468595b..0c36ddcac257 100644 --- a/staticwebapp.config.json +++ b/staticwebapp.config.json @@ -103,7 +103,7 @@ } }, "globalHeaders": { - "content-security-policy": "default-src https: 'unsafe-eval' 'unsafe-inline'; object-src 'self' blob:; img-src 'self' blob: data: *" + "content-security-policy": "default-src https: blob: 'unsafe-eval' 'unsafe-inline'; object-src 'self' blob:; img-src 'self' blob: data: *" }, "mimeTypes": { ".json": "text/json" From f978031b21ed9b612e57cbeb32b47ea122e28b44 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Wed, 31 Jul 2024 20:19:16 -0400 Subject: [PATCH 043/130] sanitize secure score html --- .../tenant/administration/SecureScore.jsx | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/views/tenant/administration/SecureScore.jsx b/src/views/tenant/administration/SecureScore.jsx index be036997339c..bfa9d2e751c2 100644 --- a/src/views/tenant/administration/SecureScore.jsx +++ b/src/views/tenant/administration/SecureScore.jsx @@ -28,6 +28,8 @@ import { CellTip, cellGenericFormatter } from 'src/components/tables/CellGeneric import { CippCallout } from 'src/components/layout' import CippPrettyCard from 'src/components/contentcards/CippPrettyCard' import { TableModalButton } from 'src/components/buttons' +import DOMPurify from 'dompurify' +import ReactHtmlParser from 'react-html-parser' const SecureScore = () => { const textRef = useRef() @@ -66,6 +68,12 @@ const SecureScore = () => { }, }) + const sanitizeHtml = (html) => { + var sanitizedHtml = DOMPurify.sanitize(html) + var parsedHtml = ReactHtmlParser(sanitizedHtml) + return parsedHtml + } + useEffect(() => { if (isSuccess) { setTranslatedData(securescore.Results[0]) @@ -341,23 +349,16 @@ const SecureScore = () => {
Description
-
+
+ {sanitizeHtml(`${info.description} ${info.implementationStatus}`)} +
{info.scoreInPercentage !== 100 && (
Remediation Recommendation
- { -
- } + {
{sanitizeHtml(info.remediation)}
}
)} From e4e5ab15c86afa76f2e77028728e1bb599012c6b Mon Sep 17 00:00:00 2001 From: John Duprey Date: Wed, 31 Jul 2024 20:44:54 -0400 Subject: [PATCH 044/130] Fix revokesession bulk action --- src/views/identity/administration/Users.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/views/identity/administration/Users.jsx b/src/views/identity/administration/Users.jsx index 3bd663d7e063..669e401a3611 100644 --- a/src/views/identity/administration/Users.jsx +++ b/src/views/identity/administration/Users.jsx @@ -589,7 +589,7 @@ const Users = (row) => { label: 'Revoke sessions', color: 'info', modal: true, - modalUrl: `/api/ExecRevokeSessions?Enable=true&TenantFilter=!Tenant&ID=!userPrincipalName`, + modalUrl: `/api/ExecRevokeSessions?Enable=true&TenantFilter=!Tenant&ID=!id&Username=!userPrincipalName`, modalMessage: 'Are you sure you want to revoke all sessions for these users?', }, { From 8be3b6d85b95ef903ad1522d667483b4c845cbed Mon Sep 17 00:00:00 2001 From: John Duprey Date: Thu, 1 Aug 2024 01:11:50 -0400 Subject: [PATCH 045/130] SAM Roles --- .../cipp/app-settings/SettingsSuperAdmin.jsx | 38 +---- .../components/SettingsSAMRoles.jsx | 133 ++++++++++++++++++ 2 files changed, 135 insertions(+), 36 deletions(-) create mode 100644 src/views/cipp/app-settings/components/SettingsSAMRoles.jsx diff --git a/src/views/cipp/app-settings/SettingsSuperAdmin.jsx b/src/views/cipp/app-settings/SettingsSuperAdmin.jsx index 4e38038fb68c..18cb6b397980 100644 --- a/src/views/cipp/app-settings/SettingsSuperAdmin.jsx +++ b/src/views/cipp/app-settings/SettingsSuperAdmin.jsx @@ -7,6 +7,7 @@ import { CippCallout } from 'src/components/layout/index.js' import CippAccordionItem from 'src/components/contentcards/CippAccordionItem' import SettingsCustomRoles from 'src/views/cipp/app-settings/components/SettingsCustomRoles' import CippButtonCard from 'src/components/contentcards/CippButtonCard' +import SettingsSAMRoles from './components/SettingsSAMRoles' export function SettingsSuperAdmin() { const partnerConfig = useGenericGetRequestQuery({ @@ -65,46 +66,11 @@ export function SettingsSuperAdmin() {

- - -

Tenant Mode

-
( - <> - {partnerConfig.isFetching && } - - - - - - - )} - /> - {webhookCreateResult.isSuccess && ( - - {webhookCreateResult?.data?.results} - - )} - - + ) } diff --git a/src/views/cipp/app-settings/components/SettingsSAMRoles.jsx b/src/views/cipp/app-settings/components/SettingsSAMRoles.jsx new file mode 100644 index 000000000000..cb687914def3 --- /dev/null +++ b/src/views/cipp/app-settings/components/SettingsSAMRoles.jsx @@ -0,0 +1,133 @@ +import React, { useRef, useState } from 'react' +import { + CButton, + CCallout, + CCol, + CForm, + CRow, + CAccordion, + CAccordionHeader, + CAccordionBody, + CAccordionItem, +} from '@coreui/react' +import { Field, Form, FormSpy } from 'react-final-form' +import { RFFCFormRadioList, RFFSelectSearch } from 'src/components/forms' +import { useGenericGetRequestQuery, useLazyGenericPostRequestQuery } from 'src/store/api/app' +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' +import { TenantSelectorMultiple, ModalService, CippOffcanvas } from 'src/components/utilities' +import PropTypes from 'prop-types' +import { OnChange } from 'react-final-form-listeners' +import { useListTenantsQuery } from 'src/store/api/tenants' +import { OffcanvasListSection } from 'src/components/utilities/CippListOffcanvas' +import CippButtonCard from 'src/components/contentcards/CippButtonCard' +import GDAPRoles from 'src/data/GDAPRoles' + +const SettingsSAMRoles = () => { + const [genericPostRequest, postResults] = useLazyGenericPostRequestQuery() + const [selectedTenant, setSelectedTenant] = useState([]) + const tenantSelectorRef = useRef() + const { data: tenants = [], tenantsFetching } = useListTenantsQuery({ + showAllTenantSelector: true, + }) + + const { + data: cippSAMRoles = [], + isFetching: roleListFetching, + isSuccess: roleListSuccess, + refetch: refetchRoleList, + } = useGenericGetRequestQuery({ + path: 'api/ExecSAMRoles', + }) + + const handleTenantChange = (e) => { + setSelectedTenant(e) + } + + const handleSubmit = async (values) => { + //filter on only objects that are 'true' + genericPostRequest({ + path: '/api/ExecSAMRoles?Action=Update', + values: { + Roles: values.Roles, + Tenants: selectedTenant.map((tenant) => tenant.value), + }, + }).then(() => { + refetchRoleList() + }) + } + + return ( + + <> +

+ Add your CIPP-SAM application Service Principal directly to Admin Roles in the tenant. + This is an advanced use case where you need access to additional Graph endpoints or + Exchange Cmdlets otherwise unavailable via Delegated permissions. +

+

+ This functionality is in + beta and should be treated as such. Roles are added during the Update Permissions process + or a CPV refresh. +

+ + { + return ( + + + +
+ ({ + name: role.Name, + value: role.ObjectId, + }))} + isLoading={roleListFetching} + multi={true} + refreshFunction={() => refetchRoleList()} + placeholder="Select admin roles" + /> +
+
+
Selected Tenants
+ handleTenantChange(e)} + /> +
+
+
+ + {postResults.isSuccess && ( + {postResults.data.Results} + )} + + + + + Save + + + + +
+ ) + }} + /> + +
+ ) +} + +export default SettingsSAMRoles From 8ac22e9abecb8a95a922bf88d0586dc21dc97509 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Thu, 1 Aug 2024 12:06:34 +0200 Subject: [PATCH 046/130] add device compliance alert --- src/data/alerts.json | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/data/alerts.json b/src/data/alerts.json index 2d635fb529f9..835216740c4d 100644 --- a/src/data/alerts.json +++ b/src/data/alerts.json @@ -94,5 +94,10 @@ "name": "SoftDeletedMailboxes", "label": "Alert on soft deleted mailboxes", "recommendedRunInterval": "1d" + }, + { + "name": "DeviceCompliance", + "label": "Alert on device compliance issues", + "recommendedRunInterval": "4h" } -] \ No newline at end of file +] From 2cb908a8d2aed95491cd7aad18773186d2da3ddc Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Thu, 1 Aug 2024 12:49:37 +0200 Subject: [PATCH 047/130] fixes https://github.com/KelvinTegelaar/CIPP/issues/2710 --- src/views/identity/administration/RiskyUsers.jsx | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/views/identity/administration/RiskyUsers.jsx b/src/views/identity/administration/RiskyUsers.jsx index d51a899bef85..0b8ae07e7e8d 100644 --- a/src/views/identity/administration/RiskyUsers.jsx +++ b/src/views/identity/administration/RiskyUsers.jsx @@ -88,6 +88,20 @@ const RiskyUsers = () => { } const columns = [ + { + name: 'Tenant', + selector: (row) => row['Tenant'], + sortable: true, + exportSelector: 'Tenant', + omit: tenant.defaultDomainName === 'allTenants' ? false : true, + }, + { + name: 'Status', + selector: (row) => row['CippStatus'], + sortable: true, + exportSelector: 'CippStatus', + omit: tenant.defaultDomainName === 'allTenants' ? false : true, + }, { name: 'Risk Last Updated Date', selector: (row) => row['riskLastUpdatedDateTime'], From f79e0c819db99857856e73a35ca2bdc0649326e4 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Thu, 1 Aug 2024 12:52:38 +0200 Subject: [PATCH 048/130] fixes https://github.com/KelvinTegelaar/CIPP/issues/2710 --- src/views/identity/administration/RiskyUsers.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/views/identity/administration/RiskyUsers.jsx b/src/views/identity/administration/RiskyUsers.jsx index 0b8ae07e7e8d..9d0b949b135a 100644 --- a/src/views/identity/administration/RiskyUsers.jsx +++ b/src/views/identity/administration/RiskyUsers.jsx @@ -93,14 +93,14 @@ const RiskyUsers = () => { selector: (row) => row['Tenant'], sortable: true, exportSelector: 'Tenant', - omit: tenant.defaultDomainName === 'allTenants' ? false : true, + omit: tenant.defaultDomainName === 'AllTenants' ? false : true, }, { name: 'Status', selector: (row) => row['CippStatus'], sortable: true, exportSelector: 'CippStatus', - omit: tenant.defaultDomainName === 'allTenants' ? false : true, + omit: tenant.defaultDomainName === 'AllTenants' ? false : true, }, { name: 'Risk Last Updated Date', From 06ba66bea0963ab7996d7dedbda428968daa9005 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Thu, 1 Aug 2024 08:35:25 -0400 Subject: [PATCH 049/130] Fix tenant selector --- .../components/SettingsSAMRoles.jsx | 125 ++++++++++-------- 1 file changed, 71 insertions(+), 54 deletions(-) diff --git a/src/views/cipp/app-settings/components/SettingsSAMRoles.jsx b/src/views/cipp/app-settings/components/SettingsSAMRoles.jsx index cb687914def3..ebc8310b6abd 100644 --- a/src/views/cipp/app-settings/components/SettingsSAMRoles.jsx +++ b/src/views/cipp/app-settings/components/SettingsSAMRoles.jsx @@ -1,4 +1,4 @@ -import React, { useRef, useState } from 'react' +import React, { useEffect, useRef, useState } from 'react' import { CButton, CCallout, @@ -26,7 +26,11 @@ const SettingsSAMRoles = () => { const [genericPostRequest, postResults] = useLazyGenericPostRequestQuery() const [selectedTenant, setSelectedTenant] = useState([]) const tenantSelectorRef = useRef() - const { data: tenants = [], tenantsFetching } = useListTenantsQuery({ + const { + data: tenants = [], + isFetching: tenantsFetching, + isSuccess: tenantSuccess, + } = useListTenantsQuery({ showAllTenantSelector: true, }) @@ -56,8 +60,20 @@ const SettingsSAMRoles = () => { }) } + useEffect(() => { + if (roleListSuccess && cippSAMRoles.Tenants.length > 0) { + var selectedTenants = [] + tenants.map((tenant) => { + if (cippSAMRoles.Tenants.includes(tenant.customerId)) { + selectedTenants.push({ label: tenant.displayName, value: tenant.customerId }) + } + }) + tenantSelectorRef.current.setValue(selectedTenants) + } + }, [cippSAMRoles, roleListSuccess, tenantSuccess, tenantSelectorRef, tenants]) + return ( - + <>

Add your CIPP-SAM application Service Principal directly to Admin Roles in the tenant. @@ -70,61 +86,62 @@ const SettingsSAMRoles = () => { or a CPV refresh.

- { - return ( - - - -
- ({ - name: role.Name, - value: role.ObjectId, - }))} - isLoading={roleListFetching} - multi={true} - refreshFunction={() => refetchRoleList()} - placeholder="Select admin roles" - /> -
-
-
Selected Tenants
- handleTenantChange(e)} - /> -
-
-
- - {postResults.isSuccess && ( - {postResults.data.Results} - )} + {roleListSuccess && ( + { + return ( + - - - +
+ ({ + name: role.Name, + value: role.ObjectId, + }))} + multi={true} + refreshFunction={() => refetchRoleList()} + placeholder="Select admin roles" /> - Save - +
+
+
Selected Tenants
+ handleTenantChange(e)} + /> +
-
-
- ) - }} - /> + + {postResults.isSuccess && ( + {postResults.data.Results} + )} + + + + + Save + + + + + + ) + }} + /> + )}
) From 47e8e7f59feb14bdc2439a85b948df943317fbc1 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Thu, 1 Aug 2024 15:29:53 +0200 Subject: [PATCH 050/130] Add edit named locations --- .../tenant/conditional/NamedLocations.jsx | 87 +++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/src/views/tenant/conditional/NamedLocations.jsx b/src/views/tenant/conditional/NamedLocations.jsx index b7f1ebb0f68c..817528a2078c 100644 --- a/src/views/tenant/conditional/NamedLocations.jsx +++ b/src/views/tenant/conditional/NamedLocations.jsx @@ -22,6 +22,88 @@ function DateNotNull(date) { return date.toString().trim() + 'Z' } +const Offcanvas = (row, rowIndex, formatExtraData) => { + const tenant = useSelector((state) => state.app.currentTenant) + const [ocVisible, setOCVisible] = useState(false) + return ( + <> + setOCVisible(true)}> + + + setOCVisible(false)} + /> + + ) +} const columns = [ { name: 'Name', @@ -62,6 +144,11 @@ const columns = [ exportSelector: 'modifiedDateTime', maxWidth: '150px', }, + { + name: 'Actions', + cell: Offcanvas, + maxWidth: '80px', + }, ] const NamedLocationsList = () => { From c70d679fe0570187774a9a98fb5a912feefd5ebc Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Thu, 1 Aug 2024 15:43:52 +0200 Subject: [PATCH 051/130] test --- src/views/cipp/ExtensionMappings.jsx | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/views/cipp/ExtensionMappings.jsx b/src/views/cipp/ExtensionMappings.jsx index 4de976555ccc..816a679e9905 100644 --- a/src/views/cipp/ExtensionMappings.jsx +++ b/src/views/cipp/ExtensionMappings.jsx @@ -218,11 +218,7 @@ export default function ExtensionMappings({ type, fieldMappings = false, autoMap { - return !Object.keys(listMappingBackendResult.data?.Mappings).includes( - tenant.customerId, - ) - }).map((tenant) => ({ + values={listMappingBackendResult.data?.Tenants.map((tenant) => ({ name: tenant.displayName, value: tenant.customerId, }))} From 930f99700d2b3d1c3c20c800d202d3ece43f458c Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Thu, 1 Aug 2024 15:48:47 +0200 Subject: [PATCH 052/130] test fix for extension multi mappings --- src/views/cipp/ExtensionMappings.jsx | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/views/cipp/ExtensionMappings.jsx b/src/views/cipp/ExtensionMappings.jsx index 816a679e9905..5bcf9e23e8e8 100644 --- a/src/views/cipp/ExtensionMappings.jsx +++ b/src/views/cipp/ExtensionMappings.jsx @@ -218,7 +218,11 @@ export default function ExtensionMappings({ type, fieldMappings = false, autoMap ({ + values={listMappingBackendResult.data?.Tenants.filter((tenant) => { + return !Object.keys(listMappingBackendResult.data?.Mappings).includes( + tenant.customerId, + ) + }).map((tenant) => ({ name: tenant.displayName, value: tenant.customerId, }))} @@ -247,9 +251,7 @@ export default function ExtensionMappings({ type, fieldMappings = false, autoMap if ( mappingValue.value !== undefined && mappingValue.value !== '-1' && - Object.values(mappingArray) - .map((item) => item.companyId) - .includes(mappingValue.value) === false + Object.values(mappingArray).map((item) => item.companyId) ) { setMappingArray([ ...mappingArray, From 1d94b1e20fa67bc9e2f54de62462cb2c61c65360 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Thu, 1 Aug 2024 15:57:45 +0200 Subject: [PATCH 053/130] fallback to actual id --- src/components/tables/CellLicense.jsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/components/tables/CellLicense.jsx b/src/components/tables/CellLicense.jsx index 50b88b978c4f..ff5df5329743 100644 --- a/src/components/tables/CellLicense.jsx +++ b/src/components/tables/CellLicense.jsx @@ -8,6 +8,8 @@ export function CellLicense({ cell }) { if (licenseAssignment.skuId == M365Licenses[x].GUID) { licenses.push(M365Licenses[x].Product_Display_Name) break + } else { + licenses.push(licenseAssignment.skuId) } } }) From ed1e05be4004d18af54533032feb522e000532b0 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Thu, 1 Aug 2024 14:14:25 -0400 Subject: [PATCH 054/130] Audit logs --- src/_nav.jsx | 9 +- src/importsMap.jsx | 3 +- src/routes.json | 10 +- .../tenant/administration/ListAlertsQueue.jsx | 2 +- .../tenant/administration/ListAuditLogs.jsx | 233 ++++++++++++++++++ 5 files changed, 251 insertions(+), 6 deletions(-) create mode 100644 src/views/tenant/administration/ListAuditLogs.jsx diff --git a/src/_nav.jsx b/src/_nav.jsx index 59d2980e2ae1..bc1505aa763e 100644 --- a/src/_nav.jsx +++ b/src/_nav.jsx @@ -145,8 +145,13 @@ const _nav = [ }, { component: CNavItem, - name: 'Alerts', - to: '/tenant/administration/alertsqueue', + name: 'Alert Configuration', + to: '/tenant/administration/alert-configuration', + }, + { + component: CNavItem, + name: 'Audit Logs', + to: '/tenant/administration/audit-logs', }, { component: CNavItem, diff --git a/src/importsMap.jsx b/src/importsMap.jsx index f7c2a6e83234..3708a44f4ed9 100644 --- a/src/importsMap.jsx +++ b/src/importsMap.jsx @@ -42,7 +42,8 @@ import React from 'react' "/tenant/administration/domains": React.lazy(() => import('./views/tenant/administration/Domains')), "/tenant/administration/alertswizard": React.lazy(() => import('./views/tenant/administration/AlertWizard')), "/tenant/administration/alertrules": React.lazy(() => import('./views/tenant/administration/AlertRules')), - "/tenant/administration/alertsqueue": React.lazy(() => import('./views/tenant/administration/ListAlertsQueue')), + "/tenant/administration/alert-configuration": React.lazy(() => import('./views/tenant/administration/ListAlertsQueue')), + "/tenant/administration/audit-logs": React.lazy(() => import('./views/tenant/administration/ListAuditLogs')), "/tenant/administration/graph-explorer": React.lazy(() => import('./views/tenant/administration/GraphExplorer')), "/tenant/administration/service-health": React.lazy(() => import('./views/tenant/administration/ServiceHealth')), "/tenant/administration/enterprise-apps": React.lazy(() => import('./views/tenant/administration/ListEnterpriseApps')), diff --git a/src/routes.json b/src/routes.json index be956782af6d..73f0383bbd20 100644 --- a/src/routes.json +++ b/src/routes.json @@ -279,11 +279,17 @@ "allowedRoles": ["admin", "editor", "readonly"] }, { - "path": "/tenant/administration/alertsqueue", - "name": "Alerts Queue", + "path": "/tenant/administration/alert-configuration", + "name": "Alert Configuration", "component": "views/tenant/administration/ListAlertsQueue", "allowedRoles": ["admin", "editor", "readonly"] }, + { + "path": "/tenant/administration/audit-logs", + "name": "Audit Logs", + "component": "views/tenant/administration/ListAuditLogs", + "allowedRoles": ["admin", "editor", "readonly"] + }, { "path": "/tenant/administration/graph-explorer", "name": "Graph Explorer", diff --git a/src/views/tenant/administration/ListAlertsQueue.jsx b/src/views/tenant/administration/ListAlertsQueue.jsx index 7efe849c13a4..7a715188a824 100644 --- a/src/views/tenant/administration/ListAlertsQueue.jsx +++ b/src/views/tenant/administration/ListAlertsQueue.jsx @@ -65,7 +65,7 @@ const ListClassicAlerts = () => { allTenants: true, helpContext: 'https://google.com', }} - title="Alerts List" + title="Alert Configuration" titleButton={ { + const [interval, setInterval] = React.useState('d') + const [time, setTime] = React.useState(1) + const [relativeTime, setRelativeTime] = React.useState('1d') + const [startDate, setStartDate] = React.useState(null) + const [endDate, setEndDate] = React.useState(null) + const [visibleA, setVisibleA] = React.useState(true) + const [tenantColumnSet, setTenantColumn] = React.useState(false) + const tenant = useSelector((state) => state.app.currentTenant) + + useEffect(() => { + if (tenant.defaultDomainName === 'AllTenants') { + setTenantColumn(false) + } + if (tenant.defaultDomainName !== 'AllTenants') { + setTenantColumn(true) + } + }, [tenant.defaultDomainName, tenantColumnSet]) + + const handleSearch = (values) => { + if (values.dateFilter === 'relative') { + setRelativeTime(`${values.Time}${values.Interval}`) + setStartDate(null) + setEndDate(null) + } else if (values.dateFilter === 'startEnd') { + setRelativeTime(null) + setStartDate(values.startDate) + setEndDate(values.endDate) + } + setVisibleA(false) + } + + const Actions = () => { + return ( + + + + + + ) + } + + const columns = [ + { + name: 'Timestamp', + selector: (row) => row['Timestamp'], + sortable: true, + exportSelector: 'Timestamp', + cell: cellDateFormatter({ format: 'short' }), + maxWidth: '200px', + }, + { + name: 'Tenant', + selector: (row) => row['Tenant'], + exportSelector: 'Tenant', + omit: !tenantColumnSet, + cell: cellGenericFormatter(), + maxWidth: '150px', + }, + { + name: 'Title', + selector: (row) => row['Title'], + exportSelector: 'Title', + cell: cellGenericFormatter(), + }, + { + name: 'Actions', + cell: Actions, + maxWidth: '100px', + }, + ] + return ( +
+ + + + + + Search Options + setVisibleA(!visibleA)} + > + + + + + + + + + + { + return ( + + + + Date Filter Type +
+ +
+
+
+
+ + + + Relative Time + + + Last + + + {({ input, meta }) => } + + + {({ input, meta }) => ( + + + + + + )} + + + + + + + + + + + + + + + + + + + + Search + + + +
+ ) + }} + /> +
+
+
+
+
+
+ +
+ ) +} + +export default ListAuditLogs From 70853600b9183487bffe959e8168ae93b8e6d8eb Mon Sep 17 00:00:00 2001 From: John Duprey Date: Thu, 1 Aug 2024 19:40:38 -0400 Subject: [PATCH 055/130] Add refresh config following a save --- src/views/cipp/Extensions.jsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/views/cipp/Extensions.jsx b/src/views/cipp/Extensions.jsx index eec80f5a1068..5923599a6f66 100644 --- a/src/views/cipp/Extensions.jsx +++ b/src/views/cipp/Extensions.jsx @@ -39,6 +39,8 @@ export default function CIPPExtensions() { setExtensionconfig({ path: 'api/ExecExtensionsConfig', values: values, + }).then((res) => { + listBackend({ path: 'api/ListExtensionsConfig' }) }) } From aae375a43a93b2ca62889330c6c7f9583407f824 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Fri, 2 Aug 2024 12:23:34 +0200 Subject: [PATCH 056/130] updates to layout --- .../tenant/standards/ListAppliedStandards.jsx | 36 ++++--------------- 1 file changed, 6 insertions(+), 30 deletions(-) diff --git a/src/views/tenant/standards/ListAppliedStandards.jsx b/src/views/tenant/standards/ListAppliedStandards.jsx index f60370975ee6..d93d6609148c 100644 --- a/src/views/tenant/standards/ListAppliedStandards.jsx +++ b/src/views/tenant/standards/ListAppliedStandards.jsx @@ -751,23 +751,15 @@ const ApplyNewStandard = () => { }, ].map((template, index) => ( - +
{template.name}
Deploy {template.name}
- -
Report
- -
- -
Alert
- -
Remediate
- +
Settings
{template.templates.isSuccess && ( {
))} - +
Autopilot Profile
Deploy Autopilot profile
- -
Report
- -
- -
Alert
- -
Remediate
- +
Settings
@@ -938,23 +922,15 @@ const ApplyNewStandard = () => { - +
Autopilot Status Page
Deploy Autopilot Status Page
- -
Report
- -
- -
Alert
- -
Remediate
- +
Settings
From fb51fb943a128b52c05ecc8fa68cef2db29e6ca9 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Fri, 2 Aug 2024 13:31:04 +0200 Subject: [PATCH 057/130] new standards apply templates for intune --- .../tenant/standards/ListAppliedStandards.jsx | 123 ++++++++++++++++-- 1 file changed, 112 insertions(+), 11 deletions(-) diff --git a/src/views/tenant/standards/ListAppliedStandards.jsx b/src/views/tenant/standards/ListAppliedStandards.jsx index d93d6609148c..d591ff4b7168 100644 --- a/src/views/tenant/standards/ListAppliedStandards.jsx +++ b/src/views/tenant/standards/ListAppliedStandards.jsx @@ -29,7 +29,12 @@ import { useLazyGenericGetRequestQuery, useLazyGenericPostRequestQuery, } from 'src/store/api/app' -import { faCheck, faCircleNotch, faExclamationTriangle } from '@fortawesome/free-solid-svg-icons' +import { + faCheck, + faCircleNotch, + faExclamationTriangle, + faTrash, +} from '@fortawesome/free-solid-svg-icons' import { CippCallout, CippContentCard, CippPage } from 'src/components/layout' import { useSelector } from 'react-redux' import { ModalService, validateAlphabeticalSort } from 'src/components/utilities' @@ -368,6 +373,32 @@ const ApplyNewStandard = () => { setEnabledWarningsCount, ]) + const handleAddIntuneTemplate = (form) => { + const formvalues = form.getState().values + const newTemplate = { + label: formvalues.intunedataList.label, + value: formvalues.intunedataList.value, + AssignedTo: + formvalues.IntuneAssignto === 'customGroup' + ? formvalues.customGroup + : formvalues.IntuneAssignto, + } + const originalTemplates = formvalues.standards?.IntuneTemplate?.TemplateList || [] + const updatedTemplateList = [...originalTemplates, newTemplate] + + form.change('standards.IntuneTemplate.TemplateList', updatedTemplateList) + form.change('intunedataList', undefined) + form.change('intuneAssignTo', undefined) + form.change('customGroup', undefined) + } + const handleRemoveDeployedTemplate = (form, row) => { + console.log(row) + const formvalues = form.getState().values + const updatedTemplateList = formvalues.standards.IntuneTemplate.TemplateList.filter( + (template) => template.value !== row.value, + ) + form.change('standards.IntuneTemplate.TemplateList', updatedTemplateList) + } return ( <> @@ -484,7 +515,7 @@ const ApplyNewStandard = () => { }, }} onSubmit={handleSubmit} - render={({ handleSubmit, submitting, values }) => { + render={({ handleSubmit, submitting, values, form }) => { return ( @@ -728,6 +759,7 @@ const ApplyNewStandard = () => { switchName: 'standards.IntuneTemplate', assignable: true, templates: intuneTemplates, + table: true, }, { name: 'Transport Rule Template', @@ -761,11 +793,53 @@ const ApplyNewStandard = () => {
Settings
+ {template.table && ( + row['label'], + sortable: true, + exportSelector: 'name', + cell: cellGenericFormatter(), + }, + { + name: 'Assigned to', + selector: (row) => row['AssignedTo'], + sortable: true, + exportSelector: 'GUID', + }, + { + name: 'Actions', + cell: (row) => ( + + handleRemoveDeployedTemplate(form, row) + } + > + + + ), + }, + ]} + /> + )} {template.templates.isSuccess && ( { <> + handleAddIntuneTemplate(form)}> + Add to deployment + )}
From 5facbd7cd4fd8a2c6a1ced151439d7cfe38f3dd9 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Fri, 2 Aug 2024 13:50:31 +0200 Subject: [PATCH 058/130] add remove of old undefined. --- src/views/tenant/standards/ListAppliedStandards.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/views/tenant/standards/ListAppliedStandards.jsx b/src/views/tenant/standards/ListAppliedStandards.jsx index d591ff4b7168..10eab27c96fd 100644 --- a/src/views/tenant/standards/ListAppliedStandards.jsx +++ b/src/views/tenant/standards/ListAppliedStandards.jsx @@ -385,7 +385,7 @@ const ApplyNewStandard = () => { } const originalTemplates = formvalues.standards?.IntuneTemplate?.TemplateList || [] const updatedTemplateList = [...originalTemplates, newTemplate] - + form.change('standards.IntuneTemplate.AssignTo', undefined) form.change('standards.IntuneTemplate.TemplateList', updatedTemplateList) form.change('intunedataList', undefined) form.change('intuneAssignTo', undefined) From c7b6f31f510dedb7e9b633e4986712463be08a33 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Fri, 2 Aug 2024 15:47:40 +0200 Subject: [PATCH 059/130] revert due to license column bug. --- src/components/tables/CellLicense.jsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/components/tables/CellLicense.jsx b/src/components/tables/CellLicense.jsx index ff5df5329743..50b88b978c4f 100644 --- a/src/components/tables/CellLicense.jsx +++ b/src/components/tables/CellLicense.jsx @@ -8,8 +8,6 @@ export function CellLicense({ cell }) { if (licenseAssignment.skuId == M365Licenses[x].GUID) { licenses.push(M365Licenses[x].Product_Display_Name) break - } else { - licenses.push(licenseAssignment.skuId) } } }) From fde2501818265f9e52bbc2209be01b52bc7d3423 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Fri, 2 Aug 2024 11:36:59 -0400 Subject: [PATCH 060/130] Add message header parsing --- .../email-exchange/tools/MessageViewer.jsx | 34 ++++++++++++++----- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/src/views/email-exchange/tools/MessageViewer.jsx b/src/views/email-exchange/tools/MessageViewer.jsx index 52d7c3b637a4..f010c0b37c4f 100644 --- a/src/views/email-exchange/tools/MessageViewer.jsx +++ b/src/views/email-exchange/tools/MessageViewer.jsx @@ -27,6 +27,7 @@ const MessageViewer = ({ emailSource }) => { const [emlContent, setEmlContent] = useState(null) const [emlError, setEmlError] = useState(false) const [messageHtml, setMessageHtml] = useState('') + const [emlHeaders, setEmlHeaders] = useState(null) const getAttachmentIcon = (contentType) => { if (contentType.includes('image')) { @@ -126,21 +127,32 @@ const MessageViewer = ({ emailSource }) => { return d instanceof Date && !isNaN(d) } - const showEmailModal = (emailSource) => { + const showEmailModal = (emailSource, title = 'Email Source') => { ModalService.open({ data: emailSource, componentType: 'codeblock', - title: 'Email Source', + title: title, size: 'lg', }) } - const EmailButtons = (emailSource) => { + const EmailButtons = (emailHeaders, emailSource) => { + const emailSourceBytes = new TextEncoder().encode(emailSource) + const blob = new Blob([emailSourceBytes], { type: 'message/rfc822' }) + const url = URL.createObjectURL(blob) return ( - showEmailModal(emailSource)}> - - View Source - + + {emailHeaders && ( + showEmailModal(emailHeaders, 'Email Headers')} className="me-2"> + + View Headers + + )} + showEmailModal(emailSource)}> + + View Source + + ) } @@ -150,6 +162,7 @@ const MessageViewer = ({ emailSource }) => { setEmlError(true) setEmlContent(null) setMessageHtml(null) + setEmlHeaders(null) } else { setEmlContent(ReadEmlJson) setEmlError(false) @@ -160,11 +173,14 @@ const MessageViewer = ({ emailSource }) => { } else { setMessageHtml(null) } + const header_regex = /(?:^[\w-]+:\s?.*(?:\r?\n[ \t].*)*\r?\n?)+/gm + const headers = emailSource.match(header_regex) + setEmlHeaders(headers ? headers[0] : null) } }) - }, [emailSource, setMessageHtml, setEmlError, setEmlContent]) + }, [emailSource, setMessageHtml, setEmlError, setEmlContent, setEmlHeaders]) - var buttons = EmailButtons(emailSource) + var buttons = EmailButtons(emlHeaders, emailSource) return ( <> From c755dce05a4775570b719b934a757166ba42d52f Mon Sep 17 00:00:00 2001 From: John Duprey Date: Fri, 2 Aug 2024 12:31:27 -0400 Subject: [PATCH 061/130] Audit Logs Add basic offcanvas --- .../tenant/administration/ListAuditLogs.jsx | 63 +++++++++++++++++-- 1 file changed, 57 insertions(+), 6 deletions(-) diff --git a/src/views/tenant/administration/ListAuditLogs.jsx b/src/views/tenant/administration/ListAuditLogs.jsx index 2ec02c53cf6c..4e1d30392b3d 100644 --- a/src/views/tenant/administration/ListAuditLogs.jsx +++ b/src/views/tenant/administration/ListAuditLogs.jsx @@ -26,8 +26,13 @@ import { import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import { Condition, RFFCFormInput, RFFCFormRadioList } from 'src/components/forms' import { Field, Form } from 'react-final-form' +import { useSearchParams } from 'react-router-dom' +import { CippCodeBlock, CippOffcanvas } from 'src/components/utilities' const ListAuditLogs = () => { + // get query parameters + const [searchParams, setSearchParams] = useSearchParams() + const logId = searchParams.get('LogId') const [interval, setInterval] = React.useState('d') const [time, setTime] = React.useState(1) const [relativeTime, setRelativeTime] = React.useState('1d') @@ -59,13 +64,58 @@ const ListAuditLogs = () => { setVisibleA(false) } - const Actions = () => { + const Actions = (row) => { + const [visible, setVisible] = React.useState(false) return ( - - - - - + <> + setVisible(true)}> + + + + + setVisible(false)} + visible={visible} + addedClass="offcanvas-large" + placement="end" + > + + + +

Log Details

+
+
+ + {row?.Data?.ActionText && ( + + + + + {row?.Data?.ActionText} + + + + )} + + +

Raw Log

+ +
+
+
+
+
+ ) } @@ -219,6 +269,7 @@ const ListAuditLogs = () => { RelativeTime: relativeTime, StartDate: startDate, EndDate: endDate, + LogId: logId, }, tableProps: { selectableRows: true, From 53445e671a41ba4ffd0c7b36e8c095b2e1f89493 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Fri, 2 Aug 2024 18:39:50 +0200 Subject: [PATCH 062/130] release ready --- src/importsMap.jsx | 1 + src/routes.json | 6 + src/views/cipp/TemplateLibrary.jsx | 149 ++++++++++++++++++ .../intune/MEMListPolicyTemplates.jsx | 6 + .../tenant/conditional/ListCATemplates.jsx | 6 + 5 files changed, 168 insertions(+) create mode 100644 src/views/cipp/TemplateLibrary.jsx diff --git a/src/importsMap.jsx b/src/importsMap.jsx index 3708a44f4ed9..49f07b806f00 100644 --- a/src/importsMap.jsx +++ b/src/importsMap.jsx @@ -2,6 +2,7 @@ import React from 'react' export const importsMap = { "/home": React.lazy(() => import('./views/home/Home')), "/cipp/logs": React.lazy(() => import('./views/cipp/Logs')), + "/cipp/template-library": React.lazy(() => import('./views/cipp/TemplateLibrary')), "/cipp/scheduler": React.lazy(() => import('./views/cipp/Scheduler')), "/cipp/statistics": React.lazy(() => import('./views/cipp/Statistics')), "/cipp/404": React.lazy(() => import('./views/pages/page404/Page404')), diff --git a/src/routes.json b/src/routes.json index 73f0383bbd20..532343cc83e4 100644 --- a/src/routes.json +++ b/src/routes.json @@ -11,6 +11,12 @@ "component": "views/cipp/Logs", "allowedRoles": ["admin", "editor", "readonly"] }, + { + "path": "/cipp/template-library", + "name": "Logs", + "component": "views/cipp/TemplateLibrary", + "allowedRoles": ["admin", "editor", "readonly"] + }, { "path": "/cipp/scheduler", "name": "Scheduler", diff --git a/src/views/cipp/TemplateLibrary.jsx b/src/views/cipp/TemplateLibrary.jsx new file mode 100644 index 000000000000..4dbf493d2293 --- /dev/null +++ b/src/views/cipp/TemplateLibrary.jsx @@ -0,0 +1,149 @@ +import React, { useState } from 'react' +import { CAlert, CButton, CCallout, CCol, CForm, CRow, CSpinner, CTooltip } from '@coreui/react' +import { useSelector } from 'react-redux' +import { Field, Form } from 'react-final-form' +import { RFFCFormInput, RFFCFormSwitch } from 'src/components/forms' +import { + useGenericGetRequestQuery, + useLazyGenericGetRequestQuery, + useLazyGenericPostRequestQuery, +} from 'src/store/api/app' +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' +import { faCircleNotch, faEdit, faEye } from '@fortawesome/free-solid-svg-icons' +import { CippPage, CippPageList } from 'src/components/layout' +import 'react-datepicker/dist/react-datepicker.css' +import { ModalService, TenantSelector } from 'src/components/utilities' +import arrayMutators from 'final-form-arrays' +import { useListConditionalAccessPoliciesQuery } from 'src/store/api/tenants' +import CippButtonCard from 'src/components/contentcards/CippButtonCard' +import { CellTip, cellGenericFormatter } from 'src/components/tables/CellGenericFormat' +import { cellBadgeFormatter, cellDateFormatter } from 'src/components/tables' +import { Alert } from '@coreui/coreui' + +const TemplateLibrary = () => { + const [ExecuteGetRequest, getResults] = useLazyGenericGetRequestQuery() + const tenantDomain = useSelector((state) => state.app.currentTenant.defaultDomainName) + const [refreshState, setRefreshState] = useState(false) + const [genericPostRequest, postResults] = useLazyGenericPostRequestQuery() + + const onSubmit = (values) => { + const startDate = new Date() + startDate.setHours(0, 0, 0, 0) + const unixTime = Math.floor(startDate.getTime() / 1000) - 45 + const shippedValues = { + TenantFilter: tenantDomain, + Name: `CIPP Template ${tenantDomain}`, + Command: { value: `New-CIPPTemplateRun` }, + Parameters: { TemplateSettings: { ...values } }, + ScheduledTime: unixTime, + Recurrence: { value: '4h' }, + } + genericPostRequest({ + path: '/api/AddScheduledItem?DisallowDuplicateName=true', + values: shippedValues, + }).then((res) => { + setRefreshState(res.requestId) + }) + } + + const { + data: caPolicies = [], + isFetching: caIsFetching, + error: caError, + } = useListConditionalAccessPoliciesQuery({ domain: tenantDomain }) + + return ( + + <> + + + + Set Tenant as Template Library + {postResults.isFetching && ( + + )} + + } + title="Add Template Library" + icon={faEdit} + > + { + return ( + +

+ Template libraries are tenants setup to retrieve the latest version of + policies from. By setting a tenant as a template library, automatic updates + will be made to the templates within CIPP based on this template library + every 4 hours. + + Enabling this feature will overwrite templates with the same name. + +

+ + + + + {(props) => } + + + + +
+
+ + +

Conditional Access

+ +

Intune

+ + + +
+
+ {postResults.isSuccess && ( + +
  • {postResults.data.Results}
  • +
    + )} + {getResults.isFetching && ( + + Loading + + )} + {getResults.isSuccess && ( + {getResults.data?.Results} + )} + {getResults.isError && ( + + Could not connect to API: {getResults.error.message} + + )} +
    + ) + }} + /> +
    +
    +
    + +
    + ) +} + +export default TemplateLibrary diff --git a/src/views/endpoint/intune/MEMListPolicyTemplates.jsx b/src/views/endpoint/intune/MEMListPolicyTemplates.jsx index 4ca9452daeff..1b389af653bc 100644 --- a/src/views/endpoint/intune/MEMListPolicyTemplates.jsx +++ b/src/views/endpoint/intune/MEMListPolicyTemplates.jsx @@ -16,6 +16,7 @@ import { useLazyGenericGetRequestQuery } from 'src/store/api/app' import { CippPage } from 'src/components/layout' import { ModalService } from 'src/components/utilities' import CippCodeOffCanvas from 'src/components/utilities/CippCodeOffcanvas' +import { TitleButton } from 'src/components/buttons' //todo: expandable with RAWJson property. @@ -106,6 +107,11 @@ const AutopilotListTemplates = () => { Endpoint Manager Templates + {getResults.isFetching && ( diff --git a/src/views/tenant/conditional/ListCATemplates.jsx b/src/views/tenant/conditional/ListCATemplates.jsx index 555a595c3ddb..13b652854a42 100644 --- a/src/views/tenant/conditional/ListCATemplates.jsx +++ b/src/views/tenant/conditional/ListCATemplates.jsx @@ -15,6 +15,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import { useLazyGenericGetRequestQuery } from 'src/store/api/app' import { CippPage } from 'src/components/layout' import { ModalService, CippCodeOffCanvas } from 'src/components/utilities' +import { TitleButton } from 'src/components/buttons' //todo: expandable with RAWJson property. @@ -87,6 +88,11 @@ const AutopilotListTemplates = () => { Results + {getResults.isFetching && ( From d0b1f4f956cfdb2e41469e9425cdf32f51933890 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Fri, 2 Aug 2024 19:28:17 +0200 Subject: [PATCH 063/130] update --- package.json | 2 +- public/version_latest.txt | 2 +- version_latest.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 169a8fbc8a05..dde03c41dba7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cipp", - "version": "6.1.1", + "version": "6.2.0", "description": "The CyberDrain Improved Partner Portal is a portal to help manage administration for Microsoft Partners.", "homepage": "https://cipp.app/", "bugs": { diff --git a/public/version_latest.txt b/public/version_latest.txt index f3b5af39e430..6abaeb2f9072 100644 --- a/public/version_latest.txt +++ b/public/version_latest.txt @@ -1 +1 @@ -6.1.1 +6.2.0 diff --git a/version_latest.txt b/version_latest.txt index f3b5af39e430..6abaeb2f9072 100644 --- a/version_latest.txt +++ b/version_latest.txt @@ -1 +1 @@ -6.1.1 +6.2.0 From 308a44c3aaa9eba264f6fdf1209c851a059811d1 Mon Sep 17 00:00:00 2001 From: jdr8 <63188001+jdr8@users.noreply.github.com> Date: Mon, 5 Aug 2024 15:34:38 +1000 Subject: [PATCH 064/130] Re-add Tenant Mode radio buttons --- .../cipp/app-settings/SettingsSuperAdmin.jsx | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/views/cipp/app-settings/SettingsSuperAdmin.jsx b/src/views/cipp/app-settings/SettingsSuperAdmin.jsx index 18cb6b397980..e6c7c8facc8e 100644 --- a/src/views/cipp/app-settings/SettingsSuperAdmin.jsx +++ b/src/views/cipp/app-settings/SettingsSuperAdmin.jsx @@ -66,6 +66,42 @@ export function SettingsSuperAdmin() {

    + + +

    Tenant Mode

    + ( + <> + {partnerConfig.isFetching && } + + + + + + + )} + /> + {webhookCreateResult.isSuccess && ( + + {webhookCreateResult?.data?.results} + + )} +
    +
    From 275641eaf24055e4110a7ae39ea9df7e5ad43a2a Mon Sep 17 00:00:00 2001 From: John Duprey Date: Mon, 5 Aug 2024 11:55:54 -0400 Subject: [PATCH 065/130] fix titlebutton link --- src/views/tenant/administration/TenantOnboardingWizard.jsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/views/tenant/administration/TenantOnboardingWizard.jsx b/src/views/tenant/administration/TenantOnboardingWizard.jsx index ebbab2a8e178..981a047702d0 100644 --- a/src/views/tenant/administration/TenantOnboardingWizard.jsx +++ b/src/views/tenant/administration/TenantOnboardingWizard.jsx @@ -136,7 +136,10 @@ const TenantOnboardingWizard = () => {
    - +
    {(props) => ( From 6f67e941479648371940a9829ef72627bd5425fb Mon Sep 17 00:00:00 2001 From: Esco Date: Tue, 6 Aug 2024 17:04:11 +0200 Subject: [PATCH 066/130] added very important T --- src/data/standards.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/data/standards.json b/src/data/standards.json index ef14f236cd1a..40380a53a9f0 100644 --- a/src/data/standards.json +++ b/src/data/standards.json @@ -93,7 +93,7 @@ "value": "default" }, { - "label": "Parial-screen background", + "label": "Partial-screen background", "value": "verticalSplit" } ] From 28d3600435f84ab999dc62bdf9c542e82a524bf5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Wed, 7 Aug 2024 18:11:52 +0200 Subject: [PATCH 067/130] Update DeletedUserRentention based on MC836942 --- src/data/standards.json | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/data/standards.json b/src/data/standards.json index 40380a53a9f0..b767bf142194 100644 --- a/src/data/standards.json +++ b/src/data/standards.json @@ -1985,14 +1985,22 @@ "name": "standards.DeletedUserRentention", "cat": "SharePoint Standards", "tag": ["lowimpact"], - "helpText": "Sets the retention period for deleted users OneDrive to the specified number of years. The default is 1 year.", - "docsDescription": "When a OneDrive user gets deleted, the personal SharePoint site is saved for selected time in years and data can be retrieved from it.", + "helpText": "Sets the retention period for deleted users OneDrive to the specified period of time. The default is 30 days.", + "docsDescription": "When a OneDrive user gets deleted, the personal SharePoint site is saved for selected amount of time that data can be retrieved from it.", "addedComponent": [ { "type": "Select", "name": "standards.DeletedUserRentention.Days", - "label": "Retention in years (Default 1)", + "label": "Retention time (Default 30 days)", "values": [ + { + "label": "30 days", + "value": "30" + }, + { + "label": "90 days", + "value": "90" + }, { "label": "1 year", "value": "365" From dc292ae69f12fdbabe37ac3da23658c35a870ae6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Thu, 8 Aug 2024 21:31:41 +0200 Subject: [PATCH 068/130] Refactor user password reset confirmation message --- src/views/identity/administration/Users.jsx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/views/identity/administration/Users.jsx b/src/views/identity/administration/Users.jsx index 669e401a3611..4d236659ad7f 100644 --- a/src/views/identity/administration/Users.jsx +++ b/src/views/identity/administration/Users.jsx @@ -275,7 +275,8 @@ const Offcanvas = (row, rowIndex, formatExtraData) => { color: 'info', modal: true, modalUrl: `/api/ExecResetPass?MustChange=true&TenantFilter=${tenant.defaultDomainName}&ID=${row.id}&displayName=${row.displayName}`, - modalMessage: 'Are you sure you want to reset the password for this user?', + modalMessage: + 'Are you sure you want to reset the password for this user? The user must change their password at next logon.', }, { label: 'Reset Password', @@ -285,11 +286,11 @@ const Offcanvas = (row, rowIndex, formatExtraData) => { modalMessage: 'Are you sure you want to reset the password for this user?', }, { - label: 'Preprovision OneDrive', + label: 'Pre-provision OneDrive', color: 'info', modal: true, modalUrl: `/api/ExecOneDriveProvision?TenantFilter=${tenant.defaultDomainName}&UserPrincipalName=${row.userPrincipalName}`, - modalMessage: 'Are you sure you want to preprovision onedrive for this user??', + modalMessage: 'Are you sure you want to pre-provision OneDrive for this user??', }, { label: 'Clear ImmutableId', From 6a77f2b58c81ca323b763e71e1ee407a773a0104 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Thu, 8 Aug 2024 15:55:35 -0400 Subject: [PATCH 069/130] Add confirmation dialog to save standards --- .../tenant/standards/ListAppliedStandards.jsx | 37 ++++++++++++------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/src/views/tenant/standards/ListAppliedStandards.jsx b/src/views/tenant/standards/ListAppliedStandards.jsx index 10eab27c96fd..226f2cf028c6 100644 --- a/src/views/tenant/standards/ListAppliedStandards.jsx +++ b/src/views/tenant/standards/ListAppliedStandards.jsx @@ -76,6 +76,7 @@ const DeleteAction = () => { ) } + const ApplyNewStandard = () => { const [templateStandard, setTemplateStandard] = useState() const [loadedTemplate, setLoadedTemplate] = useState(false) @@ -268,6 +269,7 @@ const ApplyNewStandard = () => { }) const tenantDomain = useSelector((state) => state.app.currentTenant.defaultDomainName) + const tenantDisplayName = useSelector((state) => state.app.currentTenant.displayName) //console.log('tenantDomain', tenantDomain) const [genericPostRequest, postResults] = useLazyGenericPostRequestQuery() @@ -294,20 +296,27 @@ const ApplyNewStandard = () => { }) const handleSubmit = async (values) => { - Object.keys(values.standards).filter(function (x) { - if (values.standards[x] === false) { - delete values.standards[x] - } - return null - }) - - //filter on only objects that are 'true' - genericPostRequest({ - path: '/api/AddStandardsDeploy', - values: { ...values.standards, tenant: tenantDomain }, - }).then(() => { - refetchStandards() - refetchConsolidated() + ModalService.confirm({ + title: 'Save Standards', + body: ( +
    +

    + Are you sure you want to save these standards to {tenantDisplayName}? This will apply + all Remediate options on the next run. +

    +
    + ), + confirmLabel: 'Save', + cancelLabel: 'Cancel', + onConfirm: () => { + genericPostRequest({ + path: '/api/AddStandardsDeploy', + values: { ...values.standards, tenant: tenantDomain }, + }).then(() => { + refetchStandards() + refetchConsolidated() + }) + }, }) } const [intuneGetRequest, intuneTemplates] = useLazyGenericGetRequestQuery() From 5739fc4e144952a3deb617436d2e3141a8ae50fe Mon Sep 17 00:00:00 2001 From: John Duprey Date: Thu, 8 Aug 2024 15:57:49 -0400 Subject: [PATCH 070/130] fix link --- src/views/tenant/administration/GDAPRoleWizard.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/views/tenant/administration/GDAPRoleWizard.jsx b/src/views/tenant/administration/GDAPRoleWizard.jsx index acaca41de84a..8607617cfb0a 100644 --- a/src/views/tenant/administration/GDAPRoleWizard.jsx +++ b/src/views/tenant/administration/GDAPRoleWizard.jsx @@ -168,7 +168,7 @@ const GDAPRoleWizard = () => { return
  • {message}
  • })} - + Create GDAP Invite From 28a551d709a5a0f1597336ee50bdcd5c8e13fccd Mon Sep 17 00:00:00 2001 From: John Duprey Date: Thu, 8 Aug 2024 16:30:20 -0400 Subject: [PATCH 071/130] Up version --- package.json | 2 +- public/version_latest.txt | 2 +- version_latest.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index dde03c41dba7..9e3b09fd6c58 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cipp", - "version": "6.2.0", + "version": "6.2.1", "description": "The CyberDrain Improved Partner Portal is a portal to help manage administration for Microsoft Partners.", "homepage": "https://cipp.app/", "bugs": { diff --git a/public/version_latest.txt b/public/version_latest.txt index 6abaeb2f9072..024b066c0bb7 100644 --- a/public/version_latest.txt +++ b/public/version_latest.txt @@ -1 +1 @@ -6.2.0 +6.2.1 diff --git a/version_latest.txt b/version_latest.txt index 6abaeb2f9072..024b066c0bb7 100644 --- a/version_latest.txt +++ b/version_latest.txt @@ -1 +1 @@ -6.2.0 +6.2.1 From 1e89c9843a48630408763b7c363c34cf506aa3f0 Mon Sep 17 00:00:00 2001 From: Ryan Kempt Date: Thu, 8 Aug 2024 23:18:21 -0400 Subject: [PATCH 072/130] add missing country codes --- src/data/AuditLogSchema.json | 3 +++ src/data/countryList.json | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/data/AuditLogSchema.json b/src/data/AuditLogSchema.json index c05a1187386b..35530d0fb583 100644 --- a/src/data/AuditLogSchema.json +++ b/src/data/AuditLogSchema.json @@ -731,6 +731,7 @@ { "value": "AR", "name": "Argentina" }, { "value": "AM", "name": "Armenia" }, { "value": "AW", "name": "Aruba" }, + { "value": "AC", "name": "Ascension Island" }, { "value": "AU", "name": "Australia" }, { "value": "AT", "name": "Austria" }, { "value": "AZ", "name": "Azerbaijan" }, @@ -779,6 +780,7 @@ { "value": "CY", "name": "Cyprus" }, { "value": "CZ", "name": "Czech Republic" }, { "value": "DK", "name": "Denmark" }, + { "value": "DG", "name": "Diego Garcia" }, { "value": "DJ", "name": "Djibouti" }, { "value": "DM", "name": "Dominica" }, { "value": "DO", "name": "Dominican Republic" }, @@ -837,6 +839,7 @@ { "value": "KI", "name": "Kiribati" }, { "value": "KP", "name": "Korea, Democratic People's Republic of" }, { "value": "KR", "name": "Korea, Republic of" }, + { "value": "XK", "name": "Kosovo" }, { "value": "KW", "name": "Kuwait" }, { "value": "KG", "name": "Kyrgyzstan" }, { "value": "LA", "name": "Lao People's Democratic Republic" }, diff --git a/src/data/countryList.json b/src/data/countryList.json index 9db31e21192d..9595ba9f517c 100644 --- a/src/data/countryList.json +++ b/src/data/countryList.json @@ -12,6 +12,7 @@ { "Code": "AR", "Name": "Argentina" }, { "Code": "AM", "Name": "Armenia" }, { "Code": "AW", "Name": "Aruba" }, + { "Code": "AC", "Name": "Ascension Island" }, { "Code": "AU", "Name": "Australia" }, { "Code": "AT", "Name": "Austria" }, { "Code": "AZ", "Name": "Azerbaijan" }, @@ -60,6 +61,7 @@ { "Code": "CY", "Name": "Cyprus" }, { "Code": "CZ", "Name": "Czech Republic" }, { "Code": "DK", "Name": "Denmark" }, + { "Code": "DG", "Name": "Diego Garcia" }, { "Code": "DJ", "Name": "Djibouti" }, { "Code": "DM", "Name": "Dominica" }, { "Code": "DO", "Name": "Dominican Republic" }, @@ -118,6 +120,7 @@ { "Code": "KI", "Name": "Kiribati" }, { "Code": "KP", "Name": "Korea, Democratic People's Republic of" }, { "Code": "KR", "Name": "Korea, Republic of" }, + { "Code": "XK", "Name": "Kosovo" }, { "Code": "KW", "Name": "Kuwait" }, { "Code": "KG", "Name": "Kyrgyzstan" }, { "Code": "LA", "Name": "Lao People's Democratic Republic" }, From e08e8752d7c27fec7fb72003fe70b2b4813e0ad7 Mon Sep 17 00:00:00 2001 From: isgq-github01 <159874617+isgq-github01@users.noreply.github.com> Date: Mon, 12 Aug 2024 09:49:12 +1000 Subject: [PATCH 073/130] Update standards.json - fixed typo Fixed "restirct" typo --- src/data/standards.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/data/standards.json b/src/data/standards.json index b767bf142194..45e7c0438ea1 100644 --- a/src/data/standards.json +++ b/src/data/standards.json @@ -2341,7 +2341,7 @@ "value": "none" }, { - "label": "Restirct sharing to specific domains", + "label": "Restrict sharing to specific domains", "value": "allowList" }, { From 7ee823bc9077524cac9928fe374f39385e545ecb Mon Sep 17 00:00:00 2001 From: John Duprey Date: Mon, 12 Aug 2024 11:18:58 -0400 Subject: [PATCH 074/130] Up version --- package-lock.json | 4 ++-- package.json | 2 +- public/version_latest.txt | 2 +- version_latest.txt | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5148294a75a6..52097c7d8d38 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "cipp", - "version": "6.1.1", + "version": "6.2.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "cipp", - "version": "6.1.1", + "version": "6.2.2", "license": "AGPL-3.0", "dependencies": { "@coreui/chartjs": "^3.0.0", diff --git a/package.json b/package.json index 9e3b09fd6c58..41b4ceedb492 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cipp", - "version": "6.2.1", + "version": "6.2.2", "description": "The CyberDrain Improved Partner Portal is a portal to help manage administration for Microsoft Partners.", "homepage": "https://cipp.app/", "bugs": { diff --git a/public/version_latest.txt b/public/version_latest.txt index 024b066c0bb7..ca06394388d6 100644 --- a/public/version_latest.txt +++ b/public/version_latest.txt @@ -1 +1 @@ -6.2.1 +6.2.2 diff --git a/version_latest.txt b/version_latest.txt index 024b066c0bb7..ca06394388d6 100644 --- a/version_latest.txt +++ b/version_latest.txt @@ -1 +1 @@ -6.2.1 +6.2.2 From aff91489a98aa71e7ea7cdfad5d41203604e14aa Mon Sep 17 00:00:00 2001 From: John Duprey Date: Tue, 13 Aug 2024 22:47:48 -0400 Subject: [PATCH 075/130] Add processor function support Expects CIPP-API-Processor as folder name --- Tools/Start-CippDevEmulators.ps1 | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/Tools/Start-CippDevEmulators.ps1 b/Tools/Start-CippDevEmulators.ps1 index b4f6ca696ffe..bde7511caac1 100644 --- a/Tools/Start-CippDevEmulators.ps1 +++ b/Tools/Start-CippDevEmulators.ps1 @@ -1,4 +1,12 @@ -Write-Host "Starting CIPP Dev Emulators" +Write-Host 'Starting CIPP Dev Emulators' +Get-Process node -ErrorAction SilentlyContinue | Stop-Process -ErrorAction SilentlyContinue $Path = (Get-Item $PSScriptRoot).Parent.Parent.FullName -wt --title CIPP`; new-tab --title 'Azurite' -d $Path pwsh -c azurite`; new-tab --title 'FunctionApp' -d $Path\CIPP-API pwsh -c func start`; new-tab --title 'CIPP Frontend' -d $Path\CIPP pwsh -c npm run start`; new-tab --title 'SWA' -d $Path\CIPP pwsh -c npm run start-swa + +$Process = Read-Host -Prompt 'Start Process Function (y/N)?' + +if ($Process -eq 'y') { + wt --title CIPP`; new-tab --title 'Azurite' -d $Path pwsh -c azurite`; new-tab --title 'FunctionApp' -d $Path\CIPP-API pwsh -c func start`; new-tab --title 'CIPP Frontend' -d $Path\CIPP pwsh -c npm run start`; new-tab --title 'SWA' -d $Path\CIPP pwsh -c npm run start-swa`; new-tab --title 'CIPP-API-Processor' -d $Path\CIPP-API-Processor pwsh -c func start --port 7072 +} else { + wt --title CIPP`; new-tab --title 'Azurite' -d $Path pwsh -c azurite`; new-tab --title 'FunctionApp' -d $Path\CIPP-API pwsh -c func start`; new-tab --title 'CIPP Frontend' -d $Path\CIPP pwsh -c npm run start`; new-tab --title 'SWA' -d $Path\CIPP pwsh -c npm run start-swa +} From a7308f45f15892dba954ba834c744d15e92f788e Mon Sep 17 00:00:00 2001 From: John Duprey Date: Tue, 13 Aug 2024 22:50:29 -0400 Subject: [PATCH 076/130] Add extension call to action support --- src/views/cipp/Extensions.jsx | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/views/cipp/Extensions.jsx b/src/views/cipp/Extensions.jsx index 5923599a6f66..84841ec3ec18 100644 --- a/src/views/cipp/Extensions.jsx +++ b/src/views/cipp/Extensions.jsx @@ -22,6 +22,7 @@ import CippButtonCard from 'src/components/contentcards/CippButtonCard.jsx' import { RFFCFormInput, RFFCFormSwitch } from 'src/components/forms/RFFComponents.jsx' import { Form } from 'react-final-form' import ExtensionMappings from 'src/views/cipp/ExtensionMappings.jsx' +import ReactHtmlParser from 'react-html-parser' export default function CIPPExtensions() { const [listBackend, listBackendResult] = useLazyGenericGetRequestQuery() @@ -121,6 +122,12 @@ export default function CIPPExtensions() { clients. )} + {integration?.callToAction && ( + + + {ReactHtmlParser(integration.callToAction)} + + )} Date: Tue, 13 Aug 2024 23:24:57 -0400 Subject: [PATCH 077/130] CIPP-SAM API Permissions - Add new components - SettingsAppPermissions - CippAppPermissionBuilder - Modify CippButtonCard, make isFetching not required and default false - Modify CellTip & CellGenericFormat, allow for wrapping text - Add onCreateOption to Creatable - CSS tweaks - Make adjust CippTable filter z-index to not conflict with select search - Add CIPP-SAM permission SuperAdmin section --- .../contentcards/CippButtonCard.jsx | 4 +- src/components/forms/RFFComponents.jsx | 6 +- src/components/tables/CellGenericFormat.jsx | 12 +- src/components/tables/CellTip.jsx | 4 +- .../utilities/CippAppPermissionBuilder.jsx | 585 ++++++++++++++++++ src/scss/_custom.scss | 6 + src/scss/_themes.scss | 1 + .../cipp/app-settings/SettingsSuperAdmin.jsx | 212 +++++-- .../components/SettingsAppPermissions.jsx | 65 ++ 9 files changed, 821 insertions(+), 74 deletions(-) create mode 100644 src/components/utilities/CippAppPermissionBuilder.jsx create mode 100644 src/views/cipp/app-settings/components/SettingsAppPermissions.jsx diff --git a/src/components/contentcards/CippButtonCard.jsx b/src/components/contentcards/CippButtonCard.jsx index 8e74d5470693..8e280ab067d3 100644 --- a/src/components/contentcards/CippButtonCard.jsx +++ b/src/components/contentcards/CippButtonCard.jsx @@ -8,7 +8,7 @@ export default function CippButtonCard({ titleType = 'normal', CardButton, children, - isFetching, + isFetching = false, className = 'h-100', }) { return ( @@ -32,6 +32,6 @@ CippButtonCard.propTypes = { titleType: PropTypes.string, CardButton: PropTypes.element.isRequired, children: PropTypes.element.isRequired, - isFetching: PropTypes.bool.isRequired, + isFetching: PropTypes.bool, className: PropTypes.string, } diff --git a/src/components/forms/RFFComponents.jsx b/src/components/forms/RFFComponents.jsx index 14163a033d62..30e096a71aa8 100644 --- a/src/components/forms/RFFComponents.jsx +++ b/src/components/forms/RFFComponents.jsx @@ -516,6 +516,7 @@ export const RFFSelectSearch = ({ retainInput = true, isLoading = false, allowCreate = false, + onCreateOption, refreshFunction, ...props }) => { @@ -589,7 +590,7 @@ export const RFFSelectSearch = ({ )} {allowCreate ? ( - + ) : ( - {dropMessage} - -
    - + <> + {returnCard ? ( + +
    + + + {dropMessage} + +
    +
    + ) : ( +
    + + + {dropMessage} + +
    + )} + ) } @@ -73,6 +92,7 @@ CippDropzone.propTypes = { dropMessage: PropTypes.string, accept: PropTypes.object, maxFiles: PropTypes.number, + returnCard: PropTypes.bool, } export default CippDropzone From 7e87b2a1cdde1d23a885f31aa829bbbf02966ad5 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Wed, 14 Aug 2024 16:09:56 -0400 Subject: [PATCH 083/130] Create service principal capabilities --- .../utilities/CippAppPermissionBuilder.jsx | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/components/utilities/CippAppPermissionBuilder.jsx b/src/components/utilities/CippAppPermissionBuilder.jsx index 93b1b9abef8c..e4c2ee3bfdf8 100644 --- a/src/components/utilities/CippAppPermissionBuilder.jsx +++ b/src/components/utilities/CippAppPermissionBuilder.jsx @@ -13,7 +13,7 @@ import { } from '@coreui/react' import { Field, Form, FormSpy } from 'react-final-form' import { RFFCFormRadioList, RFFSelectSearch } from 'src/components/forms' -import { useGenericGetRequestQuery, useLazyGenericPostRequestQuery } from 'src/store/api/app' +import { useGenericGetRequestQuery, useLazyGenericGetRequestQuery } from 'src/store/api/app' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import { TenantSelectorMultiple, @@ -53,6 +53,8 @@ const CippAppPermissionBuilder = ({ onSubmit, currentPermissions = {}, isSubmitt path: 'api/ExecServicePrincipals', }) + const [createServicePrincipal, createResult] = useLazyGenericGetRequestQuery() + const removeServicePrincipal = (appId) => { var servicePrincipal = selectedApp.find((sp) => sp?.appId === appId) var newServicePrincipals = selectedApp.filter((sp) => sp?.appId !== appId) @@ -91,6 +93,15 @@ const CippAppPermissionBuilder = ({ onSubmit, currentPermissions = {}, isSubmitt } } + const onCreateServicePrincipal = (appId) => { + createServicePrincipal({ + path: 'api/ExecServicePrincipals?Action=Create&AppId=' + appId, + }).then(() => { + refetchSpList() + setCalloutMessage(createResult?.data?.Results) + }) + } + const addPermissionRow = (servicePrincipal, permissionType, permission) => { var updatedPermissions = JSON.parse(JSON.stringify(newPermissions)) @@ -683,7 +694,7 @@ const CippAppPermissionBuilder = ({ onSubmit, currentPermissions = {}, isSubmitt refreshFunction={() => refetchSpList()} allowCreate={true} onCreateOption={(newSp) => { - console.log(newSp) + onCreateServicePrincipal(newSp) }} placeholder="(Advanced) Select a Service Principal" /> From f22f756ed8dec5115bf0c12bf232b3bc7df9a36b Mon Sep 17 00:00:00 2001 From: John Duprey Date: Wed, 14 Aug 2024 18:39:29 -0400 Subject: [PATCH 084/130] Permission builder --- .../utilities/CippAppPermissionBuilder.jsx | 79 +++++++++++++++++++ .../components/SettingsAppPermissions.jsx | 13 ++- 2 files changed, 88 insertions(+), 4 deletions(-) diff --git a/src/components/utilities/CippAppPermissionBuilder.jsx b/src/components/utilities/CippAppPermissionBuilder.jsx index e4c2ee3bfdf8..c986b67145f2 100644 --- a/src/components/utilities/CippAppPermissionBuilder.jsx +++ b/src/components/utilities/CippAppPermissionBuilder.jsx @@ -821,6 +821,85 @@ const CippAppPermissionBuilder = ({ onSubmit, currentPermissions = {}, isSubmitt )} + + {newPermissions?.MissingPermissions && + newPermissions?.Type === 'Table' && + Object.keys(newPermissions?.MissingPermissions).length > 0 && ( + + + + + + + New Permissions Available + {Object.keys(newPermissions?.MissingPermissions).map((perm) => { + // translate appid to display name + var sp = servicePrincipals?.Results?.find( + (sp) => sp.appId === perm, + ) + return ( +
    + {sp?.displayName}:{' '} + {Object.keys(newPermissions?.MissingPermissions[perm]).map( + (type) => { + return ( + <> + {newPermissions?.MissingPermissions[perm][type] + .length > 0 && ( + + {type == 'applicationPermissions' + ? 'Application' + : 'Delegated'}{' '} + -{' '} + {newPermissions?.MissingPermissions[perm][type] + .map((p) => { + return p.value + }) + .join(', ')} + + )} + + ) + }, + )} +
    + ) + })} +
    + + + { + var updatedPermissions = JSON.parse( + JSON.stringify(newPermissions), + ) + Object.keys(newPermissions?.MissingPermissions).map( + (perm) => { + Object.keys( + newPermissions?.MissingPermissions[perm], + ).map((type) => { + newPermissions?.MissingPermissions[perm][type].map( + (p) => { + updatedPermissions.Permissions[perm][type].push(p) + }, + ) + }) + }, + ) + updatedPermissions.MissingPermissions = {} + setNewPermissions(updatedPermissions) + }} + className={`circular-button float-end`} + > + + + + +
    +
    +
    +
    + )} <> {selectedApp?.length > 0 && diff --git a/src/views/cipp/app-settings/components/SettingsAppPermissions.jsx b/src/views/cipp/app-settings/components/SettingsAppPermissions.jsx index c3b6da3ffbd7..d36dffb0b597 100644 --- a/src/views/cipp/app-settings/components/SettingsAppPermissions.jsx +++ b/src/views/cipp/app-settings/components/SettingsAppPermissions.jsx @@ -28,13 +28,18 @@ const SettingsAppPermissions = () => { genericPostRequest({ path: 'api/ExecSAMAppPermissions?Action=Update', values: values, + }).then(() => { + refetchSam() }) } - const { data: samAppPermissions = [], isFetching: samAppPermissionsFetching } = - useGenericGetRequestQuery({ - path: 'api/ExecSAMAppPermissions', - }) + const { + data: samAppPermissions = [], + isFetching: samAppPermissionsFetching, + refetch: refetchSam, + } = useGenericGetRequestQuery({ + path: 'api/ExecSAMAppPermissions', + }) return ( From d642177ad73c52b5f621de97377161f70108c2aa Mon Sep 17 00:00:00 2001 From: John Duprey Date: Fri, 16 Aug 2024 12:17:38 -0400 Subject: [PATCH 085/130] Fix CellTable item count for single objects --- src/components/tables/CellTable.jsx | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/components/tables/CellTable.jsx b/src/components/tables/CellTable.jsx index cfcbd5403065..2186a406fe6b 100644 --- a/src/components/tables/CellTable.jsx +++ b/src/components/tables/CellTable.jsx @@ -23,6 +23,15 @@ export default function cellTable( if (columnProp === undefined || columnProp === null) { columnProp = [] } else { + var objectLength = 1 + var lengthText = 'Item' + if (columnProp instanceof Array) { + objectLength = columnProp.length + if (objectLength > 1) { + lengthText = 'Items' + } + } + if (!Array.isArray(columnProp) && typeof columnProp === 'object') { columnProp = Object.keys(columnProp).map((key) => { return { @@ -93,7 +102,7 @@ export default function cellTable( size="sm" onClick={() => handleTable({ columnProp })} > - {columnProp.length} Items + {objectLength} {lengthText} ) } From 22c72644a9da76cffcc9c2d4a8e1c1725eddc824 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Fri, 16 Aug 2024 17:29:11 -0400 Subject: [PATCH 086/130] Huntress RogueApps - Add new scripted alert - Update alert wizard to accept a description property for scripted alerts --- src/data/alerts.json | 6 +++++ .../tenant/administration/AlertWizard.jsx | 24 +++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/src/data/alerts.json b/src/data/alerts.json index 835216740c4d..13f18265caf4 100644 --- a/src/data/alerts.json +++ b/src/data/alerts.json @@ -99,5 +99,11 @@ "name": "DeviceCompliance", "label": "Alert on device compliance issues", "recommendedRunInterval": "4h" + }, + { + "name": "HuntressRogueApps", + "label": "Alert on Huntress Rogue Apps detected", + "recommendedRunInterval": "4h", + "description": "Huntress has provided a repository of known rogue apps that are commonly used in BEC, data exfiltration and other Microsoft 365 attacks. This alert will notify you if any of these apps are detected in the selected tenant(s). For more information, see https://huntresslabs.github.io/rogueapps/." } ] diff --git a/src/views/tenant/administration/AlertWizard.jsx b/src/views/tenant/administration/AlertWizard.jsx index 9b5253ef7351..e444c11ec123 100644 --- a/src/views/tenant/administration/AlertWizard.jsx +++ b/src/views/tenant/administration/AlertWizard.jsx @@ -21,6 +21,7 @@ import auditLogSchema from 'src/data/AuditLogSchema.json' import auditLogTemplates from 'src/data/AuditLogTemplates.json' import Skeleton from 'react-loading-skeleton' import { required } from 'src/validators' +import HtmlParser from 'react-html-parser' const AlertWizard = () => { const tenantDomain = useSelector((state) => state.app.currentTenant.defaultDomainName) @@ -112,6 +113,18 @@ const AlertWizard = () => { } } + const getScriptDescription = () => { + const values = currentFormState?.values + if (values) { + const command = values.command?.value + if (command?.description) { + return HtmlParser(command.description) + } else { + return null + } + } + } + const setAuditForm = (e) => { const preset = presetValues.find((p) => p.value === e.value) setAuditFormState(preset.template) @@ -368,6 +381,16 @@ const AlertWizard = () => { render={({ handleSubmit, submitting, values }) => { return ( + {getScriptDescription() && ( + + + + + {getScriptDescription()} + + + + )} { /> + From b86f0dd65321e28ff61a0752147fc2595c024d59 Mon Sep 17 00:00:00 2001 From: Chris Brannon Date: Sat, 17 Aug 2024 17:03:54 -0400 Subject: [PATCH 087/130] Assign & Unassign Teams Voice User Numbers --- src/views/teams-share/teams/BusinessVoice.jsx | 249 ++++++++++++++---- 1 file changed, 194 insertions(+), 55 deletions(-) diff --git a/src/views/teams-share/teams/BusinessVoice.jsx b/src/views/teams-share/teams/BusinessVoice.jsx index 6c132806d8bf..ada434df6895 100644 --- a/src/views/teams-share/teams/BusinessVoice.jsx +++ b/src/views/teams-share/teams/BusinessVoice.jsx @@ -1,68 +1,207 @@ -import React from 'react' +import React, { useState } from 'react' +import { CButton } from '@coreui/react' import { useSelector } from 'react-redux' import { CellBoolean } from 'src/components/tables' import { CippPageList } from 'src/components/layout' - -const Formatter = (cell) => CellBoolean({ cell }) -const columns = [ - { - name: 'Assigned to User', - selector: (row) => row['AssignedTo'], - sortable: true, - exportSelector: 'AssignedTo', - }, - { - name: 'Phone Number', - selector: (row) => row['TelephoneNumber'], - sortable: true, - exportSelector: 'TelephoneNumber', - }, - { - name: 'Number Type', - selector: (row) => row['NumberType'], - sortable: true, - exportSelector: 'NumberType', - }, - { - name: 'Country', - selector: (row) => row['IsoCountryCode'], - sortable: true, - exportSelector: 'IsCountryCode', - }, - { - name: 'Location', - selector: (row) => row['PlaceName'], - sortable: true, - exportSelector: 'PlaceName', - }, - { - name: 'Activation State', - selector: (row) => row['ActivationState'], - formatter: Formatter, - exportSelector: 'ActivationState', - sortable: true, - }, - { - name: 'Operator Connect', - selector: (row) => row['IsOperatorConnect'], - formatter: Formatter, - sortable: true, - exportSelector: 'IsOperatorConnect', - }, - { - name: 'Purchased on', - selector: (row) => row['AcquisitionDate'], - sortable: true, - exportSelector: 'AcquisitionDate', - }, -] +import { TitleButton } from 'src/components/buttons' +import { CippActionsOffcanvas } from 'src/components/utilities' +import { faEllipsisV } from '@fortawesome/free-solid-svg-icons' +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' const BusinessVoice = () => { const tenant = useSelector((state) => state.app.currentTenant) + const Offcanvas = (row, rowIndex, formatExtraData) => { + const tenant = useSelector((state) => state.app.currentTenant) + const [ocVisible, setOCVisible] = useState(false) + return ( + <> + setOCVisible(true)}> + + + setOCVisible(false)} + /> + + ) + } + const Formatter = (cell) => CellBoolean({ cell }) + const usageFormatter = (cell) => { + if (cell.includes('UserAssignment')) { + return 'User' + } + if (cell.includes('FirstPartyAppAssignment')) { + return 'Voice App' + } + if (cell.includes('ConferenceAssignment')) { + return 'Conference' + } + return cell[0] + } + const columns = [ + { + name: 'Assigned to User', + selector: (row) => row['AssignedTo'], + sortable: true, + exportSelector: 'AssignedTo', + }, + { + name: 'Phone Number', + selector: (row) => row['TelephoneNumber'], + sortable: true, + exportSelector: 'TelephoneNumber', + }, + { + name: 'Assignment Status', + selector: (row) => row['AssignmentStatus'], + sortable: true, + exportSelector: 'AssignmentStatus', + }, + { + name: 'Number Type', + selector: (row) => row['NumberType'], + sortable: true, + exportSelector: 'NumberType', + }, + { + name: 'Licensed Usage', + selector: (row) => usageFormatter(row['AcquiredCapabilities']), + sortable: true, + exportSelector: 'AcquiredCapabilities', + }, + { + name: 'Country', + selector: (row) => row['IsoCountryCode'], + sortable: true, + exportSelector: 'IsCountryCode', + }, + { + name: 'Location', + selector: (row) => row['PlaceName'], + sortable: true, + exportSelector: 'PlaceName', + }, + { + name: 'Activation State', + selector: (row) => row['ActivationState'], + formatter: Formatter, + exportSelector: 'ActivationState', + sortable: true, + }, + { + name: 'Operator Connect', + selector: (row) => row['IsOperatorConnect'], + formatter: Formatter, + sortable: true, + exportSelector: 'IsOperatorConnect', + }, + { + name: 'Purchased on', + selector: (row) => row['AcquisitionDate'], + sortable: true, + exportSelector: 'AcquisitionDate', + }, + { + name: 'Actions', + cell: Offcanvas, + }, + ] + const titleButtons = ( +
    +
    + +
    +
    + ) return ( Date: Sat, 17 Aug 2024 17:26:25 -0400 Subject: [PATCH 088/130] Formatting Issue --- src/views/teams-share/teams/BusinessVoice.jsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/views/teams-share/teams/BusinessVoice.jsx b/src/views/teams-share/teams/BusinessVoice.jsx index ada434df6895..5f2c0d32598a 100644 --- a/src/views/teams-share/teams/BusinessVoice.jsx +++ b/src/views/teams-share/teams/BusinessVoice.jsx @@ -199,7 +199,8 @@ const BusinessVoice = () => { filterlist: [ { filterName: 'Unassigned User Numbers', - filter: 'Complex: AssignmentStatus eq Unassigned; AcquiredCapabilities like UserAssignment', + filter: + 'Complex: AssignmentStatus eq Unassigned; AcquiredCapabilities like UserAssignment', }, ], columns, From cc0eda1b7ac6c105c1ae5f70b9a817102117b88e Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Sun, 18 Aug 2024 18:29:48 +0200 Subject: [PATCH 089/130] Fixes jitadmin issues --- src/views/identity/administration/DeployJITAdmin.jsx | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/views/identity/administration/DeployJITAdmin.jsx b/src/views/identity/administration/DeployJITAdmin.jsx index 81d23666fa61..146ab7d6fef1 100644 --- a/src/views/identity/administration/DeployJITAdmin.jsx +++ b/src/views/identity/administration/DeployJITAdmin.jsx @@ -47,10 +47,13 @@ const DeployJITAdmin = () => { const onSubmit = (values) => { const startTime = Math.floor(startDate.getTime() / 1000) const endTime = Math.floor(endDate.getTime() / 1000) + const shippedValues = { TenantFilter: tenantDomain, - UserId: values.UserId?.value, - UserPrincipalName: `${values.username}@${values.domain}`, + UserId: values.UserId?.value.id, + UserPrincipalName: values.username + ? `${values.username}@${values.domain}` + : values.UserId?.value.userPrincipalName, FirstName: values.FirstName, LastName: values.LastName, useraction: values.useraction, @@ -168,7 +171,7 @@ const DeployJITAdmin = () => { ({ - value: user.id, + value: { userPrincipalName: user.userPrincipalName, id: user.id }, name: `${user.displayName} <${user.userPrincipalName}>`, }))} placeholder={!usersIsFetching ? 'Select user' : 'Loading...'} From e6258b92973e6ca8c9fc7ead4f1852f476d81682 Mon Sep 17 00:00:00 2001 From: MoltenTesseract Date: Mon, 19 Aug 2024 14:44:09 +1000 Subject: [PATCH 090/130] Fix delete rule confirmation text The delete popup incorrectly asked to confirm to disable the rule, not delete it. --- src/views/email-exchange/connectors/ConnectorList.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/views/email-exchange/connectors/ConnectorList.jsx b/src/views/email-exchange/connectors/ConnectorList.jsx index c18d5eeb0004..1f3829abcb1d 100644 --- a/src/views/email-exchange/connectors/ConnectorList.jsx +++ b/src/views/email-exchange/connectors/ConnectorList.jsx @@ -57,7 +57,7 @@ const Offcanvas = (row, rowIndex, formatExtraData) => { modal: true, icon: , modalUrl: `/api/RemoveExConnector?TenantFilter=${tenant.defaultDomainName}&GUID=${row.Guid}&Type=${row.cippconnectortype}`, - modalMessage: 'Are you sure you want to disable this rule?', + modalMessage: 'Are you sure you want to delete this rule?', }, ]} placement="end" From aaa50b96f810c51e2f7c3fa9ba167ce201166682 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Mon, 19 Aug 2024 18:58:09 +0200 Subject: [PATCH 091/130] version up --- package.json | 2 +- public/version_latest.txt | 2 +- version_latest.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 41b4ceedb492..b74d149fe82e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cipp", - "version": "6.2.2", + "version": "6.3.0", "description": "The CyberDrain Improved Partner Portal is a portal to help manage administration for Microsoft Partners.", "homepage": "https://cipp.app/", "bugs": { diff --git a/public/version_latest.txt b/public/version_latest.txt index ca06394388d6..798e38995c4d 100644 --- a/public/version_latest.txt +++ b/public/version_latest.txt @@ -1 +1 @@ -6.2.2 +6.3.0 diff --git a/version_latest.txt b/version_latest.txt index ca06394388d6..798e38995c4d 100644 --- a/version_latest.txt +++ b/version_latest.txt @@ -1 +1 @@ -6.2.2 +6.3.0 From b3d79e60f23a239c9c049a3d79d4a5240854af58 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Mon, 19 Aug 2024 13:16:47 -0400 Subject: [PATCH 092/130] Fix reset mfa --- src/views/identity/administration/Users.jsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/views/identity/administration/Users.jsx b/src/views/identity/administration/Users.jsx index 4d236659ad7f..eb0cd4f29f6c 100644 --- a/src/views/identity/administration/Users.jsx +++ b/src/views/identity/administration/Users.jsx @@ -99,10 +99,10 @@ const Offcanvas = (row, rowIndex, formatExtraData) => { }, { label: 'Rerequire MFA registration', - link: entraLink, color: 'info', - target: '_blank', - external: true, + modal: true, + modalUrl: `/api/ExecResetMFA?TenantFilter=${tenant.defaultDomainName}&ID=${row.userPrincipalName}`, + modalMessage: 'Are you sure you want to reset MFA for this user?', }, { label: 'Send MFA Push', @@ -527,8 +527,8 @@ const Users = (row) => { { label: 'Rerequire MFA registration', modal: true, - modalUrl: `/api/ExecResetMFA?TenantFilter=!Tenant&ID=!id`, - modalMessage: 'Are you sure you want to enable MFA for these users?', + modalUrl: `/api/ExecResetMFA?TenantFilter=!Tenant&ID=!userPrincipalName`, + modalMessage: 'Are you sure you want to reset MFA for these users?', }, { label: 'Set Per-User MFA', From c880aad889c50615269d8cccb1e63e6e17b3c6d8 Mon Sep 17 00:00:00 2001 From: MoltenTesseract Date: Tue, 20 Aug 2024 09:33:27 +1000 Subject: [PATCH 093/130] Delete exchange rule confirmation fixed Delete exchange rule confirmation text still said disable rule instead of delete. --- src/views/email-exchange/transport/TransportRules.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/views/email-exchange/transport/TransportRules.jsx b/src/views/email-exchange/transport/TransportRules.jsx index 9d534e17dee5..549f245a2ea5 100644 --- a/src/views/email-exchange/transport/TransportRules.jsx +++ b/src/views/email-exchange/transport/TransportRules.jsx @@ -57,7 +57,7 @@ const Offcanvas = (row, rowIndex, formatExtraData) => { modal: true, icon: , modalUrl: `/api/RemoveTransportRule?TenantFilter=${tenant.defaultDomainName}&GUID=${row.Guid}`, - modalMessage: 'Are you sure you want to disable this rule?', + modalMessage: 'Are you sure you want to delete this rule?', }, ]} placement="end" From a00ba2fd7083336e224f10895f58eb61070caaf5 Mon Sep 17 00:00:00 2001 From: MoltenTesseract Date: Tue, 20 Aug 2024 12:40:24 +1000 Subject: [PATCH 094/130] Fix flyout extended information and incorrect wording Flyout extended information was pulling the incorrect columns, so all info was showing as 'undefined' . Updated all references to "rule" and replaced with "connector". --- .../connectors/ConnectorList.jsx | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/views/email-exchange/connectors/ConnectorList.jsx b/src/views/email-exchange/connectors/ConnectorList.jsx index 1f3829abcb1d..c5c2b2d0951a 100644 --- a/src/views/email-exchange/connectors/ConnectorList.jsx +++ b/src/views/email-exchange/connectors/ConnectorList.jsx @@ -20,44 +20,46 @@ const Offcanvas = (row, rowIndex, formatExtraData) => { , modalBody: row, modalType: 'POST', modalUrl: `/api/AddExConnectorTemplate`, - modalMessage: 'Are you sure you want to create a template based on this rule?', + modalMessage: 'Are you sure you want to create a template based on this connector?', }, { - label: 'Enable Rule', + label: 'Enable Connector', color: 'info', icon: , modal: true, modalUrl: `/api/EditExConnector?State=Enable&TenantFilter=${tenant.defaultDomainName}&GUID=${row.Guid}&Type=${row.cippconnectortype}`, - modalMessage: 'Are you sure you want to enable this rule?', + modalMessage: 'Are you sure you want to enable this connector?', }, { - label: 'Disable Rule', + label: 'Disable Connector', color: 'info', icon: , modal: true, modalUrl: `/api/EditExConnector?State=Disable&TenantFilter=${tenant.defaultDomainName}&GUID=${row.Guid}&Type=${row.cippconnectortype}`, - modalMessage: 'Are you sure you want to disable this rule?', + modalMessage: 'Are you sure you want to disable this connector?', }, { - label: 'Delete Rule', + label: 'Delete Connector', color: 'danger', modal: true, icon: , modalUrl: `/api/RemoveExConnector?TenantFilter=${tenant.defaultDomainName}&GUID=${row.Guid}&Type=${row.cippconnectortype}`, - modalMessage: 'Are you sure you want to delete this rule?', + modalMessage: 'Are you sure you want to delete this connector?', }, ]} placement="end" From 2894f938faff881d468349131df01a57114d0254 Mon Sep 17 00:00:00 2001 From: Esco Date: Sat, 17 Aug 2024 12:03:10 +0200 Subject: [PATCH 095/130] Improvements to MEMListPolicies --- .../endpoint/intune/MEMListCompliance.jsx | 1 + src/views/endpoint/intune/MEMListPolicies.jsx | 32 +++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/src/views/endpoint/intune/MEMListCompliance.jsx b/src/views/endpoint/intune/MEMListCompliance.jsx index 328a387566fd..87c2fdfabdf3 100644 --- a/src/views/endpoint/intune/MEMListCompliance.jsx +++ b/src/views/endpoint/intune/MEMListCompliance.jsx @@ -138,6 +138,7 @@ const ComplianceList = () => { Endpoint: 'deviceManagement/deviceCompliancePolicies', $orderby: 'displayName', $count: true, + $expand: 'assignments', }, columns, reportName: `${tenant?.defaultDomainName}-MEMPolicies-List`, diff --git a/src/views/endpoint/intune/MEMListPolicies.jsx b/src/views/endpoint/intune/MEMListPolicies.jsx index f63db28effef..725c4cc0cd42 100644 --- a/src/views/endpoint/intune/MEMListPolicies.jsx +++ b/src/views/endpoint/intune/MEMListPolicies.jsx @@ -15,6 +15,7 @@ import { CippPageList } from 'src/components/layout' import { Link } from 'react-router-dom' import { CippActionsOffcanvas, CippCodeBlock } from 'src/components/utilities' import { TitleButton } from 'src/components/buttons' +import { cellBooleanFormatter, cellDateFormatter } from 'src/components/tables' const Actions = (row, rowIndex, formatExtraData) => { const [ocVisible, setOCVisible] = useState(false) @@ -90,12 +91,43 @@ const columns = [ name: 'Name', sortable: true, exportSelector: 'displayName', + maxWidth: 'auto', }, { selector: (row) => row['PolicyTypeName'], name: 'Profile Type', sortable: true, exportSelector: 'PolicyTypeName', + maxWidth: '300px', + }, + { + selector: (row) => row['PolicyAssignment'], + name: 'Assigned', + sortable: true, + exportSelector: 'PolicyAssignment', + maxWidth: '300px', + }, + { + selector: (row) => row['PolicyExclude'], + name: 'Excluded', + sortable: true, + exportSelector: 'PolicyExclude', + maxWidth: '300px', + }, + { + selector: (row) => row['description'], + name: 'Description', + sortable: true, + exportSelector: 'description', + maxWidth: 'auto', + }, + { + selector: (row) => row['lastModifiedDateTime'], + name: 'Last Modified', + sortable: true, + exportSelector: 'lastModifiedDateTime', + cell: cellDateFormatter({ format: 'relative' }), + maxWidth: '150px', }, { selector: (row) => row['id'], From a1ce07dd3165310b15a854fb7099672fcbedabb5 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Wed, 21 Aug 2024 16:09:27 -0400 Subject: [PATCH 096/130] Add owner property to anonymization check --- src/components/tables/CippDatatable.jsx | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/components/tables/CippDatatable.jsx b/src/components/tables/CippDatatable.jsx index 125eeda3e00a..7d00d9730e82 100644 --- a/src/components/tables/CippDatatable.jsx +++ b/src/components/tables/CippDatatable.jsx @@ -14,16 +14,18 @@ export default function CippDatatable({ path, params, ...rest }) { refetch, } = useListDatatableQuery({ path, params: { $filter: graphFilter, ...params } }) - let anonimized = false // Assuming default value is false + let anonymized = false // Assuming default value is false const regex = new RegExp('^[A-Z0-9]+$') const principalNameOrUPN = data[0]?.userPrincipalName ?? data[0]?.UPN ?? + data[0]?.Owner ?? data.Results?.[0]?.upn ?? - data.Results?.[0]?.userPrincipalName + data.Results?.[0]?.userPrincipalName ?? + data.Results?.[0]?.Owner if (principalNameOrUPN && regex.test(principalNameOrUPN)) { - anonimized = true + anonymized = true } var defaultFilterText = '' @@ -32,7 +34,7 @@ export default function CippDatatable({ path, params, ...rest }) { } return ( <> - {anonimized && ( + {anonymized && ( This table might contain anonymized data. Please check this Date: Wed, 21 Aug 2024 16:09:52 -0400 Subject: [PATCH 097/130] Extend permission builder for app approval --- .../utilities/CippAppPermissionBuilder.jsx | 138 ++++++++++++------ 1 file changed, 92 insertions(+), 46 deletions(-) diff --git a/src/components/utilities/CippAppPermissionBuilder.jsx b/src/components/utilities/CippAppPermissionBuilder.jsx index c986b67145f2..69d6c8c516d3 100644 --- a/src/components/utilities/CippAppPermissionBuilder.jsx +++ b/src/components/utilities/CippAppPermissionBuilder.jsx @@ -34,7 +34,14 @@ import { Editor } from '@monaco-editor/react' import { useSelector } from 'react-redux' import { CippCallout } from '../layout' -const CippAppPermissionBuilder = ({ onSubmit, currentPermissions = {}, isSubmitting }) => { +const CippAppPermissionBuilder = ({ + onSubmit, + currentPermissions = {}, + isSubmitting, + colSize = 8, + removePermissionConfirm = true, + appDisplayName = 'CIPP-SAM', +}) => { const [selectedApp, setSelectedApp] = useState([]) const [permissionsImported, setPermissionsImported] = useState(false) const [newPermissions, setNewPermissions] = useState({}) @@ -42,6 +49,7 @@ const CippAppPermissionBuilder = ({ onSubmit, currentPermissions = {}, isSubmitt const [manifestVisible, setManifestVisible] = useState(false) const currentTheme = useSelector((state) => state.app.currentTheme) const [calloutMessage, setCalloutMessage] = useState(null) + const [initialPermissions, setInitialPermissions] = useState() const { data: servicePrincipals = [], @@ -59,35 +67,49 @@ const CippAppPermissionBuilder = ({ onSubmit, currentPermissions = {}, isSubmitt var servicePrincipal = selectedApp.find((sp) => sp?.appId === appId) var newServicePrincipals = selectedApp.filter((sp) => sp?.appId !== appId) - ModalService.confirm({ - title: 'Remove Service Principal', - body: `Are you sure you want to remove ${servicePrincipal.displayName}?`, - onConfirm: () => { - setSelectedApp(newServicePrincipals) - var updatedPermissions = JSON.parse(JSON.stringify(newPermissions)) - delete updatedPermissions.Permissions[appId] - setNewPermissions(updatedPermissions) - }, - }) + if (removePermissionConfirm) { + ModalService.confirm({ + title: 'Remove Service Principal', + body: `Are you sure you want to remove ${servicePrincipal.displayName}?`, + onConfirm: () => { + setSelectedApp(newServicePrincipals) + var updatedPermissions = JSON.parse(JSON.stringify(newPermissions)) + delete updatedPermissions.Permissions[appId] + setNewPermissions(updatedPermissions) + }, + }) + } else { + setSelectedApp(newServicePrincipals) + var updatedPermissions = JSON.parse(JSON.stringify(newPermissions)) + delete updatedPermissions.Permissions[appId] + setNewPermissions(updatedPermissions) + } } const confirmReset = () => { - ModalService.confirm({ - title: 'Reset to Default', - body: 'Are you sure you want to reset all permissions to default?', - onConfirm: () => { - setSelectedApp([]) - setPermissionsImported(false) - setManifestVisible(false) - setCalloutMessage('Permissions reset to default.') - }, - }) + if (removePermissionConfirm) { + ModalService.confirm({ + title: 'Reset to Default', + body: 'Are you sure you want to reset all permissions to default?', + onConfirm: () => { + setSelectedApp([]) + setPermissionsImported(false) + setManifestVisible(false) + setCalloutMessage('Permissions reset to default.') + }, + }) + } else { + setSelectedApp([]) + setPermissionsImported(false) + setManifestVisible(false) + setCalloutMessage('Permissions reset to default.') + } } const handleSubmit = (values) => { if (onSubmit) { var postBody = { - Permissions: newPermissions, + Permissions: newPermissions.Permissions, } onSubmit(postBody) } @@ -127,30 +149,43 @@ const CippAppPermissionBuilder = ({ onSubmit, currentPermissions = {}, isSubmitt } const removePermissionRow = (servicePrincipal, permissionType, permissionId, permissionValue) => { - // modal confirm - ModalService.confirm({ - title: 'Remove Permission', - body: `Are you sure you want to remove the permission: ${permissionValue}?`, - onConfirm: () => { - var updatedPermissions = JSON.parse(JSON.stringify(newPermissions)) - var currentPermission = updatedPermissions?.Permissions[servicePrincipal][permissionType] - var newPermission = [] - if (currentPermission) { - currentPermission.map((perm) => { - if (perm.id !== permissionId) { - newPermission.push(perm) - } - }) - } - updatedPermissions.Permissions[servicePrincipal][permissionType] = newPermission - setNewPermissions(updatedPermissions) - }, - }) + if (removePermissionConfirm) { + ModalService.confirm({ + title: 'Remove Permission', + body: `Are you sure you want to remove the permission: ${permissionValue}?`, + onConfirm: () => { + var updatedPermissions = JSON.parse(JSON.stringify(newPermissions)) + var currentPermission = updatedPermissions?.Permissions[servicePrincipal][permissionType] + var newPermission = [] + if (currentPermission) { + currentPermission.map((perm) => { + if (perm.id !== permissionId) { + newPermission.push(perm) + } + }) + } + updatedPermissions.Permissions[servicePrincipal][permissionType] = newPermission + setNewPermissions(updatedPermissions) + }, + }) + } else { + var updatedPermissions = JSON.parse(JSON.stringify(newPermissions)) + var currentPermission = updatedPermissions?.Permissions[servicePrincipal][permissionType] + var newPermission = [] + if (currentPermission) { + currentPermission.map((perm) => { + if (perm.id !== permissionId) { + newPermission.push(perm) + } + }) + } + updatedPermissions.Permissions[servicePrincipal][permissionType] = newPermission + setNewPermissions(updatedPermissions) + } } - const generateManifest = (appDisplayName = 'CIPP-SAM', prompt = false) => { - if (prompt) { - // modal input form for appDisplayName + const generateManifest = ({ appDisplayName = 'CIPP-SAM', prompt = false }) => { + if (prompt || appDisplayName === '') { ModalService.prompt({ title: 'Generate Manifest', body: 'Please enter the display name for the application.', @@ -337,6 +372,11 @@ const CippAppPermissionBuilder = ({ onSubmit, currentPermissions = {}, isSubmitt }, }, }) + } else if (spSuccess & (currentPermissions !== initialPermissions)) { + setSelectedApp([]) + setNewPermissions(currentPermissions) + setInitialPermissions(currentPermissions) + setPermissionsImported(false) } else if (spSuccess && initialAppIds.length > 0 && permissionsImported == false) { var newApps = [] initialAppIds?.map((appId) => { @@ -350,10 +390,12 @@ const CippAppPermissionBuilder = ({ onSubmit, currentPermissions = {}, isSubmitt }) setSelectedApp(newApps) setNewPermissions(currentPermissions) + setInitialPermissions(currentPermissions) setPermissionsImported(true) } }, [ currentPermissions, + initialPermissions, permissionsImported, spSuccess, selectedApp, @@ -361,6 +403,7 @@ const CippAppPermissionBuilder = ({ onSubmit, currentPermissions = {}, isSubmitt setSelectedApp, setPermissionsImported, setNewPermissions, + setInitialPermissions, ]) const ApiPermissionRow = ({ servicePrincipal = null }) => { @@ -679,7 +722,7 @@ const CippAppPermissionBuilder = ({ onSubmit, currentPermissions = {}, isSubmitt return ( - + {servicePrincipals?.Metadata?.Success && ( @@ -738,7 +781,7 @@ const CippAppPermissionBuilder = ({ onSubmit, currentPermissions = {}, isSubmitt { - generateManifest() + generateManifest({ appDisplayName: appDisplayName }) }} className={`circular-button`} title={'+'} @@ -957,6 +1000,9 @@ CippAppPermissionBuilder.propTypes = { onSubmit: PropTypes.func, currentPermissions: PropTypes.object, isSubmitting: PropTypes.bool, + colSize: PropTypes.number, + removePermissionConfirm: PropTypes.bool, + appDisplayName: PropTypes.string, } export default CippAppPermissionBuilder From be79c62682621c1c145eb726c3cc5d262c8a8587 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Wed, 21 Aug 2024 16:10:08 -0400 Subject: [PATCH 098/130] approval template page --- src/views/cipp/AppApprovalTemplates.jsx | 140 ++++++++++++++++++++++++ 1 file changed, 140 insertions(+) create mode 100644 src/views/cipp/AppApprovalTemplates.jsx diff --git a/src/views/cipp/AppApprovalTemplates.jsx b/src/views/cipp/AppApprovalTemplates.jsx new file mode 100644 index 000000000000..6f9159565dcd --- /dev/null +++ b/src/views/cipp/AppApprovalTemplates.jsx @@ -0,0 +1,140 @@ +import React from 'react' +import { + CCol, + CRow, + CCallout, + CSpinner, + CButton, + CFormInput, + CFormLabel, + CTooltip, +} from '@coreui/react' +import { Field, Form, FormSpy } from 'react-final-form' +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' +import { faExclamationTriangle } from '@fortawesome/free-solid-svg-icons' +import { CippPageList, CippWizard } from 'src/components/layout' +import { cellDateFormatter, CippTable, WizardTableField } from 'src/components/tables' +import PropTypes from 'prop-types' +import { + Condition, + RFFCFormCheck, + RFFCFormInput, + RFFCFormSwitch, + RFFSelectSearch, +} from 'src/components/forms' +import { useLazyGenericPostRequestQuery } from 'src/store/api/app' +import CippButtonCard from 'src/components/contentcards/CippButtonCard' +import { cellGenericFormatter } from 'src/components/tables/CellGenericFormat' +import { CippOffcanvas } from 'src/components/utilities' +import CippAppPermissionBuilder from 'src/components/utilities/CippAppPermissionBuilder' + +const AppApprovalTemplates = () => { + const [editorVisible, setEditorVisible] = React.useState(false) + const [selectedTemplate, setSelectedTemplate] = React.useState(null) + const templateNameRef = React.useRef(null) + const [genericPostRequest, postResults] = useLazyGenericPostRequestQuery() + + const onSubmit = (values) => { + var body = { + TemplateName: templateNameRef.current.value, + Permissions: values.Permissions, + } + if (selectedTemplate?.TemplateId) { + body.TemplateId = selectedTemplate.TemplateId + } + + console.log(body) + genericPostRequest({ + path: '/api/ExecAppPermissionTemplate?Action=Save', + values: body, + }).then(() => {}) + } + const titleButton = ( + { + setSelectedTemplate({}) + templateNameRef.current.value = '' + setEditorVisible(true) + }} + > + Add Template + + ) + return ( + <> + row['TemplateName'], + sortable: true, + exportSelector: 'TemplateName', + }, + { + name: 'Updated By', + selector: (row) => row['UpdatedBy'], + sortable: true, + exportSelector: 'UpdatedBy', + }, + { + name: 'Updated At', + selector: (row) => row['Timestamp'], + sortable: true, + exportSelector: 'Timestamp', + cell: cellDateFormatter({ format: 'short' }), + }, + { + name: 'Actions', + cell: (row) => ( + + { + setSelectedTemplate(row) + templateNameRef.current.value = row.TemplateName + setEditorVisible(true) + }} + > + + + + ), + }, + ], + reportName: 'AppApprovalTemplates', + }} + /> + setEditorVisible(false)} + > + Template Name + + Permissions + + + + ) +} + +export default AppApprovalTemplates From 8ecaf078015c56cfd83c5ef08a0c97ca81f15cf5 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Wed, 21 Aug 2024 16:41:20 -0400 Subject: [PATCH 099/130] Hide permission builder while loading --- .../components/SettingsAppPermissions.jsx | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/views/cipp/app-settings/components/SettingsAppPermissions.jsx b/src/views/cipp/app-settings/components/SettingsAppPermissions.jsx index d36dffb0b597..55a56aea7f5e 100644 --- a/src/views/cipp/app-settings/components/SettingsAppPermissions.jsx +++ b/src/views/cipp/app-settings/components/SettingsAppPermissions.jsx @@ -21,6 +21,7 @@ import { useListTenantsQuery } from 'src/store/api/tenants' import { OffcanvasListSection } from 'src/components/utilities/CippListOffcanvas' import CippButtonCard from 'src/components/contentcards/CippButtonCard' import CippAppPermissionBuilder from 'src/components/utilities/CippAppPermissionBuilder' +import Skeleton from 'react-loading-skeleton' const SettingsAppPermissions = () => { const [genericPostRequest, postResults] = useLazyGenericPostRequestQuery() @@ -36,6 +37,7 @@ const SettingsAppPermissions = () => { const { data: samAppPermissions = [], isFetching: samAppPermissionsFetching, + isSuccess: samAppPermissionsSuccess, refetch: refetchSam, } = useGenericGetRequestQuery({ path: 'api/ExecSAMAppPermissions', @@ -51,11 +53,14 @@ const SettingsAppPermissions = () => { advised.

    - + {samAppPermissionsFetching && } + {samAppPermissionsSuccess && ( + + )} {postResults.data && ( From 8e16606ee435f2c84e5f81a70d18a141ed36d8d0 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Wed, 21 Aug 2024 18:37:02 -0400 Subject: [PATCH 100/130] Add username to BEC refresh --- src/views/identity/administration/ViewBEC.jsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/views/identity/administration/ViewBEC.jsx b/src/views/identity/administration/ViewBEC.jsx index 4f1173042008..3142af80d61e 100644 --- a/src/views/identity/administration/ViewBEC.jsx +++ b/src/views/identity/administration/ViewBEC.jsx @@ -239,6 +239,7 @@ const ViewBec = () => { execBecView({ tenantFilter: tenantDomain, userId: userId, + userName: userName, overwrite: true, }) } From 3bb85f83a000a74f4be95ffb37c956ef6d2844d5 Mon Sep 17 00:00:00 2001 From: cipptesting Date: Wed, 21 Aug 2024 18:47:49 -0400 Subject: [PATCH 101/130] Added Anti-Phishing and Anti-Spam policies to backup --- src/views/tenant/backup/CreateBackup.jsx | 9 +++++++++ src/views/tenant/backup/RestoreBackup.jsx | 7 +++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/views/tenant/backup/CreateBackup.jsx b/src/views/tenant/backup/CreateBackup.jsx index faec25e074a3..d0dd6350219c 100644 --- a/src/views/tenant/backup/CreateBackup.jsx +++ b/src/views/tenant/backup/CreateBackup.jsx @@ -194,6 +194,15 @@ const CreateBackup = () => { name="intuneprotection" label="Intune Protection Policies" /> +

    Email Security

    + +

    CIPP

    {

    Conditional Access

    -
    -

    Intune

    +
    + +

    Email Security

    + +

    CIPP

    From f690aff93493ea553b87d5d30316d009977196f3 Mon Sep 17 00:00:00 2001 From: OwenC3 <156828136+OwenC3@users.noreply.github.com> Date: Thu, 22 Aug 2024 16:56:07 -0400 Subject: [PATCH 102/130] Update standards.json --- src/data/standards.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/data/standards.json b/src/data/standards.json index 45e7c0438ea1..4b12a7181b10 100644 --- a/src/data/standards.json +++ b/src/data/standards.json @@ -349,7 +349,7 @@ "name": "standards.TAP", "cat": "Entra (AAD) Standards", "tag": ["lowimpact"], - "helpText": "Enables TAP and sets the default TAP lifetime to 1 hour. This configuration also allows you to select is a TAP is single use or multi-logon.", + "helpText": "Enables TAP and sets the default TAP lifetime to 1 hour. This configuration also allows you to select if a TAP is single use or multi-logon.", "docsDescription": "Enables Temporary Password generation for the tenant.", "addedComponent": [ { @@ -648,7 +648,7 @@ "name": "standards.DisableEmail", "cat": "Entra (AAD) Standards", "tag": ["highimpact"], - "helpText": "This blocks users from using email as an MFA method. This disables the email OTP option for guest users, and instead promts them to create a Microsoft account.", + "helpText": "This blocks users from using email as an MFA method. This disables the email OTP option for guest users, and instead prompts them to create a Microsoft account.", "addedComponent": [], "label": "Disables Email as an MFA method", "impact": "High Impact", From 2fd93963586bd387d32752c453ee206966d56b40 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Thu, 22 Aug 2024 17:42:52 -0400 Subject: [PATCH 103/130] Update CippAppPermissionBuilder.jsx --- src/components/utilities/CippAppPermissionBuilder.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/utilities/CippAppPermissionBuilder.jsx b/src/components/utilities/CippAppPermissionBuilder.jsx index 69d6c8c516d3..d270cfc4a7a7 100644 --- a/src/components/utilities/CippAppPermissionBuilder.jsx +++ b/src/components/utilities/CippAppPermissionBuilder.jsx @@ -807,7 +807,7 @@ const CippAppPermissionBuilder = ({ title="Import Manifest" id="importManifest" visible={manifestVisible} - onHide={() => { + hideFunction={() => { setManifestVisible(false) }} addedClass="offcanvas-large" From 4fb3eae37824fc55945eeac306ad492253a4e845 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Sat, 24 Aug 2024 15:44:51 +0200 Subject: [PATCH 104/130] Add delete rule button to mailboxrulelist --- .../administration/MailboxRuleList.jsx | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/src/views/email-exchange/administration/MailboxRuleList.jsx b/src/views/email-exchange/administration/MailboxRuleList.jsx index 34f3798900d8..53d4d57cbc6e 100644 --- a/src/views/email-exchange/administration/MailboxRuleList.jsx +++ b/src/views/email-exchange/administration/MailboxRuleList.jsx @@ -3,6 +3,43 @@ import { useSelector } from 'react-redux' import { CippPageList } from 'src/components/layout' import { CellTip } from 'src/components/tables' import { cellGenericFormatter } from 'src/components/tables/CellGenericFormat' +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' +import { CButton } from '@coreui/react' +import { faTrash } from '@fortawesome/free-solid-svg-icons' +import { ModalService } from 'src/components/utilities' +import { useLazyGenericGetRequestQuery } from 'src/store/api/app' + +const DeleteMailboxRuleButton = (ruleId, userPrincipalName, ruleName) => { + const tenant = useSelector((state) => state.app.currentTenant) + const [genericGetRequest, getResults] = useLazyGenericGetRequestQuery() + const handleModal = (modalMessage, modalUrl) => { + ModalService.confirm({ + body: ( +
    +
    {modalMessage}
    +
    + ), + title: 'Confirm', + onConfirm: () => genericGetRequest({ path: modalUrl }), + }) + } + return ( + { + ModalService.confirm( + handleModal( + 'Are you sure you want to remove this mailbox rule?', + `/api/ExecRemoveMailboxRule?TenantFilter=${tenant?.defaultDomainName}&ruleId=${ruleId}&ruleName=${ruleName}&userPrincipalName=${userPrincipalName}`, + ), + ) + }} + > + + + ) +} const MailboxRuleList = () => { const tenant = useSelector((state) => state.app.currentTenant) @@ -62,6 +99,12 @@ const MailboxRuleList = () => { exportSelector: 'ForwardTo', cell: cellGenericFormatter(), }, + { + name: 'Action', + maxWidth: '100px', + cell: (row) => + DeleteMailboxRuleButton(row['Identity'], row['UserPrincipalName'], row['Name']), + }, ] return ( From 1f71fe93797cdce9172173347a44f1709e3f03f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Sat, 24 Aug 2024 16:14:33 +0200 Subject: [PATCH 105/130] Add todo's --- src/views/email-exchange/administration/MailboxRuleList.jsx | 2 ++ src/views/identity/administration/ViewUser.jsx | 3 +++ 2 files changed, 5 insertions(+) diff --git a/src/views/email-exchange/administration/MailboxRuleList.jsx b/src/views/email-exchange/administration/MailboxRuleList.jsx index 53d4d57cbc6e..b941e501e01b 100644 --- a/src/views/email-exchange/administration/MailboxRuleList.jsx +++ b/src/views/email-exchange/administration/MailboxRuleList.jsx @@ -108,6 +108,8 @@ const MailboxRuleList = () => { ] return ( + // TODO: Add support for displaying the result of the delete operation. Currently, the delete operation is performed but the result is not displayed anywhere but the networking tab of the dev tools in the browser. + // All API code is in place and should return the needed HTTP status information. -Bobby { + {/* // TODO: Add support for displaying the result of the delete operation. Currently, the delete operation is performed but the result is not displayed anywhere but the networking tab of the dev tools in the browser. + All API code is in place and should return the needed HTTP status information. + Possibly even remove the row in the table if the delete operation was successful? -Bobby */} Date: Sat, 24 Aug 2024 16:15:01 +0200 Subject: [PATCH 106/130] feat: Add delete rule button to mailboxrulelist --- .../administration/UserMailboxRuleList.jsx | 43 ++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/src/views/identity/administration/UserMailboxRuleList.jsx b/src/views/identity/administration/UserMailboxRuleList.jsx index ae2592866e85..f0a1e05a4d31 100644 --- a/src/views/identity/administration/UserMailboxRuleList.jsx +++ b/src/views/identity/administration/UserMailboxRuleList.jsx @@ -2,7 +2,12 @@ import React from 'react' import PropTypes from 'prop-types' import { CellBoolean, cellBooleanFormatter, CellTip } from 'src/components/tables' import { DatatableContentCard } from 'src/components/contentcards' -import { faEnvelope } from '@fortawesome/free-solid-svg-icons' +import { faEnvelope, faTrash } from '@fortawesome/free-solid-svg-icons' +import { cellGenericFormatter } from 'src/components/tables/CellGenericFormat' +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' +import { CButton } from '@coreui/react' +import { ModalService } from 'src/components/utilities' +import { useLazyGenericGetRequestQuery } from 'src/store/api/app' const rowStyle = (row, rowIndex) => { const style = {} @@ -10,6 +15,37 @@ const rowStyle = (row, rowIndex) => { return style } +const DeleteMailboxRuleButton = (tenantDomain, ruleId, userPrincipalName, ruleName) => { + const [genericGetRequest, getResults] = useLazyGenericGetRequestQuery() + const handleModal = (modalMessage, modalUrl) => { + ModalService.confirm({ + body: ( +
    +
    {modalMessage}
    +
    + ), + title: 'Confirm', + onConfirm: () => genericGetRequest({ path: modalUrl }), + }) + } + return ( + { + ModalService.confirm( + handleModal( + 'Are you sure you want to remove this mailbox rule?', + `/api/ExecRemoveMailboxRule?TenantFilter=${tenantDomain}&ruleId=${ruleId}&ruleName=${ruleName}&userPrincipalName=${userPrincipalName}`, + ), + ) + }} + > + + + ) +} + export default function UserMailboxRuleList({ userId, userEmail, tenantDomain, className = null }) { const formatter = (cell) => CellBoolean({ cell }) const columns = [ @@ -70,6 +106,11 @@ export default function UserMailboxRuleList({ userId, userEmail, tenantDomain, c exportSelector: 'DeleteMessage', width: '200px', }, + { + name: 'Action', + maxWidth: '100px', + cell: (row) => DeleteMailboxRuleButton(tenantDomain, row['Identity'], userEmail, row['Name']), + }, ] return ( Date: Sat, 24 Aug 2024 17:16:08 +0200 Subject: [PATCH 107/130] Fix angry linter --- src/views/identity/administration/DeployJITAdmin.jsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/views/identity/administration/DeployJITAdmin.jsx b/src/views/identity/administration/DeployJITAdmin.jsx index 146ab7d6fef1..b8d5945f001b 100644 --- a/src/views/identity/administration/DeployJITAdmin.jsx +++ b/src/views/identity/administration/DeployJITAdmin.jsx @@ -23,7 +23,6 @@ import 'react-datepicker/dist/react-datepicker.css' import { TenantSelector } from 'src/components/utilities' import arrayMutators from 'final-form-arrays' import DatePicker from 'react-datepicker' -import 'react-datepicker/dist/react-datepicker.css' import { useListUsersQuery } from 'src/store/api/users' import GDAPRoles from 'src/data/GDAPRoles' import { CippDatatable, cellDateFormatter } from 'src/components/tables' From b403887bb0689b6f1edff21d44f0fc37f94db50a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Sat, 24 Aug 2024 17:17:45 +0200 Subject: [PATCH 108/130] Fix another angry linter --- src/views/tenant/backup/CreateBackup.jsx | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/views/tenant/backup/CreateBackup.jsx b/src/views/tenant/backup/CreateBackup.jsx index d0dd6350219c..c4dbf63ba81c 100644 --- a/src/views/tenant/backup/CreateBackup.jsx +++ b/src/views/tenant/backup/CreateBackup.jsx @@ -195,14 +195,8 @@ const CreateBackup = () => { label="Intune Protection Policies" />

    Email Security

    - - + +

    CIPP

    Date: Mon, 26 Aug 2024 21:24:34 -0400 Subject: [PATCH 109/130] Quarantine messages --- src/scss/_custom.scss | 4 ++ .../administration/QuarantineList.jsx | 52 ++++++++++++++++--- .../email-exchange/tools/MessageViewer.jsx | 2 +- 3 files changed, 51 insertions(+), 7 deletions(-) diff --git a/src/scss/_custom.scss b/src/scss/_custom.scss index b118641b872e..2b1e6c2aa248 100644 --- a/src/scss/_custom.scss +++ b/src/scss/_custom.scss @@ -257,6 +257,10 @@ h3.underline:after { } } +.modal { + z-index: 1555 !important; +} + .modal-content { border-radius: var(--cipp-border-radius); } diff --git a/src/views/email-exchange/administration/QuarantineList.jsx b/src/views/email-exchange/administration/QuarantineList.jsx index 6c5de828afec..cc3ac793ad53 100644 --- a/src/views/email-exchange/administration/QuarantineList.jsx +++ b/src/views/email-exchange/administration/QuarantineList.jsx @@ -1,22 +1,44 @@ import React, { useState } from 'react' import { useSelector } from 'react-redux' import { CippPageList } from 'src/components/layout' -import { CButton } from '@coreui/react' +import { CButton, CSpinner, CTooltip } from '@coreui/react' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import { faEllipsisV, faMinusCircle, faPaperPlane } from '@fortawesome/free-solid-svg-icons' -import { CippActionsOffcanvas } from 'src/components/utilities' +import { CippActionsOffcanvas, CippOffcanvas } from 'src/components/utilities' import { cellDateFormatter, CellTip } from 'src/components/tables' +import { MessageViewer } from 'src/views/email-exchange/tools/MessageViewer' +import { ModalService } from 'src/components/utilities' +import { useLazyGenericGetRequestQuery } from 'src/store/api/app' +import PropTypes from 'prop-types' const QuarantineList = () => { const tenant = useSelector((state) => state.app.currentTenant) - const Offcanvas = (row, rowIndex, formatExtraData) => { const [ocVisible, setOCVisible] = useState(false) + const [msgOcVisible, setMsgOcVisible] = useState(false) + const [getQuarantineMessage, quarantineMessage] = useLazyGenericGetRequestQuery() return ( <> - setOCVisible(true)}> - - + + { + setMsgOcVisible(true) + getQuarantineMessage({ + path: `/api/ListMailQuarantineMessage`, + params: { TenantFilter: tenant.defaultDomainName, Identity: row?.Identity }, + }) + }} + > + + + + + setOCVisible(true)}> + + + { id={row.id} hideFunction={() => setOCVisible(false)} /> + setMsgOcVisible(false)} + visible={msgOcVisible} + placement="end" + > + <> + {quarantineMessage.isLoading && ( +
    + Loading message +
    + )} + {quarantineMessage.isSuccess && ( + + )} + +
    ) } diff --git a/src/views/email-exchange/tools/MessageViewer.jsx b/src/views/email-exchange/tools/MessageViewer.jsx index f010c0b37c4f..bc63e647b186 100644 --- a/src/views/email-exchange/tools/MessageViewer.jsx +++ b/src/views/email-exchange/tools/MessageViewer.jsx @@ -23,7 +23,7 @@ import DOMPurify from 'dompurify' import ReactHtmlParser from 'react-html-parser' import CippDropzone from 'src/components/utilities/CippDropzone' -const MessageViewer = ({ emailSource }) => { +export const MessageViewer = ({ emailSource }) => { const [emlContent, setEmlContent] = useState(null) const [emlError, setEmlError] = useState(false) const [messageHtml, setMessageHtml] = useState('') From c47696393f16ea647f3d7ef4d276a28ea4b74426 Mon Sep 17 00:00:00 2001 From: RunningFreak <156828136+OwenIbarra@users.noreply.github.com> Date: Tue, 27 Aug 2024 12:38:28 -0400 Subject: [PATCH 110/130] Update AzureDeploymentTemplate.json --- deployment/AzureDeploymentTemplate.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deployment/AzureDeploymentTemplate.json b/deployment/AzureDeploymentTemplate.json index ff7e9a97bada..dc3222498ec6 100644 --- a/deployment/AzureDeploymentTemplate.json +++ b/deployment/AzureDeploymentTemplate.json @@ -200,7 +200,7 @@ "name": "[variables('funcStorageName')]", "location": "[resourceGroup().location]", "tags": { - "displayName": "funStorageName" + "displayName": "funcStorageName" }, "sku": { "name": "Standard_LRS" From 2173e51d8e6586755842c6ad785c474eb1a3bed8 Mon Sep 17 00:00:00 2001 From: RunningFreak <156828136+OwenIbarra@users.noreply.github.com> Date: Tue, 27 Aug 2024 12:41:33 -0400 Subject: [PATCH 111/130] Update AzureDeploymentTemplate_regionoptions.json --- deployment/AzureDeploymentTemplate_regionoptions.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/deployment/AzureDeploymentTemplate_regionoptions.json b/deployment/AzureDeploymentTemplate_regionoptions.json index bc2f24089d4d..ac6691593a0b 100644 --- a/deployment/AzureDeploymentTemplate_regionoptions.json +++ b/deployment/AzureDeploymentTemplate_regionoptions.json @@ -6,7 +6,7 @@ "defaultValue": "CIPP", "type": "string", "metadata": { - "description": "Name use as base-template to named the resources deployed in Azure." + "description": "Name used as base-template to name the resources deployed in Azure." } }, "GithubRepository": { @@ -20,7 +20,7 @@ "defaultValue": "GeneratedPassword", "type": "string", "metadata": { - "description": "Your Github Repository token (see https://docs.microsoft.com/en-us/azure/static-web-apps/publish-azure-resource-manager?tabs=azure-cli#create-a-github-personal-access-token" + "description": "Your Github Repository token (see https://docs.microsoft.com/en-us/azure/static-web-apps/publish-azure-resource-manager?tabs=azure-cli#create-a-github-personal-access-token)" } }, "GithubAPIRepository": { @@ -197,7 +197,7 @@ "name": "[variables('funcStorageName')]", "location": "[resourceGroup().location]", "tags": { - "displayName": "funStorageName" + "displayName": "funcStorageName" }, "sku": { "name": "Standard_LRS" From b72a4e7df56941dea5aad475790046575829355c Mon Sep 17 00:00:00 2001 From: RunningFreak <156828136+OwenIbarra@users.noreply.github.com> Date: Tue, 27 Aug 2024 12:43:20 -0400 Subject: [PATCH 112/130] Update DevAzureDeploymentTemplate.json --- deployment/DevAzureDeploymentTemplate.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/deployment/DevAzureDeploymentTemplate.json b/deployment/DevAzureDeploymentTemplate.json index 8beefadd450c..5e6077beab41 100644 --- a/deployment/DevAzureDeploymentTemplate.json +++ b/deployment/DevAzureDeploymentTemplate.json @@ -6,7 +6,7 @@ "defaultValue": "CIPPDev", "type": "string", "metadata": { - "description": "Name use as base-template to named the resources deployed in Azure." + "description": "Name used as base-template to name the resources deployed in Azure." } }, "TenantID": { @@ -48,7 +48,7 @@ "defaultValue": "GeneratedPassword", "type": "string", "metadata": { - "description": "Your Github Repository token (see https://docs.microsoft.com/en-us/azure/static-web-apps/publish-azure-resource-manager?tabs=azure-cli#create-a-github-personal-access-token" + "description": "Your Github Repository token (see https://docs.microsoft.com/en-us/azure/static-web-apps/publish-azure-resource-manager?tabs=azure-cli#create-a-github-personal-access-token)" } }, "GithubAPIRepository": { @@ -250,7 +250,7 @@ "name": "[variables('funcStorageName')]", "location": "[resourceGroup().location]", "tags": { - "displayName": "funStorageName" + "displayName": "funcStorageName" }, "sku": { "name": "Standard_LRS" From 1c4d5dd313e6e51dc11a801cc7ee48aea1cd91a5 Mon Sep 17 00:00:00 2001 From: RunningFreak <156828136+OwenIbarra@users.noreply.github.com> Date: Tue, 27 Aug 2024 12:44:08 -0400 Subject: [PATCH 113/130] Update DevAzureDeploymentTemplate_regionoptions.json --- deployment/DevAzureDeploymentTemplate_regionoptions.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/deployment/DevAzureDeploymentTemplate_regionoptions.json b/deployment/DevAzureDeploymentTemplate_regionoptions.json index 0fb300af06c9..f41e669076e5 100644 --- a/deployment/DevAzureDeploymentTemplate_regionoptions.json +++ b/deployment/DevAzureDeploymentTemplate_regionoptions.json @@ -6,7 +6,7 @@ "defaultValue": "CIPP", "type": "string", "metadata": { - "description": "Name use as base-template to named the resources deployed in Azure." + "description": "Name used as base-template to name the resources deployed in Azure." } }, "TenantID": { @@ -48,7 +48,7 @@ "defaultValue": "GeneratedPassword", "type": "string", "metadata": { - "description": "Your Github Repository token (see https://docs.microsoft.com/en-us/azure/static-web-apps/publish-azure-resource-manager?tabs=azure-cli#create-a-github-personal-access-token" + "description": "Your Github Repository token (see https://docs.microsoft.com/en-us/azure/static-web-apps/publish-azure-resource-manager?tabs=azure-cli#create-a-github-personal-access-token)" } }, "GithubAPIRepository": { From 608343461800e7f36d59a7223a5e0fb02f08722b Mon Sep 17 00:00:00 2001 From: RunningFreak <156828136+OwenIbarra@users.noreply.github.com> Date: Tue, 27 Aug 2024 12:56:58 -0400 Subject: [PATCH 114/130] Update SettingsExtensionMappings.jsx --- src/views/cipp/app-settings/SettingsExtensionMappings.jsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/views/cipp/app-settings/SettingsExtensionMappings.jsx b/src/views/cipp/app-settings/SettingsExtensionMappings.jsx index 6d7a63d2a3d0..4ed3362e2b59 100644 --- a/src/views/cipp/app-settings/SettingsExtensionMappings.jsx +++ b/src/views/cipp/app-settings/SettingsExtensionMappings.jsx @@ -169,7 +169,7 @@ export function SettingsExtensionMappings({ type }) { ) } - const halocolumns = [ + const haloColumns = [ { name: 'Tenant', selector: (row) => row.Tenant?.displayName, @@ -205,7 +205,7 @@ export function SettingsExtensionMappings({ type }) { }, ] - const ninjacolumns = [ + const ninjaColumns = [ { name: 'Tenant', selector: (row) => row.Tenant?.displayName, @@ -286,7 +286,7 @@ export function SettingsExtensionMappings({ type }) { @@ -439,7 +439,7 @@ export function SettingsExtensionMappings({ type }) { From a9b88a27b81c1c20bddaba700e444502eee0e96c Mon Sep 17 00:00:00 2001 From: John Duprey Date: Tue, 27 Aug 2024 21:18:24 -0400 Subject: [PATCH 115/130] Update QuarantineList.jsx --- src/views/email-exchange/administration/QuarantineList.jsx | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/views/email-exchange/administration/QuarantineList.jsx b/src/views/email-exchange/administration/QuarantineList.jsx index cc3ac793ad53..87582178f38d 100644 --- a/src/views/email-exchange/administration/QuarantineList.jsx +++ b/src/views/email-exchange/administration/QuarantineList.jsx @@ -10,6 +10,7 @@ import { MessageViewer } from 'src/views/email-exchange/tools/MessageViewer' import { ModalService } from 'src/components/utilities' import { useLazyGenericGetRequestQuery } from 'src/store/api/app' import PropTypes from 'prop-types' +import Skeleton from 'react-loading-skeleton' const QuarantineList = () => { const tenant = useSelector((state) => state.app.currentTenant) @@ -95,11 +96,7 @@ const QuarantineList = () => { placement="end" > <> - {quarantineMessage.isLoading && ( -
    - Loading message -
    - )} + {quarantineMessage.isLoading && } {quarantineMessage.isSuccess && ( )} From 43491fff83809857bb19b601088a6088e7f3ffb3 Mon Sep 17 00:00:00 2001 From: RunningFreak <156828136+OwenIbarra@users.noreply.github.com> Date: Wed, 28 Aug 2024 10:51:17 -0400 Subject: [PATCH 116/130] Typo --- src/views/endpoint/applications/ApplicationsAddRMM.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/views/endpoint/applications/ApplicationsAddRMM.jsx b/src/views/endpoint/applications/ApplicationsAddRMM.jsx index a6583e00fd4c..e90e31ff78e3 100644 --- a/src/views/endpoint/applications/ApplicationsAddRMM.jsx +++ b/src/views/endpoint/applications/ApplicationsAddRMM.jsx @@ -325,7 +325,7 @@ const AddRMM = () => {
    From 2b4f94abdb319c70d9b2f146b67365eb629c3f96 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Wed, 28 Aug 2024 16:52:33 -0400 Subject: [PATCH 117/130] BEC prettification --- src/store/api/users.js | 1 + src/views/identity/administration/ViewBEC.jsx | 76 ++++++++++++------- 2 files changed, 48 insertions(+), 29 deletions(-) diff --git a/src/store/api/users.js b/src/store/api/users.js index 7ef16f12fdb3..552481567406 100644 --- a/src/store/api/users.js +++ b/src/store/api/users.js @@ -64,6 +64,7 @@ export const usersApi = baseApi.injectEndpoints({ userId: _args.userId, tenantFilter: _args.tenantFilter, userName: _args.userName, + overwrite: _args.overwrite, }, }) if (startRequest.error) { diff --git a/src/views/identity/administration/ViewBEC.jsx b/src/views/identity/administration/ViewBEC.jsx index 3142af80d61e..9a4338d79b88 100644 --- a/src/views/identity/administration/ViewBEC.jsx +++ b/src/views/identity/administration/ViewBEC.jsx @@ -22,6 +22,7 @@ import { CippContentCard, CippMasonry, CippMasonryItem, CippPage } from 'src/com import 'react-loading-skeleton/dist/skeleton.css' import Skeleton from 'react-loading-skeleton' import useConfirmModal from 'src/hooks/useConfirmModal' +import { cellGenericFormatter } from 'src/components/tables/CellGenericFormat' const ViewBec = () => { let query = useQuery() @@ -85,28 +86,33 @@ const ViewBec = () => { const logonColumns = [ { name: 'App', - selector: (row) => row['AppDisplayName'], + selector: (row) => row['appDisplayName'], sortable: true, + cell: cellGenericFormatter(), }, { name: 'Date Time', - selector: (row) => row['CreatedDateTime'], + selector: (row) => row['createdDateTime'], sortable: true, + cell: cellGenericFormatter(), }, { name: 'Error code', selector: (row) => row.id, sortable: true, + cell: cellGenericFormatter(), }, { name: 'Details', selector: (row) => row.Status, sortable: true, + cell: cellGenericFormatter(), }, { name: 'IP', selector: (row) => row.IPAddress, sortable: true, + cell: cellGenericFormatter(), }, ] @@ -115,21 +121,25 @@ const ViewBec = () => { name: 'IP', selector: (row) => row['IPAddress'], sortable: true, + cell: cellGenericFormatter(), }, { name: 'User', selector: (row) => row['userPrincipalName'], sortable: true, + cell: cellGenericFormatter(), }, { name: 'Application', selector: (row) => row['AppDisplayName'], sortable: true, + cell: cellGenericFormatter(), }, { name: 'Result', selector: (row) => row['Status'], sortable: true, + cell: cellGenericFormatter(), }, ] const newUserColumns = [ @@ -137,16 +147,19 @@ const ViewBec = () => { name: 'DisplayName', selector: (row) => row['displayName'], sortable: true, + cell: cellGenericFormatter(), }, { name: 'Username', selector: (row) => row['userPrincipalName'], sortable: true, + cell: cellGenericFormatter(), }, { name: 'Date', - selector: (row) => row['CreatedDateTime'], + selector: (row) => row['createdDateTime'], sortable: true, + cell: cellGenericFormatter(), }, ] @@ -155,16 +168,19 @@ const ViewBec = () => { name: 'displayName', selector: (row) => row['displayName'], sortable: true, + cell: cellGenericFormatter(), }, { name: 'Username', selector: (row) => row['userPrincipalName'], sortable: true, + cell: cellGenericFormatter(), }, { name: 'Date', selector: (row) => row['lastPasswordChangeDateTime'], sortable: true, + cell: cellGenericFormatter(), }, ] @@ -173,44 +189,46 @@ const ViewBec = () => { name: 'Operation', selector: (row) => row['Operation'], sortable: true, + cell: cellGenericFormatter(), }, { name: 'Executed by', selector: (row) => row['UserKey'], sortable: true, + cell: cellGenericFormatter(), }, { name: 'Executed on', selector: (row) => row['ObjectId'], sortable: true, + cell: cellGenericFormatter(), }, { name: 'Permissions', selector: (row) => row['Permissions'], sortable: true, + cell: cellGenericFormatter(), }, ] const appColumns = [ { - name: 'Type', - selector: (row) => row['Operation'], - sortable: true, - }, - { - name: 'User', - selector: (row) => row['UserId'], + name: 'Application', + selector: (row) => row['appDisplayName'], sortable: true, + cell: cellGenericFormatter(), }, { - name: 'Application', - selector: (row) => row['ObjectId'], + name: 'Application ID', + selector: (row) => row['appId'], sortable: true, + cell: cellGenericFormatter(), }, { - name: 'Result', - selector: (row) => row['ResultStatus'], + name: 'Created', + selector: (row) => row['createdDateTime'], sortable: true, + cell: cellGenericFormatter(), }, ] const handleReMediate = useConfirmModal({ @@ -304,9 +322,9 @@ const ViewBec = () => { data={alerts.SuspectUserDevices} striped responsive={true} - tableProps={{ subHeaderComponent: false, pagination: false }} + isModal={true} wrapperClasses="table-responsive" - reportName="none" + reportName="bec-user-devices" /> )} @@ -322,8 +340,8 @@ const ViewBec = () => { data={alerts.NewRules} striped responsive={true} - tableProps={{ subHeaderComponent: false }} - reportName="none" + isModal={true} + reportName="bec-inbox-rules" /> )} @@ -338,8 +356,8 @@ const ViewBec = () => { data={alerts.LastSuspectUserLogon} striped responsive={true} - tableProps={{ subHeaderComponent: false }} - reportName="none" + isModal={true} + reportName="bec-suspect-user-logons" /> )} @@ -355,9 +373,9 @@ const ViewBec = () => { data={alerts.NewUsers} striped responsive={true} - tableProps={{ subHeaderComponent: false }} + isModal={true} wrapperClasses="table-responsive" - reportName="none" + reportName="bec-new-users" /> )} @@ -373,9 +391,9 @@ const ViewBec = () => { data={alerts.ChangedPasswords} striped responsive={true} - tableProps={{ subHeaderComponent: false }} + isModal={true} wrapperClasses="table-responsive" - reportName="none" + reportName="bec-changed-passwords" /> )} @@ -391,9 +409,9 @@ const ViewBec = () => { data={alerts.MailboxPermissionChanges} striped responsive={true} - tableProps={{ subHeaderComponent: false }} + isModal={true} wrapperClasses="table-responsive" - reportName="none" + reportName="bec-mailbox-permission-changes" /> )} @@ -409,9 +427,9 @@ const ViewBec = () => { data={alerts.AddedApps} striped responsive={true} - tableProps={{ subHeaderComponent: false }} wrapperClasses="table-responsive" - reportName="none" + isModal={true} + reportName="bec-added-apps" /> )} @@ -427,7 +445,7 @@ const ViewBec = () => { data={alerts.SuspectUserMailboxLogons} striped responsive={true} - tableProps={{ subHeaderComponent: false }} + isModal={true} wrapperClasses="table-responsive" reportName="none" /> From 8a04e24681a08bcfb5dd5a931b030b4c13c5e9d3 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Thu, 29 Aug 2024 10:25:39 -0400 Subject: [PATCH 118/130] Update orchestration starter url --- src/views/endpoint/applications/ListApplicationQueue.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/views/endpoint/applications/ListApplicationQueue.jsx b/src/views/endpoint/applications/ListApplicationQueue.jsx index 53f1e9197d33..eb42ed86ec47 100644 --- a/src/views/endpoint/applications/ListApplicationQueue.jsx +++ b/src/views/endpoint/applications/ListApplicationQueue.jsx @@ -20,7 +20,7 @@ const RefreshAction = () => { Please note: This job runs automatically every 12 hours.
    ), - onConfirm: () => execStandards({ path: 'api/AddChocoApp_OrchestrationStarter' }), + onConfirm: () => execStandards({ path: 'api/ExecAppUpload' }), }) return ( From fae4360d9cd5bee3db671bf5aacd95812b4e94d0 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Thu, 29 Aug 2024 10:42:36 -0400 Subject: [PATCH 119/130] Cleanup queries in Mailbox Settings - Change forwarding to look at proxyAddresses instead of mail - Remove extra queries --- .../administration/EditMailboxPermissions.jsx | 21 ++++--------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/src/views/email-exchange/administration/EditMailboxPermissions.jsx b/src/views/email-exchange/administration/EditMailboxPermissions.jsx index 3f16a1e389d9..ff1e7d2b64ce 100644 --- a/src/views/email-exchange/administration/EditMailboxPermissions.jsx +++ b/src/views/email-exchange/administration/EditMailboxPermissions.jsx @@ -195,7 +195,7 @@ const MailboxPermissions = () => { params: { Endpoint: 'users', TenantFilter: tenantDomain, - $filter: 'assignedLicenses/$count ne 0 and accountEnabled eq true', + $filter: "assignedLicenses/$count ne 0 and accountEnabled eq true and userType eq 'Member'", $count: true, }, }) @@ -586,7 +586,7 @@ const MailboxForwarding = () => { params: { Endpoint: 'users', TenantFilter: tenantDomain, - $filter: "userType eq 'Member' and mail ge ' '", // filter out guests and users with no mailbox. #HACK "mail ne 'null'" does not work so this horrible hack is required + $filter: "userType eq 'Member' and proxyAddresses/$count ne 0", }, }) useEffect(() => { @@ -803,19 +803,6 @@ const OutOfOffice = () => { error: userError, } = useListMailboxPermissionsQuery({ tenantDomain, userId }) - const { - data: users = [], - isFetching: usersIsFetching, - error: usersError, - } = useGenericGetRequestQuery({ - path: '/api/ListGraphRequest', - params: { - Endpoint: 'users', - TenantFilter: tenantDomain, - $filter: 'assignedLicenses/$count ne 0 and accountEnabled eq true', - $count: true, - }, - }) useEffect(() => { if (postResults.isSuccess) { // @TODO do something here? @@ -865,9 +852,9 @@ const OutOfOffice = () => { )} - {usersIsFetching && } + {userIsFetching && } {userError && Error loading user} - {!usersIsFetching && ( + {!userIsFetching && ( Date: Thu, 29 Aug 2024 11:10:00 -0400 Subject: [PATCH 120/130] Update paths for starting BPA/Domain Analyser --- src/store/api/reports.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/store/api/reports.js b/src/store/api/reports.js index 83be1b4fa361..2292662ad2be 100644 --- a/src/store/api/reports.js +++ b/src/store/api/reports.js @@ -6,10 +6,10 @@ export const reportsApi = baseApi.injectEndpoints({ query: () => ({ path: '/api/BestPracticeAnalyser_List' }), }), execBestPracticeAnalyser: builder.mutation({ - query: () => ({ path: '/api/BestPracticeAnalyser_OrchestrationStarter' }), + query: () => ({ path: '/api/ExecBPA' }), }), execDomainsAnalyser: builder.mutation({ - query: () => ({ path: '/api/DomainAnalyser_OrchestrationStarter' }), + query: () => ({ path: '/api/ExecDomainAnalyser' }), }), }), }) From 0c308b2abb08275824b835526368f7af8a42febb Mon Sep 17 00:00:00 2001 From: John Duprey Date: Thu, 29 Aug 2024 11:17:01 -0400 Subject: [PATCH 121/130] Update BestPracticeAnalyser.jsx --- src/views/tenant/standards/BestPracticeAnalyser.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/views/tenant/standards/BestPracticeAnalyser.jsx b/src/views/tenant/standards/BestPracticeAnalyser.jsx index a0e1cb00b101..692c39478591 100644 --- a/src/views/tenant/standards/BestPracticeAnalyser.jsx +++ b/src/views/tenant/standards/BestPracticeAnalyser.jsx @@ -61,7 +61,7 @@ const RefreshAction = ({ singleTenant = false, refreshFunction = null }) => { ), onConfirm: () => execBestPracticeAnalyser({ - path: 'api/BestPracticeAnalyser_OrchestrationStarter', + path: 'api/ExecBPA', params: params, }), }) From 94eb15fe07074521254b2f36cf0b2c254b76fc4c Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Fri, 30 Aug 2024 01:11:46 +0200 Subject: [PATCH 122/130] alert update --- src/data/alerts.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/data/alerts.json b/src/data/alerts.json index 13f18265caf4..fe03d7b6a968 100644 --- a/src/data/alerts.json +++ b/src/data/alerts.json @@ -19,6 +19,11 @@ "label": "Alert on changed admin Passwords", "recommendedRunInterval": "30m" }, + { + "name": "InactiveLicensedUsers", + "label": "Alert on licensed users that have not logged in for 90 days", + "recommendedRunInterval": "1d" + }, { "name": "QuotaUsed", "label": "Alert on % mailbox quota used", From 529277ea490bfe67409f89a8f267783737e8e67b Mon Sep 17 00:00:00 2001 From: John Duprey Date: Thu, 29 Aug 2024 22:14:20 -0400 Subject: [PATCH 123/130] Improve edit mailbox page --- src/store/api/app.js | 1 + .../administration/EditMailboxPermissions.jsx | 180 ++++++++++++++---- 2 files changed, 143 insertions(+), 38 deletions(-) diff --git a/src/store/api/app.js b/src/store/api/app.js index 3eaa06328f84..bb2e4bb45ce2 100644 --- a/src/store/api/app.js +++ b/src/store/api/app.js @@ -139,4 +139,5 @@ export const { useLazyGenericPostRequestQuery, useLazyGenericGetRequestQuery, useGenericGetRequestQuery, + useGenericPostRequestQuery, } = appApi diff --git a/src/views/email-exchange/administration/EditMailboxPermissions.jsx b/src/views/email-exchange/administration/EditMailboxPermissions.jsx index ff1e7d2b64ce..efd01a155d52 100644 --- a/src/views/email-exchange/administration/EditMailboxPermissions.jsx +++ b/src/views/email-exchange/administration/EditMailboxPermissions.jsx @@ -14,6 +14,8 @@ import { CForm, CRow, CSpinner, + CLink, + CBadge, } from '@coreui/react' import useQuery from 'src/hooks/useQuery' import { useDispatch } from 'react-redux' @@ -24,14 +26,16 @@ import { useLazyGenericPostRequestQuery, useLazyGenericGetRequestQuery, useGenericGetRequestQuery, + useGenericPostRequestQuery, } from 'src/store/api/app' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import { faCircleNotch } from '@fortawesome/free-solid-svg-icons' import { useListMailboxDetailsQuery, useListMailboxPermissionsQuery } from 'src/store/api/mailbox' -import { CellBoolean, CippDatatable } from 'src/components/tables' +import { CellBadge, CellBoolean, CippDatatable } from 'src/components/tables' import DatePicker from 'react-datepicker' import 'react-datepicker/dist/react-datepicker.css' import PropTypes from 'prop-types' +import Skeleton from 'react-loading-skeleton' const formatter = (cell, warning = false, reverse = false, colourless = false) => CellBoolean({ cell, warning, reverse, colourless }) @@ -196,7 +200,9 @@ const MailboxPermissions = () => { Endpoint: 'users', TenantFilter: tenantDomain, $filter: "assignedLicenses/$count ne 0 and accountEnabled eq true and userType eq 'Member'", + $select: 'id,displayName,userPrincipalName', $count: true, + $orderby: 'displayName', }, }) @@ -258,8 +264,8 @@ const MailboxPermissions = () => { label="Remove Full Access" disabled={formDisabled} values={users?.Results?.map((user) => ({ - value: user.mail, - name: `${user.displayName} - ${user.mail} `, + value: user.userPrincipalName, + name: `${user.displayName} - ${user.userPrincipalName} `, }))} placeholder={!usersIsFetching ? 'Select user' : 'Loading...'} name="RemoveFullAccess" @@ -272,8 +278,8 @@ const MailboxPermissions = () => { label="Add Full Access - Automapping Enabled" disabled={formDisabled} values={users?.Results?.map((user) => ({ - value: user.mail, - name: `${user.displayName} - ${user.mail} `, + value: user.userPrincipalName, + name: `${user.displayName} - ${user.userPrincipalName} `, }))} placeholder={!usersIsFetching ? 'Select user' : 'Loading...'} name="AddFullAccess" @@ -286,8 +292,8 @@ const MailboxPermissions = () => { label="Add Full Access - Automapping Disabled" disabled={formDisabled} values={users?.Results?.map((user) => ({ - value: user.mail, - name: `${user.displayName} - ${user.mail} `, + value: user.userPrincipalName, + name: `${user.displayName} - ${user.userPrincipalName} `, }))} placeholder={!usersIsFetching ? 'Select user' : 'Loading...'} name="AddFullAccessNoAutoMap" @@ -300,8 +306,8 @@ const MailboxPermissions = () => { label="Add Send-as permissions" disabled={formDisabled} values={users?.Results?.map((user) => ({ - value: user.mail, - name: `${user.displayName} - ${user.mail} `, + value: user.userPrincipalName, + name: `${user.displayName} - ${user.userPrincipalName} `, }))} placeholder={!usersIsFetching ? 'Select user' : 'Loading...'} name="AddSendAs" @@ -314,8 +320,8 @@ const MailboxPermissions = () => { label="Remove Send-as permissions" disabled={formDisabled} values={users?.Results?.map((user) => ({ - value: user.mail, - name: `${user.displayName} - ${user.mail} `, + value: user.userPrincipalName, + name: `${user.displayName} - ${user.userPrincipalName} `, }))} placeholder={!usersIsFetching ? 'Select user' : 'Loading...'} name="RemoveSendAs" @@ -328,8 +334,8 @@ const MailboxPermissions = () => { label="Add Send On Behalf permissions" disabled={formDisabled} values={users?.Results?.map((user) => ({ - value: user.mail, - name: `${user.displayName} - ${user.mail} `, + value: user.userPrincipalName, + name: `${user.displayName} - ${user.userPrincipalName} `, }))} placeholder={!usersIsFetching ? 'Select user' : 'Loading...'} name="AddSendOnBehalf" @@ -342,8 +348,8 @@ const MailboxPermissions = () => { label="Remove Send On Behalf permissions" disabled={formDisabled} values={users?.Results?.map((user) => ({ - value: user.mail, - name: `${user.displayName} - ${user.mail} `, + value: user.userPrincipalName, + name: `${user.displayName} - ${user.userPrincipalName} `, }))} placeholder={!usersIsFetching ? 'Select user' : 'Loading...'} name="RemoveSendOnBehalf" @@ -587,6 +593,9 @@ const MailboxForwarding = () => { Endpoint: 'users', TenantFilter: tenantDomain, $filter: "userType eq 'Member' and proxyAddresses/$count ne 0", + $select: 'id,displayName,userPrincipalName', + $count: true, + $orderby: 'displayName', }, }) useEffect(() => { @@ -664,8 +673,8 @@ const MailboxForwarding = () => { multi={true} disabled={formDisabled} values={users?.Results?.map((user) => ({ - value: user.mail, - name: `${user.displayName} - ${user.mail} `, + value: user.userPrincipalName, + name: `${user.displayName} - ${user.userPrincipalName} `, }))} placeholder={!usersIsFetching ? 'Select user' : 'Loading...'} name="ForwardInternal" @@ -759,31 +768,126 @@ const ForwardingSettings = () => { const query = useQuery() const userId = query.get('userId') const tenantDomain = query.get('tenantDomain') - const { data: details, isFetching, error } = useListMailboxDetailsQuery({ userId, tenantDomain }) - const content = [ - { - heading: 'Forward and Deliver', - body: formatter(details?.ForwardAndDeliver, false, false, true), - }, - { - heading: 'Forwarding Address', - body: details?.ForwardingAddress ? details?.ForwardingAddress : 'N/A', + const [content, setContent] = useState([]) + const { + data: details, + isFetching, + isSuccess, + error, + } = useGenericPostRequestQuery({ + path: `/api/ListExoRequest?Cmdlet=Get-Mailbox&TenantFilter=${tenantDomain}&Select=ForwardingAddress,ForwardingSmtpAddress,DeliverToMailboxAndForward`, + values: { Identity: userId }, + }) + + const { + data: users = [], + isFetching: usersIsFetching, + isSuccess: usersSuccess, + error: usersError, + } = useGenericGetRequestQuery({ + path: '/api/ListGraphRequest', + params: { + Endpoint: 'users', + TenantFilter: tenantDomain, + $filter: "userType eq 'Member' and proxyAddresses/$count ne 0", + $select: 'id,displayName,userPrincipalName', + $count: true, }, - ] + }) + + useEffect(() => { + if (usersSuccess && isSuccess) { + if (details?.Results?.ForwardingAddress) { + var user = null + if ( + details?.Results?.ForwardingAddress.match( + /^[A-Fa-f0-9]{8}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{12}$/, + ) + ) { + const userId = details?.Results?.ForwardingAddress + user = users?.Results?.find((u) => u.id === userId) + } + if (user) { + setContent([ + { + heading: 'Forward and Deliver', + body: formatter(details?.Results?.DeliverToMailboxAndForward, false, false, true), + }, + { + heading: 'Forwarding Address', + body: ( + <> + + Internal + + {user.displayName} + + ), + }, + ]) + } else { + setContent([ + { + heading: 'Forward and Deliver', + body: formatter(details?.Results?.DeliverToMailboxAndForward, false, false, true), + }, + { + heading: 'Forwarding Address', + body: ( + <> + + Internal + + {details?.Results?.ForwardingAddress} + + ), + }, + ]) + } + } else if (details?.Results?.ForwardingSmtpAddress) { + var smtpAddress = details?.Results?.ForwardingSmtpAddress.replace('smtp:', '') + setContent([ + { + heading: 'Forward and Deliver', + body: formatter(details?.Results?.DeliverToMailboxAndForward, false, false, true), + }, + { + heading: 'Forwarding Address', + body: ( + <> + + External + + {smtpAddress} + + ), + }, + ]) + } + } else if (usersIsFetching || isFetching) { + setContent([ + { + heading: 'Forward and Deliver', + body: , + }, + { + heading: 'Forwarding Address', + body: , + }, + ]) + } + }, [users, details, usersSuccess, isSuccess]) return ( - {isFetching && } - {!isFetching && ( - - {content.map((item, index) => ( -
    -
    {item.heading}
    -

    {item.body}

    -
    - ))} -
    - )} + + {content.map((item, index) => ( +
    +
    {item.heading}
    +

    {item.body}

    +
    + ))} +
    ) } From 90b09c7ab1f86d32c6b240d0b9b825ec56599ba4 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Thu, 29 Aug 2024 22:55:46 -0400 Subject: [PATCH 124/130] Update settings panel on save for fwd and ooo --- .../administration/EditMailboxPermissions.jsx | 160 ++++++++++++++---- 1 file changed, 127 insertions(+), 33 deletions(-) diff --git a/src/views/email-exchange/administration/EditMailboxPermissions.jsx b/src/views/email-exchange/administration/EditMailboxPermissions.jsx index efd01a155d52..bb6613f63d33 100644 --- a/src/views/email-exchange/administration/EditMailboxPermissions.jsx +++ b/src/views/email-exchange/administration/EditMailboxPermissions.jsx @@ -46,6 +46,8 @@ const MailboxSettings = () => { const userId = query.get('userId') const tenantDomain = query.get('tenantDomain') const [active, setActive] = useState(1) + const [forwardingRefresh, setForwardingRefresh] = useState('0') + const [oooRefresh, setOooRefresh] = useState('0') const columnsCal = [ { name: 'User', @@ -126,12 +128,20 @@ const MailboxSettings = () => { - + + setForwardingRefresh((Math.random() + 1).toString(36).substring(7)) + } + /> - + + setOooRefresh((Math.random() + 1).toString(36).substring(7)) + } + /> @@ -162,12 +172,20 @@ const MailboxSettings = () => { )} {active === 3 && ( <> - + )} {active === 4 && ( <> - + )} @@ -566,7 +584,7 @@ const CalendarPermissions = () => { ) } -const MailboxForwarding = () => { +const MailboxForwarding = ({ refreshFunction }) => { const dispatch = useDispatch() let query = useQuery() const userId = query.get('userId') @@ -622,7 +640,9 @@ const MailboxForwarding = () => { disableForwarding: values.forwardOption === 'disabled', } //window.alert(JSON.stringify(shippedValues)) - genericPostRequest({ path: '/api/ExecEmailForward', values: shippedValues }) + genericPostRequest({ path: '/api/ExecEmailForward', values: shippedValues }).then(() => { + refreshFunction() + }) } const initialState = { ...user, @@ -670,7 +690,6 @@ const MailboxForwarding = () => { {values.forwardOption === 'internalAddress' && ( ({ value: user.userPrincipalName, @@ -763,19 +782,24 @@ const MailboxForwarding = () => { ) } +MailboxForwarding.propTypes = { + refreshFunction: PropTypes.func, +} -const ForwardingSettings = () => { +const ForwardingSettings = ({ refresh }) => { const query = useQuery() const userId = query.get('userId') const tenantDomain = query.get('tenantDomain') const [content, setContent] = useState([]) + const [showLoading, setShowLoading] = useState(false) + const [currentRefresh, setCurrentRefresh] = useState('') const { data: details, isFetching, isSuccess, error, } = useGenericPostRequestQuery({ - path: `/api/ListExoRequest?Cmdlet=Get-Mailbox&TenantFilter=${tenantDomain}&Select=ForwardingAddress,ForwardingSmtpAddress,DeliverToMailboxAndForward`, + path: `/api/ListExoRequest?Cmdlet=Get-Mailbox&TenantFilter=${tenantDomain}&Select=ForwardingAddress,ForwardingSmtpAddress,DeliverToMailboxAndForward&refresh=${refresh}`, values: { Identity: userId }, }) @@ -796,8 +820,13 @@ const ForwardingSettings = () => { }) useEffect(() => { + if (refresh !== currentRefresh) { + setShowLoading(false) + setCurrentRefresh(refresh) + } + if (usersSuccess && isSuccess) { - if (details?.Results?.ForwardingAddress) { + if (details?.Results?.ForwardingAddress !== null) { var user = null if ( details?.Results?.ForwardingAddress.match( @@ -844,7 +873,7 @@ const ForwardingSettings = () => { }, ]) } - } else if (details?.Results?.ForwardingSmtpAddress) { + } else if (details?.Results?.ForwardingSmtpAddress !== null) { var smtpAddress = details?.Results?.ForwardingSmtpAddress.replace('smtp:', '') setContent([ { @@ -863,8 +892,19 @@ const ForwardingSettings = () => { ), }, ]) + } else { + setContent([ + { + heading: 'Forward and Deliver', + body: formatter(details?.Results?.DeliverToMailboxAndForward, false, false, true), + }, + { + heading: 'Forwarding Address', + body: 'N/A', + }, + ]) } - } else if (usersIsFetching || isFetching) { + } else if ((isFetching || usersIsFetching) && showLoading === false) { setContent([ { heading: 'Forward and Deliver', @@ -875,8 +915,19 @@ const ForwardingSettings = () => { body: , }, ]) + setShowLoading(true) } - }, [users, details, usersSuccess, isSuccess]) + }, [ + refresh, + currentRefresh, + users, + details, + usersSuccess, + isSuccess, + isFetching, + usersIsFetching, + showLoading, + ]) return ( @@ -888,11 +939,24 @@ const ForwardingSettings = () => { ))}
    + + setCurrentRefresh((Math.random() + 1).toString(36).substring(7))} + color="primary" + variant="ghost" + className="float-end" + > + + +
    ) } +ForwardingSettings.propTypes = { + refresh: PropTypes.string, +} -const OutOfOffice = () => { +const OutOfOffice = ({ refreshFunction }) => { const dispatch = useDispatch() let query = useQuery() const userId = query.get('userId') @@ -932,7 +996,9 @@ const OutOfOffice = () => { ExternalMessage: values.ExternalMessage ? values.ExternalMessage : '', } //window.alert(JSON.stringify(shippedValues)) - genericPostRequest({ path: '/api/ExecSetOoO', values: shippedValues }) + genericPostRequest({ path: '/api/ExecSetOoO', values: shippedValues }).then(() => { + refreshFunction() + }) } const initialState = { ...user, @@ -1049,18 +1115,26 @@ const OutOfOffice = () => { ) } -const OutOfOfficeSettings = () => { +const OutOfOfficeSettings = ({ refresh }) => { const query = useQuery() const userId = query.get('userId') const tenantDomain = query.get('tenantDomain') const tenantFilter = tenantDomain + const [currentRefresh, setCurrentRefresh] = useState('') + + useEffect(() => { + if (refresh !== currentRefresh) { + setCurrentRefresh(refresh) + } + }, [refresh, currentRefresh, setCurrentRefresh]) + const { data: details, isFetching, error, } = useGenericGetRequestQuery({ path: '/api/ListOoO', - params: { userId, tenantFilter }, + params: { userId, tenantFilter, currentRefresh }, }) const combinedRegex = /(<([^>]+)>)|| /gi const content = [ @@ -1087,22 +1161,42 @@ const OutOfOfficeSettings = () => { ] return ( - {isFetching && ( - - Loading - - )} - {!isFetching && ( - - {content.map((item, index) => ( -
    -
    {item.heading}
    -

    {item.body}

    -
    - ))} -
    - )} - {error && Could not connect to API: {error.message}} + + {isFetching && ( + <> + {content.map((item, index) => ( +
    +
    {item.heading}
    +

    + +

    +
    + ))} + + )} + {!isFetching && ( + <> + {content.map((item, index) => ( +
    +
    {item.heading}
    +

    {item.body}

    +
    + ))} + + )} + + {error && Could not connect to API: {error.message}} +
    + + setCurrentRefresh((Math.random() + 1).toString(36).substring(7))} + color="primary" + variant="ghost" + className="float-end" + > + + +
    ) } From 423ed7e4254b32ff9fdd89a399792f9fc0c64b83 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Thu, 29 Aug 2024 23:10:27 -0400 Subject: [PATCH 125/130] Update EditMailboxPermissions.jsx --- .../administration/EditMailboxPermissions.jsx | 63 +++++++++---------- 1 file changed, 29 insertions(+), 34 deletions(-) diff --git a/src/views/email-exchange/administration/EditMailboxPermissions.jsx b/src/views/email-exchange/administration/EditMailboxPermissions.jsx index bb6613f63d33..9283001ca1f3 100644 --- a/src/views/email-exchange/administration/EditMailboxPermissions.jsx +++ b/src/views/email-exchange/administration/EditMailboxPermissions.jsx @@ -791,7 +791,6 @@ const ForwardingSettings = ({ refresh }) => { const userId = query.get('userId') const tenantDomain = query.get('tenantDomain') const [content, setContent] = useState([]) - const [showLoading, setShowLoading] = useState(false) const [currentRefresh, setCurrentRefresh] = useState('') const { data: details, @@ -799,7 +798,7 @@ const ForwardingSettings = ({ refresh }) => { isSuccess, error, } = useGenericPostRequestQuery({ - path: `/api/ListExoRequest?Cmdlet=Get-Mailbox&TenantFilter=${tenantDomain}&Select=ForwardingAddress,ForwardingSmtpAddress,DeliverToMailboxAndForward&refresh=${refresh}`, + path: `/api/ListExoRequest?Cmdlet=Get-Mailbox&TenantFilter=${tenantDomain}&Select=ForwardingAddress,ForwardingSmtpAddress,DeliverToMailboxAndForward&refresh=${currentRefresh}`, values: { Identity: userId }, }) @@ -821,7 +820,6 @@ const ForwardingSettings = ({ refresh }) => { useEffect(() => { if (refresh !== currentRefresh) { - setShowLoading(false) setCurrentRefresh(refresh) } @@ -904,42 +902,39 @@ const ForwardingSettings = ({ refresh }) => { }, ]) } - } else if ((isFetching || usersIsFetching) && showLoading === false) { - setContent([ - { - heading: 'Forward and Deliver', - body: , - }, - { - heading: 'Forwarding Address', - body: , - }, - ]) - setShowLoading(true) } - }, [ - refresh, - currentRefresh, - users, - details, - usersSuccess, - isSuccess, - isFetching, - usersIsFetching, - showLoading, - ]) + }, [refresh, currentRefresh, users, details, usersSuccess, isSuccess]) return ( - - {content.map((item, index) => ( -
    -
    {item.heading}
    -

    {item.body}

    -
    - ))} + + {isFetching || usersIsFetching ? ( + <> +
    +
    Forward and Deliver
    +

    + +

    +
    +
    +
    Forwarding Address
    +

    + +

    +
    + + ) : ( + <> + {content.map((item, index) => ( +
    +
    {item.heading}
    +

    {item.body}

    +
    + ))} + + )}
    - + setCurrentRefresh((Math.random() + 1).toString(36).substring(7))} color="primary" From 6495cb15b3d68fd6275ed9886557c20d65768cbd Mon Sep 17 00:00:00 2001 From: John Duprey Date: Thu, 29 Aug 2024 23:11:43 -0400 Subject: [PATCH 126/130] add proptypes --- .../administration/EditMailboxPermissions.jsx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/views/email-exchange/administration/EditMailboxPermissions.jsx b/src/views/email-exchange/administration/EditMailboxPermissions.jsx index 9283001ca1f3..bddce9e02628 100644 --- a/src/views/email-exchange/administration/EditMailboxPermissions.jsx +++ b/src/views/email-exchange/administration/EditMailboxPermissions.jsx @@ -1109,6 +1109,9 @@ const OutOfOffice = ({ refreshFunction }) => { ) } +OutOfOffice.propTypes = { + refreshFunction: PropTypes.func, +} const OutOfOfficeSettings = ({ refresh }) => { const query = useQuery() @@ -1195,3 +1198,6 @@ const OutOfOfficeSettings = ({ refresh }) => {
    ) } +OutOfOfficeSettings.propTypes = { + refresh: PropTypes.string, +} From 9eb600c5a1fe70bcd66a78a616a187a61bc22614 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Fri, 30 Aug 2024 13:44:07 +0200 Subject: [PATCH 127/130] added get bitlocker key --- src/views/identity/administration/Devices.jsx | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/views/identity/administration/Devices.jsx b/src/views/identity/administration/Devices.jsx index 664f7552757c..f7808c39034a 100644 --- a/src/views/identity/administration/Devices.jsx +++ b/src/views/identity/administration/Devices.jsx @@ -36,6 +36,13 @@ const DevicesList = () => { modalUrl: `/api/ExecDeviceDelete?TenantFilter=${tenant.defaultDomainName}&ID=${row.id}&Action=Enable`, modalMessage: 'Are you sure you want to enable this device.', }, + { + label: 'Retrieve Bitlocker Keys', + color: 'info', + modal: true, + modalUrl: `/api/ExecGetRecoveryKey?TenantFilter=${tenant.defaultDomainName}&GUID=${row.id}`, + modalMessage: 'Are you sure you want to retrieve the Bitlocker keys?', + }, { label: 'Disable Device', color: 'info', From cb32a993ed4aa1e60240ab7cb09802f79cd1a1c2 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Fri, 30 Aug 2024 09:01:59 -0400 Subject: [PATCH 128/130] Move entire request to post body --- .../administration/EditMailboxPermissions.jsx | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/views/email-exchange/administration/EditMailboxPermissions.jsx b/src/views/email-exchange/administration/EditMailboxPermissions.jsx index bddce9e02628..740aa2417455 100644 --- a/src/views/email-exchange/administration/EditMailboxPermissions.jsx +++ b/src/views/email-exchange/administration/EditMailboxPermissions.jsx @@ -798,8 +798,14 @@ const ForwardingSettings = ({ refresh }) => { isSuccess, error, } = useGenericPostRequestQuery({ - path: `/api/ListExoRequest?Cmdlet=Get-Mailbox&TenantFilter=${tenantDomain}&Select=ForwardingAddress,ForwardingSmtpAddress,DeliverToMailboxAndForward&refresh=${currentRefresh}`, - values: { Identity: userId }, + path: `/api/ListExoRequest`, + values: { + TenantFilter: tenantDomain, + Cmdlet: 'Get-Mailbox', + cmdParams: { Identity: userId }, + Select: 'ForwardingAddress,ForwardingSmtpAddress,DeliverToMailboxAndForward', + refresh: currentRefresh, + }, }) const { From 2e15063054f1c58f386cb1bf1d3e8cac7516386a Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Fri, 30 Aug 2024 15:47:46 +0200 Subject: [PATCH 129/130] Right of Boom logo --- public/img/RoB-light.svg | 17 +++++++++++++++++ public/img/RoB.svg | 25 +++++++++++++++++++++++++ public/img/datto.png | Bin 15316 -> 0 bytes src/components/layout/AppFooter.jsx | 10 +++++++--- 4 files changed, 49 insertions(+), 3 deletions(-) create mode 100644 public/img/RoB-light.svg create mode 100644 public/img/RoB.svg delete mode 100644 public/img/datto.png diff --git a/public/img/RoB-light.svg b/public/img/RoB-light.svg new file mode 100644 index 000000000000..0673b2a8a449 --- /dev/null +++ b/public/img/RoB-light.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/public/img/RoB.svg b/public/img/RoB.svg new file mode 100644 index 000000000000..d188e1eb541b --- /dev/null +++ b/public/img/RoB.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/img/datto.png b/public/img/datto.png deleted file mode 100644 index b0fad6f50233e46eed52acb6d6c5e037aabecfda..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15316 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 diff --git a/src/components/layout/AppFooter.jsx b/src/components/layout/AppFooter.jsx index c720c8f5a35b..09087af3a00e 100644 --- a/src/components/layout/AppFooter.jsx +++ b/src/components/layout/AppFooter.jsx @@ -10,7 +10,7 @@ const AppFooter = () => { const isDark = currentTheme === 'impact' || (currentTheme === 'default' && preferredTheme === 'impact') - const datto = isDark ? '/img/datto.png' : '/img/datto.png' + const RoB = isDark ? '/img/RoB.svg' : '/img/RoB-light.svg' const huntress = isDark ? '/img/huntress_teal.png' : '/img/huntress_teal.png' const rewst = isDark ? '/img/rewst_dark.png' : '/img/rewst.png' const ninjaone = isDark ? '/img/ninjaone_dark.png' : '/img/ninjaone.png' @@ -24,8 +24,12 @@ const AppFooter = () => { - - + + From 46b15c72b3b907618fe273d88e6a7188a2ae58fb Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Fri, 30 Aug 2024 18:59:28 +0200 Subject: [PATCH 130/130] update version --- package.json | 2 +- public/version_latest.txt | 2 +- version_latest.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index b74d149fe82e..2739d1d2801a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cipp", - "version": "6.3.0", + "version": "6.4.0", "description": "The CyberDrain Improved Partner Portal is a portal to help manage administration for Microsoft Partners.", "homepage": "https://cipp.app/", "bugs": { diff --git a/public/version_latest.txt b/public/version_latest.txt index 798e38995c4d..19b860c1872d 100644 --- a/public/version_latest.txt +++ b/public/version_latest.txt @@ -1 +1 @@ -6.3.0 +6.4.0 diff --git a/version_latest.txt b/version_latest.txt index 798e38995c4d..19b860c1872d 100644 --- a/version_latest.txt +++ b/version_latest.txt @@ -1 +1 @@ -6.3.0 +6.4.0