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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .github/workflows/cipp_dev_build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,13 @@ jobs:
- name: Build Project
run: npm run build

# Update version.json with commit hash
- name: Update version.json
run: |
VERSION=$(jq -r '.version' public/version.json)
SHORT_SHA="${GITHUB_SHA::7}"
echo "{\"version\": \"${VERSION}\", \"commit\": \"${SHORT_SHA}\"}" > out/version.json

# Create ZIP File in a New Source Directory
- name: Prepare and Zip Build Files
run: |
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "cipp",
"version": "10.2.1",
"version": "10.2.2",
"author": "CIPP Contributors",
"homepage": "https://cipp.app/",
"bugs": {
Expand Down
2 changes: 1 addition & 1 deletion public/version.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
"version": "10.2.1"
"version": "10.2.2"
}
5 changes: 3 additions & 2 deletions src/components/CippComponents/CippSponsor.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ export const CippSponsor = () => {
<Typography
color="text.secondary"
variant="caption"
sx={{ lineHeight: 4, textAlign: "center" }}
sx={{ lineHeight: 2, textAlign: "center", display: "block", mt: 2 }}
>
This application is sponsored by
</Typography>
Expand All @@ -82,6 +82,7 @@ export const CippSponsor = () => {
justifyContent: "center",
alignItems: "center",
height: "55px",
mb: 1,
}}
>
<Tooltip title={randomimg.tooltip} arrow>
Expand All @@ -92,7 +93,7 @@ export const CippSponsor = () => {
cursor: "pointer",
maxHeight: "50px",
width: "auto",
maxWidth: "100px",
maxWidth: "150px",
}}
onClick={() => window.open(randomimg.link)}
/>
Expand Down
127 changes: 127 additions & 0 deletions src/components/CippSettings/CippSiemSettings.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
import { Button, Typography, Alert, Box, TextField, InputAdornment } from "@mui/material";
import { Key } from "@mui/icons-material";
import CippButtonCard from "../CippCards/CippButtonCard";
import { ApiPostCall } from "../../api/ApiCall";
import { CippCopyToClipBoard } from "../CippComponents/CippCopyToClipboard";
import CippFormComponent from "../CippComponents/CippFormComponent";
import { useForm } from "react-hook-form";

const CippSiemSettings = () => {
const generateSas = ApiPostCall({
datafromUrl: true,
});

const formControl = useForm({
mode: "onChange",
defaultValues: {
Days: { label: "365 days", value: "365" },
},
});

const handleGenerate = () => {
const formData = formControl.getValues();
const days = formData.Days?.value ?? "365";
generateSas.mutate({
url: "/api/ExecCippLogsSas",
data: { Days: parseInt(days, 10) },
queryKey: "ExecCippLogsSas",
});
};

return (
<CippButtonCard
title="CIPP Logs Table Access"
cardSx={{ display: "flex", flexDirection: "column", height: "100%" }}
CardButton={
<Button
variant="contained"
size="small"
onClick={handleGenerate}
disabled={generateSas.isPending || !formControl.formState.isValid}
startIcon={<Key style={{ width: 16, height: 16 }} />}
>
Generate SAS Token
</Button>
}
>
<Box sx={{ display: "flex", flexDirection: "column", gap: 2, flex: 1 }}>
<Alert severity="info">
Generate a read-only SAS token for the CIPP Logs table. This token can be used to query
log data from external SIEM tools or scripts using the Azure Table Storage REST API. Note
that generating a new URL does not invalidate previous URLs.
</Alert>

<Box>
<CippFormComponent
type="autoComplete"
name="Days"
label="Token Validity"
helperText="Select how long the SAS token should be valid for. Enter a custom value in days if needed."
multiple={false}
creatable={true}
options={[
{ label: "30 days", value: "30" },
{ label: "60 days", value: "60" },
{ label: "90 days", value: "90" },
{ label: "180 days", value: "180" },
{ label: "365 days", value: "365" },
{ label: "730 days (2 years)", value: "730" },
{ label: "1095 days (3 years)", value: "1095" },
{ label: "1825 days (5 years)", value: "1825" },
{ label: "3650 days (10 years)", value: "3650" },
]}
formControl={formControl}
validators={{ required: "Please select a validity period" }}
/>
</Box>

{generateSas.isError && (
<Alert severity="error">
{generateSas.error?.response?.data?.Results ||
generateSas.error?.message ||
"Failed to generate SAS token"}
</Alert>
)}

{generateSas.isSuccess && generateSas.data?.data?.Results && (
<>
<Alert severity="success">
SAS URL generated successfully. Copy this for your records, it will only be shown
once.
</Alert>
<Box>
<Typography variant="subtitle2" sx={{ mb: 0.5 }}>
SAS URL
</Typography>
<TextField
fullWidth
size="small"
value={generateSas.data.data.Results.SASUrl}
slotProps={{
input: {
readOnly: true,
endAdornment: (
<InputAdornment position="end">
<CippCopyToClipBoard text={generateSas.data.data.Results.SASUrl} />
</InputAdornment>
),
},
}}
/>
</Box>
<Box>
<Typography variant="subtitle2" sx={{ mb: 0.5 }}>
Expires On
</Typography>
<Typography variant="body2">
{new Date(generateSas.data.data.Results.ExpiresOn).toLocaleString()}
</Typography>
</Box>
</>
)}
</Box>
</CippButtonCard>
);
};

