Skip to content

Commit 7b59620

Browse files
authored
Merge branch 'KelvinTegelaar:main' into main
2 parents 4911595 + c38bdc6 commit 7b59620

34 files changed

Lines changed: 1664 additions & 400 deletions

File tree

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "cipp",
3-
"version": "10.5.4",
3+
"version": "10.5.5",
44
"author": "CIPP Contributors",
55
"homepage": "https://cipp.app/",
66
"bugs": {
@@ -116,4 +116,4 @@
116116
"eslint-config-prettier": "^10.1.8",
117117
"prettier": "^3.8.1"
118118
}
119-
}
119+
}

public/version.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
{
2-
"version": "10.5.4"
3-
}
2+
"version": "10.5.5"
3+
}

src/components/CippComponents/AuthMethodCard.jsx

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,23 @@ export const AuthMethodCard = ({ data, isLoading }) => {
1616
return null;
1717
}
1818

19-
const phishableMethods = ["mobilePhone", "email", "microsoftAuthenticatorPush"];
20-
const phishResistantMethods = ["fido2", "windowsHelloForBusiness", "x509Certificate"];
19+
const phishableMethods = [
20+
"mobilePhone",
21+
"alternateMobilePhone",
22+
"officePhone",
23+
"email",
24+
"microsoftAuthenticatorPush",
25+
"softwareOneTimePasscode",
26+
"hardwareOneTimePasscode",
27+
];
28+
const passkeyMethods = [
29+
"fido2SecurityKey",
30+
"passKeyDeviceBound",
31+
"passKeyDeviceBoundAuthenticator",
32+
"passKeyDeviceBoundWindowsHello",
33+
"x509Certificate",
34+
];
35+
const phishResistantMethods = [...passkeyMethods, "windowsHelloForBusiness"];
2136

