Skip to content

Commit fa4b57d

Browse files
committed
adding new UI option for vertical/customizable nav bar
1 parent 90128d0 commit fa4b57d

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+1027
-91
lines changed

CHANGELOG.MD

+6
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file.
44
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
55
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

7+
## [3.3.1-rc35] - 2024-12-28
8+
9+
### Changed
10+
11+
- Added a check in file download to return error if chunk num > 0 and no chunk data present
12+
713
## [3.3.1-rc34] - 2024-12-23
814

915
### Changed

MythicReactUI/CHANGELOG.MD

+9
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,15 @@ All notable changes to this project will be documented in this file.
44
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
55
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

7+
## [0.2.71] - 2024-12-28
8+
9+
### Changed
10+
11+
- Fixed an issue where color wasn't being updated with callback table's dropdown arrow only context menu
12+
- Added an experimental UI option to use a side navigation bar instead of a top one
13+
- The side navbar allows you to edit/reorder your shortcuts
14+
- Fixed an issue where tasks with no output would have a spinning circle forever
15+
716
## [0.2.70] - 2024-12-25
817

918
### Changed

MythicReactUI/src/assets/graphql.png

52.1 KB
Loading

MythicReactUI/src/assets/jupyter.png

7.62 KB
Loading

MythicReactUI/src/components/App.js

+105-41
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import { Callbacks } from './pages/Callbacks/Callbacks';
1414
import { Search } from './pages/Search/Search';
1515
import { ConsumingServices } from './pages/ConsumingServices/ConsumingServices';
1616
import React, {createContext} from 'react';
17-
import { TopAppBar } from './TopAppBar';
17+
import { Typography } from '@mui/material';
1818
import { useReactiveVar } from '@apollo/client';
1919
import { useDarkMode } from './utilities/useDarkMode';
2020
import { SingleTaskView } from './pages/SingleTaskView/SingleTaskView';
@@ -38,6 +38,8 @@ import "react-toastify/dist/ReactToastify.css";
3838
import {Eventing} from "./pages/Eventing/Eventing";
3939
import {InviteForm} from "./pages/Login/InviteForm";
4040
import {snackActions} from "./utilities/Snackbar";
41+
import {TopAppBarVertical} from "./TopAppBarVertical";
42+
import {TopAppBar} from "./TopAppBar";
4143