export default CippSiemSettings;
60 changes: 51 additions & 9 deletions src/components/CippStandards/CippStandardAccordion.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ const CippStandardAccordion = ({
initialConfigured[standardName] = isStandardConfigured(
standardName,
standard,
currentValues
currentValues,
);
}
});
Expand All @@ -271,6 +271,48 @@ const CippStandardAccordion = ({
}
}, [watchedValues, selectedStandards, editMode]);

// Sync internal state when selectedStandards keys change (e.g., after re-indexing on removal)
useEffect(() => {
const currentKeys = Object.keys(selectedStandards);
const stateKeys = Object.keys(savedValues);
if (stateKeys.length === 0) return;

const currentSet = new Set(currentKeys);
const stateSet = new Set(stateKeys);

const removedKeys = stateKeys.filter((k) => !currentSet.has(k));
const addedKeys = currentKeys.filter((k) => !stateSet.has(k));

if (removedKeys.length > 0 || addedKeys.length > 0) {
setSavedValues((prev) => {
const updated = { ...prev };
removedKeys.forEach((k) => delete updated[k]);
addedKeys.forEach((k) => {
const currentValues = _.get(watchedValues, k);
if (currentValues) {
updated[k] = _.cloneDeep(currentValues);
}
});
return updated;
});

setConfiguredState((prev) => {
const updated = { ...prev };
removedKeys.forEach((k) => delete updated[k]);
addedKeys.forEach((k) => {
const baseStandardName = k.split("[")[0];
const standard = providedStandards.find((s) => s.name === baseStandardName);
const currentValues = _.get(watchedValues, k);
if (standard && currentValues) {
updated[k] = isStandardConfigured(k, standard, currentValues);
}
});
return updated;
});
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [selectedStandards]);

// Save changes for a standard
const handleSave = (standardName, standard, current) => {
// Clone the current values to avoid reference issues
Expand Down Expand Up @@ -587,8 +629,8 @@ const CippStandardAccordion = ({
const accordionTitle = templateDisplayName
? `${standard.label} - ${templateDisplayName}`
: selectedTemplateName && _.get(selectedTemplateName, "label")
? `${standard.label} - ${_.get(selectedTemplateName, "label")}`
: standard.label;
? `${standard.label} - ${_.get(selectedTemplateName, "label")}`
: standard.label;

// Get current values and check if they differ from saved values
const current = _.get(watchedValues, standardName);
Expand All @@ -598,7 +640,7 @@ const CippStandardAccordion = ({

// Check if all required fields are filled
const requiredFieldsFilled = current
? standard.addedComponent?.every((component) => {
? (standard.addedComponent?.every((component) => {
// Always skip switches regardless of their required property
if (component.type === "switch") return true;

Expand Down Expand Up @@ -630,7 +672,7 @@ const CippStandardAccordion = ({
switch (compareType) {
case "valueEq":
conditionMet = conditionValue.some(
(item) => item?.[propertyName] === compareValue
(item) => item?.[propertyName] === compareValue,
);
break;
default:
Expand Down Expand Up @@ -658,7 +700,7 @@ const CippStandardAccordion = ({

// For other field types
return !!fieldValue;
}) ?? true
}) ?? true)
: false;

// ALWAYS require an action for all standards
Expand All @@ -668,7 +710,7 @@ const CippStandardAccordion = ({
const hasRequiredComponents =
standard.addedComponent &&
standard.addedComponent.some(
(comp) => comp.type !== "switch" && comp.required !== false
(comp) => comp.type !== "switch" && comp.required !== false,
);

// Action is always required and must be an array with at least one element
Expand Down Expand Up @@ -904,7 +946,7 @@ const CippStandardAccordion = ({
component={component}
formControl={formControl}
/>
)
),
)}
</>
)}
Expand Down Expand Up @@ -962,7 +1004,7 @@ const CippStandardAccordion = ({
component={component}
formControl={formControl}
/>
)
),
)}
</Grid>
</Grid>
Expand Down
29 changes: 13 additions & 16 deletions src/contexts/settings-context.js
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,12 @@ export const SettingsProvider = (props) => {
}
}, []);

useEffect(() => {
if (state.isInitialized) {
storeSettings(state);
}
}, [state]);

const handleReset = useCallback(() => {
deleteSettings();
setState((prevState) => ({
Expand All @@ -142,11 +148,6 @@ export const SettingsProvider = (props) => {
return acc;
}, {});

storeSettings({
...prevState,
...filteredSettings,
});

return {
...prevState,
...filteredSettings,
Expand All @@ -171,17 +172,13 @@ export const SettingsProvider = (props) => {
handleUpdate,
isCustom,
setLastUsedFilter: (page, filter) => {
setState((prevState) => {
const updated = {
...prevState,
lastUsedFilters: {
...prevState.lastUsedFilters,
[page]: filter,
},
};
storeSettings(updated);
return updated;
});
setState((prevState) => ({
...prevState,
lastUsedFilters: {
...prevState.lastUsedFilters,
[page]: filter,
},
}));
},
}}
>
Expand Down
2 changes: 2 additions & 0 deletions src/layouts/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,7 @@ export const Layout = (props) => {
var bookmarkLocked = settings.bookmarkLocked;
var bookmarkSortOrder = settings.bookmarkSortOrder;
var bookmarksOpen = settings.bookmarksOpen;
var compactNav = settings.compactNav;

settings.handleUpdate({
...userSettingsAPI.data,
Expand All @@ -246,6 +247,7 @@ export const Layout = (props) => {
bookmarkLocked,
bookmarkSortOrder,
bookmarksOpen,
compactNav,
showDevtools,
});

Expand Down
Loading