From b4865156e2028590002a5dee6d036f40bd8baf28 Mon Sep 17 00:00:00 2001 From: BNWEIN Date: Sun, 23 Jun 2024 22:22:37 +0100 Subject: [PATCH 01/58] EditGroupChanges --- src/store/api/groups.js | 10 ++++++ .../identity/administration/EditGroup.jsx | 31 +++++++++++++++++-- 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/src/store/api/groups.js b/src/store/api/groups.js index 385770a4ecd6..faf6f32bd46e 100644 --- a/src/store/api/groups.js +++ b/src/store/api/groups.js @@ -59,6 +59,15 @@ export const groupsApi = baseApi.injectEndpoints({ params: { tenantFilter: tenantDomain, userId }, }), }), + listGroupSenderAuth: builder.query({ + query: ({ tenantDomain, groupId }) => ({ + path: '/api/ListGroupSenderAuthentication', + params: { + TenantFilter: tenantDomain, + GroupId: groupId, + }, + }), + }), }), }) export const { @@ -69,4 +78,5 @@ export const { useListGroupMembersQuery, useListGroupOwnersQuery, useListUserGroupsQuery, + useListGroupSenderAuthQuery, } = groupsApi diff --git a/src/views/identity/administration/EditGroup.jsx b/src/views/identity/administration/EditGroup.jsx index 7e81fc66306e..eb4e7a8bf899 100644 --- a/src/views/identity/administration/EditGroup.jsx +++ b/src/views/identity/administration/EditGroup.jsx @@ -18,6 +18,7 @@ import { useListGroupMembersQuery, useListGroupOwnersQuery, useListGroupQuery, + useListGroupSenderAuthQuery, } from 'src/store/api/groups' import { useDispatch } from 'react-redux' import { ModalService } from 'src/components/utilities' @@ -41,6 +42,13 @@ const EditGroup = () => { isSuccess, } = useListGroupQuery({ tenantDomain, groupId }) + const { + data: SenderAuth = {}, + isFetching: SenderAuthisFetching, + error: SenderAuthError, + isSuccess: SenderAuthIsSuccess, + } = useListGroupSenderAuthQuery({ tenantDomain, groupId }) + const { data: members = [], isFetching: membersisFetching, @@ -68,6 +76,7 @@ const EditGroup = () => { const [genericPostRequest, postResults] = useLazyGenericPostRequestQuery() const [roleInfo, setroleInfo] = React.useState([]) + const [allowExternal, setAllowExternal] = useState(false) useEffect(() => { if (ownersIsSuccess && membersIsSuccess) { const ownerWithRole = owners.map((owner) => { @@ -97,6 +106,13 @@ const EditGroup = () => { setQueryError(true) } }, [groupId, tenantDomain, dispatch]) + + useEffect(() => { + if (SenderAuthIsSuccess) { + setAllowExternal(!SenderAuth) // If SenderAuth is true, setAllowExternal to false, and vice versa + } + }, [SenderAuthIsSuccess, SenderAuth]) + const onSubmit = (values) => { const shippedValues = { tenantID: tenantDomain, @@ -154,6 +170,7 @@ const EditGroup = () => { {isSuccess && (
{ return ( @@ -304,8 +321,18 @@ const EditGroup = () => { {isFetching && } {isSuccess && ( <> - This is the (raw) information for this group. -
{JSON.stringify(group, null, 2)}
+
+ This is the (raw) information for this group. +
{JSON.stringify(group, null, 2)}
+
+
+ This is the (raw) information for SenderAuth. + {SenderAuthisFetching && } + {SenderAuthIsSuccess &&
{JSON.stringify(SenderAuth, null, 2)}
} + {SenderAuthError && ( +
Error fetching SenderAuth data: {SenderAuthError.message}
+ )} +
)} From bf43f6457ec7f1a38783f5f1ec28aaae697b6571 Mon Sep 17 00:00:00 2001 From: chase-vgo <168204519+chase-vgo@users.noreply.github.com> Date: Tue, 25 Jun 2024 09:18:22 -0500 Subject: [PATCH 02/58] Litigation Hold Standard --- src/data/standards.json | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/data/standards.json b/src/data/standards.json index 39f4dfef6108..430960d7de5d 100644 --- a/src/data/standards.json +++ b/src/data/standards.json @@ -698,6 +698,16 @@ "impact": "Low Impact", "impactColour": "info" }, + { + "name": "standards.EnableLitigationHold", + "cat": "Exchange Standards", + "tag": ["lowimpact"], + "helpText": "Enables litigation hold for all UserMailboxes with a valid license.", + "addedComponent": [], + "label": "Enable Litigation Hold for all users", + "impact": "Low Impact", + "impactColour": "info" + }, { "name": "standards.SpoofWarn", "cat": "Exchange Standards", From 17432bf9fbbf332bfd4e80a5ca602603c8c54320 Mon Sep 17 00:00:00 2001 From: BNWEIN Date: Wed, 26 Jun 2024 14:03:42 +0100 Subject: [PATCH 03/58] Update EditGroup.jsx --- src/views/identity/administration/EditGroup.jsx | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/views/identity/administration/EditGroup.jsx b/src/views/identity/administration/EditGroup.jsx index eb4e7a8bf899..7f3bd6af78a8 100644 --- a/src/views/identity/administration/EditGroup.jsx +++ b/src/views/identity/administration/EditGroup.jsx @@ -76,7 +76,6 @@ const EditGroup = () => { const [genericPostRequest, postResults] = useLazyGenericPostRequestQuery() const [roleInfo, setroleInfo] = React.useState([]) - const [allowExternal, setAllowExternal] = useState(false) useEffect(() => { if (ownersIsSuccess && membersIsSuccess) { const ownerWithRole = owners.map((owner) => { @@ -107,12 +106,6 @@ const EditGroup = () => { } }, [groupId, tenantDomain, dispatch]) - useEffect(() => { - if (SenderAuthIsSuccess) { - setAllowExternal(!SenderAuth) // If SenderAuth is true, setAllowExternal to false, and vice versa - } - }, [SenderAuthIsSuccess, SenderAuth]) - const onSubmit = (values) => { const shippedValues = { tenantID: tenantDomain, @@ -170,7 +163,12 @@ const EditGroup = () => { {isSuccess && ( { return ( From 5298a92cc1385396ed9d5891bea5f83207fdcb5c Mon Sep 17 00:00:00 2001 From: BNWEIN Date: Thu, 27 Jun 2024 12:14:55 +0100 Subject: [PATCH 04/58] Update Users.jsx Removed the need for the ExecDisableEmailForward function --- src/views/identity/administration/Users.jsx | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/views/identity/administration/Users.jsx b/src/views/identity/administration/Users.jsx index 0b0ea525497e..c387cd4697c5 100644 --- a/src/views/identity/administration/Users.jsx +++ b/src/views/identity/administration/Users.jsx @@ -247,11 +247,13 @@ const Offcanvas = (row, rowIndex, formatExtraData) => { modal: true, modalType: 'POST', modalBody: { - user: row.userPrincipalName, + username: row.userPrincipalName, + userid: row.userPrincipalName, TenantFilter: tenant.defaultDomainName, + DisableForwarding: true, message: row.message, }, - modalUrl: `/api/ExecDisableEmailForward`, + modalUrl: `/api/ExecEmailForward`, modalMessage: 'Are you sure you want to disable forwarding of this users emails?', }, { @@ -688,10 +690,12 @@ const Users = (row) => { modal: true, modalType: 'POST', modalBody: { - user: '!userPrincipalName', + username: '!userPrincipalName', + userid: '!userPrincipalName', TenantFilter: tenant.defaultDomainName, + DisableForwarding: true, }, - modalUrl: `/api/ExecDisableEmailForward`, + modalUrl: `/api/ExecEmailForward`, modalMessage: 'Are you sure you want to disable forwarding of these users emails?', }, { From 764f027d43f60335d870003e6898242394d0bf41 Mon Sep 17 00:00:00 2001 From: BNWEIN Date: Thu, 27 Jun 2024 23:11:05 +0100 Subject: [PATCH 05/58] Added Soft Deleted Mailbox Page Added Soft Deleted Mailbox page, with the ability to restore from Offcanvas --- src/_nav.jsx | 5 + src/importsMap.jsx | 3 +- src/routes.json | 6 + .../administration/DeletedMailboxes.jsx | 152 ++++++++++++++++++ 4 files changed, 165 insertions(+), 1 deletion(-) create mode 100644 src/views/email-exchange/administration/DeletedMailboxes.jsx diff --git a/src/_nav.jsx b/src/_nav.jsx index 874b6e28eb42..6be438de14d4 100644 --- a/src/_nav.jsx +++ b/src/_nav.jsx @@ -608,6 +608,11 @@ const _nav = [ name: 'Mailboxes', to: '/email/administration/mailboxes', }, + { + component: CNavItem, + name: 'Deleted Mailboxes', + to: '/email/administration/deleted-mailboxes', + }, { component: CNavItem, name: 'Mailbox Rules', diff --git a/src/importsMap.jsx b/src/importsMap.jsx index 6cd0031a1c6c..7906ca7921a7 100644 --- a/src/importsMap.jsx +++ b/src/importsMap.jsx @@ -116,7 +116,8 @@ import React from 'react' "/email/administration/edit-calendar-permissions": React.lazy(() => import('./views/email-exchange/administration/EditCalendarPermissions')), "/email/administration/view-mobile-devices": React.lazy(() => import('./views/email-exchange/administration/ViewMobileDevices')), "/email/administration/edit-contact": React.lazy(() => import('./views/email-exchange/administration/EditContact')), - "/email/administration/mailboxes": React.lazy(() => import('./views/email-exchange/administration/MailboxesList')), + "/email/administration/mailboxes": React.lazy(() => import('./views/email-exchange/administration/MailboxesList')), + "/email/administration/deleted-mailboxes": React.lazy(() => import('./views/email-exchange/administration/DeletedMailboxes')), "/email/administration/mailbox-rules": React.lazy(() => import('./views/email-exchange/administration/MailboxRuleList')), "/email/administration/Quarantine": React.lazy(() => import('./views/email-exchange/administration/QuarantineList')), "/email/administration/tenant-allow-block-lists": React.lazy(() => import('./views/email-exchange/administration/ListTenantAllowBlockList')), diff --git a/src/routes.json b/src/routes.json index 2975b4c168ac..635d5f85c060 100644 --- a/src/routes.json +++ b/src/routes.json @@ -786,6 +786,12 @@ "component": "views/email-exchange/administration/MailboxesList", "allowedRoles": ["admin", "editor", "readonly"] }, + { + "name": "Deleted Mailboxes", + "path": "/email/administration/deleted-mailboxes", + "component": "views/email-exchange/administration/DeletedMailboxes", + "allowedRoles": ["admin", "editor", "readonly"] + }, { "name": "List Mailbox Rules", "path": "/email/administration/mailbox-rules", diff --git a/src/views/email-exchange/administration/DeletedMailboxes.jsx b/src/views/email-exchange/administration/DeletedMailboxes.jsx new file mode 100644 index 000000000000..51a1665121cc --- /dev/null +++ b/src/views/email-exchange/administration/DeletedMailboxes.jsx @@ -0,0 +1,152 @@ +import React, { useState } from 'react' +import { CButton } from '@coreui/react' +import { useSelector } from 'react-redux' +import { faEllipsisV } from '@fortawesome/free-solid-svg-icons' +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' +import { cellBooleanFormatter } from 'src/components/tables' +import { CippPageList } from 'src/components/layout' +import { TitleButton } from 'src/components/buttons' +import { CippActionsOffcanvas } from 'src/components/utilities' + +const Offcanvas = (row, rowIndex, formatExtraData) => { + const tenant = useSelector((state) => state.app.currentTenant) + const [ocVisible, setOCVisible] = useState(false) + + const now = new Date() // Get the current date and time + const requestName = `${row.UPN}-${String(now.getDate()).padStart(2, '0')}-${String( + now.getMonth() + 1, + ).padStart(2, '0')}-${now.getFullYear()}-${String(now.getHours()).padStart(2, '0')}${String( + now.getMinutes(), + ).padStart(2, '0')}` + + return ( + <> + setOCVisible(true)}> + + + setOCVisible(false)} + /> + + ) +} + +const columns = [ + { + name: 'Display Name', + selector: (row) => row['displayName'], + sortable: true, + exportSelector: 'displayName', + }, + { + name: 'User Principal Name', + selector: (row) => row['UPN'], + sortable: true, + exportSelector: 'UPN', + minWidth: '350px', + }, + { + name: 'Primary SMTP Address', + selector: (row) => row['primarySmtpAddress'], + sortable: true, + exportSelector: 'primarySmtpAddress', + minWidth: '350px', + }, + { + name: 'Recipient Type', + selector: (row) => row['recipientType'], + omit: true, + exportSelector: 'recipientType', + }, + { + name: 'Recipient Type Details', + selector: (row) => row['recipientTypeDetails'], + omit: true, + exportSelector: 'recipientTypeDetails', + }, + { + name: 'Additional Email Addresses', + selector: (row) => row['AdditionalEmailAddresses'], + omit: true, + exportSelector: 'AdditionalEmailAddresses', + }, + { + name: 'Exchange Guid', + selector: (row) => row['ExchangeGuid'], + sortable: true, + exportSelector: 'ExchangeGuid', + minWidth: '350px', + }, + { + name: 'Archive Guid', + selector: (row) => row['ArchiveGuid'], + sortable: true, + exportSelector: 'ArchiveGuid', + }, + { + name: 'id', + selector: (row) => row['Id'], + omit: true, + exportSelector: 'Id', + }, + { + name: 'Actions', + cell: Offcanvas, + }, +] + +const DeletedMailboxes = () => { + const tenant = useSelector((state) => state.app.currentTenant) + const titleButton = ( + + ) + return ( + + ) +} + +export default DeletedMailboxes From ef0dfb7b26a2b815fcfd402669ea26ca94f826b8 Mon Sep 17 00:00:00 2001 From: BNWEIN Date: Fri, 28 Jun 2024 08:45:02 +0100 Subject: [PATCH 06/58] Update DeletedMailboxes.jsx Added Date Deleted --- .../email-exchange/administration/DeletedMailboxes.jsx | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/views/email-exchange/administration/DeletedMailboxes.jsx b/src/views/email-exchange/administration/DeletedMailboxes.jsx index 51a1665121cc..0c115973a2b0 100644 --- a/src/views/email-exchange/administration/DeletedMailboxes.jsx +++ b/src/views/email-exchange/administration/DeletedMailboxes.jsx @@ -36,6 +36,7 @@ const Offcanvas = (row, rowIndex, formatExtraData) => { { label: 'Exchange Guid', value: `${row.ExchangeGuid}` }, { label: 'Archive Guid', value: `${row.ArchiveGuid}` }, { label: 'Id', value: `${row.Id}` }, + { label: 'Date Deleted', value: `${row.WhenSoftDeleted}` }, ]} actions={[ { @@ -87,6 +88,12 @@ const columns = [ exportSelector: 'primarySmtpAddress', minWidth: '350px', }, + { + name: 'Date Deleted', + selector: (row) => row['WhenSoftDeleted'], + sortable: true, + exportSelector: 'WhenSoftDeleted', + }, { name: 'Recipient Type', selector: (row) => row['recipientType'], From ceef18d0208610d9bd5cd2444d847edc03789d35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Fri, 28 Jun 2024 11:05:57 +0200 Subject: [PATCH 07/58] New UserReportDestinationEmail standard --- src/data/standards.json | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/data/standards.json b/src/data/standards.json index 39f4dfef6108..558428ef9731 100644 --- a/src/data/standards.json +++ b/src/data/standards.json @@ -1057,6 +1057,22 @@ "impact": "Medium Impact", "impactColour": "warning" }, + { + "name": "standards.UserReportDestinationEmail", + "cat": "Exchange Standards", + "tag": ["mediumimpact"], + "helpText": "Sets the destination for email when users report them as spam or phishing. Works well together with the 'Set the state of the built-in Report button in Outlook standard'.", + "addedComponent": [ + { + "type": "input", + "name": "standards.UserReportDestinationEmail.Email", + "label": "Destination email address" + } + ], + "label": "Set the destination email for user reported phishing emails", + "impact": "Medium Impact", + "impactColour": "warning" + }, { "name": "standards.DisableSharedMailbox", "cat": "Exchange Standards", From 4c7510b3f268a09392a894124ef9bd9c5f9d90ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Fri, 28 Jun 2024 11:26:01 +0200 Subject: [PATCH 08/58] Remove word --- 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 558428ef9731..558688351053 100644 --- a/src/data/standards.json +++ b/src/data/standards.json @@ -1069,7 +1069,7 @@ "label": "Destination email address" } ], - "label": "Set the destination email for user reported phishing emails", + "label": "Set the destination email for user reported emails", "impact": "Medium Impact", "impactColour": "warning" }, From 5196254098725f839b13b4e1838b71b3b8108d90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Fri, 28 Jun 2024 11:29:50 +0200 Subject: [PATCH 09/58] Update readme --- README.md | 21 ++++----------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 677617c1ae29..c5e20b4af33f 100644 --- a/README.md +++ b/README.md @@ -1,22 +1,9 @@ ![CyberDrain Light](github_assets/img/CIPP.png#gh-dark-mode-only) ![CyberDrain Dark](github_assets/img/CIPP-Light.png#gh-light-mode-only) -

Sponsored by

-

- -![OIT](github_assets/img/oitpsonsor_light.png)     -![Immybot](github_assets/img/Immybot.png)     -![NinjaOne](github_assets/img/NinjaOne-Light.png#gh-dark-mode-only) -![NinjaOne](github_assets/img/NinjaOne-Dark.png#gh-light-mode-only)     -![Huntress](github_assets/img/Huntress.png) -![HaloPSA](github_assets/img/halopsa-red-grey.svg) - -

- # What is this? -The CyberDrain Improved Partner Portal is a portal to help manage administration for Microsoft Partners. The current Microsoft partner landscape makes it fairly hard to manage multi tenant situations, with loads of manual work. Microsoft Lighthouse might resolve this in the future but development of this is lagging far behind development of the current market for Microsoft Partners. - -This project is a way to help you with administration, with user management, and deploying your own preferred standards. It's not a replacement for security tools, or a way to cut costs on specific subscriptions. The tool should assist you in removing the gripes with standard partner management and save you several hours per engineer per month. - -for more information, we recommend checking out our website [here](https://cipp.app) +The CyberDrain Improved Partner Portal is a portal to help manage administration for Microsoft Partners. The current Microsoft partner landscape makes it fairly hard to manage multi tenant situations, with loads of manual work. Microsoft Lighthouse might resolve this in the future but development of this is lagging far behind development of the current market for Microsoft Partners. +This project is a way to help you with administration, with user management, and deploying your own preferred standards. It's not a replacement for security tools, or a way to cut costs on specific subscriptions. The tool should assist you in removing the gripes with standard partner management and save you several hours per engineer per month. +For more information, we recommend checking out our website [here](https://cipp.app) +For detailed documentation about features of CIPP, please check out our [documentation.](https://docs.cipp.app) From b0bc56ffb4364b0f438c40ac17cb24964ee2c899 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Fri, 28 Jun 2024 11:39:49 +0200 Subject: [PATCH 10/58] Add back a link to sponsors in the docs site --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c5e20b4af33f..29ef370db018 100644 --- a/README.md +++ b/README.md @@ -5,5 +5,9 @@ The CyberDrain Improved Partner Portal is a portal to help manage administration for Microsoft Partners. The current Microsoft partner landscape makes it fairly hard to manage multi tenant situations, with loads of manual work. Microsoft Lighthouse might resolve this in the future but development of this is lagging far behind development of the current market for Microsoft Partners. This project is a way to help you with administration, with user management, and deploying your own preferred standards. It's not a replacement for security tools, or a way to cut costs on specific subscriptions. The tool should assist you in removing the gripes with standard partner management and save you several hours per engineer per month. -For more information, we recommend checking out our website [here](https://cipp.app) +For more information, we recommend checking out our website [here](https://cipp.app) For detailed documentation about features of CIPP, please check out our [documentation.](https://docs.cipp.app) + +# Our sponsors + +You can find our sponsors [here.](https://docs.cipp.app/#our-sponsors) From d1f84b32bda562526b7ba737d99c210a9360fd11 Mon Sep 17 00:00:00 2001 From: cipptesting Date: Mon, 24 Jun 2024 19:47:14 -0400 Subject: [PATCH 11/58] Updated Anti-Phishing Policy Standards for more granular configuration --- src/data/standards.json | 72 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/src/data/standards.json b/src/data/standards.json index a02600469766..4ffd6739c698 100644 --- a/src/data/standards.json +++ b/src/data/standards.json @@ -1164,6 +1164,40 @@ "name": "standards.AntiPhishPolicy.EnableUnusualCharactersSafetyTips", "default": true }, + { + "type": "Select", + "label": "If the message is detected as spoof by spoof intelligence", + "name": "standards.AntiPhishPolicy.AuthenticationFailAction", + "values": [ + { + "label": "Move to Junk Folder", + "value": "MoveToJmf" + }, + { + "label": "Quarantine the message", + "value": "Quarantine" + } + ] + }, + { + "type": "Select", + "label": "Quarantine policy for Spoof", + "name": "standards.AntiPhishPolicy.SpoofQuarantineTag", + "values": [ + { + "label": "DefaultFullAccessPolicy", + "value": "DefaultFullAccessPolicy" + }, + { + "label": "DefaultFullAccessWithNotificationPolicy", + "value": "DefaultFullAccessWithNotificationPolicy" + }, + { + "label": "AdminOnlyAccessPolicy", + "value": "AdminOnlyAccessPolicy" + } + ] + }, { "type": "Select", "label": "If a message is detected as user impersonation", @@ -1183,6 +1217,25 @@ } ] }, + { + "type": "Select", + "label": "Quarantine policy for user impersonation", + "name": "standards.AntiPhishPolicy.TargetedUserQuarantineTag", + "values": [ + { + "label": "DefaultFullAccessPolicy", + "value": "DefaultFullAccessPolicy" + }, + { + "label": "DefaultFullAccessWithNotificationPolicy", + "value": "DefaultFullAccessWithNotificationPolicy" + }, + { + "label": "AdminOnlyAccessPolicy", + "value": "AdminOnlyAccessPolicy" + } + ] + }, { "type": "Select", "label": "If a message is detected as domain impersonation", @@ -1202,6 +1255,25 @@ } ] }, + { + "type": "Select", + "label": "Quarantine policy for domain impersonation", + "name": "standards.AntiPhishPolicy.TargetedDomainQuarantineTag", + "values": [ + { + "label": "DefaultFullAccessPolicy", + "value": "DefaultFullAccessPolicy" + }, + { + "label": "DefaultFullAccessWithNotificationPolicy", + "value": "DefaultFullAccessWithNotificationPolicy" + }, + { + "label": "AdminOnlyAccessPolicy", + "value": "AdminOnlyAccessPolicy" + } + ] + }, { "type": "Select", "label": "If Mailbox Intelligence detects an impersonated user", From 9cfe4c2a47e8735667183f6df1e428f061772a1b Mon Sep 17 00:00:00 2001 From: cipptesting Date: Fri, 28 Jun 2024 11:13:43 -0400 Subject: [PATCH 12/58] Updated standards.json based on feedback --- src/data/standards.json | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/data/standards.json b/src/data/standards.json index 4ffd6739c698..2f10e81ffb3c 100644 --- a/src/data/standards.json +++ b/src/data/standards.json @@ -1169,13 +1169,13 @@ "label": "If the message is detected as spoof by spoof intelligence", "name": "standards.AntiPhishPolicy.AuthenticationFailAction", "values": [ - { - "label": "Move to Junk Folder", - "value": "MoveToJmf" - }, { "label": "Quarantine the message", "value": "Quarantine" + }, + { + "label": "Move to Junk Folder", + "value": "MoveToJmf" } ] }, @@ -1184,6 +1184,10 @@ "label": "Quarantine policy for Spoof", "name": "standards.AntiPhishPolicy.SpoofQuarantineTag", "values": [ + { + "label": "AdminOnlyAccessPolicy", + "value": "AdminOnlyAccessPolicy" + }, { "label": "DefaultFullAccessPolicy", "value": "DefaultFullAccessPolicy" @@ -1191,10 +1195,6 @@ { "label": "DefaultFullAccessWithNotificationPolicy", "value": "DefaultFullAccessWithNotificationPolicy" - }, - { - "label": "AdminOnlyAccessPolicy", - "value": "AdminOnlyAccessPolicy" } ] }, @@ -1222,6 +1222,10 @@ "label": "Quarantine policy for user impersonation", "name": "standards.AntiPhishPolicy.TargetedUserQuarantineTag", "values": [ + { + "label": "AdminOnlyAccessPolicy", + "value": "AdminOnlyAccessPolicy" + }, { "label": "DefaultFullAccessPolicy", "value": "DefaultFullAccessPolicy" @@ -1229,10 +1233,6 @@ { "label": "DefaultFullAccessWithNotificationPolicy", "value": "DefaultFullAccessWithNotificationPolicy" - }, - { - "label": "AdminOnlyAccessPolicy", - "value": "AdminOnlyAccessPolicy" } ] }, @@ -1260,10 +1260,6 @@ "label": "Quarantine policy for domain impersonation", "name": "standards.AntiPhishPolicy.TargetedDomainQuarantineTag", "values": [ - { - "label": "DefaultFullAccessPolicy", - "value": "DefaultFullAccessPolicy" - }, { "label": "DefaultFullAccessWithNotificationPolicy", "value": "DefaultFullAccessWithNotificationPolicy" @@ -1271,6 +1267,10 @@ { "label": "AdminOnlyAccessPolicy", "value": "AdminOnlyAccessPolicy" + }, + { + "label": "DefaultFullAccessPolicy", + "value": "DefaultFullAccessPolicy" } ] }, From 7ec9a65b6031f237bf194e28bd08054bf9bcf838 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Fri, 28 Jun 2024 18:32:34 +0200 Subject: [PATCH 13/58] backend hosted test --- .../cipp/app-settings/SettingsBackend.jsx | 231 ++++++++++-------- 1 file changed, 132 insertions(+), 99 deletions(-) diff --git a/src/views/cipp/app-settings/SettingsBackend.jsx b/src/views/cipp/app-settings/SettingsBackend.jsx index 3dc9a9548af5..57ea62a28000 100644 --- a/src/views/cipp/app-settings/SettingsBackend.jsx +++ b/src/views/cipp/app-settings/SettingsBackend.jsx @@ -70,127 +70,160 @@ export function SettingsBackend() { {title} ) + const hostedMetaContent = document.querySelector('meta[name="hosted"]')?.getAttribute('content') return ( <> - {listBackendResult.isUninitialized && listBackend({ path: 'api/ExecBackendURLs' })} - - {BackendCardList.map((card, index) => ( - - - {card.description} - - - ))} - + {hostedMetaContent === 'true' ? ( + <> - {' '} window.open( - 'https://shell.azure.com/powershell', + 'https://management.cipp.app', '_blank', 'toolbar=no,scrollbars=yes,resizable=yes,menubar=no,location=no,status=no', ) } rel="noreferrer" > - Cloud Shell + Management Portal - setVisible(true)} className="me-2"> - Command Reference - } > -

Launch an Azure Cloud Shell Window

+ The Management Portal allows you to manage your CIPP resources for the hosted + environment.
-
-
- setVisible(false)} - title="Command Reference" - > -
Function App Config
- -
Function App Deployment
- -
Watch Function Logs
- -
Static Web App Config
- -
List CIPP Users
- -
+ + ) : ( + <> + {listBackendResult.isUninitialized && listBackend({ path: 'api/ExecBackendURLs' })} + + {BackendCardList.map((card, index) => ( + + + {card.description} + + + ))} + + + {' '} + + window.open( + 'https://shell.azure.com/powershell', + '_blank', + 'toolbar=no,scrollbars=yes,resizable=yes,menubar=no,location=no,status=no', + ) + } + rel="noreferrer" + > + Cloud Shell + + setVisible(true)} className="me-2"> + Command Reference + + + } + > +

Launch an Azure Cloud Shell Window

+
+
+
+ setVisible(false)} + title="Command Reference" + > +
Function App Config
+ +
Function App Deployment
+ +
Watch Function Logs
+ +
Static Web App Config
+ +
List CIPP Users
+ +
+ + )} ) } From c51882e42112191b3739d74db1cd68e3e467554a Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Fri, 28 Jun 2024 18:53:23 +0200 Subject: [PATCH 14/58] extensions disable --- src/data/Extensions.json | 1 + src/views/cipp/Extensions.jsx | 20 ++++++++++++++++---- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/data/Extensions.json b/src/data/Extensions.json index 1ca3a87b94d7..bc556899e4a8 100644 --- a/src/data/Extensions.json +++ b/src/data/Extensions.json @@ -4,6 +4,7 @@ "type": "CIPP-API", "cat": "API", "forceSyncButton": false, + "disableWhenhosted": true, "helpText": "This integration allows you to enable CIPP-API access outside of CIPP. Requires Global Administrator permissions inside your tenant for activation of the API. The API credentials will only be shown once.", "SettingOptions": [ { diff --git a/src/views/cipp/Extensions.jsx b/src/views/cipp/Extensions.jsx index 7bfe1d7feb86..d12fa8675177 100644 --- a/src/views/cipp/Extensions.jsx +++ b/src/views/cipp/Extensions.jsx @@ -42,15 +42,15 @@ export default function CIPPExtensions() { }) } - const ButtonGenerate = (integrationType, forceSync) => ( + const ButtonGenerate = (integrationType, forceSync, disabled) => ( <> - + {extensionConfigResult.isFetching && ( )} Set Extension Settings - onSubmitTest(integrationType)} className="me-2"> + onSubmitTest(integrationType)} className="me-2"> {listExtensionTestResult.isFetching && ( )} @@ -83,6 +83,7 @@ export default function CIPPExtensions() { queryString.set('tab', tab.toString()) navigate(`${location.pathname}?${queryString}`) } + const hostedMetaContent = document.querySelector('meta[name="hosted"]')?.getAttribute('content') return ( @@ -105,11 +106,22 @@ export default function CIPPExtensions() { + {hostedMetaContent === 'true' && integration.disableWhenhosted && ( + + This extension requires activation in the management portal for hosted + clients. + + )} + {integration.description}

{integration.helpText}

From 74495525123d6dfd87080f4ac68a972c6170ca72 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Fri, 28 Jun 2024 18:57:36 +0200 Subject: [PATCH 15/58] extensions update --- src/views/cipp/Extensions.jsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/views/cipp/Extensions.jsx b/src/views/cipp/Extensions.jsx index d12fa8675177..8a165cbc0dfd 100644 --- a/src/views/cipp/Extensions.jsx +++ b/src/views/cipp/Extensions.jsx @@ -112,7 +112,6 @@ export default function CIPPExtensions() { clients. )} - {integration.description} Date: Mon, 1 Jul 2024 21:21:41 +0100 Subject: [PATCH 16/58] Added Authentication Methods Added ability to view current authentication methods, and their current state --- src/_nav.jsx | 5 ++ src/importsMap.jsx | 1 + src/routes.json | 6 ++ .../tenant/administration/AuthMethods.jsx | 77 +++++++++++++++++++ 4 files changed, 89 insertions(+) create mode 100644 src/views/tenant/administration/AuthMethods.jsx diff --git a/src/_nav.jsx b/src/_nav.jsx index 6be438de14d4..e6567546bf11 100644 --- a/src/_nav.jsx +++ b/src/_nav.jsx @@ -162,6 +162,11 @@ const _nav = [ name: 'App Consent Requests', to: '/tenant/administration/app-consent-requests', }, + { + component: CNavItem, + name: 'Authentication Methods', + to: '/tenant/administration/authentication-methods', + }, { component: CNavItem, name: 'Tenant Onboarding', diff --git a/src/importsMap.jsx b/src/importsMap.jsx index 7906ca7921a7..63ae50439b0d 100644 --- a/src/importsMap.jsx +++ b/src/importsMap.jsx @@ -53,6 +53,7 @@ import React from 'react' "/tenant/conditional/deploy-named-location": React.lazy(() => import('./views/tenant/conditional/DeployNamedLocation')), "/tenant/conditional/list-template": React.lazy(() => import('./views/tenant/conditional/ListCATemplates')), "/tenant/conditional/add-template": React.lazy(() => import('./views/tenant/conditional/AddCATemplate')), + "/tenant/administration/authentication-methods": React.lazy(() => import('./views/tenant/administration/AuthMethods')), "/tenant/administration/list-licenses": React.lazy(() => import('./views/tenant/administration/ListLicences')), "/tenant/administration/application-consent": React.lazy(() => import('./views/tenant/administration/ListOauthApps')), "/tenant/standards/list-applied-standards": React.lazy(() => import('./views/tenant/standards/ListAppliedStandards')), diff --git a/src/routes.json b/src/routes.json index 635d5f85c060..669c385e6d3d 100644 --- a/src/routes.json +++ b/src/routes.json @@ -300,6 +300,12 @@ "component": "views/tenant/conditional/ConditionalAccess", "allowedRoles": ["admin", "editor", "readonly"] }, + { + "path": "/tenant/administration/authentication-methods", + "name": "Authentication Methods", + "component": "views/tenant/administration/AuthMethods", + "allowedRoles": ["admin", "editor", "readonly"] + }, { "path": "/tenant/conditional/deploy-vacation", "name": "Deploy Vacation Mode", diff --git a/src/views/tenant/administration/AuthMethods.jsx b/src/views/tenant/administration/AuthMethods.jsx new file mode 100644 index 000000000000..8e50a21f7846 --- /dev/null +++ b/src/views/tenant/administration/AuthMethods.jsx @@ -0,0 +1,77 @@ +import React, { useState } from 'react' +import { CButton, CCardBody, CSpinner, CCard, CCardHeader, CCardTitle } from '@coreui/react' +import { useSelector } from 'react-redux' +import { faEllipsisV } from '@fortawesome/free-solid-svg-icons' +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' +import { CippPageList, CippPage } from 'src/components/layout' +import { TitleButton } from 'src/components/buttons' +import { CippActionsOffcanvas } from 'src/components/utilities' +import { useGenericGetRequestQuery } from 'src/store/api/app' +import { CippTable, cellBooleanFormatter } from 'src/components/tables' +import { CellTip, cellGenericFormatter } from 'src/components/tables/CellGenericFormat' + +const columns = [ + { + name: 'id', + selector: (row) => row['id'], + sortable: true, + exportSelector: 'id', + }, + { + name: 'state', + selector: (row) => row['state'], + cell: cellBooleanFormatter({ colourless: false }), + sortable: true, + exportSelector: 'state', + minWidth: '100px', + }, + { + name: 'includeTargets', + selector: (row) => row['includeTargets'], + sortable: true, + cell: cellGenericFormatter(), + exportSelector: 'includeTargets', + }, + { + name: 'excludeTargets', + selector: (row) => row['excludeTargets'], + sortable: true, + cell: cellGenericFormatter(), + exportSelector: 'excludeTargets', + }, +] + +const AuthenticationMethods = () => { + const tenant = useSelector((state) => state.app.currentTenant) + const { data, isFetching, error, isSuccess, refetch } = useGenericGetRequestQuery({ + path: 'api/ListGraphRequest', + params: { + Endpoint: 'authenticationMethodsPolicy', + TenantFilter: tenant?.defaultDomainName, + }, + }) + return ( + <> + + + + Auth Methods + + + {isFetching && } + {isSuccess && ( + refetch()} + /> + )} + + + + + ) +} + +export default AuthenticationMethods From fabdeff41555b93827ad063739d07a28723fae61 Mon Sep 17 00:00:00 2001 From: BNWEIN Date: Tue, 2 Jul 2024 17:28:47 +0100 Subject: [PATCH 17/58] Added Offcanvas actions to Auth Methods page, and added Scripted Alert for Soft Deleted Mailboxes Added Offcanvas actions to Auth Methods page Added Scripted Alert for Soft Deleted Mailboxes --- src/data/alerts.json | 7 +- .../tenant/administration/AuthMethods.jsx | 64 +++++++++++++++++++ 2 files changed, 70 insertions(+), 1 deletion(-) diff --git a/src/data/alerts.json b/src/data/alerts.json index d6c7215f2d04..2d635fb529f9 100644 --- a/src/data/alerts.json +++ b/src/data/alerts.json @@ -89,5 +89,10 @@ "name": "DepTokenExpiry", "label": "Alert on expiring DEP tokens", "recommendedRunInterval": "1d" + }, + { + "name": "SoftDeletedMailboxes", + "label": "Alert on soft deleted mailboxes", + "recommendedRunInterval": "1d" } -] +] \ No newline at end of file diff --git a/src/views/tenant/administration/AuthMethods.jsx b/src/views/tenant/administration/AuthMethods.jsx index 8e50a21f7846..adc16e49108c 100644 --- a/src/views/tenant/administration/AuthMethods.jsx +++ b/src/views/tenant/administration/AuthMethods.jsx @@ -10,6 +10,66 @@ import { useGenericGetRequestQuery } from 'src/store/api/app' import { CippTable, cellBooleanFormatter } from 'src/components/tables' import { CellTip, cellGenericFormatter } from 'src/components/tables/CellGenericFormat' +const Offcanvas = (row, rowIndex, formatExtraData) => { + const tenant = useSelector((state) => state.app.currentTenant) + const [ocVisible, setOCVisible] = useState(false) + const formatTargets = (targets) => { + if (Array.isArray(targets)) { + return targets.map((target) => JSON.stringify(target)).join(', ') + } + return targets + } + + return ( + <> + setOCVisible(true)}> + + + setOCVisible(false)} + /> + + ) +} + const columns = [ { name: 'id', @@ -39,6 +99,10 @@ const columns = [ cell: cellGenericFormatter(), exportSelector: 'excludeTargets', }, + { + name: 'Actions', + cell: Offcanvas, + }, ] const AuthenticationMethods = () => { From 6a6869245c96644a0937a5d124e74520a8a553c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Wed, 3 Jul 2024 00:07:09 +0200 Subject: [PATCH 18/58] Add all new needed properties and fix a lot of PS commands and general stuff --- src/data/standards.json | 412 ++++++++++++++++++++++++++++++---------- 1 file changed, 316 insertions(+), 96 deletions(-) diff --git a/src/data/standards.json b/src/data/standards.json index 2f10e81ffb3c..dd0f005d19a6 100644 --- a/src/data/standards.json +++ b/src/data/standards.json @@ -4,6 +4,7 @@ "cat": "Global Standards", "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, @@ -33,7 +34,9 @@ ], "label": "Set contact e-mails", "impact": "Low Impact", - "impactColour": "info" + "impactColour": "info", + "powershellEquivalent": "Set-MsolCompanyContactInformation", + "recommendedBy": [] }, { "name": "standards.AuditLog", @@ -43,7 +46,9 @@ "addedComponent": [], "label": "Enable the Unified Audit Log", "impact": "Low Impact", - "impactColour": "info" + "impactColour": "info", + "powershellEquivalent": "Enable-OrganizationCustomization", + "recommendedBy": ["CIS"] }, { "name": "standards.PhishProtection", @@ -58,7 +63,9 @@ "report": true, "warn": true, "remediate": false - } + }, + "powershellEquivalent": "Portal only", + "recommendedBy": ["CIPP"] }, { "name": "standards.Branding", @@ -109,17 +116,22 @@ ], "label": "Set branding for the tenant", "impact": "Low Impact", - "impactColour": "info" + "impactColour": "info", + "powershellEquivalent": "Portal only", + "recommendedBy": [] }, { "name": "standards.EnableCustomerLockbox", "cat": "Global Standards", "tag": ["lowimpact", "CIS", "CustomerLockBoxEnabled"], "helpText": "Enables Customer Lockbox that offers an approval process for Microsoft support to access organization data", + "docsDescription": "Customer Lockbox ensures that Microsoft can't access your content to do service operations without your explicit approval. Customer Lockbox ensures only authorized requests allow access to your organizations data.", "addedComponent": [], "label": "Enable Customer Lockbox", "impact": "Low Impact", - "impactColour": "info" + "impactColour": "info", + "powershellEquivalent": "Set-OrganizationConfig -CustomerLockBoxEnabled $true", + "recommendedBy": ["CIS"] }, { "name": "standards.EnablePronouns", @@ -129,37 +141,48 @@ "addedComponent": [], "label": "Enable Pronouns", "impact": "Low Impact", - "impactColour": "info" + "impactColour": "info", + "powershellEquivalent": "Update-MgBetaAdminPeoplePronoun -IsEnabledInOrganization:$true", + "recommendedBy": [] }, { "name": "standards.AnonReportDisable", "cat": "Global Standards", "tag": ["lowimpact"], "helpText": "Shows usernames instead of pseudo anonymised names in reports. This standard is required for reporting to work correctly.", + "docsDescription": "Microsoft announced some APIs and reports no longer return names, to comply with compliance and legal requirements in specific countries. This proves an issue for a lot of MSPs because those reports are often helpful for engineers. This standard applies a setting that shows usernames in those API calls / reports.", "addedComponent": [], "label": "Enable Usernames instead of pseudo anonymised names in reports", "impact": "Low Impact", - "impactColour": "info" + "impactColour": "info", + "powershellEquivalent": "Update-MgBetaAdminReportSetting -BodyParameter @{displayConcealedNames = $true}", + "recommendedBy": [] }, { "name": "standards.DisableGuestDirectory", "cat": "Global Standards", "tag": ["lowimpact"], "helpText": "Disables Guest access to enumerate directory objects. This prevents guest users from seeing other users or guests in the directory.", + "docsDescription": "Sets it so guests can view only their own user profile. Permission to view other users isn't allowed. Also restricts guest users from seeing the membership of groups they're in. See exactly what get locked down in the [Microsoft documentation.](https://learn.microsoft.com/en-us/entra/fundamentals/users-default-permissions)", "addedComponent": [], "label": "Restrict guest user access to directory objects", "impact": "Low Impact", - "impactColour": "info" + "impactColour": "info", + "powershellEquivalent": "Set-AzureADMSAuthorizationPolicy -GuestUserRoleId '2af84b1e-32c8-42b7-82bc-daa82404023b'", + "recommendedBy": [] }, { "name": "standards.DisableBasicAuthSMTP", "cat": "Global Standards", "tag": ["mediumimpact"], "helpText": "Disables SMTP AUTH for the organization and all users. This is the default for new tenants. ", + "docsDescription": "Disables SMTP basic authentication for the tenant and all users with it explicitly enabled.", "addedComponent": [], "label": "Disable SMTP Basic Authentication", "impact": "Medium Impact", - "impactColour": "warning" + "impactColour": "warning", + "powershellEquivalent": "Set-TransportConfig -SmtpClientAuthenticationDisabled $true", + "recommendedBy": [] }, { "name": "standards.ActivityBasedTimeout", @@ -197,43 +220,55 @@ ], "label": "Enable Activity based Timeout", "impact": "Medium Impact", - "impactColour": "warning" + "impactColour": "warning", + "powershellEquivalent": "Portal or Graph API", + "recommendedBy": ["CIS"] }, { "name": "standards.laps", "cat": "Entra (AAD) Standards", "tag": ["lowimpact"], "helpText": "Enables the tenant to use LAPS. You must still create a policy for LAPS to be active on all devices. Use the template standards to deploy this by default.", + "docsDescription": "Enables the LAPS functionality on the tenant. Prerequisite for using Windows LAPS via Azure AD.", "addedComponent": [], "label": "Enable LAPS on the tenant", "impact": "Low Impact", - "impactColour": "info" + "impactColour": "info", + "powershellEquivalent": "Portal or Graph API", + "recommendedBy": [] }, { "name": "standards.PWdisplayAppInformationRequiredState", "cat": "Entra (AAD) Standards", "tag": ["lowimpact", "CIS"], "helpText": "Enables the MS authenticator app to display information about the app that is requesting authentication. This displays the application name.", + "docsDescription": "Allows users to use Passwordless with Number Matching and adds location information from the last request", "addedComponent": [], "label": "Enable Passwordless with Location information and Number Matching", "impact": "Low Impact", - "impactColour": "info" + "impactColour": "info", + "powershellEquivalent": "Update-MgBetaPolicyAuthenticationMethodPolicyAuthenticationMethodConfiguration", + "recommendedBy": ["CIS"] }, { "name": "standards.allowOTPTokens", "cat": "Entra (AAD) Standards", "tag": ["lowimpact"], "helpText": "Allows you to use MS authenticator OTP token generator", + "docsDescription": "Allows you to use Microsoft Authenticator OTP token generator. Useful for using the NPS extension as MFA on VPN clients.", "addedComponent": [], "label": "Enable OTP via Authenticator", "impact": "Low Impact", - "impactColour": "info" + "impactColour": "info", + "powershellEquivalent": "Update-MgBetaPolicyAuthenticationMethodPolicyAuthenticationMethodConfiguration", + "recommendedBy": [] }, { "name": "standards.PWcompanionAppAllowedState", "cat": "Entra (AAD) Standards", "tag": ["lowimpact"], "helpText": "Sets the state of Authenticator Lite, Authenticator lite is a companion app for passwordless authentication.", + "docsDescription": "Sets the Authenticator Lite state to enabled. This allows users to use the Authenticator Lite built into the Outlook app instead of the full Authenticator app.", "addedComponent": [ { "type": "Select", @@ -253,43 +288,55 @@ ], "label": "Set Authenticator Lite state", "impact": "Low Impact", - "impactColour": "info" + "impactColour": "info", + "powershellEquivalent": "Update-MgBetaPolicyAuthenticationMethodPolicyAuthenticationMethodConfiguration", + "recommendedBy": [] }, { "name": "standards.EnableFIDO2", "cat": "Entra (AAD) Standards", "tag": ["lowimpact"], "helpText": "Enables the FIDO2 authenticationMethod for the tenant", + "docsDescription": "Enables FIDO2 capabilities for the tenant. This allows users to use FIDO2 keys like a Yubikey for authentication.", "addedComponent": [], "label": "Enable FIDO2 capabilities", "impact": "Low Impact", - "impactColour": "info" + "impactColour": "info", + "powershellEquivalent": "Update-MgBetaPolicyAuthenticationMethodPolicyAuthenticationMethodConfiguration", + "recommendedBy": [] }, { "name": "standards.EnableHardwareOAuth", "cat": "Entra (AAD) Standards", "tag": ["lowimpact"], "helpText": "Enables the HardwareOath authenticationMethod for the tenant. This allows you to use hardware tokens for generating 6 digit MFA codes.", + "docsDescription": "Enables Hardware OAuth tokens for the tenant. This allows users to use hardware tokens like a Yubikey for authentication.", "addedComponent": [], "label": "Enable Hardware OAuth tokens", "impact": "Low Impact", - "impactColour": "info" + "impactColour": "info", + "powershellEquivalent": "Update-MgBetaPolicyAuthenticationMethodPolicyAuthenticationMethodConfiguration", + "recommendedBy": [] }, { "name": "standards.allowOAuthTokens", "cat": "Entra (AAD) Standards", "tag": ["lowimpact"], "helpText": "Allows you to use any software OAuth token generator", + "docsDescription": "Enables OTP Software OAuth tokens for the tenant. This allows users to use OTP codes generated via software, like a password manager to be used as an authentication method.", "addedComponent": [], "label": "Enable OTP Software OAuth tokens", "impact": "Low Impact", - "impactColour": "info" + "impactColour": "info", + "powershellEquivalent": "Update-MgBetaPolicyAuthenticationMethodPolicyAuthenticationMethodConfiguration", + "recommendedBy": [] }, { "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.", + "docsDescription": "Enables Temporary Password generation for the tenant.", "addedComponent": [ { "type": "Select", @@ -309,17 +356,22 @@ ], "label": "Enable Temporary Access Passwords", "impact": "Low Impact", - "impactColour": "info" + "impactColour": "info", + "powershellEquivalent": "Update-MgBetaPolicyAuthenticationMethodPolicyAuthenticationMethodConfiguration", + "recommendedBy": [] }, { "name": "standards.PasswordExpireDisabled", "cat": "Entra (AAD) Standards", "tag": ["lowimpact", "CIS", "PWAgePolicyNew"], "helpText": "Disables the expiration of passwords for the tenant by setting the password expiration policy to never expire for any user.", + "docsDescription": "Sets passwords to never expire for tenant, recommended to use in conjunction with secure password requirements.", "addedComponent": [], "label": "Do not expire passwords", "impact": "Low Impact", - "impactColour": "info" + "impactColour": "info", + "powershellEquivalent": "Update-MgDomain", + "recommendedBy": ["CIS"] }, { "name": "standards.ExternalMFATrusted", @@ -345,23 +397,29 @@ ], "label": "Sets the Cross-tenant access setting to trust external MFA", "impact": "Low Impact", - "impactColour": "info" + "impactColour": "info", + "powershellEquivalent": "Update-MgBetaPolicyCrossTenantAccessPolicyDefault", + "recommendedBy": [] }, { "name": "standards.DisableTenantCreation", "cat": "Entra (AAD) Standards", "tag": ["lowimpact", "CIS"], "helpText": "Restricts creation of M365 tenants to the Global Administrator or Tenant Creator roles. ", + "docsDescription": "Users by default are allowed to create M365 tenants. This disables that so only admins can create new M365 tenants.", "addedComponent": [], "label": "Disable M365 Tenant creation by users", "impact": "Low Impact", - "impactColour": "info" + "impactColour": "info", + "powershellEquivalent": "Update-MgPolicyAuthorizationPolicy", + "recommendedBy": ["CIS"] }, { "name": "standards.EnableAppConsentRequests", "cat": "Entra (AAD) Standards", "tag": ["lowimpact", "CIS"], "helpText": "Enables App consent admin requests for the tenant via the GA role. Does not overwrite existing reviewer settings", + "docsDescription": "Enables the ability for users to request admin consent for applications. Should be used in conjunction with the \"Require admin consent for applications\" standards", "addedComponent": [ { "type": "AdminRolesMultiSelect", @@ -371,13 +429,16 @@ ], "label": "Enable App consent admin requests", "impact": "Low Impact", - "impactColour": "info" + "impactColour": "info", + "powershellEquivalent": "Update-MgPolicyAdminConsentRequestPolicy", + "recommendedBy": ["CIS"] }, { "name": "standards.NudgeMFA", "cat": "Entra (AAD) Standards", "tag": ["lowimpact"], "helpText": "Sets the state of the registration campaign for the tenant", + "docsDescription": "Sets the state of the registration campaign for the tenant. If enabled nudges users to set up the Microsoft Authenticator during sign-in.", "addedComponent": [ { "type": "Select", @@ -403,27 +464,35 @@ ], "label": "Sets the state for the request to setup Authenticator", "impact": "Low Impact", - "impactColour": "info" + "impactColour": "info", + "powershellEquivalent": "Update-MgPolicyAuthenticationMethodPolicy", + "recommendedBy": [] }, { "name": "standards.DisableM365GroupUsers", "cat": "Entra (AAD) Standards", "tag": ["lowimpact"], "helpText": "Restricts M365 group creation to certain admin roles. This disables the ability to create Teams, Sharepoint sites, Planner, etc", + "docsDescription": "Users by default are allowed to create M365 groups. This restricts M365 group creation to certain admin roles. This disables the ability to create Teams, SharePoint sites, Planner, etc", "addedComponent": [], "label": "Disable M365 Group creation by users", "impact": "Low Impact", - "impactColour": "info" + "impactColour": "info", + "powershellEquivalent": "Update-MgBetaDirectorySetting", + "recommendedBy": [] }, { "name": "standards.DisableAppCreation", "cat": "Entra (AAD) Standards", "tag": ["lowimpact", "CIS"], "helpText": "Disables the ability for users to create App registrations in the tenant.", + "docsDescription": "Disables the ability for users to create applications in Entra. Done to prevent breached accounts from creating an app to maintain access to the tenant, even after the breached account has been secured.", "addedComponent": [], "label": "Disable App creation by users", "impact": "Low Impact", - "impactColour": "info" + "impactColour": "info", + "powershellEquivalent": "Update-MgPolicyAuthorizationPolicy", + "recommendedBy": ["CIS"] }, { "name": "standards.DisableSecurityGroupUsers", @@ -433,7 +502,9 @@ "addedComponent": [], "label": "Disable Security Group creation by users", "impact": "Medium Impact", - "impactColour": "warning" + "impactColour": "warning", + "powershellEquivalent": "Update-MgBetaPolicyAuthorizationPolicy", + "recommendedBy": [] }, { "name": "standards.LegacyMFACleanup", @@ -443,7 +514,9 @@ "addedComponent": [], "label": "Remove Legacy MFA if SD or CA is active", "impact": "Medium Impact", - "impactColour": "warning" + "impactColour": "warning", + "powershellEquivalent": "Set-MsolUser -StrongAuthenticationRequirements $null", + "recommendedBy": [] }, { "name": "standards.DisableSelfServiceLicenses", @@ -453,7 +526,9 @@ "addedComponent": [], "label": "Disable Self Service Licensing", "impact": "Medium Impact", - "impactColour": "warning" + "impactColour": "warning", + "powershellEquivalent": "Set-MsolCompanySettings -AllowAdHocSubscriptions $false", + "recommendedBy": [] }, { "name": "standards.DisableGuests", @@ -463,13 +538,16 @@ "addedComponent": [], "label": "Disable Guest accounts that have not logged on for 90 days", "impact": "Medium Impact", - "impactColour": "warning" + "impactColour": "warning", + "powershellEquivalent": "Graph API", + "recommendedBy": [] }, { "name": "standards.OauthConsent", "cat": "Entra (AAD) Standards", "tag": ["mediumimpact", "CIS"], "helpText": "Disables users from being able to consent to applications, except for those specified in the field below", + "docsDescription": "Requires users to get administrator consent before sharing data with applications. You can preapprove specific applications.", "addedComponent": [ { "type": "input", @@ -479,16 +557,21 @@ ], "label": "Require admin consent for applications (Prevent OAuth phishing)", "impact": "Medium Impact", - "impactColour": "warning" + "impactColour": "warning", + "powershellEquivalent": "Update-MgPolicyAuthorizationPolicy", + "recommendedBy": ["CIS"] }, { "name": "standards.OauthConsentLowSec", "cat": "Entra (AAD) Standards", "tag": ["mediumimpact"], "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)", "impact": "Medium Impact", - "impactColour": "warning" + "impactColour": "warning", + "powershellEquivalent": "Update-MgPolicyAuthorizationPolicy", + "recommendedBy": [] }, { "name": "standards.UndoOauth", @@ -498,33 +581,42 @@ "addedComponent": [], "label": "Undo App Consent Standard", "impact": "High Impact", - "impactColour": "danger" + "impactColour": "danger", + "powershellEquivalent": "Update-MgPolicyAuthorizationPolicy", + "recommendedBy": [] }, { "name": "standards.SecurityDefaults", "cat": "Entra (AAD) Standards", "tag": ["highimpact"], "helpText": "Enables security defaults for the tenant, for newer tenants this is enabled by default. Do not enable this feature if you use Conditional Access.", + "docsDescription": "Enables SD for the tenant, which disables all forms of basic authentication and enforces users to configure MFA. Users are only prompted for MFA when a logon is considered 'suspect' by Microsoft.", "addedComponent": [], "label": "Enable Security Defaults", "impact": "High Impact", - "impactColour": "danger" + "impactColour": "danger", + "powershellEquivalent": "[Read more here](https://www.cyberdrain.com/automating-with-powershell-enabling-secure-defaults-and-sd-explained/)", + "recommendedBy": [] }, { "name": "standards.DisableSMS", "cat": "Entra (AAD) Standards", "tag": ["highimpact"], - "helpText": "This blocks users from using SMS as an MFA method. If a user only has SMS as a MFA method, they will be unable to login.", + "helpText": "This blocks users from using SMS as an MFA method. If a user only has SMS as a MFA method, they will be unable to log in.", + "docsDescription": "Disables SMS as an MFA method for the tenant. If a user only has SMS as a MFA method, they will be unable to sign in.", "addedComponent": [], "label": "Disables SMS as an MFA method", "impact": "High Impact", - "impactColour": "danger" + "impactColour": "danger", + "powershellEquivalent": "Update-MgBetaPolicyAuthenticationMethodPolicyAuthenticationMethodConfiguration", + "recommendedBy": [] }, { "name": "standards.DisableVoice", "cat": "Entra (AAD) Standards", "tag": ["highimpact"], - "helpText": "This blocks users from using Voice call as an MFA method. If a user only has Voice as a MFA method, they will be unable to login.", + "helpText": "This blocks users from using Voice call as an MFA method. If a user only has Voice as a MFA method, they will be unable to log in.", + "docsDescription": "Disables Voice call as an MFA method for the tenant. If a user only has Voice call as a MFA method, they will be unable to sign in.", "addedComponent": [], "label": "Disables Voice call as an MFA method", "impact": "High Impact", @@ -538,17 +630,22 @@ "addedComponent": [], "label": "Disables Email as an MFA method", "impact": "High Impact", - "impactColour": "danger" + "impactColour": "danger", + "powershellEquivalent": "Update-MgBetaPolicyAuthenticationMethodPolicyAuthenticationMethodConfiguration", + "recommendedBy": [] }, { "name": "standards.Disablex509Certificate", "cat": "Entra (AAD) Standards", "tag": ["highimpact"], "helpText": "This blocks users from using Certificates as an MFA method.", + "docsDescription": "", "addedComponent": [], "label": "Disables Certificates as an MFA method", "impact": "High Impact", - "impactColour": "danger" + "impactColour": "danger", + "powershellEquivalent": "Update-MgBetaPolicyAuthenticationMethodPolicyAuthenticationMethodConfiguration", + "recommendedBy": [] }, { "name": "standards.PerUserMFA", @@ -558,13 +655,16 @@ "addedComponent": [], "label": "Enables per user MFA for all users.", "impact": "High Impact", - "impactColour": "danger" + "impactColour": "danger", + "powershellEquivalent": "Graph API", + "recommendedBy": [] }, { "name": "standards.OutBoundSpamAlert", "cat": "Exchange Standards", "tag": ["lowimpact", "CIS"], "helpText": "Set the Outbound Spam Alert e-mail address", + "docsDescription": "Sets the e-mail address to which outbound spam alerts are sent.", "addedComponent": [ { "type": "input", @@ -574,23 +674,29 @@ ], "label": "Set Outbound Spam Alert e-mail", "impact": "Low Impact", - "impactColour": "info" + "impactColour": "info", + "powershellEquivalent": "Set-HostedOutboundSpamFilterPolicy", + "recommendedBy": ["CIS"] }, { "name": "standards.MessageExpiration", "cat": "Exchange Standards", "tag": ["lowimpact"], "helpText": "Sets the transport message configuration to timeout a message at 12 hours.", + "docsDescription": "Expires messages in the transport queue after 12 hours. Makes the NDR for failed messages show up faster for users. Default is 24 hours.", "addedComponent": [], "label": "Lower Transport Message Expiration to 12 hours", "impact": "Low Impact", - "impactColour": "info" + "impactColour": "info", + "powershellEquivalent": "Set-TransportConfig -MessageExpirationTimeout 12.00:00:00", + "recommendedBy": [] }, { "name": "standards.GlobalQuarantineNotifications", "cat": "Exchange Standards", "tag": ["lowimpact"], "helpText": "Sets the Global Quarantine Notification Interval to the selected value. Determines how often the quarantine notification is sent to users.", + "docsDescription": "Sets the global quarantine notification interval for the tenant. This is the time between the quarantine notification emails are sent out to users. Default is 24 hours.", "addedComponent": [ { "type": "Select", @@ -614,23 +720,29 @@ ], "label": "Set Global Quarantine Notification Interval", "impact": "Low Impact", - "impactColour": "info" + "impactColour": "info", + "powershellEquivalent": "Set-QuarantinePolicy -EndUserSpamNotificationFrequency", + "recommendedBy": [] }, { "name": "standards.DisableTNEF", "cat": "Exchange Standards", "tag": ["lowimpact"], "helpText": "Disables Transport Neutral Encapsulation Format (TNEF)/winmail.dat for the tenant. TNEF can cause issues if the recipient is not using a client supporting TNEF.", + "docsDescription": "Disables Transport Neutral Encapsulation Format (TNEF)/winmail.dat for the tenant. TNEF can cause issues if the recipient is not using a client supporting TNEF. Cannot be overridden by the user. For more information, see [Microsoft's documentation.](https://learn.microsoft.com/en-us/exchange/mail-flow/content-conversion/tnef-conversion?view=exchserver-2019)", "addedComponent": [], "label": "Disable TNEF/winmail.dat", "impact": "Low Impact", - "impactColour": "info" + "impactColour": "info", + "powershellEquivalent": "Set-RemoteDomain -Identity 'Default' -TNEFEnabled $false", + "recommendedBy": [] }, { "name": "standards.FocusedInbox", "cat": "Exchange Standards", "tag": ["lowimpact"], "helpText": "Sets the default Focused Inbox state for the tenant. This can be overridden by the user.", + "docsDescription": "Sets the default Focused Inbox state for the tenant. This can be overridden by the user in their Outlook settings. For more information, see [Microsoft's documentation.](https://support.microsoft.com/en-us/office/focused-inbox-for-outlook-f445ad7f-02f4-4294-a82e-71d8964e3978)", "addedComponent": [ { "type": "Select", @@ -650,13 +762,16 @@ ], "label": "Set Focused Inbox state", "impact": "Low Impact", - "impactColour": "info" + "impactColour": "info", + "powershellEquivalent": "Set-OrganizationConfig -FocusedInboxOn $true or $false", + "recommendedBy": [] }, { "name": "standards.CloudMessageRecall", "cat": "Exchange Standards", "tag": ["lowimpact"], "helpText": "Sets the Cloud Message Recall state for the tenant. This allows users to recall messages from the cloud.", + "docsDescription": "Sets the default state for Cloud Message Recall for the tenant. By default this is enabled. You can read more about the feature [here.](https://techcommunity.microsoft.com/t5/exchange-team-blog/cloud-based-message-recall-in-exchange-online/ba-p/3744714)", "addedComponent": [ { "type": "Select", @@ -676,17 +791,22 @@ ], "label": "Set Cloud Message Recall state", "impact": "Low Impact", - "impactColour": "info" + "impactColour": "info", + "powershellEquivalent": "Set-OrganizationConfig -MessageRecallEnabled", + "recommendedBy": [] }, { "name": "standards.AutoExpandArchive", "cat": "Exchange Standards", "tag": ["lowimpact"], "helpText": "Enables auto-expanding archives for the tenant", + "docsDescription": "Enables auto-expanding archives for the tenant. Does not enable archives for users.", "addedComponent": [], "label": "Enable Auto-expanding archives", "impact": "Low Impact", - "impactColour": "info" + "impactColour": "info", + "powershellEquivalent": "Set-OrganizationConfig -AutoExpandingArchive", + "recommendedBy": [] }, { "name": "standards.EnableOnlineArchiving", @@ -696,23 +816,28 @@ "addedComponent": [], "label": "Enable Online Archive for all users", "impact": "Low Impact", - "impactColour": "info" + "impactColour": "info", + "powershellEquivalent": "Enable-Mailbox -Archive $true", + "recommendedBy": [] }, { - "name": "standards.EnableLitigationHold", - "cat": "Exchange Standards", - "tag": ["lowimpact"], - "helpText": "Enables litigation hold for all UserMailboxes with a valid license.", - "addedComponent": [], - "label": "Enable Litigation Hold for all users", - "impact": "Low Impact", - "impactColour": "info" + "name": "standards.EnableLitigationHold", + "cat": "Exchange Standards", + "tag": ["lowimpact"], + "helpText": "Enables litigation hold for all UserMailboxes with a valid license.", + "addedComponent": [], + "label": "Enable Litigation Hold for all users", + "impact": "Low Impact", + "impactColour": "info", + "powershellEquivalent": "Set-Mailbox -LitigationHoldEnabled $true", + "recommendedBy": [] }, { "name": "standards.SpoofWarn", "cat": "Exchange Standards", "tag": ["lowimpact", "CIS"], "helpText": "Adds or removes indicators to e-mail messages received from external senders in Outlook. Works on all Outlook clients/OWA", + "docsDescription": "Adds or removes indicators to e-mail messages received from external senders in Outlook. You can read more about this feature on [Microsoft's Exchange Team Blog.](https://techcommunity.microsoft.com/t5/exchange-team-blog/native-external-sender-callouts-on-email-in-outlook/ba-p/2250098)", "addedComponent": [ { "type": "Select", @@ -732,7 +857,9 @@ ], "label": "Enable or disable 'external' warning in Outlook", "impact": "Low Impact", - "impactColour": "info" + "impactColour": "info", + "powershellEquivalent": "et-ExternalInOutlook –Enabled $true or $false", + "recommendedBy": ["CIS"] }, { "name": "standards.EnableMailTips", @@ -750,7 +877,9 @@ ], "label": "Enable all MailTips", "impact": "Low Impact", - "impactColour": "info" + "impactColour": "info", + "powershellEquivalent": "Set-OrganizationConfig", + "recommendedBy": ["CIS"] }, { "name": "standards.TeamsMeetingsByDefault", @@ -776,17 +905,22 @@ ], "label": "Set Teams Meetings by default state", "impact": "Low Impact", - "impactColour": "info" + "impactColour": "info", + "powershellEquivalent": "Set-OrganizationConfig -OnlineMeetingsByDefaultEnabled", + "recommendedBy": [] }, { "name": "standards.DisableViva", "cat": "Exchange Standards", "tag": ["lowimpact"], "helpText": "Disables the daily viva reports for all users.", + "docsDescription": "", "addedComponent": [], "label": "Disable daily Insight/Viva reports", "impact": "Low Impact", - "impactColour": "info" + "impactColour": "info", + "powershellEquivalent": "Set-UserBriefingConfig", + "recommendedBy": [] }, { "name": "standards.RotateDKIM", @@ -796,7 +930,9 @@ "addedComponent": [], "label": "Rotate DKIM keys that are 1024 bit to 2048 bit", "impact": "Low Impact", - "impactColour": "info" + "impactColour": "info", + "powershellEquivalent": "Rotate-DkimSigningConfig", + "recommendedBy": ["CIS"] }, { "name": "standards.AddDKIM", @@ -806,17 +942,22 @@ "addedComponent": [], "label": "Enables DKIM for all domains that currently support it", "impact": "Low Impact", - "impactColour": "info" + "impactColour": "info", + "powershellEquivalent": "New-DkimSigningConfig and Set-DkimSigningConfig", + "recommendedBy": ["CIS"] }, { "name": "standards.EnableMailboxAuditing", "cat": "Exchange Standards", "tag": ["lowimpact", "CIS", "exo_mailboxaudit"], "helpText": "Enables Mailbox auditing for all mailboxes and on tenant level. Disables audit bypass on all mailboxes. Unified Audit Log needs to be enabled for this standard to function.", + "docsDescription": "Enables mailbox auditing on tenant level and for all mailboxes. Disables audit bypass on all mailboxes. By default Microsoft does not enable mailbox auditing for Resource Mailboxes, Public Folder Mailboxes and DiscoverySearch Mailboxes. Unified Audit Log needs to be enabled for this standard to function.", "addedComponent": [], "label": "Enable Mailbox auditing", "impact": "Low Impact", - "impactColour": "info" + "impactColour": "info", + "powershellEquivalent": "Set-OrganizationConfig -AuditDisabled $false", + "recommendedBy": ["CIS"] }, { "name": "standards.SendReceiveLimitTenant", @@ -839,13 +980,16 @@ ], "label": "Set send/receive size limits", "impact": "Low Impact", - "impactColour": "info" + "impactColour": "info", + "powershellEquivalent": "Set-MailboxPlan", + "recommendedBy": [] }, { "name": "standards.calDefault", "cat": "Exchange Standards", "tag": ["lowimpact"], "helpText": "Sets the default sharing level for the default calendar, for all users", + "docsDescription": "Sets the default sharing level for the default calendar for all users in the tenant. You can read about the different sharing levels [here.](https://learn.microsoft.com/en-us/powershell/module/exchange/set-mailboxfolderpermission?view=exchange-ps#-accessrights)", "disabledFeatures": { "report": true, "warn": true, @@ -906,27 +1050,35 @@ ], "label": "Set Sharing Level for Default calendar", "impact": "Low Impact", - "impactColour": "info" + "impactColour": "info", + "powershellEquivalent": "Set-MailboxFolderPermission", + "recommendedBy": [] }, { "name": "standards.DisableExternalCalendarSharing", "cat": "Exchange Standards", "tag": ["lowimpact", "CIS", "exo_individualsharing"], "helpText": "Disables the ability for users to share their calendar with external users. Only for the default policy, so exclusions can be made if needed.", + "docsDescription": "Disables external calendar sharing for the entire tenant. This is not a widely used feature, and it's therefore unlikely that this will impact users. Only for the default policy, so exclusions can be made if needed by making a new policy and assigning it to users.", "addedComponent": [], "label": "Disable external calendar sharing", "impact": "Low Impact", - "impactColour": "info" + "impactColour": "info", + "powershellEquivalent": "Get-SharingPolicy | Set-SharingPolicy -Enabled $False", + "recommendedBy": ["CIS"] }, { "name": "standards.DisableAdditionalStorageProviders", "cat": "Exchange Standards", "tag": ["lowimpact", "CIS", "exo_storageproviderrestricted"], "helpText": "Disables the ability for users to open files in Outlook on the Web, from other providers such as Box, Dropbox, Facebook, Google Drive, OneDrive Personal, etc.", + "docsDescription": "Disables additional storage providers in OWA. This is to prevent users from using personal storage providers like Dropbox, Google Drive, etc. Usually this has little user impact.", "addedComponent": [], "label": "Disable additional storage providers in OWA", "impact": "Low Impact", - "impactColour": "info" + "impactColour": "info", + "powershellEquivalent": "Get-OwaMailboxPolicy | Set-OwaMailboxPolicy -AdditionalStorageProvidersEnabled $False", + "recommendedBy": ["CIS"] }, { "name": "standards.ShortenMeetings", @@ -968,13 +1120,16 @@ ], "label": "Set shorten meetings state", "impact": "Medium Impact", - "impactColour": "warning" + "impactColour": "warning", + "powershellEquivalent": "Set-OrganizationConfig -ShortenEventScopeDefault -DefaultMinutesToReduceShortEventsBy -DefaultMinutesToReduceLongEventsBy", + "recommendedBy": [] }, { "name": "standards.Bookings", "cat": "Exchange Standards", "tag": ["mediumimpact"], "helpText": "Sets the state of Bookings on the tenant. Bookings is a scheduling tool that allows users to book appointments with others both internal and external.", + "docsDescription": "", "addedComponent": [ { "type": "Select", @@ -994,17 +1149,22 @@ ], "label": "Set Bookings state", "impact": "Medium Impact", - "impactColour": "warning" + "impactColour": "warning", + "powershellEquivalent": "Set-OrganizationConfig -BookingsEnabled", + "recommendedBy": [] }, { "name": "standards.DisableOutlookAddins", "cat": "Exchange Standards", "tag": ["mediumimpact", "CIS", "exo_outlookaddins"], "helpText": "Disables the ability for users to install add-ins in Outlook. This is to prevent users from installing malicious add-ins.", + "docsDescription": "Disables users from being able to install add-ins in Outlook. Only admins are able to approve add-ins for the users. This is done to reduce the threat surface for data exfiltration.", "addedComponent": [], "label": "Disable users from installing add-ins in Outlook", "impact": "Medium Impact", - "impactColour": "warning" + "impactColour": "warning", + "powershellEquivalent": "Get-ManagementRoleAssignment | Remove-ManagementRoleAssignment", + "recommendedBy": ["CIS"] }, { "name": "standards.SafeSendersDisable", @@ -1019,33 +1179,42 @@ }, "label": "Remove Safe Senders to prevent SPF bypass", "impact": "Medium Impact", - "impactColour": "warning" + "impactColour": "warning", + "powershellEquivalent": "Set-MailboxJunkEmailConfiguration", + "recommendedBy": [] }, { "name": "standards.DelegateSentItems", "cat": "Exchange Standards", "tag": ["mediumimpact"], "helpText": "Sets emails sent as and on behalf of shared mailboxes to also be stored in the shared mailbox sent items folder", + "docsDescription": "This makes sure that e-mails sent from shared mailboxes or delegate mailboxes, end up in the mailbox of the shared/delegate mailbox instead of the sender, allowing you to keep replies in the same mailbox as the original e-mail.", "addedComponent": [], "label": "Set mailbox Sent Items delegation (Sent items for shared mailboxes)", "impact": "Medium Impact", - "impactColour": "warning" + "impactColour": "warning", + "powershellEquivalent": "Set-Mailbox", + "recommendedBy": [] }, { "name": "standards.SendFromAlias", "cat": "Exchange Standards", "tag": ["mediumimpact"], "helpText": "Enables the ability for users to send from their alias addresses.", + "docsDescription": "Allows users to change the 'from' address to any set in their Azure AD Profile.", "addedComponent": [], "label": "Allow users to send from their alias addresses", "impact": "Medium Impact", - "impactColour": "warning" + "impactColour": "warning", + "powershellEquivalent": "Set-Mailbox", + "recommendedBy": [] }, { "name": "standards.UserSubmissions", "cat": "Exchange Standards", "tag": ["mediumimpact"], "helpText": "Set the state of the spam submission button in Outlook", + "docsDescription": "Set the state of the built-in Report button in Outlook. This gives the users the ability to report emails as spam or phish.", "addedComponent": [ { "type": "Select", @@ -1065,7 +1234,9 @@ ], "label": "Set the state of the built-in Report button in Outlook", "impact": "Medium Impact", - "impactColour": "warning" + "impactColour": "warning", + "powershellEquivalent": "New-ReportSubmissionPolicy or Set-ReportSubmissionPolicy", + "recommendedBy": [] }, { "name": "standards.UserReportDestinationEmail", @@ -1081,17 +1252,22 @@ ], "label": "Set the destination email for user reported emails", "impact": "Medium Impact", - "impactColour": "warning" + "impactColour": "warning", + "powershellEquivalent": "New-ReportSubmissionRule or Set-ReportSubmissionRule", + "recommendedBy": [] }, { "name": "standards.DisableSharedMailbox", "cat": "Exchange Standards", "tag": ["mediumimpact", "CIS"], "helpText": "Blocks login for all accounts that are marked as a shared mailbox. This is Microsoft best practice to prevent direct logons to shared mailboxes.", + "docsDescription": "Shared mailboxes can be directly logged into if the password is reset, this presents a security risk as do all shared login credentials. Microsoft's recommendation is to disable the user account for shared mailboxes. It would be a good idea to review the sign-in reports to establish potential impact.", "addedComponent": [], "label": "Disable Shared Mailbox AAD accounts", "impact": "Medium Impact", - "impactColour": "warning" + "impactColour": "warning", + "powershellEquivalent": "Get-Mailbox & Update-MgUser", + "recommendedBy": ["CIS"] }, { "name": "standards.SafeLinksPolicy", @@ -1117,7 +1293,9 @@ ], "label": "Default SafeLinks Policy", "impact": "Low Impact", - "impactColour": "info" + "impactColour": "info", + "powershellEquivalent": "Set-SafeLinksPolicy or New-SafeLinksPolicy", + "recommendedBy": ["CIS"] }, { "name": "standards.AntiPhishPolicy", @@ -1315,7 +1493,9 @@ ], "label": "Default Anti-Phishing Policy", "impact": "Low Impact", - "impactColour": "info" + "impactColour": "info", + "powershellEquivalent": "Set-AntiphishPolicy or New-AntiphishPolicy", + "recommendedBy": ["CIS"] }, { "name": "standards.SafeAttachmentPolicy", @@ -1380,7 +1560,9 @@ ], "label": "Default Safe Attachment Policy", "impact": "Low Impact", - "impactColour": "info" + "impactColour": "info", + "powershellEquivalent": "Set-SafeAttachmentPolicy or New-SafeAttachmentPolicy", + "recommendedBy": ["CIS"] }, { "name": "standards.AtpPolicyForO365", @@ -1397,7 +1579,9 @@ ], "label": "Default Atp Policy For O365", "impact": "Low Impact", - "impactColour": "info" + "impactColour": "info", + "powershellEquivalent": "Set-AtpPolicyForO365", + "recommendedBy": ["CIS"] }, { "name": "standards.MalwareFilterPolicy", @@ -1462,7 +1646,9 @@ ], "label": "Default Malware Filter Policy", "impact": "Low Impact", - "impactColour": "info" + "impactColour": "info", + "powershellEquivalent": "Set-MalwareFilterPolicy or New-MalwareFilterPolicy", + "recommendedBy": ["CIS"] }, { "name": "standards.intuneDeviceRetirementDays", @@ -1478,7 +1664,9 @@ ], "label": "Set inactive device retirement days", "impact": "Low Impact", - "impactColour": "info" + "impactColour": "info", + "powershellEquivalent": "Graph API", + "recommendedBy": [] }, { "name": "standards.intuneBrandingProfile", @@ -1539,7 +1727,9 @@ ], "label": "Set Intune Company Portal branding profile", "impact": "Low Impact", - "impactColour": "info" + "impactColour": "info", + "powershellEquivalent": "Graph API", + "recommendedBy": [] }, { "name": "standards.intuneDeviceReg", @@ -1555,7 +1745,9 @@ ], "label": "Set Maximum Number of Devices per user", "impact": "Medium Impact", - "impactColour": "warning" + "impactColour": "warning", + "powershellEquivalent": "Update-MgBetaPolicyDeviceRegistrationPolicy", + "recommendedBy": [] }, { "name": "standards.intuneRequireMFA", @@ -1564,17 +1756,22 @@ "helpText": "Requires MFA for all users to register devices with Intune. This is useful when not using Conditional Access.", "label": "Require Multifactor Authentication to register or join devices with Microsoft Entra", "impact": "Medium Impact", - "impactColour": "warning" + "impactColour": "warning", + "powershellEquivalent": "Update-MgBetaPolicyDeviceRegistrationPolicy", + "recommendedBy": [] }, { "name": "standards.DeletedUserRentention", "cat": "SharePoint Standards", "tag": ["lowimpact"], "helpText": "Sets the retention period for deleted users OneDrive to 1 year/365 days", + "docsDescription": "When a OneDrive user gets deleted, the personal SharePoint site is saved for 1 year and data can be retrieved from it.", "addedComponent": [], "label": "Retain a deleted user OneDrive for 1 year", "impact": "Low Impact", - "impactColour": "info" + "impactColour": "info", + "powershellEquivalent": "Update-MgBetaAdminSharepointSetting", + "recommendedBy": [] }, { "name": "standards.TenantDefaultTimezone", @@ -1590,7 +1787,9 @@ ], "label": "Set Default Timezone for Tenant", "impact": "Low Impact", - "impactColour": "info" + "impactColour": "info", + "powershellEquivalent": "Update-MgBetaAdminSharepointSetting", + "recommendedBy": [] }, { "name": "standards.DisableAddShortcutsToOneDrive", @@ -1605,17 +1804,22 @@ "addedComponent": [], "label": "Disable Add Shortcuts To OneDrive", "impact": "Medium Impact", - "impactColour": "warning" + "impactColour": "warning", + "powershellEquivalent": "Graph API or Portal", + "recommendedBy": [] }, { "name": "standards.DisableSharePointLegacyAuth", "cat": "SharePoint Standards", "tag": ["mediumimpact", "CIS"], "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": [], "label": "Disable legacy basic authentication for SharePoint", "impact": "Medium Impact", - "impactColour": "warning" + "impactColour": "warning", + "powershellEquivalent": "Set-SPOTenant -LegacyAuthProtocolsEnabled $false", + "recommendedBy": ["CIS"] }, { "name": "standards.sharingCapability", @@ -1649,27 +1853,35 @@ ], "label": "Set Sharing Level for OneDrive and Sharepoint", "impact": "High Impact", - "impactColour": "danger" + "impactColour": "danger", + "powershellEquivalent": "Update-MgBetaAdminSharepointSetting", + "recommendedBy": ["CIS"] }, { "name": "standards.DisableReshare", "cat": "SharePoint Standards", "tag": ["highimpact", "CIS"], "helpText": "Disables the ability for external users to share files they don't own. Sharing links can only be made for People with existing access", + "docsDescription": "Disables the ability for external users to share files they don't own. Sharing links can only be made for People with existing access. This is a tenant wide setting and overrules any settings set on the site level", "addedComponent": [], "label": "Disable Resharing by External Users", "impact": "High Impact", - "impactColour": "danger" + "impactColour": "danger", + "powershellEquivalent": "Update-MgBetaAdminSharepointSetting", + "recommendedBy": ["CIS"] }, { "name": "standards.DisableUserSiteCreate", "cat": "SharePoint Standards", "tag": ["highimpact"], "helpText": "Disables users from creating new SharePoint sites", + "docsDescription": "Disables standard users from creating SharePoint sites, also disables the ability to fully create teams", "addedComponent": [], "label": "Disable site creation by standard users", "impact": "High Impact", - "impactColour": "danger" + "impactColour": "danger", + "powershellEquivalent": "Update-MgAdminSharepointSetting", + "recommendedBy": [] }, { "name": "standards.ExcludedfileExt", @@ -1685,7 +1897,9 @@ ], "label": "Exclude File Extensions from Syncing", "impact": "High Impact", - "impactColour": "danger" + "impactColour": "danger", + "powershellEquivalent": "Update-MgAdminSharepointSetting", + "recommendedBy": [] }, { "name": "standards.disableMacSync", @@ -1695,17 +1909,21 @@ "addedComponent": [], "label": "Do not allow Mac devices to sync using OneDrive", "impact": "High Impact", - "impactColour": "danger" + "impactColour": "danger", + "powershellEquivalent": "Update-MgAdminSharepointSetting", + "recommendedBy": [] }, { "name": "standards.unmanagedSync", "cat": "SharePoint Standards", "tag": ["highimpact"], - "helpText": "This standard will only allow devices that are AD joined, or AAD joined to sync with OneDrive", + "helpText": "The unmanaged Sync standard has been temporarily disabled and does nothing.", "addedComponent": [], "label": "Only allow users to sync OneDrive from AAD joined devices", "impact": "High Impact", - "impactColour": "danger" + "impactColour": "danger", + "powershellEquivalent": "Update-MgAdminSharepointSetting", + "recommendedBy": [] }, { "name": "standards.sharingDomainRestriction", @@ -1740,6 +1958,8 @@ ], "label": "Restrict sharing to a specific domain", "impact": "High Impact", - "impactColour": "danger" + "impactColour": "danger", + "powershellEquivalent": "Update-MgAdminSharepointSetting", + "recommendedBy": [] } ] From 7397b24188fe8e45c296b13a6c11908f65c5c592 Mon Sep 17 00:00:00 2001 From: rvdwegen Date: Wed, 3 Jul 2024 22:27:41 +0200 Subject: [PATCH 19/58] Adding self-service license management Standard --- src/data/standards.json | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/data/standards.json b/src/data/standards.json index dd0f005d19a6..803199755bdc 100644 --- a/src/data/standards.json +++ b/src/data/standards.json @@ -522,8 +522,14 @@ "name": "standards.DisableSelfServiceLicenses", "cat": "Entra (AAD) Standards", "tag": ["mediumimpact"], - "helpText": "This standard currently does not function and can be safely disabled", - "addedComponent": [], + "helpText": "This standard disables all self service licenses and enables all exclusions", + "addedComponent": [ + { + "type": "input", + "name": "standards.DisableSelfServiceLicenses.Exclusions", + "label": "License Ids to exclude from this standard" + } + ], "label": "Disable Self Service Licensing", "impact": "Medium Impact", "impactColour": "warning", From d30452b0c27397081c11974c091cf570a7179bae Mon Sep 17 00:00:00 2001 From: John Duprey Date: Wed, 3 Jul 2024 17:13:41 -0400 Subject: [PATCH 20/58] Extension tweaks Add Hudu Cleanup mappings --- src/data/Extensions.json | 57 +++- src/views/cipp/ExtensionMappings.jsx | 412 +++++++++++++++++++++++++++ src/views/cipp/Extensions.jsx | 14 +- 3 files changed, 469 insertions(+), 14 deletions(-) create mode 100644 src/views/cipp/ExtensionMappings.jsx diff --git a/src/data/Extensions.json b/src/data/Extensions.json index bc556899e4a8..e46565493f28 100644 --- a/src/data/Extensions.json +++ b/src/data/Extensions.json @@ -1,6 +1,6 @@ [ { - "name": "CIPP-API Integration", + "name": "CIPP-API", "type": "CIPP-API", "cat": "API", "forceSyncButton": false, @@ -21,7 +21,7 @@ "mappingRequired": false }, { - "name": "Gradient Integration", + "name": "Gradient", "type": "Gradient", "cat": "Billing & Invoicing", "forceSyncButton": true, @@ -55,7 +55,7 @@ "mappingRequired": false }, { - "name": "Halo PSA Ticketing Integration", + "name": "Halo PSA Ticketing", "type": "HaloPSA", "cat": "Ticketing", "forceSyncButton": false, @@ -112,7 +112,7 @@ "mappingRequired": true }, { - "name": "NinjaOne Integration", + "name": "NinjaOne", "type": "NinjaOne", "cat": "Documentation & Monitoring", "forceSyncButton": true, @@ -141,18 +141,18 @@ }, { "type": "checkbox", - "name": "NinjaOne.UserDocumentsEnabled", - "label": "Synchronize Detailed User Information (Requires NinjaOne Documentation)" + "name": "NinjaOne.LicenseDocumentsEnabled", + "label": "Sync Licenses (Requires NinjaOne Documentation)" }, { "type": "checkbox", - "name": "NinjaOne.LicenseDocumentsEnabled", - "label": "Synchronize Detailed License Information (Requires NinjaOne Documentation)" + "name": "NinjaOne.UserDocumentsEnabled", + "label": "Sync Users (Requires NinjaOne Documentation)" }, { "type": "checkbox", "name": "NinjaOne.LicensedOnly", - "label": "Only Synchronize Licensed Users" + "label": "Only Sync Licensed Users (Requires NinjaOne Documentation)" }, { "type": "checkbox", @@ -160,7 +160,44 @@ "label": "Enable Integration" } ], - "mappingRequired": true + "mappingRequired": true, + "fieldMapping": true, + "autoMapSyncApi": true + }, + { + "name": "Hudu", + "type": "Hudu", + "cat": "Documentation", + "forceSyncButton": true, + "helpText": "This integration allows you to populate custom asset layouts with Tenant information, monitor device compliance state, document other items and generate relationships inside Hudu.", + "SettingOptions": [ + { + "type": "input", + "fieldtype": "input", + "name": "Hudu.BaseUrl", + "label": "Please enter your Hudu URL", + "placeholder": "https://yourcompany.huducloud.com" + }, + { + "type": "input", + "fieldtype": "password", + "name": "Hudu.APIKey", + "label": "Hudu API Key", + "placeholder": "Enter your Hudu API Key" + }, + { + "type": "checkbox", + "name": "Hudu.LicensedUsersOnly", + "label": "Only Sync Licensed Users" + }, + { + "type": "checkbox", + "name": "Hudu.Enabled", + "label": "Enable Integration" + } + ], + "mappingRequired": true, + "fieldMapping": true }, { "name": "PasswordPusher", diff --git a/src/views/cipp/ExtensionMappings.jsx b/src/views/cipp/ExtensionMappings.jsx new file mode 100644 index 000000000000..131d04bece52 --- /dev/null +++ b/src/views/cipp/ExtensionMappings.jsx @@ -0,0 +1,412 @@ +import { useLazyGenericGetRequestQuery, useLazyGenericPostRequestQuery } from 'src/store/api/app.js' +import { CButton, CCallout, CCardText, CCol, CForm, CRow, CSpinner, CTooltip } from '@coreui/react' +import { Form } from 'react-final-form' +import { RFFSelectSearch } from 'src/components/forms/index.js' +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' +import { faCircleNotch } from '@fortawesome/free-solid-svg-icons' +import React, { useEffect } from 'react' +import { CippCallout } from 'src/components/layout/index.js' +import { CippTable } from 'src/components/tables' +import { CellTip, cellGenericFormatter } from 'src/components/tables/CellGenericFormat' +import CippButtonCard from 'src/components/contentcards/CippButtonCard' + +/** + * Retrieves and sets the extension mappings for HaloPSA and NinjaOne. + * + * @returns {JSX.Element} - JSX component representing the settings extension mappings. + */ +export default function ExtensionMappings({ type, fieldMappings = false, autoMapSyncApi = false }) { + const [mappingArray, setMappingArray] = React.useState('defaultMapping') + const [mappingValue, setMappingValue] = React.useState({}) + const [tenantMappingArray, setTenantMappingsArray] = React.useState([]) + const [autoMap, setAutoMap] = React.useState(false) + const [listMappingBackend, listMappingBackendResult = []] = useLazyGenericGetRequestQuery() + const [listFieldsBackend, listFieldsBackendResult] = useLazyGenericGetRequestQuery() + const [setExtensionConfig, extensionConfigResult = []] = useLazyGenericPostRequestQuery() + const [setExtensionAutomap, extensionAutomapResult] = useLazyGenericPostRequestQuery() + const [setFieldsExtensionConfig, extensionFieldsConfigResult] = useLazyGenericPostRequestQuery() + + const onOrgSubmit = () => { + console.log(mappingArray) + const originalFormat = mappingArray.reduce((acc, item) => { + acc[item.Tenant?.customerId] = { label: item.companyName, value: item.companyId } + return acc + }, {}) + setExtensionConfig({ + path: `api/ExecExtensionMapping?AddMapping=${type}`, + values: { mappings: originalFormat }, + }).then(() => { + listMappingBackend({ path: `api/ExecExtensionMapping?List=${type}` }) + setMappingValue({}) + }) + } + /*const onNinjaOrgsSubmit = () => { + const originalFormat = ninjaMappingsArray.reduce((acc, item) => { + acc[item.Tenant?.customerId] = { label: item.ninjaName, value: item.ninjaId } + return acc + }, {}) + + setNinjaOrgsExtensionconfig({ + path: 'api/ExecExtensionMapping?AddMapping=NinjaOrgs', + values: { mappings: originalFormat }, + }).then(() => { + listNinjaOrgsBackend({ path: 'api/ExecExtensionMapping?List=NinjaOrgs' }) + setMappingValue({}) + }) + }*/ + + const onOrgsAutomap = async (values) => { + if (autoMapSyncApi) { + await setExtensionAutomap({ + path: `api/ExecExtensionMapping?AutoMapping=${type}`, + values: { mappings: values }, + }) + await listMappingBackend({ + path: `api/ExecExtensionMapping?List=${type}`, + }) + } + + const newMappings = listMappingBackendResult.data?.Tenants.map((tenant) => { + const company = listMappingBackendResult.data?.Companies.find( + (client) => client.name === tenant.displayName, + ) + if (company) { + return { + Tenant: tenant, + companyName: company.name, + companyId: company.value, + } + } + }) + setMappingArray((currentMappings) => [...currentMappings, ...newMappings]) + setAutoMap(true) + } + + const onFieldsSubmit = (values) => { + setFieldsExtensionConfig({ + path: `api/ExecExtensionMapping?AddMapping=${type}Fields`, + values: { mappings: values }, + }) + } + + /*const onHaloAutomap = () => { + const newMappings = listBackendHaloResult.data?.Tenants.map( + (tenant) => { + const haloClient = listBackendHaloResult.data?.HaloClients.find( + (client) => client.name === tenant.displayName, + ) + if (haloClient) { + console.log(haloClient) + console.log(tenant) + return { + Tenant: tenant, + haloName: haloClient.name, + haloId: haloClient.value, + } + } + }, + //filter out any undefined values + ).filter((item) => item !== undefined) + setHaloMappingsArray((currentHaloMappings) => [...currentHaloMappings, ...newMappings]).then( + () => { + listHaloBackend({ path: 'api/ExecExtensionMapping?List=Halo' }) + }, + ) + setHaloAutoMap(true) + }*/ + + useEffect(() => { + if (listMappingBackendResult.isSuccess) { + setMappingArray( + Object.keys(listMappingBackendResult.data?.Mappings).map((key) => ({ + Tenant: listMappingBackendResult.data?.Tenants.find( + (tenant) => tenant.customerId === key, + ), + companyName: listMappingBackendResult.data?.Mappings[key].label, + companyId: listMappingBackendResult.data?.Mappings[key].value, + })), + ) + } + }, [listMappingBackendResult]) + + const Actions = (row, rowIndex, formatExtraData) => { + return ( + <> + + + setMappingArray((currentMappings) => currentMappings.filter((item) => item !== row)) + } + > + + + + + ) + } + const columns = [ + { + name: 'Tenant', + selector: (row) => row.Tenant?.displayName, + sortable: true, + cell: (row) => CellTip(row.Tenant?.displayName), + exportSelector: 'Tenant', + }, + { + name: 'TenantId', + selector: (row) => row.Tenant?.customerId, + sortable: true, + exportSelector: 'Tenant/customerId', + omit: true, + }, + { + name: `${type} Company Name`, + selector: (row) => row['companyName'], + sortable: true, + cell: cellGenericFormatter(), + exportSelector: 'companyName', + }, + { + name: `${type} Company ID`, + selector: (row) => row['companyId'], + sortable: true, + cell: (row) => CellTip(row['companyId']), + exportSelector: 'companyId', + }, + { + name: 'Actions', + cell: Actions, + maxWidth: '80px', + }, + ] + + return ( + + <> + {listMappingBackendResult.isUninitialized && + listMappingBackend({ path: `api/ExecExtensionMapping?List=${type}` })} + {listFieldsBackendResult.isUninitialized && + fieldMappings && + listFieldsBackend({ path: `api/ExecExtensionMapping?List=${type}Fields` })} + + + {extensionConfigResult.isFetching && ( + + )} + Set Mappings + + onOrgsAutomap()} className="me-2"> + {extensionAutomapResult.isFetching && ( + + )} + Automap {type} Organizations + + + } + > + {listMappingBackendResult.isFetching && listMappingBackendResult.isUninitialized ? ( + + ) : ( + { + return ( + + + Use the table below to map your client to the correct {type} Organization. + { + //load all the existing mappings and show them first in a table. + listMappingBackendResult.isSuccess && ( + + ) + } + + + { + return !Object.keys(listMappingBackendResult.data?.Mappings).includes( + tenant.customerId, + ) + }).map((tenant) => ({ + name: tenant.displayName, + value: tenant.customerId, + }))} + onChange={(e) => { + setMappingArray(e.value) + }} + isLoading={listMappingBackendResult.isFetching} + /> + + + + + + { + return !Object.values(listMappingBackendResult.data?.Mappings) + .map((value) => { + return value.value + }) + .includes(client.value.toString()) + }).map((client) => ({ + name: client.name, + value: client.value, + }))} + onChange={(e) => setMappingValue(e)} + placeholder={`Select a ${type} Organization`} + isLoading={listMappingBackendResult.isFetching} + /> + + { + //set the new mapping in the array + if ( + mappingValue.value !== undefined && + mappingValue.value !== '-1' && + Object.values(mappingArray) + .map((item) => item.companyId) + .includes(mappingValue.value) === false + ) { + setMappingArray([ + ...mappingArray, + { + Tenant: listMappingBackendResult.data?.Tenants.find( + (tenant) => tenant.customerId === mappingArray, + ), + companyName: mappingValue.label, + companyId: mappingValue.value, + }, + ]) + } + }} + className={`my-4 circular-button`} + title={'+'} + > + + + + + + {(extensionAutomapResult.isSuccess || extensionAutomapResult.isError) && + !extensionAutomapResult.isFetching && ( + + {extensionAutomapResult.isSuccess + ? extensionAutomapResult.data.Results + : 'Error'} + + )} + {(extensionConfigResult.isSuccess || extensionConfigResult.isError) && + !extensionConfigResult.isFetching && ( + + {extensionConfigResult.isSuccess + ? extensionConfigResult.data.Results + : 'Error'} + + )} + + + + After editing the mappings you must click Save Mappings for the changes to + take effect. The table will be saved exactly as presented. + + + ) + }} + /> + )} + + + {fieldMappings && ( + + {extensionFieldsConfigResult.isFetching && ( + + )} + Set Mappings +
+ } + > + {listFieldsBackendResult.isFetching && listFieldsBackendResult.isUninitialized && ( + + )} + {listFieldsBackendResult.isSuccess && listFieldsBackendResult.data?.Mappings && ( + { + return ( + + {listFieldsBackendResult?.data?.CIPPFieldHeaders?.map((header, key) => ( + +
{header.Title}
+

{header.Description}

+ {listFieldsBackendResult?.data?.CIPPFields?.filter( + (f) => f.FieldType == header.FieldType, + ).map((field, fieldkey) => ( + item.FieldType === field.FieldType || item.type === 'unset', + )} + placeholder="Select a Field" + /> + ))} +
+ ))} + + {(extensionFieldsConfigResult.isSuccess || + extensionFieldsConfigResult.isError) && + !extensionFieldsConfigResult.isFetching && ( + + {extensionFieldsConfigResult.isSuccess + ? extensionFieldsConfigResult.data.Results + : 'Error'} + + )} + +
+ ) + }} + /> + )} + + )} + + ) +} diff --git a/src/views/cipp/Extensions.jsx b/src/views/cipp/Extensions.jsx index 8a165cbc0dfd..d08ac0636174 100644 --- a/src/views/cipp/Extensions.jsx +++ b/src/views/cipp/Extensions.jsx @@ -21,7 +21,7 @@ import { faCircleNotch } from '@fortawesome/free-solid-svg-icons' import CippButtonCard from 'src/components/contentcards/CippButtonCard.jsx' import { RFFCFormInput, RFFCFormSwitch } from 'src/components/forms/RFFComponents.jsx' import { Form } from 'react-final-form' -import { SettingsExtensionMappings } from './app-settings/SettingsExtensionMappings' +import ExtensionMappings from 'src/views/cipp/ExtensionMappings.jsx' export default function CIPPExtensions() { const [listBackend, listBackendResult] = useLazyGenericGetRequestQuery() @@ -191,9 +191,15 @@ export default function CIPPExtensions() { )} - - - + {integration.mappingRequired && ( + + + + )} From 109692dd4503b28170f524329bc86f61423b07f4 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Wed, 3 Jul 2024 17:33:38 -0400 Subject: [PATCH 21/58] Update ExtensionMappings.jsx --- src/views/cipp/ExtensionMappings.jsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/views/cipp/ExtensionMappings.jsx b/src/views/cipp/ExtensionMappings.jsx index 131d04bece52..04665d1cfdee 100644 --- a/src/views/cipp/ExtensionMappings.jsx +++ b/src/views/cipp/ExtensionMappings.jsx @@ -378,7 +378,8 @@ export default function ExtensionMappings({ type, fieldMappings = false, autoMap name={field.FieldName} label={field.FieldLabel} values={listFieldsBackendResult.data.IntegrationFields.filter( - (item) => item.FieldType === field.FieldType || item.type === 'unset', + (item) => + item?.FieldType === field.FieldType || item?.type === 'unset', )} placeholder="Select a Field" /> From 4c0e47451b57ea584ff5c84c31115924e2ced7ab Mon Sep 17 00:00:00 2001 From: John Duprey Date: Wed, 3 Jul 2024 18:01:57 -0400 Subject: [PATCH 22/58] Cleanup comments, add refresh --- src/views/cipp/ExtensionMappings.jsx | 43 ++-------------------------- 1 file changed, 3 insertions(+), 40 deletions(-) diff --git a/src/views/cipp/ExtensionMappings.jsx b/src/views/cipp/ExtensionMappings.jsx index 04665d1cfdee..c7bffa53f624 100644 --- a/src/views/cipp/ExtensionMappings.jsx +++ b/src/views/cipp/ExtensionMappings.jsx @@ -40,20 +40,6 @@ export default function ExtensionMappings({ type, fieldMappings = false, autoMap setMappingValue({}) }) } - /*const onNinjaOrgsSubmit = () => { - const originalFormat = ninjaMappingsArray.reduce((acc, item) => { - acc[item.Tenant?.customerId] = { label: item.ninjaName, value: item.ninjaId } - return acc - }, {}) - - setNinjaOrgsExtensionconfig({ - path: 'api/ExecExtensionMapping?AddMapping=NinjaOrgs', - values: { mappings: originalFormat }, - }).then(() => { - listNinjaOrgsBackend({ path: 'api/ExecExtensionMapping?List=NinjaOrgs' }) - setMappingValue({}) - }) - }*/ const onOrgsAutomap = async (values) => { if (autoMapSyncApi) { @@ -89,32 +75,6 @@ export default function ExtensionMappings({ type, fieldMappings = false, autoMap }) } - /*const onHaloAutomap = () => { - const newMappings = listBackendHaloResult.data?.Tenants.map( - (tenant) => { - const haloClient = listBackendHaloResult.data?.HaloClients.find( - (client) => client.name === tenant.displayName, - ) - if (haloClient) { - console.log(haloClient) - console.log(tenant) - return { - Tenant: tenant, - haloName: haloClient.name, - haloId: haloClient.value, - } - } - }, - //filter out any undefined values - ).filter((item) => item !== undefined) - setHaloMappingsArray((currentHaloMappings) => [...currentHaloMappings, ...newMappings]).then( - () => { - listHaloBackend({ path: 'api/ExecExtensionMapping?List=Halo' }) - }, - ) - setHaloAutoMap(true) - }*/ - useEffect(() => { if (listMappingBackendResult.isSuccess) { setMappingArray( @@ -232,6 +192,9 @@ export default function ExtensionMappings({ type, fieldMappings = false, autoMap columns={columns} data={mappingArray} isModal={true} + refreshFunction={() => + listMappingBackend({ path: `api/ExecExtensionMapping?List=${type}` }) + } /> ) } From f3e0e3586c1221b812ad8e322dfd6a30248f714a Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Thu, 4 Jul 2024 23:43:47 +0200 Subject: [PATCH 23/58] added backups --- src/_nav.jsx | 20 ++ src/importsMap.jsx | 8 +- src/routes.json | 14 + src/views/tenant/backup/CreateBackup.jsx | 267 +++++++++++++++++ src/views/tenant/backup/RestoreBackup.jsx | 333 ++++++++++++++++++++++ 5 files changed, 639 insertions(+), 3 deletions(-) create mode 100644 src/views/tenant/backup/CreateBackup.jsx create mode 100644 src/views/tenant/backup/RestoreBackup.jsx diff --git a/src/_nav.jsx b/src/_nav.jsx index e6567546bf11..631d6eaf1169 100644 --- a/src/_nav.jsx +++ b/src/_nav.jsx @@ -19,6 +19,7 @@ import { faUserShield, faEnvelope, faToolbox, + faDownload, } from '@fortawesome/free-solid-svg-icons' const _nav = [ @@ -184,6 +185,25 @@ const _nav = [ }, ], }, + { + component: CNavGroup, + name: 'Configuration Backup', + section: 'Tenant Administration', + to: '/cipp/gdap', + icon: , + items: [ + { + component: CNavItem, + name: 'Backup Wizard', + to: '/tenant/backup/backup-wizard', + }, + { + component: CNavItem, + name: 'Restore Wizard', + to: '/tenant/backup/restore-wizard', + }, + ], + }, { component: CNavGroup, name: 'Tools', diff --git a/src/importsMap.jsx b/src/importsMap.jsx index 63ae50439b0d..9666488abfc9 100644 --- a/src/importsMap.jsx +++ b/src/importsMap.jsx @@ -34,6 +34,8 @@ import React from 'react' "/identity/reports/Signin-report": React.lazy(() => import('./views/identity/reports/SignIns')), "/identity/reports/azure-ad-connect-report": React.lazy(() => import('./views/identity/reports/AzureADConnectReport')), "/identity/reports/risk-detections": React.lazy(() => import('./views/identity/reports/RiskDetections')), + "/tenant/backup/backup-wizard": React.lazy(() => import('./views/tenant/backup/CreateBackup')), + "/tenant/backup/restore-wizard": React.lazy(() => import('./views/tenant/backup/RestoreBackup')), "/tenant/administration/tenants": React.lazy(() => import('./views/tenant/administration/Tenants')), "/tenant/administration/tenants/edit": React.lazy(() => import('./views/tenant/administration/EditTenant')), "/tenant/administration/partner-relationships": React.lazy(() => import('./views/tenant/administration/PartnerRelationships')), @@ -46,6 +48,7 @@ import React from 'react' "/tenant/administration/enterprise-apps": React.lazy(() => import('./views/tenant/administration/ListEnterpriseApps')), "/tenant/administration/app-consent-requests": React.lazy(() => import('./views/tenant/administration/ListAppConsentRequests')), "/tenant/conditional/list-policies": React.lazy(() => import('./views/tenant/conditional/ConditionalAccess')), + "/tenant/administration/authentication-methods": React.lazy(() => import('./views/tenant/administration/AuthMethods')), "/tenant/conditional/deploy-vacation": React.lazy(() => import('./views/tenant/conditional/DeployVacation')), "/tenant/conditional/test-policy": React.lazy(() => import('./views/tenant/conditional/TestCAPolicy')), "/tenant/conditional/list-named-locations": React.lazy(() => import('./views/tenant/conditional/NamedLocations')), @@ -53,7 +56,6 @@ import React from 'react' "/tenant/conditional/deploy-named-location": React.lazy(() => import('./views/tenant/conditional/DeployNamedLocation')), "/tenant/conditional/list-template": React.lazy(() => import('./views/tenant/conditional/ListCATemplates')), "/tenant/conditional/add-template": React.lazy(() => import('./views/tenant/conditional/AddCATemplate')), - "/tenant/administration/authentication-methods": React.lazy(() => import('./views/tenant/administration/AuthMethods')), "/tenant/administration/list-licenses": React.lazy(() => import('./views/tenant/administration/ListLicences')), "/tenant/administration/application-consent": React.lazy(() => import('./views/tenant/administration/ListOauthApps')), "/tenant/standards/list-applied-standards": React.lazy(() => import('./views/tenant/standards/ListAppliedStandards')), @@ -117,8 +119,8 @@ import React from 'react' "/email/administration/edit-calendar-permissions": React.lazy(() => import('./views/email-exchange/administration/EditCalendarPermissions')), "/email/administration/view-mobile-devices": React.lazy(() => import('./views/email-exchange/administration/ViewMobileDevices')), "/email/administration/edit-contact": React.lazy(() => import('./views/email-exchange/administration/EditContact')), - "/email/administration/mailboxes": React.lazy(() => import('./views/email-exchange/administration/MailboxesList')), - "/email/administration/deleted-mailboxes": React.lazy(() => import('./views/email-exchange/administration/DeletedMailboxes')), + "/email/administration/mailboxes": React.lazy(() => import('./views/email-exchange/administration/MailboxesList')), + "/email/administration/deleted-mailboxes": React.lazy(() => import('./views/email-exchange/administration/DeletedMailboxes')), "/email/administration/mailbox-rules": React.lazy(() => import('./views/email-exchange/administration/MailboxRuleList')), "/email/administration/Quarantine": React.lazy(() => import('./views/email-exchange/administration/QuarantineList')), "/email/administration/tenant-allow-block-lists": React.lazy(() => import('./views/email-exchange/administration/ListTenantAllowBlockList')), diff --git a/src/routes.json b/src/routes.json index 669c385e6d3d..96584165d77c 100644 --- a/src/routes.json +++ b/src/routes.json @@ -228,6 +228,20 @@ "name": "Administration", "allowedRoles": ["admin", "editor", "readonly"] }, + { + "path": "/tenant/backup/backup-wizard", + "name": "Backup", + "component": "views/tenant/backup/CreateBackup", + + "allowedRoles": ["admin", "editor", "readonly"] + }, + { + "path": "/tenant/backup/restore-wizard", + "name": "Restore Backup", + "component": "views/tenant/backup/RestoreBackup", + + "allowedRoles": ["admin", "editor", "readonly"] + }, { "path": "/tenant/administration/tenants", "name": "Tenants", diff --git a/src/views/tenant/backup/CreateBackup.jsx b/src/views/tenant/backup/CreateBackup.jsx new file mode 100644 index 000000000000..b694fc225efd --- /dev/null +++ b/src/views/tenant/backup/CreateBackup.jsx @@ -0,0 +1,267 @@ +import React, { useState } from 'react' +import { CButton, CCallout, CCol, CForm, CRow, CSpinner, CTooltip } from '@coreui/react' +import { useSelector } from 'react-redux' +import { Field, Form } from 'react-final-form' +import { 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' + +const CreateBackup = () => { + const [ExecuteGetRequest, getResults] = useLazyGenericGetRequestQuery() + const currentDate = new Date() + const [startDate, setStartDate] = useState(currentDate) + const [endDate, setEndDate] = useState(currentDate) + + 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) + //decrease by 45 seconds to ensure the task runs after the current time + const unixTime = Math.floor(startDate.getTime() / 1000) - 45 + const shippedValues = { + TenantFilter: tenantDomain, + Name: `CIPP Backup ${tenantDomain}`, + Command: { value: `New-CIPPBackup` }, + Parameters: { ...values }, + ScheduledTime: unixTime, + Recurrence: '1d', + } + genericPostRequest({ path: '/api/AddScheduledItem?hidden=true', values: shippedValues }).then( + (res) => { + setRefreshState(res.requestId) + }, + ) + } + const Offcanvas = (row, rowIndex, formatExtraData) => { + const handleDeleteSchedule = (apiurl, message) => { + ModalService.confirm({ + title: 'Confirm', + body:
{message}
, + onConfirm: () => + ExecuteGetRequest({ path: apiurl }).then((res) => { + setRefreshState(res.requestId) + }), + confirmLabel: 'Continue', + cancelLabel: 'Cancel', + }) + } + let jsonResults + try { + jsonResults = JSON.parse(row.Results) + } catch (error) { + jsonResults = row.Results + } + + return ( + <> + + + handleDeleteSchedule( + `/api/RemoveScheduledItem?&ID=${row.RowKey}`, + 'Do you want to delete this job?', + ) + } + size="sm" + variant="ghost" + color="danger" + > + + + + + ) + } + const columns = [ + { + name: 'Tenant', + selector: (row) => row['Tenant'], + sortable: true, + cell: (row) => CellTip(row['Tenant']), + exportSelector: 'Tenant', + }, + { + name: 'Task State', + selector: (row) => row['TaskState'], + sortable: true, + cell: cellBadgeFormatter(), + exportSelector: 'TaskState', + }, + { + name: 'Last executed time', + selector: (row) => row['ExecutedTime'], + sortable: true, + cell: cellDateFormatter({ format: 'relative' }), + exportSelector: 'ExecutedTime', + }, + { + name: 'Actions', + cell: Offcanvas, + maxWidth: '100px', + }, + ] + + const { + data: users = [], + isFetching: usersIsFetching, + error: usersError, + } = useGenericGetRequestQuery({ + path: '/api/ListGraphRequest', + params: { + TenantFilter: tenantDomain, + Endpoint: 'users', + $select: 'id,displayName,userPrincipalName,accountEnabled', + $count: true, + $top: 999, + $orderby: 'displayName', + }, + }) + + const { + data: caPolicies = [], + isFetching: caIsFetching, + error: caError, + } = useListConditionalAccessPoliciesQuery({ domain: tenantDomain }) + + return ( + + <> + + + + Create Backup Schedule + {postResults.isFetching && ( + + )} +
+ } + title="Add backup Schedule" + icon={faEdit} + > + { + return ( + +

+ Backups are stored in CIPPs storage and can be restored using the CIPP + Restore Backup Wizard. Backups run daily or on demand by clicking the backup + now button. +

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

Identity

+ + +

Conditional Access

+ + + +

Intune

+ + + +

CIPP

+ + +
+
+ {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 CreateBackup diff --git a/src/views/tenant/backup/RestoreBackup.jsx b/src/views/tenant/backup/RestoreBackup.jsx new file mode 100644 index 000000000000..161ddc2da6a3 --- /dev/null +++ b/src/views/tenant/backup/RestoreBackup.jsx @@ -0,0 +1,333 @@ +import React, { useState } from 'react' +import { CCallout, CCol, CListGroup, CListGroupItem, CRow, CSpinner, CTooltip } from '@coreui/react' +import { Field, FormSpy } from 'react-final-form' +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' +import { faExclamationTriangle, faTimes, faCheck } from '@fortawesome/free-solid-svg-icons' +import { useSelector } from 'react-redux' +import { CippCallout, CippWizard } from 'src/components/layout' +import PropTypes from 'prop-types' +import { Condition, RFFCFormSwitch, RFFSelectSearch } from 'src/components/forms' +import { TenantSelector } from 'src/components/utilities' +import { useGenericGetRequestQuery, useLazyGenericPostRequestQuery } from 'src/store/api/app' +import 'react-datepicker/dist/react-datepicker.css' + +const Error = ({ name }) => ( + + touched && error ? ( + + + {error} + + ) : null + } + /> +) + +Error.propTypes = { + name: PropTypes.string.isRequired, +} + +const OffboardingWizard = () => { + const tenantDomain = useSelector((state) => state.app.currentTenant.defaultDomainName) + const { + data: currentBackups = [], + isFetching: currentBackupsIsFetching, + error: currentBackupsError, + } = useGenericGetRequestQuery({ + path: `/api/ExecListBackup?TenantFilter=${tenantDomain}&Type=Scheduled`, + }) + + const [genericPostRequest, postResults] = useLazyGenericPostRequestQuery() + + const handleSubmit = async (values) => { + const shippedValues = { + TenantFilter: tenantDomain, + OOO: values.OOO ? values.OOO : '', + forward: values.forward ? values.forward.value : '', + OnedriveAccess: values.OnedriveAccess ? values.OnedriveAccess : '', + AccessNoAutomap: values.AccessNoAutomap ? values.AccessNoAutomap : '', + AccessAutomap: values.AccessAutomap ? values.AccessAutomap : '', + ConvertToShared: values.ConvertToShared, + HideFromGAL: values.HideFromGAL, + DisableSignIn: values.DisableSignIn, + RemoveGroups: values.RemoveGroups, + RemoveLicenses: values.RemoveLicenses, + ResetPass: values.ResetPass, + RevokeSessions: values.RevokeSessions, + user: values.User, + deleteuser: values.DeleteUser, + removeRules: values.RemoveRules, + removeMobile: values.RemoveMobile, + keepCopy: values.keepCopy, + removePermissions: values.removePermissions, + PostExecution: values.Scheduled?.enabled + ? { webhook: values.webhook, psa: values.psa, email: values.email } + : '', + } + + //alert(JSON.stringify(values, null, 2)) + genericPostRequest({ path: '/api/ExecOffboardUser', values: shippedValues }) + } + + return ( + + +
    +

    Step 1

    +
    Choose a tenant
    +
    +
    + {(props) => } +
    +
    + +
    +

    Step 2

    +
    Select the backup to restore
    +
    +
    +
    + ({ + value: backup.RowKey, + name: `${backup.BackupDate}`, + }))} + placeholder={!currentBackupsIsFetching ? 'Select a backup' : 'Loading...'} + name="User" + /> + {currentBackupsError && Failed to load list of Current Backups} +
    +
    +
    + +
    +

    Step 3

    +
    Choose restore options
    +
    +
    +
    + + +

    Identity

    + + +

    Conditional Access

    + + + +
    + +

    Intune

    + + + +

    CIPP

    + + +
    +
    +
    + + + + + + + +
    Warning
    +

    + Overwriting existing entries will remove the current settings and replace them with + the backup settings. If you have selected to restore users, all properties will be + overwritten with the backup settings. +

    + +

    + To prevent and skip already existing entries, deselect the setting from the list + above, or disable overwrite. +

    +
    +
    +
    +
    +
    + +
    +

    Step 4

    +
    Confirm and apply
    +
    +
    +
    + {postResults.isFetching && ( + + Loading + + )} + {postResults.isSuccess && ( + + {postResults.data.Results.map((message, idx) => { + return
  • {message}
  • + })} +
    + )} + {!postResults.isSuccess && ( + + {/* eslint-disable react/prop-types */} + {(props) => ( + <> + + + + +
    Selected Tenant:
    + {tenantDomain} +
    +
    +
    +
    +
    + + + + + Revoke Sessions + + + + Remove all mobile devices + + + + Remove all mailbox rules + + + + Remove all mailbox permissions + + + + Remove Licenses + + + + Convert to Shared + + + + Disable Sign-in + + + + Reset Password + + + + Remove from all groups + + + + Hide from Global Address List + + + + Set Out of Office + + + + Give another user access to the mailbox with automap + + + + Give another user access to the mailbox without automap + + + + Give another user access to OneDrive + + + + Forward all e-mail to another user + + + + + + + )} +
    + )} +
    +
    +
    +
    + ) +} + +export default OffboardingWizard From 5b0b3ea95f8f85d80925c9732559be86d25af485 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Fri, 5 Jul 2024 00:11:26 +0200 Subject: [PATCH 24/58] improvements createbackup --- src/views/tenant/backup/CreateBackup.jsx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/views/tenant/backup/CreateBackup.jsx b/src/views/tenant/backup/CreateBackup.jsx index b694fc225efd..d00a37305ac1 100644 --- a/src/views/tenant/backup/CreateBackup.jsx +++ b/src/views/tenant/backup/CreateBackup.jsx @@ -31,16 +31,15 @@ const CreateBackup = () => { const onSubmit = (values) => { const startDate = new Date() - startDate.setHours(0, 0, 0, 0) //decrease by 45 seconds to ensure the task runs after the current time const unixTime = Math.floor(startDate.getTime() / 1000) - 45 const shippedValues = { TenantFilter: tenantDomain, Name: `CIPP Backup ${tenantDomain}`, Command: { value: `New-CIPPBackup` }, - Parameters: { ...values }, + Parameters: { backupType: 'Scheduled', ScheduledBackupValues: { ...values } }, ScheduledTime: unixTime, - Recurrence: '1d', + Recurrence: { value: '1d' }, } genericPostRequest({ path: '/api/AddScheduledItem?hidden=true', values: shippedValues }).then( (res) => { From 7fd312889b94df312d1d74fb601df230ed3e6c01 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Fri, 5 Jul 2024 12:58:41 +0200 Subject: [PATCH 25/58] fixes external sender --- src/store/api/groups.js | 3 ++- .../identity/administration/EditGroup.jsx | 24 +++++++------------ 2 files changed, 10 insertions(+), 17 deletions(-) diff --git a/src/store/api/groups.js b/src/store/api/groups.js index faf6f32bd46e..59316ad90f02 100644 --- a/src/store/api/groups.js +++ b/src/store/api/groups.js @@ -60,11 +60,12 @@ export const groupsApi = baseApi.injectEndpoints({ }), }), listGroupSenderAuth: builder.query({ - query: ({ tenantDomain, groupId }) => ({ + query: ({ tenantDomain, groupId, type }) => ({ path: '/api/ListGroupSenderAuthentication', params: { TenantFilter: tenantDomain, GroupId: groupId, + Type: type, }, }), }), diff --git a/src/views/identity/administration/EditGroup.jsx b/src/views/identity/administration/EditGroup.jsx index 7f3bd6af78a8..2c74c0542a2c 100644 --- a/src/views/identity/administration/EditGroup.jsx +++ b/src/views/identity/administration/EditGroup.jsx @@ -42,13 +42,6 @@ const EditGroup = () => { isSuccess, } = useListGroupQuery({ tenantDomain, groupId }) - const { - data: SenderAuth = {}, - isFetching: SenderAuthisFetching, - error: SenderAuthError, - isSuccess: SenderAuthIsSuccess, - } = useListGroupSenderAuthQuery({ tenantDomain, groupId }) - const { data: members = [], isFetching: membersisFetching, @@ -96,6 +89,13 @@ const EditGroup = () => { } }, [owners, members, ownersIsSuccess, membersIsSuccess, postResults]) + const { + data: SenderAuth = {}, + isFetching: SenderAuthisFetching, + error: SenderAuthError, + isSuccess: SenderAuthIsSuccess, + } = useListGroupSenderAuthQuery({ tenantDomain, groupId, type: group?.[0]?.calculatedGroupType }) + useEffect(() => { if (!groupId || !tenantDomain) { ModalService.open({ @@ -166,7 +166,7 @@ const EditGroup = () => { initialValues={{ ...(group[0].calculatedGroupType === 'Microsoft 365' || group[0].calculatedGroupType === 'Distribution List' - ? { allowExternal: !SenderAuth.enabled } + ? { allowExternal: SenderAuth.allowedToReceiveExternal } : {}), }} render={({ handleSubmit, submitting, values }) => { @@ -323,14 +323,6 @@ const EditGroup = () => { This is the (raw) information for this group.
    {JSON.stringify(group, null, 2)}
    -
    - This is the (raw) information for SenderAuth. - {SenderAuthisFetching && } - {SenderAuthIsSuccess &&
    {JSON.stringify(SenderAuth, null, 2)}
    } - {SenderAuthError && ( -
    Error fetching SenderAuth data: {SenderAuthError.message}
    - )} -
    )} From 0c0b5d8ab278274003c78b5373e5424203d0e4a8 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Fri, 5 Jul 2024 16:36:17 +0200 Subject: [PATCH 26/58] added cell copy button --- src/components/tables/CellCopyButton.jsx | 18 ++++++++++++++++++ .../teams-share/sharepoint/SharepointList.jsx | 10 ++++++++++ 2 files changed, 28 insertions(+) create mode 100644 src/components/tables/CellCopyButton.jsx diff --git a/src/components/tables/CellCopyButton.jsx b/src/components/tables/CellCopyButton.jsx new file mode 100644 index 000000000000..eeed76d73478 --- /dev/null +++ b/src/components/tables/CellCopyButton.jsx @@ -0,0 +1,18 @@ +import PropTypes from 'prop-types' +import CippCopyToClipboard from '../utilities/CippCopyToClipboard' + +export function CellCopyButton({ cell }) { + console.log('hi! cell:', cell) + return +} + +CellCopyButton.propTypes = { + propName: PropTypes.string, + cell: PropTypes.object, +} + +export const cellCopyButtonFormatter = () => (row, index, column, id) => { + const cell = column.selector(row) + console.log('cell:', cell) + return CellCopyButton({ cell }) +} diff --git a/src/views/teams-share/sharepoint/SharepointList.jsx b/src/views/teams-share/sharepoint/SharepointList.jsx index a93bb7c01250..b117b7a7ffb0 100644 --- a/src/views/teams-share/sharepoint/SharepointList.jsx +++ b/src/views/teams-share/sharepoint/SharepointList.jsx @@ -5,7 +5,9 @@ import React, { useState } from 'react' import { useSelector } from 'react-redux' import { CippPageList } from 'src/components/layout' import { CellTip } from 'src/components/tables' +import { cellCopyButtonFormatter } from 'src/components/tables/CellCopyButton' import { CippActionsOffcanvas } from 'src/components/utilities' +import CippCopyToClipboard from 'src/components/utilities/CippCopyToClipboard' const SharepointList = () => { const tenant = useSelector((state) => state.app.currentTenant) @@ -167,6 +169,14 @@ const SharepointList = () => { exportSelector: 'Template', maxWidth: '200px', }, + { + name: 'Automapping URL', + selector: (row) => row['AutoMapUrl'], + sortable: true, + cell: cellCopyButtonFormatter(), + exportSelector: 'AutoMapUrl', + maxWidth: '70px', + }, { name: 'Actions', cell: Offcanvas, From 6b0d25f989fa931b141ddce4ed88093c67c825ee Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Fri, 5 Jul 2024 16:38:13 +0200 Subject: [PATCH 27/58] add sharepoint list stuff --- src/views/teams-share/sharepoint/SharepointList.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/views/teams-share/sharepoint/SharepointList.jsx b/src/views/teams-share/sharepoint/SharepointList.jsx index b117b7a7ffb0..d5691b35f256 100644 --- a/src/views/teams-share/sharepoint/SharepointList.jsx +++ b/src/views/teams-share/sharepoint/SharepointList.jsx @@ -175,7 +175,7 @@ const SharepointList = () => { sortable: true, cell: cellCopyButtonFormatter(), exportSelector: 'AutoMapUrl', - maxWidth: '70px', + maxWidth: '170px', }, { name: 'Actions', From ac76cb8fe5887dadfd92a384a8be410ffc52afba Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Fri, 5 Jul 2024 17:28:05 +0200 Subject: [PATCH 28/58] updated list of offboarding items --- src/views/identity/administration/OffboardingWizard.jsx | 8 ++++++++ src/views/tenant/backup/CreateBackup.jsx | 4 ---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/views/identity/administration/OffboardingWizard.jsx b/src/views/identity/administration/OffboardingWizard.jsx index 4d6c496951f8..bb724ad3593d 100644 --- a/src/views/identity/administration/OffboardingWizard.jsx +++ b/src/views/identity/administration/OffboardingWizard.jsx @@ -445,6 +445,14 @@ const OffboardingWizard = () => { icon={props.values.forward ? faCheck : faTimes} /> + + Delete User + + diff --git a/src/views/tenant/backup/CreateBackup.jsx b/src/views/tenant/backup/CreateBackup.jsx index d00a37305ac1..bff94e70983c 100644 --- a/src/views/tenant/backup/CreateBackup.jsx +++ b/src/views/tenant/backup/CreateBackup.jsx @@ -21,10 +21,6 @@ import { cellBadgeFormatter, cellDateFormatter } from 'src/components/tables' const CreateBackup = () => { const [ExecuteGetRequest, getResults] = useLazyGenericGetRequestQuery() - const currentDate = new Date() - const [startDate, setStartDate] = useState(currentDate) - const [endDate, setEndDate] = useState(currentDate) - const tenantDomain = useSelector((state) => state.app.currentTenant.defaultDomainName) const [refreshState, setRefreshState] = useState(false) const [genericPostRequest, postResults] = useLazyGenericPostRequestQuery() From 018b0d09aac940701833d72c66c0f5a37774346c Mon Sep 17 00:00:00 2001 From: John Duprey Date: Fri, 5 Jul 2024 12:39:42 -0400 Subject: [PATCH 29/58] Fix automapping --- src/views/cipp/ExtensionMappings.jsx | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/views/cipp/ExtensionMappings.jsx b/src/views/cipp/ExtensionMappings.jsx index c7bffa53f624..d2fc8c48dbd2 100644 --- a/src/views/cipp/ExtensionMappings.jsx +++ b/src/views/cipp/ExtensionMappings.jsx @@ -52,16 +52,17 @@ export default function ExtensionMappings({ type, fieldMappings = false, autoMap }) } - const newMappings = listMappingBackendResult.data?.Tenants.map((tenant) => { + var newMappings = [] + listMappingBackendResult.data?.Tenants.map((tenant) => { const company = listMappingBackendResult.data?.Companies.find( (client) => client.name === tenant.displayName, ) - if (company) { - return { + if (company !== undefined && !mappingArray.find((item) => item.companyId === company.value)) { + newMappings.push({ Tenant: tenant, companyName: company.name, companyId: company.value, - } + }) } }) setMappingArray((currentMappings) => [...currentMappings, ...newMappings]) @@ -87,7 +88,7 @@ export default function ExtensionMappings({ type, fieldMappings = false, autoMap })), ) } - }, [listMappingBackendResult]) + }, [listMappingBackendResult, setMappingArray]) const Actions = (row, rowIndex, formatExtraData) => { return ( From 56773090749c230b0f341b8ba1804c632c952b5a Mon Sep 17 00:00:00 2001 From: John Duprey Date: Fri, 5 Jul 2024 12:48:08 -0400 Subject: [PATCH 30/58] Update recommended extensions and dev workflow --- .github/workflows/dev_deploy.yml | 6 +----- .vscode/extensions.json | 3 ++- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/.github/workflows/dev_deploy.yml b/.github/workflows/dev_deploy.yml index 1f5a0ee5feb6..6e1c3fe8b8c6 100644 --- a/.github/workflows/dev_deploy.yml +++ b/.github/workflows/dev_deploy.yml @@ -4,14 +4,10 @@ on: push: branches: - dev - pull_request: - types: [opened, synchronize, reopened, closed] - branches: - - dev jobs: build_and_deploy_job: - if: github.event.repository.fork == false && github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.action != 'closed') + if: github.event.repository.fork == false && github.event_name == 'push' runs-on: ubuntu-latest name: Build and Deploy Job steps: diff --git a/.vscode/extensions.json b/.vscode/extensions.json index d42c5d5a7c44..c21abba6989f 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -5,6 +5,7 @@ "eg2.vscode-npm-script", "christian-kohler.npm-intellisense", "esbenp.prettier-vscode", - "stylelint.vscode-stylelint" + "stylelint.vscode-stylelint", + "editorconfig.editorconfig" ] } From 340d09b8f134141e22763376e375e1573c7d50d5 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Fri, 5 Jul 2024 22:18:49 +0200 Subject: [PATCH 31/58] convert to string for backup tasks --- src/views/tenant/backup/CreateBackup.jsx | 2 +- src/views/tenant/backup/RestoreBackup.jsx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/views/tenant/backup/CreateBackup.jsx b/src/views/tenant/backup/CreateBackup.jsx index bff94e70983c..028b3c91f31d 100644 --- a/src/views/tenant/backup/CreateBackup.jsx +++ b/src/views/tenant/backup/CreateBackup.jsx @@ -27,7 +27,7 @@ const CreateBackup = () => { const onSubmit = (values) => { const startDate = new Date() - //decrease by 45 seconds to ensure the task runs after the current time + startDate.setHours(0, 0, 0, 0) const unixTime = Math.floor(startDate.getTime() / 1000) - 45 const shippedValues = { TenantFilter: tenantDomain, diff --git a/src/views/tenant/backup/RestoreBackup.jsx b/src/views/tenant/backup/RestoreBackup.jsx index 161ddc2da6a3..be1da6530dab 100644 --- a/src/views/tenant/backup/RestoreBackup.jsx +++ b/src/views/tenant/backup/RestoreBackup.jsx @@ -37,7 +37,7 @@ const OffboardingWizard = () => { isFetching: currentBackupsIsFetching, error: currentBackupsError, } = useGenericGetRequestQuery({ - path: `/api/ExecListBackup?TenantFilter=${tenantDomain}&Type=Scheduled`, + path: `/api/ExecListBackup?TenantFilter=${tenantDomain}`, }) const [genericPostRequest, postResults] = useLazyGenericPostRequestQuery() @@ -96,7 +96,7 @@ const OffboardingWizard = () => { ({ + values={currentBackups?.map((backup) => ({ value: backup.RowKey, name: `${backup.BackupDate}`, }))} From 1da1cff63baf5c26b71f5856850d370ec6b67a6a Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Fri, 5 Jul 2024 22:23:52 +0200 Subject: [PATCH 32/58] fixes backup list --- src/views/tenant/backup/RestoreBackup.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/views/tenant/backup/RestoreBackup.jsx b/src/views/tenant/backup/RestoreBackup.jsx index be1da6530dab..d106469d8949 100644 --- a/src/views/tenant/backup/RestoreBackup.jsx +++ b/src/views/tenant/backup/RestoreBackup.jsx @@ -37,7 +37,7 @@ const OffboardingWizard = () => { isFetching: currentBackupsIsFetching, error: currentBackupsError, } = useGenericGetRequestQuery({ - path: `/api/ExecListBackup?TenantFilter=${tenantDomain}`, + path: `/api/ExecListBackup?TenantFilter=${tenantDomain}&Type=Scheduled`, }) const [genericPostRequest, postResults] = useLazyGenericPostRequestQuery() @@ -98,7 +98,7 @@ const OffboardingWizard = () => { label={'Backups for ' + tenantDomain} values={currentBackups?.map((backup) => ({ value: backup.RowKey, - name: `${backup.BackupDate}`, + name: `${backup.RowKey}`, }))} placeholder={!currentBackupsIsFetching ? 'Select a backup' : 'Loading...'} name="User" From 75d096e54d0f647e05c286adf9def945193f83cb Mon Sep 17 00:00:00 2001 From: John Duprey Date: Sat, 6 Jul 2024 00:39:40 -0400 Subject: [PATCH 33/58] Improve UI for extensions Add button icons --- src/data/Extensions.json | 17 +++++++---- src/views/cipp/ExtensionMappings.jsx | 42 +++++++++++++++++++--------- src/views/cipp/Extensions.jsx | 34 +++++++++++++--------- 3 files changed, 62 insertions(+), 31 deletions(-) diff --git a/src/data/Extensions.json b/src/data/Extensions.json index e46565493f28..6d4b8ab242f0 100644 --- a/src/data/Extensions.json +++ b/src/data/Extensions.json @@ -122,7 +122,7 @@ "type": "input", "fieldtype": "input", "name": "NinjaOne.Instance", - "label": "Please enter your NinjaOne Instance", + "label": "Please enter your NinjaOne Instance hostname", "placeholder": "app.ninjarmm.com, eu.ninjarmm.com, oc.ninjarmm.com, ca.ninjarmm.com, us2.ninjarmm.com" }, { @@ -162,7 +162,8 @@ ], "mappingRequired": true, "fieldMapping": true, - "autoMapSyncApi": true + "autoMapSyncApi": true, + "showSyncButton": true }, { "name": "Hudu", @@ -187,8 +188,13 @@ }, { "type": "checkbox", - "name": "Hudu.LicensedUsersOnly", - "label": "Only Sync Licensed Users" + "name": "Hudu.CreateMissingUsers", + "label": "Create missing users in Hudu" + }, + { + "type": "checkbox", + "name": "Hudu.CreateMissingDevices", + "label": "Create missing devices in Hudu" }, { "type": "checkbox", @@ -197,7 +203,8 @@ } ], "mappingRequired": true, - "fieldMapping": true + "fieldMapping": true, + "showSyncButton": true }, { "name": "PasswordPusher", diff --git a/src/views/cipp/ExtensionMappings.jsx b/src/views/cipp/ExtensionMappings.jsx index d2fc8c48dbd2..0e956d917771 100644 --- a/src/views/cipp/ExtensionMappings.jsx +++ b/src/views/cipp/ExtensionMappings.jsx @@ -158,16 +158,29 @@ export default function ExtensionMappings({ type, fieldMappings = false, autoMap isFetching={listMappingBackendResult.isFetching} CardButton={ <> - - {extensionConfigResult.isFetching && ( - - )} - Set Mappings + + + Save Mappings - onOrgsAutomap()} className="me-2"> - {extensionAutomapResult.isFetching && ( - - )} + onOrgsAutomap()} + className="me-2" + disabled={listMappingBackendResult.isFetching} + > + Automap {type} Organizations @@ -313,10 +326,13 @@ export default function ExtensionMappings({ type, fieldMappings = false, autoMap isFetching={listFieldsBackendResult.isFetching} CardButton={ - {extensionFieldsConfigResult.isFetching && ( - - )} - Set Mappings + + Save Mappings } > diff --git a/src/views/cipp/Extensions.jsx b/src/views/cipp/Extensions.jsx index d08ac0636174..a88fe9931c01 100644 --- a/src/views/cipp/Extensions.jsx +++ b/src/views/cipp/Extensions.jsx @@ -45,16 +45,20 @@ export default function CIPPExtensions() { const ButtonGenerate = (integrationType, forceSync, disabled) => ( <> - {extensionConfigResult.isFetching && ( - - )} - Set Extension Settings + + Save onSubmitTest(integrationType)} className="me-2"> - {listExtensionTestResult.isFetching && ( - - )} - Test Extension + + Test {forceSync && ( - {listSyncExtensionResult.isFetching && ( - - )} + Force Sync )} @@ -118,8 +124,10 @@ export default function CIPPExtensions() { isFetching={listBackendResult.isFetching} CardButton={ButtonGenerate( integration.type, - integration.forceSync, - (hostedMetaContent === 'true' && integration.disableWhenhosted) || false, + integration.forceSyncButton, + (hostedMetaContent === 'true' && integration.disableWhenhosted) || + listBackendResult.isFetching || + false, )} key={idx} > From 4649af9888c941e69467f4b9abf021dbd95edfd6 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Sat, 6 Jul 2024 12:23:32 -0400 Subject: [PATCH 34/58] Extension layout fixes Remove extra vertical height when mapping is present Remove padding from mapping org/field cards --- src/components/contentcards/CippButtonCard.jsx | 4 +++- src/views/cipp/ExtensionMappings.jsx | 2 ++ src/views/cipp/Extensions.jsx | 1 + 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/components/contentcards/CippButtonCard.jsx b/src/components/contentcards/CippButtonCard.jsx index 4a6400ad9cca..8e74d5470693 100644 --- a/src/components/contentcards/CippButtonCard.jsx +++ b/src/components/contentcards/CippButtonCard.jsx @@ -9,9 +9,10 @@ export default function CippButtonCard({ CardButton, children, isFetching, + className = 'h-100', }) { return ( - + {titleType === 'big' ?

    {title}

    : title} @@ -32,4 +33,5 @@ CippButtonCard.propTypes = { CardButton: PropTypes.element.isRequired, children: PropTypes.element.isRequired, isFetching: PropTypes.bool.isRequired, + className: PropTypes.string, } diff --git a/src/views/cipp/ExtensionMappings.jsx b/src/views/cipp/ExtensionMappings.jsx index 0e956d917771..b493dce041a2 100644 --- a/src/views/cipp/ExtensionMappings.jsx +++ b/src/views/cipp/ExtensionMappings.jsx @@ -156,6 +156,7 @@ export default function ExtensionMappings({ type, fieldMappings = false, autoMap title={`${type} Organization Mapping`} titleType="big" isFetching={listMappingBackendResult.isFetching} + className="px-0" CardButton={ <>

    {integration.helpText}

    Date: Sat, 6 Jul 2024 16:52:59 -0500 Subject: [PATCH 35/58] Added removeCalendarInvites --- .../identity/administration/OffboardingWizard.jsx | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/views/identity/administration/OffboardingWizard.jsx b/src/views/identity/administration/OffboardingWizard.jsx index bb724ad3593d..d7008c071724 100644 --- a/src/views/identity/administration/OffboardingWizard.jsx +++ b/src/views/identity/administration/OffboardingWizard.jsx @@ -82,6 +82,7 @@ const OffboardingWizard = () => { HideFromGAL: values.HideFromGAL, DisableSignIn: values.DisableSignIn, RemoveGroups: values.RemoveGroups, + removeCalendarInvites: values.removeCalendarInvites, RemoveLicenses: values.RemoveLicenses, ResetPass: values.ResetPass, RevokeSessions: values.RevokeSessions, @@ -175,6 +176,7 @@ const OffboardingWizard = () => { + @@ -397,6 +399,14 @@ const OffboardingWizard = () => { icon={props.values.RemoveGroups ? faCheck : faTimes} /> + + Cancel all calendar invites + + Hide from Global Address List Date: Sun, 7 Jul 2024 19:49:53 +0200 Subject: [PATCH 36/58] allow app deployment via standards --- src/data/standards.json | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/data/standards.json b/src/data/standards.json index 803199755bdc..df673c360d2f 100644 --- a/src/data/standards.json +++ b/src/data/standards.json @@ -224,6 +224,25 @@ "powershellEquivalent": "Portal or Graph API", "recommendedBy": ["CIS"] }, + { + "name": "standards.AppDeploy", + "cat": "Entra (AAD) Standards", + "tag": ["lowimpact"], + "helpText": "Deploys selected applications to the tenant. Use a comma separated list of application IDs to deploy multiple applications. Permissions will be copied from the source application.", + "docsDescription": "Uses the CIPP functionality that deploys applications across an entire tenant base as a standard.", + "addedComponent": [ + { + "type": "input", + "name": "standards.AppDeploy.appids", + "label": "Application IDs, comma separated" + } + ], + "label": "Deploy Application", + "impact": "Low Impact", + "impactColour": "info", + "powershellEquivalent": "Portal or Graph API", + "recommendedBy": [] + }, { "name": "standards.laps", "cat": "Entra (AAD) Standards", From 130237c5aa54530f4bac671eb957d0a5e84d6711 Mon Sep 17 00:00:00 2001 From: Esco Date: Fri, 5 Jul 2024 16:04:24 +0200 Subject: [PATCH 37/58] Added SPAzureB2B standard --- src/data/standards.json | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/data/standards.json b/src/data/standards.json index df673c360d2f..506dcd63cdce 100644 --- a/src/data/standards.json +++ b/src/data/standards.json @@ -1816,6 +1816,20 @@ "powershellEquivalent": "Update-MgBetaAdminSharepointSetting", "recommendedBy": [] }, + { + "name": "standards.SPAzureB2B", + "cat": "SharePoint Standards", + "tag": ["lowimpact", "CIS"], + "helpText": "Ensure SharePoint and OneDrive integration with Azure AD B2B is enabled", + "addedComponent": [], + "label": "Enable SharePoint and OneDrive integration with Azure AD B2B", + "impact": "Low Impact", + "impactColour": "info", + "powershellEquivalent": "Set-SPOTenant -EnableAzureADB2BIntegration $true", + "recommendedBy": [ + "CIS 3.0" + ] + }, { "name": "standards.DisableAddShortcutsToOneDrive", "cat": "SharePoint Standards", From c12f31e81da059aa88abcac2ac6e88196093d573 Mon Sep 17 00:00:00 2001 From: Esco Date: Fri, 5 Jul 2024 16:04:51 +0200 Subject: [PATCH 38/58] Added SPDirectSharing standard --- src/data/standards.json | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/data/standards.json b/src/data/standards.json index 506dcd63cdce..c91e5c593515 100644 --- a/src/data/standards.json +++ b/src/data/standards.json @@ -1830,6 +1830,20 @@ "CIS 3.0" ] }, + { + "name": "standards.SPDirectSharing", + "cat": "SharePoint Standards", + "tag": ["mediumimpact", "CIS"], + "helpText": "Ensure default link sharing is set to Direct in SharePoint and OneDrive", + "addedComponent": [], + "label": "Default sharing to Direct users", + "impact": "Medium Impact", + "impactColour": "warning", + "powershellEquivalent": "Set-SPOTenant -DefaultSharingLinkType Direct", + "recommendedBy": [ + "CIS 3.0" + ] + }, { "name": "standards.DisableAddShortcutsToOneDrive", "cat": "SharePoint Standards", From c178380bb3c1c6b6858506dcd4c40d626d867977 Mon Sep 17 00:00:00 2001 From: Esco Date: Mon, 8 Jul 2024 13:38:46 +0200 Subject: [PATCH 39/58] Added SPExternalUserExpiration Standard --- src/data/standards.json | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/data/standards.json b/src/data/standards.json index c91e5c593515..adc9f61c5a5f 100644 --- a/src/data/standards.json +++ b/src/data/standards.json @@ -1844,6 +1844,26 @@ "CIS 3.0" ] }, + { + "name": "standards.SPExternalUserExpiration", + "cat": "SharePoint Standards", + "tag": ["mediumimpact", "CIS"], + "helpText": "Ensure guest access to a site or OneDrive will expire automatically", + "addedComponent": [ + { + "type": "number", + "name": "standards.SPExternalUserExpiration.Days", + "label": "Days until expiration (Default 60)" + } + ], + "label": "Set guest access to expire automatically", + "impact": "Medium Impact", + "impactColour": "warning", + "powershellEquivalent": "Set-SPOTenant -ExternalUserExpireInDays 30 -ExternalUserExpirationRequired $True", + "recommendedBy": [ + "CIS 3.0" + ] + }, { "name": "standards.DisableAddShortcutsToOneDrive", "cat": "SharePoint Standards", From e1e1a5a9655ebfa934ecb5679d6649f4080a5994 Mon Sep 17 00:00:00 2001 From: Esco Date: Mon, 8 Jul 2024 14:02:42 +0200 Subject: [PATCH 40/58] Added SPEmailAttestation standard --- src/data/standards.json | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/data/standards.json b/src/data/standards.json index adc9f61c5a5f..c1c338253bc1 100644 --- a/src/data/standards.json +++ b/src/data/standards.json @@ -1864,6 +1864,26 @@ "CIS 3.0" ] }, + { + "name": "standards.SPEmailAttestation", + "cat": "SharePoint Standards", + "tag": ["mediumimpact", "CIS"], + "helpText": "Ensure reauthentication with verification code is restricted", + "addedComponent": [ + { + "type": "number", + "name": "standards.SPEmailAttestation.Days", + "label": "Require reauth every X Days (Default 15)" + } + ], + "label": "Require reauthentication with verification code", + "impact": "Medium Impact", + "impactColour": "warning", + "powershellEquivalent": "Set-SPOTenant -EmailAttestationRequired $true -EmailAttestationReAuthDays 15", + "recommendedBy": [ + "CIS 3.0" + ] + }, { "name": "standards.DisableAddShortcutsToOneDrive", "cat": "SharePoint Standards", From 2ab99a075637d7690c99d343b841cc12a3ada307 Mon Sep 17 00:00:00 2001 From: Esco Date: Mon, 8 Jul 2024 14:15:37 +0200 Subject: [PATCH 41/58] Added SPDisallowInfectedFiles standard --- src/data/standards.json | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/data/standards.json b/src/data/standards.json index c1c338253bc1..ff0286d5f381 100644 --- a/src/data/standards.json +++ b/src/data/standards.json @@ -1830,6 +1830,20 @@ "CIS 3.0" ] }, + { + "name": "standards.SPDisallowInfectedFiles", + "cat": "SharePoint Standards", + "tag": ["lowimpact", "CIS"], + "helpText": "Ensure Office 365 SharePoint infected files are disallowed for download", + "addedComponent": [], + "label": "Disallow downloading infected files from SharePoint", + "impact": "Low Impact", + "impactColour": "info", + "powershellEquivalent": "Set-SPOTenant -DisallowInfectedFileDownload $true", + "recommendedBy": [ + "CIS 3.0" + ] + }, { "name": "standards.SPDirectSharing", "cat": "SharePoint Standards", From 924d661a5738bb4db9ba9f71203aa1e55e0ed04f Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Mon, 8 Jul 2024 14:25:55 +0200 Subject: [PATCH 42/58] added task to restore --- src/views/tenant/backup/RestoreBackup.jsx | 215 ++++++---------------- 1 file changed, 61 insertions(+), 154 deletions(-) diff --git a/src/views/tenant/backup/RestoreBackup.jsx b/src/views/tenant/backup/RestoreBackup.jsx index d106469d8949..aa34d219f9ac 100644 --- a/src/views/tenant/backup/RestoreBackup.jsx +++ b/src/views/tenant/backup/RestoreBackup.jsx @@ -42,34 +42,22 @@ const OffboardingWizard = () => { const [genericPostRequest, postResults] = useLazyGenericPostRequestQuery() - const handleSubmit = async (values) => { + const handleSubmit = (values) => { + const startDate = new Date() + const unixTime = Math.floor(startDate.getTime() / 1000) - 45 const shippedValues = { TenantFilter: tenantDomain, - OOO: values.OOO ? values.OOO : '', - forward: values.forward ? values.forward.value : '', - OnedriveAccess: values.OnedriveAccess ? values.OnedriveAccess : '', - AccessNoAutomap: values.AccessNoAutomap ? values.AccessNoAutomap : '', - AccessAutomap: values.AccessAutomap ? values.AccessAutomap : '', - ConvertToShared: values.ConvertToShared, - HideFromGAL: values.HideFromGAL, - DisableSignIn: values.DisableSignIn, - RemoveGroups: values.RemoveGroups, - RemoveLicenses: values.RemoveLicenses, - ResetPass: values.ResetPass, - RevokeSessions: values.RevokeSessions, - user: values.User, - deleteuser: values.DeleteUser, - removeRules: values.RemoveRules, - removeMobile: values.RemoveMobile, - keepCopy: values.keepCopy, - removePermissions: values.removePermissions, - PostExecution: values.Scheduled?.enabled - ? { webhook: values.webhook, psa: values.psa, email: values.email } - : '', + Name: `CIPP Restore ${tenantDomain}`, + Command: { value: `New-CIPPRestore` }, + Parameters: { Type: 'Scheduled', ScheduledBackupValues: { ...values } }, + ScheduledTime: unixTime, + PostExecution: { + Webhook: values.webhook, + Email: values.email, + PSA: values.psa, + }, } - - //alert(JSON.stringify(values, null, 2)) - genericPostRequest({ path: '/api/ExecOffboardUser', values: shippedValues }) + genericPostRequest({ path: '/api/AddScheduledItem', values: shippedValues }).then((res) => {}) } return ( @@ -101,7 +89,7 @@ const OffboardingWizard = () => { name: `${backup.RowKey}`, }))} placeholder={!currentBackupsIsFetching ? 'Select a backup' : 'Loading...'} - name="User" + name="backup" /> {currentBackupsError && Failed to load list of Current Backups} @@ -117,21 +105,21 @@ const OffboardingWizard = () => {

    Identity

    - - + +

    Conditional Access

    - - - + + +

    Intune

    - - - + + +

    CIPP

    - - + +

    @@ -139,22 +127,31 @@ const OffboardingWizard = () => { - - - -
    Warning
    -

    - Overwriting existing entries will remove the current settings and replace them with - the backup settings. If you have selected to restore users, all properties will be - overwritten with the backup settings. -

    + + +
    Warning
    +

    + Overwriting existing entries will remove the current settings and replace them + with the backup settings. If you have selected to restore users, all properties + will be overwritten with the backup settings. +

    -

    - To prevent and skip already existing entries, deselect the setting from the list - above, or disable overwrite. -

    -
    -
    +

    + To prevent and skip already existing entries, deselect the setting from the list + above, or disable overwrite. +

    +
    +
    + +
    + + + + + + + +
    @@ -170,13 +167,7 @@ const OffboardingWizard = () => { Loading )} - {postResults.isSuccess && ( - - {postResults.data.Results.map((message, idx) => { - return
  • {message}
  • - })} -
    - )} + {postResults.isSuccess && {postResults.data.Results}} {!postResults.isSuccess && ( {/* eslint-disable react/prop-types */} @@ -189,6 +180,10 @@ const OffboardingWizard = () => {
    Selected Tenant:
    {tenantDomain}
    + +
    Selected Backup:
    + {props.values.backup.value} +

    @@ -197,123 +192,35 @@ const OffboardingWizard = () => { - Revoke Sessions - - - - Remove all mobile devices - - - - Remove all mailbox rules - - - - Remove all mailbox permissions - - - - Remove Licenses - - - - Convert to Shared - - - - Disable Sign-in - - - - Reset Password - - - - Remove from all groups - - - - Hide from Global Address List - - - - Set Out of Office - - - - Give another user access to the mailbox with automap + Overwrite existing configuration - Give another user access to the mailbox without automap + Send results to Webhook - Give another user access to OneDrive + Send results to E-Mail - Forward all e-mail to another user + Send results to PSA From 2c4ef81d2fc7911b5bad6519d8e29a6ab0cb3c42 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Mon, 8 Jul 2024 15:14:34 +0200 Subject: [PATCH 43/58] restore wizard updates --- src/views/tenant/backup/RestoreBackup.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/views/tenant/backup/RestoreBackup.jsx b/src/views/tenant/backup/RestoreBackup.jsx index aa34d219f9ac..3712473e2be4 100644 --- a/src/views/tenant/backup/RestoreBackup.jsx +++ b/src/views/tenant/backup/RestoreBackup.jsx @@ -49,7 +49,7 @@ const OffboardingWizard = () => { TenantFilter: tenantDomain, Name: `CIPP Restore ${tenantDomain}`, Command: { value: `New-CIPPRestore` }, - Parameters: { Type: 'Scheduled', ScheduledBackupValues: { ...values } }, + Parameters: { Type: 'Scheduled', RestoreValues: { ...values } }, ScheduledTime: unixTime, PostExecution: { Webhook: values.webhook, From 6a3dc6876e17f779630a54105059ffe73e2986e7 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Tue, 9 Jul 2024 10:54:41 +0200 Subject: [PATCH 44/58] updated backup to allot alert backups --- src/views/tenant/backup/CreateBackup.jsx | 13 +++++++++---- src/views/tenant/backup/RestoreBackup.jsx | 3 ++- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/views/tenant/backup/CreateBackup.jsx b/src/views/tenant/backup/CreateBackup.jsx index 028b3c91f31d..8a3821001f88 100644 --- a/src/views/tenant/backup/CreateBackup.jsx +++ b/src/views/tenant/backup/CreateBackup.jsx @@ -179,9 +179,7 @@ const CreateBackup = () => {

    Conditional Access

    - - - +

    Intune

    { label="Intune Protection Policies" />

    CIPP

    - + +
    diff --git a/src/views/tenant/backup/RestoreBackup.jsx b/src/views/tenant/backup/RestoreBackup.jsx index 3712473e2be4..1afd3267f716 100644 --- a/src/views/tenant/backup/RestoreBackup.jsx +++ b/src/views/tenant/backup/RestoreBackup.jsx @@ -118,7 +118,8 @@ const OffboardingWizard = () => {

    CIPP

    - + + From 9f1de9cbbf4573bf7f454b57b2672f4c3d2d9c42 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Tue, 9 Jul 2024 13:57:00 +0200 Subject: [PATCH 45/58] finished restore settings --- src/views/tenant/backup/RestoreBackup.jsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/views/tenant/backup/RestoreBackup.jsx b/src/views/tenant/backup/RestoreBackup.jsx index 1afd3267f716..e2d3d1ec9a61 100644 --- a/src/views/tenant/backup/RestoreBackup.jsx +++ b/src/views/tenant/backup/RestoreBackup.jsx @@ -108,9 +108,7 @@ const OffboardingWizard = () => {

    Conditional Access

    - - - +

    Intune

    From f836fd8e4d7ee4dcbaebbd3b9ffb916e61fab5d9 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Tue, 9 Jul 2024 14:01:43 +0200 Subject: [PATCH 46/58] do not allow duplicate backups to be set. --- src/views/tenant/backup/CreateBackup.jsx | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/views/tenant/backup/CreateBackup.jsx b/src/views/tenant/backup/CreateBackup.jsx index 8a3821001f88..faec25e074a3 100644 --- a/src/views/tenant/backup/CreateBackup.jsx +++ b/src/views/tenant/backup/CreateBackup.jsx @@ -37,11 +37,12 @@ const CreateBackup = () => { ScheduledTime: unixTime, Recurrence: { value: '1d' }, } - genericPostRequest({ path: '/api/AddScheduledItem?hidden=true', values: shippedValues }).then( - (res) => { - setRefreshState(res.requestId) - }, - ) + genericPostRequest({ + path: '/api/AddScheduledItem?hidden=true&DisallowDuplicateName=true', + values: shippedValues, + }).then((res) => { + setRefreshState(res.requestId) + }) } const Offcanvas = (row, rowIndex, formatExtraData) => { const handleDeleteSchedule = (apiurl, message) => { From 8ec1c9e62077037ef7ff0fcf0f51fd0ae64468fa Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Tue, 9 Jul 2024 14:04:21 +0200 Subject: [PATCH 47/58] fixes to auditlog schema --- src/data/AuditLogSchema.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/data/AuditLogSchema.json b/src/data/AuditLogSchema.json index d29cdb5cffea..f58b08322473 100644 --- a/src/data/AuditLogSchema.json +++ b/src/data/AuditLogSchema.json @@ -70,12 +70,12 @@ }, "List:Operation": [ { "value": "UserLoggedIn", "name": "A user logged in" }, - { "value": "accessed mailbox items", "name": "accessed mailbox items" }, + { "value": "mailitemsaccessed", "name": "accessed mailbox items" }, { "value": "add delegation entry.", "name": "added delegation entry" }, { "value": "add domain to company.", "name": "added domain to company" }, { "value": "add group.", "name": "added group" }, { "value": "add member to group.", "name": "added member to group" }, - { "value": "add mailboxpermission", "name": "added delegate mailbox permissions" }, + { "value": "add-mailboxpermission", "name": "added delegate mailbox permissions" }, { "value": "add member to role.", "name": "added member to role" }, { "value": "add partner to company.", "name": "added a partner to the directory" }, { "value": "add service principal.", "name": "added service principal" }, @@ -111,7 +111,7 @@ "value": "remove service principal credentials.", "name": "removed credentials from a service principal" }, - { "value": "remove mailboxpermission", "name": "removed delegate mailbox permissions" }, + { "value": "remove-mailboxpermission", "name": "removed delegate mailbox permissions" }, { "value": "remove member from role.", "name": "removed a user from a directory role" }, { "value": "remove partner from company.", "name": "removed a partner from the directory" }, { "value": "removefolderpermissions", "name": "removed permissions from folder" }, @@ -132,7 +132,7 @@ "value": "set force change user password.", "name": "set property that forces user to change password" }, - { "value": "set inboxrule", "name": "modified inbox rule from outlook web app" }, + { "value": "set-inboxrule", "name": "modified inbox rule from outlook web app" }, { "value": "set license properties.", "name": "set license properties" }, { "value": "set password policy.", "name": "set password policy" }, { "value": "softdelete", "name": "deleted messages from deleted items folder" }, From 674131c1fb4edf247c6679cab4fe3bfc12da40c1 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Tue, 9 Jul 2024 15:02:45 +0200 Subject: [PATCH 48/58] fixes issue with duplicate group mappings. --- src/views/tenant/administration/GDAPInviteWizard.jsx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/views/tenant/administration/GDAPInviteWizard.jsx b/src/views/tenant/administration/GDAPInviteWizard.jsx index 956b8a374f00..5f303a3c827f 100644 --- a/src/views/tenant/administration/GDAPInviteWizard.jsx +++ b/src/views/tenant/administration/GDAPInviteWizard.jsx @@ -114,6 +114,12 @@ const GDAPInviteWizard = () => { const filteredResults = results.data.filter((role) => defaultRolesArray.some((defaultRole) => defaultRole.ObjectId === role.roleDefinitionId), ) + const uniqueFilteredResults = filteredResults.filter( + (role, index, self) => + index === self.findIndex((t) => t.roleDefinitionId === role.roleDefinitionId), + ) + filteredResults.length = 0 + Array.prototype.push.apply(filteredResults, uniqueFilteredResults) setEasyMode(true) const resultsarr = [] setLoopRunning(true) From 5d9c4f1276e6160cc6955ac050c1bafb4264012a Mon Sep 17 00:00:00 2001 From: John Duprey Date: Tue, 9 Jul 2024 11:56:11 -0400 Subject: [PATCH 49/58] Add callout for force sync --- src/views/cipp/Extensions.jsx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/views/cipp/Extensions.jsx b/src/views/cipp/Extensions.jsx index 8c8c9dd79dee..eec80f5a1068 100644 --- a/src/views/cipp/Extensions.jsx +++ b/src/views/cipp/Extensions.jsx @@ -67,6 +67,7 @@ export default function CIPPExtensions() { path: 'api/ExecExtensionSync?Extension=' + integrationType, }) } + disabled={disabled} className="me-2" > )} + {listSyncExtensionResult?.data?.Results && ( + + {listSyncExtensionResult?.data?.Results} + + )}
    {integration.mappingRequired && ( From 2b5d0b3169cb53c5fb5a5d7eb3241445de25b88b Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Tue, 9 Jul 2024 21:35:41 +0200 Subject: [PATCH 50/58] added ability to use exportformatters with parameters --- src/components/tables/CellBytes.jsx | 24 +++++++++++++++++++ src/components/tables/CellCopyButton.jsx | 2 -- src/components/tables/CippTable.jsx | 12 ++++++---- .../reports/MailboxStatisticsList.jsx | 22 +++++++++++++---- 4 files changed, 49 insertions(+), 11 deletions(-) create mode 100644 src/components/tables/CellBytes.jsx diff --git a/src/components/tables/CellBytes.jsx b/src/components/tables/CellBytes.jsx new file mode 100644 index 000000000000..b5b3e38211b8 --- /dev/null +++ b/src/components/tables/CellBytes.jsx @@ -0,0 +1,24 @@ +import PropTypes from 'prop-types' + +export function CellBytes({ cell }) { + return (cell / 1024 ** 3).toFixed(2) +} + +CellBytes.propTypes = { + propName: PropTypes.string, + cell: PropTypes.object, +} + +export function CellBytesToPercentage({ row, value, dividedBy }) { + return Math.round((row[value] / row[dividedBy]) * 100 * 10) / 10 +} + +CellBytesToPercentage.propTypes = { + propName: PropTypes.string, + cell: PropTypes.object, +} + +export const cellBytesFormatter = () => (row, index, column, id) => { + const cell = column.selector(row) + return CellBytes({ cell }) +} diff --git a/src/components/tables/CellCopyButton.jsx b/src/components/tables/CellCopyButton.jsx index eeed76d73478..ca3a2b7c98c2 100644 --- a/src/components/tables/CellCopyButton.jsx +++ b/src/components/tables/CellCopyButton.jsx @@ -2,7 +2,6 @@ import PropTypes from 'prop-types' import CippCopyToClipboard from '../utilities/CippCopyToClipboard' export function CellCopyButton({ cell }) { - console.log('hi! cell:', cell) return } @@ -13,6 +12,5 @@ CellCopyButton.propTypes = { export const cellCopyButtonFormatter = () => (row, index, column, id) => { const cell = column.selector(row) - console.log('cell:', cell) return CellCopyButton({ cell }) } diff --git a/src/components/tables/CippTable.jsx b/src/components/tables/CippTable.jsx index 6eee3a54e611..04ede5a4c204 100644 --- a/src/components/tables/CippTable.jsx +++ b/src/components/tables/CippTable.jsx @@ -629,12 +629,14 @@ export default function CippTable({ if (!disablePDFExport || !disableCSVExport) { const keys = [] const exportFormatter = {} + const exportFormatterArgs = {} columns.map((col) => { if (col.exportSelector) keys.push(col.exportSelector) if (col.exportFormatter) exportFormatter[col.exportSelector] = col.exportFormatter + if (col.exportFormatterArgs) + exportFormatterArgs[col.exportSelector] = col.exportFormatterArgs return null }) - // Define the flatten function const flatten = (obj, prefix = '') => { if (obj === null) return {} @@ -664,18 +666,18 @@ export default function CippTable({ // Define the applyFormatter function const applyFormatter = (obj) => { return Object.keys(obj).reduce((acc, key) => { + const formatterArgs = exportFormatterArgs[key] const formatter = exportFormatter[key] - // Since the keys after flattening will be dot-separated, we need to adjust this to support nested keys if necessary. const keyParts = key.split('.') const finalKeyPart = keyParts[keyParts.length - 1] const formattedValue = - typeof formatter === 'function' ? formatter({ cell: obj[key] }) : obj[key] + typeof formatter === 'function' + ? formatter({ row: obj, cell: obj[key], ...formatterArgs }) + : obj[key] acc[key] = formattedValue return acc }, {}) } - - // Process exportData function const processExportData = (exportData, selectedColumns) => { //filter out the columns that are not selected via selectedColumns exportData = exportData.map((item) => { diff --git a/src/views/email-exchange/reports/MailboxStatisticsList.jsx b/src/views/email-exchange/reports/MailboxStatisticsList.jsx index 0a6a4c80e9c0..abe707575e83 100644 --- a/src/views/email-exchange/reports/MailboxStatisticsList.jsx +++ b/src/views/email-exchange/reports/MailboxStatisticsList.jsx @@ -2,6 +2,11 @@ import React, { useEffect, useState } from 'react' import { useSelector } from 'react-redux' import { CellTip, cellBooleanFormatter } from 'src/components/tables' import { CippPageList } from 'src/components/layout' +import { + CellBytes, + CellBytesToPercentage, + cellBytesFormatter, +} from 'src/components/tables/CellBytes' const MailboxStatsList = () => { const [tenantColumnSet, setTenantColumn] = useState(true) @@ -64,23 +69,32 @@ const MailboxStatsList = () => { exportSelector: 'lastActivityDate', }, { - selector: (row) => (row['storageUsedInBytes'] / 1024 ** 3).toFixed(2), + selector: (row) => row['storageUsedInBytes'], + cell: cellBytesFormatter(), name: 'Used Space (GB)', sortable: true, exportSelector: 'storageUsedInBytes', + exportFormatter: CellBytes, }, { - selector: (row) => (row['prohibitSendReceiveQuotaInBytes'] / 1024 ** 3).toFixed(2), + selector: (row) => row['prohibitSendReceiveQuotaInBytes'], + cell: cellBytesFormatter(), name: 'Quota (GB)', sortable: true, - exportSelector: 'QuotaGB', + exportSelector: 'prohibitSendReceiveQuotaInBytes', + exportFormatter: CellBytes, }, { selector: (row) => Math.round((row.storageUsedInBytes / row.prohibitSendReceiveQuotaInBytes) * 100 * 10) / 10, name: 'Quota Used(%)', sortable: true, - exportSelector: 'QuotaUsed', + exportSelector: 'CippStatus', + exportFormatter: CellBytesToPercentage, + exportFormatterArgs: { + value: 'storageUsedInBytes', + dividedBy: 'prohibitSendReceiveQuotaInBytes', + }, }, { selector: (row) => row['itemCount'], From 66a298d06cc5a05ba3014d9365c3047101946100 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Tue, 9 Jul 2024 21:46:53 +0200 Subject: [PATCH 51/58] Improve DeletedUserRentention standard --- src/data/standards.json | 76 ++++++++++++++++++++++++++++++----------- 1 file changed, 57 insertions(+), 19 deletions(-) diff --git a/src/data/standards.json b/src/data/standards.json index ff0286d5f381..395a9ed33ae7 100644 --- a/src/data/standards.json +++ b/src/data/standards.json @@ -1789,10 +1789,58 @@ "name": "standards.DeletedUserRentention", "cat": "SharePoint Standards", "tag": ["lowimpact"], - "helpText": "Sets the retention period for deleted users OneDrive to 1 year/365 days", - "docsDescription": "When a OneDrive user gets deleted, the personal SharePoint site is saved for 1 year and data can be retrieved from it.", - "addedComponent": [], - "label": "Retain a deleted user OneDrive for 1 year", + "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.", + "addedComponent": [ + { + "type": "Select", + "name": "standards.DeletedUserRentention.Days", + "label": "Retention in years (Default 1)", + "values": [ + { + "label": "1 year", + "value": "365" + }, + { + "label": "2 years", + "value": "730" + }, + { + "label": "3 years", + "value": "1095" + }, + { + "label": "4 years", + "value": "1460" + }, + { + "label": "5 years", + "value": "1825" + }, + { + "label": "6 years", + "value": "2190" + }, + { + "label": "7 years", + "value": "2555" + }, + { + "label": "8 years", + "value": "2920" + }, + { + "label": "9 years", + "value": "3285" + }, + { + "label": "10 years", + "value": "3650" + } + ] + } + ], + "label": "Set deleted user retention time in OneDrive", "impact": "Low Impact", "impactColour": "info", "powershellEquivalent": "Update-MgBetaAdminSharepointSetting", @@ -1826,9 +1874,7 @@ "impact": "Low Impact", "impactColour": "info", "powershellEquivalent": "Set-SPOTenant -EnableAzureADB2BIntegration $true", - "recommendedBy": [ - "CIS 3.0" - ] + "recommendedBy": ["CIS 3.0"] }, { "name": "standards.SPDisallowInfectedFiles", @@ -1840,9 +1886,7 @@ "impact": "Low Impact", "impactColour": "info", "powershellEquivalent": "Set-SPOTenant -DisallowInfectedFileDownload $true", - "recommendedBy": [ - "CIS 3.0" - ] + "recommendedBy": ["CIS 3.0"] }, { "name": "standards.SPDirectSharing", @@ -1854,9 +1898,7 @@ "impact": "Medium Impact", "impactColour": "warning", "powershellEquivalent": "Set-SPOTenant -DefaultSharingLinkType Direct", - "recommendedBy": [ - "CIS 3.0" - ] + "recommendedBy": ["CIS 3.0"] }, { "name": "standards.SPExternalUserExpiration", @@ -1874,9 +1916,7 @@ "impact": "Medium Impact", "impactColour": "warning", "powershellEquivalent": "Set-SPOTenant -ExternalUserExpireInDays 30 -ExternalUserExpirationRequired $True", - "recommendedBy": [ - "CIS 3.0" - ] + "recommendedBy": ["CIS 3.0"] }, { "name": "standards.SPEmailAttestation", @@ -1894,9 +1934,7 @@ "impact": "Medium Impact", "impactColour": "warning", "powershellEquivalent": "Set-SPOTenant -EmailAttestationRequired $true -EmailAttestationReAuthDays 15", - "recommendedBy": [ - "CIS 3.0" - ] + "recommendedBy": ["CIS 3.0"] }, { "name": "standards.DisableAddShortcutsToOneDrive", From 4da10710055c5ed4573d5754101fee41d9d61a1c Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Tue, 9 Jul 2024 21:58:20 +0200 Subject: [PATCH 52/58] 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 039c0b97dd85..4b1a1349b19c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cipp", - "version": "5.9.3", + "version": "6.0.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 99a8b57b6f85..09b254e90c61 100644 --- a/public/version_latest.txt +++ b/public/version_latest.txt @@ -1 +1 @@ -5.9.3 +6.0.0 diff --git a/version_latest.txt b/version_latest.txt index 99a8b57b6f85..09b254e90c61 100644 --- a/version_latest.txt +++ b/version_latest.txt @@ -1 +1 @@ -5.9.3 +6.0.0 From 31a9db1c7d04305d0f81f43f9c1ab273e62a03ce Mon Sep 17 00:00:00 2001 From: John Duprey Date: Tue, 9 Jul 2024 18:02:51 -0400 Subject: [PATCH 53/58] Fix manual tenant mapping --- src/views/cipp/ExtensionMappings.jsx | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/views/cipp/ExtensionMappings.jsx b/src/views/cipp/ExtensionMappings.jsx index b493dce041a2..b0d25677ef2e 100644 --- a/src/views/cipp/ExtensionMappings.jsx +++ b/src/views/cipp/ExtensionMappings.jsx @@ -226,9 +226,7 @@ export default function ExtensionMappings({ type, fieldMappings = false, autoMap name: tenant.displayName, value: tenant.customerId, }))} - onChange={(e) => { - setMappingArray(e.value) - }} + onChange={(e) => setTenantMappingsArray(e.value)} isLoading={listMappingBackendResult.isFetching} /> @@ -267,7 +265,7 @@ export default function ExtensionMappings({ type, fieldMappings = false, autoMap ...mappingArray, { Tenant: listMappingBackendResult.data?.Tenants.find( - (tenant) => tenant.customerId === mappingArray, + (tenant) => tenant.customerId === tenantMappingArray, ), companyName: mappingValue.label, companyId: mappingValue.value, From 95db774ef1e8146e77934dfd20d02f3737f55bf7 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Tue, 9 Jul 2024 18:08:09 -0400 Subject: [PATCH 54/58] 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 4b1a1349b19c..4e17521cd42b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cipp", - "version": "6.0.0", + "version": "6.0.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 09b254e90c61..5fe60723048a 100644 --- a/public/version_latest.txt +++ b/public/version_latest.txt @@ -1 +1 @@ -6.0.0 +6.0.1 diff --git a/version_latest.txt b/version_latest.txt index 09b254e90c61..5fe60723048a 100644 --- a/version_latest.txt +++ b/version_latest.txt @@ -1 +1 @@ -6.0.0 +6.0.1 From d7bbc2669b5f2e9ada091794bdd38db304ddaecb Mon Sep 17 00:00:00 2001 From: John Duprey Date: Wed, 10 Jul 2024 10:17:26 -0400 Subject: [PATCH 55/58] Allow multiple tenant to company map --- src/views/cipp/ExtensionMappings.jsx | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/views/cipp/ExtensionMappings.jsx b/src/views/cipp/ExtensionMappings.jsx index b0d25677ef2e..4de976555ccc 100644 --- a/src/views/cipp/ExtensionMappings.jsx +++ b/src/views/cipp/ExtensionMappings.jsx @@ -236,16 +236,10 @@ export default function ExtensionMappings({ type, fieldMappings = false, autoMap { - return !Object.values(listMappingBackendResult.data?.Mappings) - .map((value) => { - return value.value - }) - .includes(client.value.toString()) - }).map((client) => ({ + values={listMappingBackendResult.data?.Companies.map((client) => ({ name: client.name, value: client.value, - }))} + })).sort((a, b) => a.name.localeCompare(b.name))} onChange={(e) => setMappingValue(e)} placeholder={`Select a ${type} Organization`} isLoading={listMappingBackendResult.isFetching} From eff03f18bd46bf26bb3f3f1681d47468fed814a5 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Wed, 10 Jul 2024 17:09:15 -0400 Subject: [PATCH 56/58] Add Extension Sync Status page --- src/_nav.jsx | 5 ++ src/importsMap.jsx | 1 + src/routes.json | 6 ++ src/views/cipp/ExtensionSync.jsx | 97 ++++++++++++++++++++++++++++++++ 4 files changed, 109 insertions(+) create mode 100644 src/views/cipp/ExtensionSync.jsx diff --git a/src/_nav.jsx b/src/_nav.jsx index 631d6eaf1169..0ab9f9db7c5b 100644 --- a/src/_nav.jsx +++ b/src/_nav.jsx @@ -821,6 +821,11 @@ const _nav = [ name: 'Extensions Settings', to: '/cipp/extensions', }, + { + component: CNavItem, + name: 'Extension Sync', + to: '/cipp/extension-sync', + }, { component: CNavItem, name: 'User Settings', diff --git a/src/importsMap.jsx b/src/importsMap.jsx index 9666488abfc9..e6a8a422c777 100644 --- a/src/importsMap.jsx +++ b/src/importsMap.jsx @@ -137,6 +137,7 @@ import React from 'react' "/license": React.lazy(() => import('./views/pages/license/License')), "/cipp/settings": React.lazy(() => import('./views/cipp/app-settings/CIPPSettings')), "/cipp/extensions": React.lazy(() => import('./views/cipp/Extensions')), + "/cipp/extension-sync": React.lazy(() => import('./views/cipp/ExtensionSync')), "/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')), diff --git a/src/routes.json b/src/routes.json index 96584165d77c..b6a54db32b03 100644 --- a/src/routes.json +++ b/src/routes.json @@ -938,6 +938,12 @@ "component": "views/cipp/Extensions", "allowedRoles": ["admin"] }, + { + "path": "/cipp/extension-sync", + "name": "Extension Sync", + "component": "views/cipp/ExtensionSync", + "allowedRoles": ["admin"] + }, { "path": "/cipp/setup", "name": "Setup", diff --git a/src/views/cipp/ExtensionSync.jsx b/src/views/cipp/ExtensionSync.jsx new file mode 100644 index 000000000000..c9937921aa86 --- /dev/null +++ b/src/views/cipp/ExtensionSync.jsx @@ -0,0 +1,97 @@ +import React, { useState } from 'react' +import { CCol, CRow } from '@coreui/react' +import { useSelector } from 'react-redux' + +import { useLazyGenericGetRequestQuery, useLazyGenericPostRequestQuery } from 'src/store/api/app' + +import { CippPage, CippPageList } from 'src/components/layout' +import { CellTip, cellGenericFormatter } from 'src/components/tables/CellGenericFormat' +import 'react-datepicker/dist/react-datepicker.css' +import { CellBadge, cellBadgeFormatter, cellDateFormatter } from 'src/components/tables' +import { TitleButton } from 'src/components/buttons' + +const ExtensionSync = () => { + const [ExecuteGetRequest, getResults] = useLazyGenericGetRequestQuery() + const tenantDomain = useSelector((state) => state.app.currentTenant.defaultDomainName) + const [refreshState, setRefreshState] = useState(false) + const [genericPostRequest, postResults] = useLazyGenericPostRequestQuery() + + const columns = [ + { + name: 'Tenant', + selector: (row) => row['Tenant'], + sortable: true, + cell: cellGenericFormatter(), + exportSelector: 'Tenants', + }, + { + name: 'Sync Type', + selector: (row) => row['SyncType'], + sortable: true, + cell: cellBadgeFormatter({ color: 'info' }), + exportSelector: 'SyncType', + }, + { + name: 'Task', + selector: (row) => row['Name'], + sortable: true, + cell: cellGenericFormatter(), + exportSelector: 'Name', + }, + { + name: 'Scheduled Time', + selector: (row) => row['ScheduledTime'], + sortable: true, + cell: cellDateFormatter({ format: 'short' }), + exportSelector: 'ScheduledTime', + }, + { + name: 'Last Run', + selector: (row) => row['ExecutedTime'], + sortable: true, + cell: cellDateFormatter({ format: 'short' }), + exportSelector: 'ExecutedTime', + }, + { + name: 'Repeats every', + selector: (row) => row['RepeatsEvery'], + sortable: true, + cell: (row) => CellTip(row['RepeatsEvery']), + exportSelector: 'RepeatsEvery', + }, + { + name: 'Results', + selector: (row) => row['Results'], + sortable: true, + cell: cellGenericFormatter(), + exportSelector: 'Results', + }, + ] + + return ( + + <> + + + + + + + + ) +} + +export default ExtensionSync From 7bafde8d27fcffe4abfabe16fa4145ef3d8ab775 Mon Sep 17 00:00:00 2001 From: STG-Tanner <102822322+STG-Tanner@users.noreply.github.com> Date: Wed, 10 Jul 2024 16:50:50 -0500 Subject: [PATCH 57/58] Fix Dashboard domain names list length Domains 4 and 5 would be hidden unless more than 5 were returned --- src/views/home/Home.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/views/home/Home.jsx b/src/views/home/Home.jsx index 7111f9e41bb2..c3dc3de2afa6 100644 --- a/src/views/home/Home.jsx +++ b/src/views/home/Home.jsx @@ -289,7 +289,7 @@ const TenantDashboard = () => { {organization.verifiedDomains?.slice(0, 3).map((item, idx) => (
  • {item.name}
  • ))} - {organization.verifiedDomains?.length > 5 && ( + {organization.verifiedDomains?.length > 3 && ( <> {organization.verifiedDomains?.slice(3).map((item, idx) => ( From e5f177271d1046321c780cdb1aba9a40879102aa Mon Sep 17 00:00:00 2001 From: John Duprey Date: Wed, 10 Jul 2024 20:28:54 -0400 Subject: [PATCH 58/58] 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 4e17521cd42b..bdf502e059b8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cipp", - "version": "6.0.1", + "version": "6.0.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 5fe60723048a..9b9a244206f6 100644 --- a/public/version_latest.txt +++ b/public/version_latest.txt @@ -1 +1 @@ -6.0.1 +6.0.2 diff --git a/version_latest.txt b/version_latest.txt index 5fe60723048a..9b9a244206f6 100644 --- a/version_latest.txt +++ b/version_latest.txt @@ -1 +1 @@ -6.0.1 +6.0.2