4244
export const userSettingsQuery = gql`
4345
query getUserSettings {
@@ -184,55 +186,117 @@ export function App(props) {
184186
<ThemeProvider theme={theme}>
185187
<GlobalStyles theme={theme} />
186188
<CssBaseline />
187-
<Tooltip id={"my-tooltip"} style={{zIndex: 100000, wordBreak: "break-word", width: "80%"}}/>
189+
<Tooltip id={"my-tooltip"} style={{zIndex: 100000, wordBreak: "break-word", maxWidth: "80%"}}/>
188190
<ToastContainer limit={2} autoClose={3000}
189191
theme={themeMode}
190192
style={{maxWidth: "100%", minWidth: "40%", width: "40%", marginTop: "20px", display: "flex", flexWrap: "wrap",
191193
wordBreak: "break-all", flexDirection: "column", justifyContent: "center"}}
192194
pauseOnFocusLoss={false} />
193-
<div style={{ maxHeight: '100%', height: '100%', display: 'flex', flexDirection: 'column' }}>
194-
<div style={{ minHeight: '50px', flexGrow: 0 }}>
195-
{me.loggedIn && me.user !== undefined && me.user !== null ? (
196-
<TopAppBar me={me} theme={themeMode} toggleTheme={themeToggler} />
197-
) : null}
198-
</div>
199-
{openRefreshDialog &&
200-
<MythicDialog fullWidth={true} maxWidth="sm" open={openRefreshDialog}
201-
onClose={()=>{setOpenRefreshDialog(false);}}
202-
innerDialog={<RefreshTokenDialog
203-
onClose={()=>{setOpenRefreshDialog(false);}} />}
195+
<div style={{ maxHeight: '100%', height: '100%', display: 'flex', flexDirection: 'row', maxWidth: "100%", width:"100%" }}>
196+
197+
{openRefreshDialog &&
198+
<MythicDialog fullWidth={true} maxWidth="sm" open={openRefreshDialog}
199+
onClose={()=>{setOpenRefreshDialog(false);}}
200+
innerDialog={<RefreshTokenDialog
201+
onClose={()=>{setOpenRefreshDialog(false);}} />}
204202
/>
205203
}
206-
<div style={{ margin: '0px 2px 0px 5px', flexGrow: 1, flexDirection: 'column', height: "calc(100% - 5rem)", }}>
207-
<Routes>
208-
<Route path='/new/login' element={<LoginForm me={me}/>}/>
209-
<Route path='/new/invite' element={<InviteForm me={me}/>}/>
210-
<Route path='/' element={<LoggedInRoute me={me}><Home me={me}/></LoggedInRoute>} />
211-
<Route exact path='/new' element={<LoggedInRoute me={me}><Home me={me}/></LoggedInRoute>} />
212-
<Route exact path='/new/settings' element={<LoggedInRoute me={me}><Settings me={me}/></LoggedInRoute>} />
213-
<Route exact path='/new/payloadtypes' element={<LoggedInRoute me={me}><PayloadTypesC2Profiles me={me}/></LoggedInRoute>} />
214-
<Route exact path='/new/eventfeed' element={<LoggedInRoute me={me}><EventFeed me={me}/></LoggedInRoute>} />
215-
<Route exact path='/new/createpayload' element={<LoggedInRoute me={me}><CreatePayload me={me}/></LoggedInRoute>} />
216-
<Route exact path='/new/createwrapper' element={<LoggedInRoute me={me}><CreatePayloadWrapper me={me}/></LoggedInRoute>} />
217-
<Route exact path='/new/payloads' element={<LoggedInRoute me={me}><Payloads me={me} /></LoggedInRoute>} />
218-
<Route exact path='/new/c2profiles' element={<LoggedInRoute me={me}><PayloadTypesC2Profiles me={me}/></LoggedInRoute>} />
219-
<Route exact path='/new/services/' element={<LoggedInRoute me={me}><PayloadTypesC2Profiles me={me}/></LoggedInRoute>} />
220-
<Route exact path='/new/callbacks' element={<LoggedInRoute me={me}><Callbacks me={me}/></LoggedInRoute>} />
221-
<Route path='/new/search' element={<LoggedInRoute me={me}><Search history={props.history} me={me} /></LoggedInRoute>} />
222-
<Route exact path='/new/browserscripts' element={<LoggedInRoute me={me}><BrowserScripts me={me}/></LoggedInRoute>} />
223-
<Route exact path='/new/task/:taskId' element={<LoggedInRoute me={me}><SingleTaskView me={me}/></LoggedInRoute>} />
224-
<Route exact path='/new/tasks/by_range' element={<LoggedInRoute me={me}><SingleTaskView me={me}/></LoggedInRoute>} />
225-
<Route exact path='/new/operations' element={<LoggedInRoute me={me}><Operations me={me}/></LoggedInRoute>} />
226-
<Route exact path='/new/callbacks/:callbackDisplayId' element={<LoggedInRoute me={me}><ExpandedCallback me={me}/></LoggedInRoute>} />
227-
<Route exact path='/new/reporting' element={<LoggedInRoute me={me}><Reporting me={me}/></LoggedInRoute>} />
228-
<Route exact path='/new/mitre' element={<LoggedInRoute me={me}><MitreAttack me={me}/></LoggedInRoute>} />
229-
<Route exact path='/new/tagtypes' element={<LoggedInRoute me={me}><Tags me={me}/></LoggedInRoute>} />
230-
<Route exact path='/new/consuming_services' element={<LoggedInRoute me={me}><ConsumingServices me={me}/></LoggedInRoute>} />
231-
<Route exact path='/new/eventing' element={<LoggedInRoute me={me}><Eventing me={me}/></LoggedInRoute>} />
232-
</Routes>
204+
{me.loggedIn && me.user !== undefined && me.user !== null && preferences?.["experiment-newSidebar"] ? (
205+
<TopAppBarVertical me={me} theme={themeMode} toggleTheme={themeToggler} />
206+
) : null}
207+
<div style={{
208+
maxHeight: '100%',
209+
height: '100%',
210+
display: 'flex',
211+
flexDirection: 'column',
212+
width: "100%"
213+
}}>
214+
{me.loggedIn && !preferences?.["experiment-newSidebar"] &&
215+
<div style={{minHeight: '50px', flexGrow: 0}}>
216+
{me.loggedIn && me.user !== undefined && me.user !== null ? (
217+
<TopAppBar me={me} theme={themeMode} toggleTheme={themeToggler}/>
218+
) : null}
219+
</div>
220+
}
221+
{me?.user?.current_operation_banner_text !== "" &&
222+
<Typography style={{
223+
backgroundColor: me?.user?.current_operation_banner_color,
224+
width: "100%",
225+
textAlign: "center",
226+
fontWeight: "600",
227+
color: "white",
228+
borderRadius: "4px",
229+
border: "1px solid grey"
230+
}}>
231+
{me?.user?.current_operation_banner_text}
232+
</Typography>
233+
}
234+
<div style={{
235+
margin: '0px 2px 0px 5px',
236+
flexGrow: 1,
237+
flexDirection: 'column',
238+
height: "calc(100% - 5rem)",
239+
}}>
240+
<Routes>
241+
<Route path='/new/login' element={<LoginForm me={me}/>}/>
242+
<Route path='/new/invite' element={<InviteForm me={me}/>}/>
243+
<Route path='/' element={<LoggedInRoute me={me}><Home me={me}/></LoggedInRoute>}/>
244+
<Route exact path='/new'
245+
element={<LoggedInRoute me={me}><Home me={me}/></LoggedInRoute>}/>
246+
<Route exact path='/new/settings'
247+
element={<LoggedInRoute me={me}><Settings me={me}/></LoggedInRoute>}/>
248+
<Route exact path='/new/payloadtypes'
249+
element={<LoggedInRoute me={me}><PayloadTypesC2Profiles
250+
me={me}/></LoggedInRoute>}/>
251+
<Route exact path='/new/eventfeed'
252+
element={<LoggedInRoute me={me}><EventFeed me={me}/></LoggedInRoute>}/>
253+
<Route exact path='/new/createpayload'
254+
element={<LoggedInRoute me={me}><CreatePayload me={me}/></LoggedInRoute>}/>
255+
<Route exact path='/new/createwrapper'
256+
element={<LoggedInRoute me={me}><CreatePayloadWrapper
257+
me={me}/></LoggedInRoute>}/>
258+
<Route exact path='/new/payloads'
259+
element={<LoggedInRoute me={me}><Payloads me={me}/></LoggedInRoute>}/>
260+
<Route exact path='/new/c2profiles'
261+
element={<LoggedInRoute me={me}><PayloadTypesC2Profiles
262+
me={me}/></LoggedInRoute>}/>
263+
<Route exact path='/new/services/'
264+
element={<LoggedInRoute me={me}><PayloadTypesC2Profiles
265+
me={me}/></LoggedInRoute>}/>
266+
<Route exact path='/new/callbacks'
267+
element={<LoggedInRoute me={me}><Callbacks me={me}/></LoggedInRoute>}/>
268+
<Route path='/new/search'
269+
element={<LoggedInRoute me={me}><Search history={props.history}
270+
me={me}/></LoggedInRoute>}/>
271+
<Route exact path='/new/browserscripts'
272+
element={<LoggedInRoute me={me}><BrowserScripts me={me}/></LoggedInRoute>}/>
273+
<Route exact path='/new/task/:taskId'
274+
element={<LoggedInRoute me={me}><SingleTaskView me={me}/></LoggedInRoute>}/>
275+
<Route exact path='/new/tasks/by_range'
276+
element={<LoggedInRoute me={me}><SingleTaskView me={me}/></LoggedInRoute>}/>
277+
<Route exact path='/new/operations'
278+
element={<LoggedInRoute me={me}><Operations me={me}/></LoggedInRoute>}/>
279+
<Route exact path='/new/callbacks/:callbackDisplayId'
280+
element={<LoggedInRoute me={me}><ExpandedCallback
281+
me={me}/></LoggedInRoute>}/>
282+
<Route exact path='/new/reporting'
283+
element={<LoggedInRoute me={me}><Reporting me={me}/></LoggedInRoute>}/>
284+
<Route exact path='/new/mitre'
285+
element={<LoggedInRoute me={me}><MitreAttack me={me}/></LoggedInRoute>}/>
286+
<Route exact path='/new/tagtypes'
287+
element={<LoggedInRoute me={me}><Tags me={me}/></LoggedInRoute>}/>
288+
<Route exact path='/new/consuming_services'
289+
element={<LoggedInRoute me={me}><ConsumingServices
290+
me={me}/></LoggedInRoute>}/>
291+
<Route exact path='/new/eventing'
292+
element={<LoggedInRoute me={me}><Eventing me={me}/></LoggedInRoute>}/>
293+
</Routes>
294+
</div>
233295
</div>
296+
297+
234298
</div>
235-
299+
236300
</ThemeProvider>
237301
</StyledEngineProvider>
238302
);

MythicReactUI/src/components/MythicComponents/MythicSavedUserSetting.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ export function useGetMythicSetting({setting_name, default_value}){
3333
React.useEffect( () => {
3434
let newSetting = GetMythicSetting({setting_name, default_value});
3535
setSetting(newSetting);
36-
}, [preferences]);
36+
}, [preferences?.[setting_name]]);
3737

3838
return setting;
3939
}

MythicReactUI/src/components/TopAppBar.js

-6
Original file line numberDiff line numberDiff line change
@@ -434,12 +434,6 @@ export function TopAppBar(props) {
434434
</List>
435435
<Divider />
436436
</StyledDrawer>
437-
{me?.user?.current_operation_banner_text !== "" &&
438-
<Typography style={{backgroundColor: me?.user?.current_operation_banner_color,
439-
width: "100%", textAlign: "center", fontWeight: "600", color: "white", borderRadius: "4px", border: "1px solid grey"}} >
440-
{me?.user?.current_operation_banner_text}
441-
</Typography>
442-
}
443437
</>
444438
);
445439
}

MythicReactUI/src/components/TopAppBarEventLogNotifications.js

+22
Original file line numberDiff line numberDiff line change
@@ -50,4 +50,26 @@ export function TopAppBarEventLogNotifications(props) {
5050
</MythicStyledTooltip>
5151
);
5252
}
53+
export function TopAppBarVerticalEventLogNotifications(props) {
54+
const { loading, error, data } = useSubscription(SUB_Event_Logs, {
55+
onError: data => {
56+
snackActions.error("Mythic encountered an error getting event log messages: " + data.toString());
57+
console.error(data);
58+
}
59+
});
60+
61+
return (
62+
error ? (
63+
<Badge color="secondary" badgeContent={0}>
64+
<NotificationsActiveTwoToneIcon style={{color: "white"}} fontSize={"medium"} />
65+
</Badge>
66+
) : (
67+
<Badge badgeContent={data?.operation_stream[0]?.alert_count || 0}
68+
color="error" max={99}
69+
>
70+
<NotificationsActiveTwoToneIcon style={{color: "white"}} fontSize={"medium"}/>
71+
</Badge>
72+
)
73+
);
74+
}
5375

0 commit comments

Comments
 (0)