2237
let singleFactor = 0;
2338
let phishableCount = 0;
@@ -48,20 +63,26 @@ export const AuthMethodCard = ({ data, isLoading }) => {
4863

4964
if (hasPhishResistant) {
5065
phishResistantCount++;
51-
if (methods.includes("fido2") || methods.includes("x509Certificate")) {
66+
if (methods.some((m) => passkeyMethods.includes(m))) {
5267
passkeyCount++;
5368
}
5469
if (methods.includes("windowsHelloForBusiness")) {
5570
whfbCount++;
5671
}
5772
} else if (hasPhishable) {
5873
phishableCount++;
59-
if (methods.includes("mobilePhone") || methods.includes("email")) {
74+
if (
75+
methods.includes("mobilePhone") ||
76+
methods.includes("alternateMobilePhone") ||
77+
methods.includes("officePhone") ||
78+
methods.includes("email")
79+
) {
6080
phoneCount++;
6181
}
6282
if (
6383
methods.includes("microsoftAuthenticatorPush") ||
64-
methods.includes("softwareOneTimePasscode")
84+
methods.includes("softwareOneTimePasscode") ||
85+
methods.includes("hardwareOneTimePasscode")
6586
) {
6687
authenticatorCount++;
6788
}

src/components/CippComponents/AuthMethodSankey.jsx

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,23 @@ export const AuthMethodSankey = ({ data }) => {
1313
return null;
1414
}
1515

16-
// Categorize MFA methods as phishable or phish-resistant
17-
const phishableMethods = ["mobilePhone", "email", "microsoftAuthenticatorPush"];
18-
const phishResistantMethods = ["fido2", "windowsHelloForBusiness", "x509Certificate"];
16+
const phishableMethods = [
17+
"mobilePhone",
18+
"alternateMobilePhone",
19+
"officePhone",
20+
"email",
21+
"microsoftAuthenticatorPush",
22+
"softwareOneTimePasscode",
23+
"hardwareOneTimePasscode",
24+
];
25+
const passkeyMethods = [
26+
"fido2SecurityKey",
27+
"passKeyDeviceBound",
28+
"passKeyDeviceBoundAuthenticator",
29+
"passKeyDeviceBoundWindowsHello",
30+
"x509Certificate",
31+
];
32+
const phishResistantMethods = [...passkeyMethods, "windowsHelloForBusiness"];
1933

2034
let singleFactor = 0;
2135
let phishableCount = 0;
@@ -54,21 +68,26 @@ export const AuthMethodSankey = ({ data }) => {
5468
if (hasPhishResistant) {
5569
phishResistantCount++;
5670
// Count specific phish-resistant methods
57-
if (methods.includes("fido2") || methods.includes("x509Certificate")) {
71+
if (methods.some((m) => passkeyMethods.includes(m))) {
5872
passkeyCount++;
5973
}
6074
if (methods.includes("windowsHelloForBusiness")) {
6175
whfbCount++;
6276
}
6377
} else if (hasPhishable) {
6478
phishableCount++;
65-
// Count specific phishable methods
66-
if (methods.includes("mobilePhone") || methods.includes("email")) {
79+
if (
80+
methods.includes("mobilePhone") ||
81+
methods.includes("alternateMobilePhone") ||
82+
methods.includes("officePhone") ||
83+
methods.includes("email")
84+
) {
6785
phoneCount++;
6886
}
6987
if (
7088
methods.includes("microsoftAuthenticatorPush") ||
71-
methods.includes("softwareOneTimePasscode")
89+
methods.includes("softwareOneTimePasscode") ||
90+
methods.includes("hardwareOneTimePasscode")
7291
) {
7392
authenticatorCount++;
7493
}

src/components/CippComponents/CippAppPermissionBuilder.jsx

Lines changed: 74 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -462,10 +462,11 @@ const CippAppPermissionBuilder = ({
462462
if (appTable !== undefined && appTable?.length === 0) {
463463
setAppTable(
464464
spPermissions?.applicationPermissions
465-
?.sort((a, b) => a.value.localeCompare(b.value))
465+
?.sort((a, b) => (a.value ?? "").localeCompare(b.value ?? ""))
466466
?.map((perm) => ({
467467
id: perm.id,
468468
value: perm.value,
469+
required: perm.required ?? false,
469470
description: spInfo?.Results?.appRoles.find((role) => role.id === perm.id)
470471
?.description,
471472
})),
@@ -474,10 +475,11 @@ const CippAppPermissionBuilder = ({
474475
if (delegatedTable !== undefined && delegatedTable.length === 0) {
475476
setDelegatedTable(
476477
spPermissions?.delegatedPermissions
477-
?.sort((a, b) => a.value.localeCompare(b.value))
478+
?.sort((a, b) => (a.value ?? "").localeCompare(b.value ?? ""))
478479
?.map((perm) => ({
479480
id: perm.id,
480481
value: perm.value,
482+
required: perm.required ?? false,
481483
description:
482484
spInfo?.Results?.publishedPermissionScopes.find((scope) => scope.id === perm.id)
483485
?.userConsentDescription ?? "Manually added",
@@ -625,6 +627,7 @@ const CippAppPermissionBuilder = ({
625627
label: "Delete Permission",
626628
icon: <Delete />,
627629
noConfirm: true,
630+
condition: (row) => !row.required,
628631
customFunction: (row) => handleRemoveRow("applicationPermissions", row),
629632
},
630633
]}
@@ -690,6 +693,7 @@ const CippAppPermissionBuilder = ({
690693
label: "Delete Permission",
691694
icon: <Delete />,
692695
noConfirm: true,
696+
condition: (row) => !row.required,
693697
customFunction: (row) => handleRemoveRow("delegatedPermissions", row),
694698
},
695699
]}
@@ -788,7 +792,7 @@ const CippAppPermissionBuilder = ({
788792
</div>
789793
</Tooltip>
790794

791-
<Tooltip title="Reset to Default">
795+
<Tooltip title="Reset to Current Defaults (discard unsaved changes)">
792796
<Button
793797
onClick={() => {
794798
confirmReset();
@@ -929,79 +933,74 @@ const CippAppPermissionBuilder = ({
929933
</Grid>
930934
)}
931935

932-
{newPermissions?.MissingPermissions &&
933-
newPermissions?.Type === "Table" &&
934-
Object.keys(newPermissions?.MissingPermissions).length > 0 && (
935-
<Grid container sx={{ width: "100%", mt: 3 }}>
936-
<Grid size={{ xl: 8, xs: 12 }}>
937-
<Alert
938-
color="warning"
939-
icon={<WarningAmberOutlined />}
940-
action={
941-
<Tooltip title="Add Missing Permissions">
942-
<IconButton
943-
onClick={() => {
944-
var updatedPermissions = JSON.parse(JSON.stringify(newPermissions));
945-
Object.keys(newPermissions?.MissingPermissions).map((perm) => {
946-
Object.keys(newPermissions?.MissingPermissions[perm]).map(
947-
(type) => {
948-
if (!updatedPermissions.Permissions[perm][type]) {
949-
updatedPermissions.Permissions[perm][type] = [];
950-
}
951-
newPermissions?.MissingPermissions[perm][type].map((p) => {
952-
updatedPermissions.Permissions[perm][type].push(p);
953-
});
954-
},
955-
);
956-
});
957-
updatedPermissions.MissingPermissions = {};
958-
setNewPermissions(updatedPermissions);
959-
}}
960-
>
961-
<SvgIcon fontSize="small">
962-
<WrenchIcon />
963-
</SvgIcon>
964-
</IconButton>
965-
</Tooltip>
966-
}
967-
>
968-
<b>New Permissions Available</b>
969-
{Object.keys(newPermissions?.MissingPermissions).map((perm) => {
970-
// translate appid to display name
971-
var sp = servicePrincipals?.Results?.find((sp) => sp.appId === perm);
972-
return (
973-
<Typography
974-
variant="body2"
975-
textColor="secondary"
976-
key={`missing-${perm}`}
977-
>
978-
{sp?.displayName}:{" "}
979-
{Object.keys(newPermissions?.MissingPermissions[perm]).map((type) => {
980-
return (
981-
<>
982-
{newPermissions?.MissingPermissions[perm][type].length > 0 && (
983-
<React.Fragment key={`missing-${perm}-${type}`}>
984-
{type == "applicationPermissions"
985-
? "Application"
986-
: "Delegated"}{" "}
987-
-{" "}
988-
{newPermissions?.MissingPermissions[perm][type]
989-
.map((p) => {
990-
return p.value;
991-
})
992-
.join(", ")}
993-
</React.Fragment>
994-
)}
995-
</>
996-
);
997-
})}
998-
</Typography>
999-
);
1000-
})}
1001-
</Alert>
936+
{newPermissions?.PartnerAppDiff &&
937+
Object.keys(newPermissions?.PartnerAppDiff).length > 0 &&
938+
(() => {
939+
const diff = newPermissions.PartnerAppDiff;
940+
const appIds = Object.keys(diff);
941+
const hasMissing = appIds.some(
942+
(perm) =>
943+
(diff[perm].missingApplicationPermissions?.length ?? 0) > 0 ||
944+
(diff[perm].missingDelegatedPermissions?.length ?? 0) > 0,
945+
);
946+
const hasExtra = appIds.some(
947+
(perm) =>
948+
(diff[perm].extraApplicationPermissions?.length ?? 0) > 0 ||
949+
(diff[perm].extraDelegatedPermissions?.length ?? 0) > 0,
950+
);
951+
const renderList = (perm, appKey, delKey) => {
952+
const sp = servicePrincipals?.Results?.find((sp) => sp.appId === perm);
953+
const app = diff[perm][appKey] ?? [];
954+
const del = diff[perm][delKey] ?? [];
955+
if (app.length === 0 && del.length === 0) return null;
956+
return (
957+
<Typography variant="body2" key={`${appKey}-${perm}`}>
958+
{sp?.displayName ?? perm}:{" "}
959+
{app.length > 0 && <>Application - {app.map((p) => p.value).join(", ")} </>}
960+
{del.length > 0 && <>Delegated - {del.map((p) => p.value).join(", ")}</>}
961+
</Typography>
962+
);
963+
};
964+
return (
965+
<Grid container sx={{ width: "100%", mt: 3 }} spacing={2}>
966+
{hasMissing && (
967+
<Grid size={{ xl: 8, xs: 12 }}>
968+
<Alert color="warning" icon={<WarningAmberOutlined />}>
969+
<b>
970+
Permissions missing from the {appDisplayName} app registration (run
971+
Repair Permissions to add, then a CPV refresh to apply to tenants)
972+
</b>
973+
{appIds.map((perm) =>
974+
renderList(
975+
perm,
976+
"missingApplicationPermissions",
977+
"missingDelegatedPermissions",
978+
),
979+
)}
980+
</Alert>
981+
</Grid>
982+
)}
983+
{hasExtra && (
984+
<Grid size={{ xl: 8, xs: 12 }}>
985+
<Alert color="info" icon={<WarningAmberOutlined />}>
986+
<b>
987+
Extra permissions present on the {appDisplayName} app registration that
988+
are not part of the CIPP defaults or your additional permissions
989+
(review and remove manually if not required)
990+
</b>
991+
{appIds.map((perm) =>
992+
renderList(
993+
perm,
994+
"extraApplicationPermissions",
995+
"extraDelegatedPermissions",
996+
),
997+
)}
998+
</Alert>
999+
</Grid>
1000+
)}
10021001
</Grid>
1003-
</Grid>
1004-
)}
1002+
);
1003+
})()}
10051004

10061005
<Box sx={{ mt: 3 }}>
10071006
{selectedApp &&

src/components/CippComponents/CippAutocomplete.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,7 @@ export const CippAutoComplete = React.forwardRef((props, ref) => {
265265
finalOptions = finalOptions.filter((o) => !removeOptions.includes(o.value))
266266
}
267267
if (sortOptions) {
268-
finalOptions.sort((a, b) => a.label?.localeCompare(b.label))
268+
finalOptions.sort((a, b) => String(a.label ?? "").localeCompare(String(b.label ?? "")))
269269
}
270270
return finalOptions
271271
}, [api, usedOptions, options, removeOptions, sortOptions])

0 commit comments

Comments
 (0)