Skip to content

Commit

Permalink
adding new ability to limit credential dropdowns in the ui
Browse files Browse the repository at this point in the history
  • Loading branch information
its-a-feature committed Aug 21, 2024
1 parent 3be20a2 commit 4bc0e59
Show file tree
Hide file tree
Showing 19 changed files with 179 additions and 94 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.MD
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [3.3.0-rc19] - 2024-08-21

### Changed

- Added a new limit_credentials_by_type option to Command Parameters to reduce noise in the UI when using CredentialJson parameter types

## [3.3.0-rc18] - 2024-08-08

### Changed
Expand Down
6 changes: 6 additions & 0 deletions MythicReactUI/CHANGELOG.MD
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.2.31] - 2024-08-21

### Changed

- Added the option to use the limit_credentials_by_type field in command parameters to limit UI choices

## [0.2.29-30] - 2024-08-20

### Changed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,7 @@ query getCommandQuery($id: Int!){
choices
choices_are_all_commands
choices_are_loaded_commands
limit_credentials_by_type
default_value
description
id
Expand Down Expand Up @@ -565,14 +566,26 @@ export function TaskParametersDialog(props) {
case "FileMultiple":
return [...prev, {...cmd, value: []}];
case "CredentialJson":
if (loadedCredentialsLoading.credential.length > 0){
let credentialChoices = loadedCredentialsLoading.credential;
if(credentialChoices === undefined || credentialChoices === null){
credentialChoices = [];
}
if(cmd.limit_credentials_by_type?.length > 0){
credentialChoices = credentialChoices.reduce( (existingCreds, curCred) => {
if(cmd.limit_credentials_by_type.includes(curCred.type)){
return [...existingCreds, curCred];
}
return [...existingCreds];
}, []);
}
if (credentialChoices.length > 0){
if(parsedParameterName){
cmd.value = props.command.parsedParameters[parsedParameterName];
}
else if(cmd.value === "" || (typeof(cmd.value) === Object && Object.keys(cmd.value).length === 0) || cmd.value === undefined){
cmd.value = loadedCredentialsLoading.credential[0];
cmd.value = credentialChoices[0];
}
return [...prev, {...cmd, choices: loadedCredentialsLoading.credential}];
return [...prev, {...cmd, choices: credentialChoices}];
}else{
return [...prev, {...cmd, value: {}, choices: []}];
}
Expand Down
64 changes: 50 additions & 14 deletions MythicReactUI/src/components/pages/Search/SearchTabCredentials.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import { MythicDialog } from '../../MythicComponents/MythicDialog';
import {CredentialTableNewCredentialDialog} from './CredentialTableNewCredentialDialog';
import MenuItem from '@mui/material/MenuItem';
import Select from '@mui/material/Select';
import VisibilityOffIcon from '@mui/icons-material/VisibilityOff';
import VisibilityIcon from '@mui/icons-material/Visibility';

const credentialFragment = gql`
fragment credentialData on credential{
Expand Down Expand Up @@ -52,52 +54,52 @@ fragment credentialData on credential{
const fetchLimit = 20;
const accountSearch = gql`
${credentialFragment}
query accountQuery($operation_id: Int!, $account: String!, $offset: Int!, $fetchLimit: Int!) {
credential_aggregate(distinct_on: id, where: {account: {_ilike: $account}, operation_id: {_eq: $operation_id}}) {
query accountQuery($operation_id: Int!, $account: String!, $offset: Int!, $fetchLimit: Int!, $deleted: Boolean!) {
credential_aggregate(distinct_on: id, where: {account: {_ilike: $account}, operation_id: {_eq: $operation_id}, deleted: {_eq: $deleted}}) {
aggregate {
count
}
}
credential(limit: $fetchLimit, distinct_on: id, offset: $offset, order_by: {id: desc}, where: {account: {_ilike: $account}, operation_id: {_eq: $operation_id}}) {
credential(limit: $fetchLimit, distinct_on: id, offset: $offset, order_by: {id: desc}, where: {account: {_ilike: $account}, operation_id: {_eq: $operation_id}, deleted: {_eq: $deleted}}) {
...credentialData
}
}
`;
const realmSearch = gql`
${credentialFragment}
query realmQuery($operation_id: Int!, $realm: String!, $offset: Int!, $fetchLimit: Int!) {
credential_aggregate(distinct_on: id, where: {realm: {_ilike: $realm}, operation_id: {_eq: $operation_id}}) {
query realmQuery($operation_id: Int!, $realm: String!, $offset: Int!, $fetchLimit: Int!, $deleted: Boolean!) {
credential_aggregate(distinct_on: id, where: {realm: {_ilike: $realm}, operation_id: {_eq: $operation_id}, deleted: {_eq: $deleted}}) {
aggregate {
count
}
}
credential(limit: $fetchLimit, distinct_on: id, offset: $offset, order_by: {id: desc}, where: {realm: {_ilike: $realm}, operation_id: {_eq: $operation_id}}) {
credential(limit: $fetchLimit, distinct_on: id, offset: $offset, order_by: {id: desc}, where: {realm: {_ilike: $realm}, operation_id: {_eq: $operation_id}, deleted: {_eq: $deleted}}) {
...credentialData
}
}
`;
const credentialSearch = gql`
${credentialFragment}
query credQuery($operation_id: Int!, $credential: String!, $offset: Int!, $fetchLimit: Int!) {
credential_aggregate(distinct_on: id, where: {credential_text: {_ilike: $credential}, operation_id: {_eq: $operation_id}}) {
query credQuery($operation_id: Int!, $credential: String!, $offset: Int!, $fetchLimit: Int!, $deleted: Boolean!) {
credential_aggregate(distinct_on: id, where: {credential_text: {_ilike: $credential}, operation_id: {_eq: $operation_id}, deleted: {_eq: $deleted}}) {
aggregate {
count
}
}
credential(limit: $fetchLimit, distinct_on: id, offset: $offset, order_by: {id: desc}, where: {credential_text: {_ilike: $credential}, operation_id: {_eq: $operation_id}}) {
credential(limit: $fetchLimit, distinct_on: id, offset: $offset, order_by: {id: desc}, where: {credential_text: {_ilike: $credential}, operation_id: {_eq: $operation_id}, deleted: {_eq: $deleted}}) {
...credentialData
}
}
`;
const commentSearch = gql`
${credentialFragment}
query commentQuery($operation_id: Int!, $comment: String!, $offset: Int!, $fetchLimit: Int!) {
credential_aggregate(distinct_on: id, where: {comment: {_ilike: $comment}, operation_id: {_eq: $operation_id}}) {
query commentQuery($operation_id: Int!, $comment: String!, $offset: Int!, $fetchLimit: Int!, $deleted: Boolean!) {
credential_aggregate(distinct_on: id, where: {comment: {_ilike: $comment}, operation_id: {_eq: $operation_id}, deleted: {_eq: $deleted}}) {
aggregate {
count
}
}
credential(limit: $fetchLimit, distinct_on: id, offset: $offset, order_by: {id: desc}, where: {comment: {_ilike: $comment}, operation_id: {_eq: $operation_id}}) {
credential(limit: $fetchLimit, distinct_on: id, offset: $offset, order_by: {id: desc}, where: {comment: {_ilike: $comment}, operation_id: {_eq: $operation_id}, deleted: {_eq: $deleted}}) {
...credentialData
}
}
Expand Down Expand Up @@ -136,6 +138,7 @@ export function SearchTabCredentialsLabel(props){

const SearchTabCredentialsSearchPanel = (props) => {
const [search, setSearch] = React.useState("");
const [showDeleted, setShowDeleted] = React.useState(false);
const [searchField, setSearchField] = React.useState("Account");
const searchFieldOptions = ["Account", "Realm", "Comment", "Credential", "Tag"];
const [createCredentialDialogOpen, setCreateCredentialDialogOpen] = React.useState(false);
Expand Down Expand Up @@ -188,6 +191,10 @@ const SearchTabCredentialsSearchPanel = (props) => {
break;
}
}
const handleToggleShowDeleted = (event) => {
setShowDeleted(!showDeleted);
props.onChangeDeletedField(!showDeleted);
}
const onCreateCredential = ({type, account, realm, comment, credential}) => {
createCredential({variables: {type, account, realm, comment, credential}})
}
Expand Down Expand Up @@ -247,7 +254,26 @@ const SearchTabCredentialsSearchPanel = (props) => {
/>
}

<Button size="small" color="success" onClick={ () => {setCreateCredentialDialogOpen(true);}} variant="contained">New Credential</Button>
<Button style={{marginRight: "5px"}}
size="small" color="success" onClick={ () => {setCreateCredentialDialogOpen(true);}} variant="contained">
<VpnKeyIcon style={{marginRight: "5px"}} />
New
</Button>
<Button variant={"contained"} color={"primary"} size={"small"} onClick={handleToggleShowDeleted}>
{showDeleted ? (
<>
<VisibilityIcon style={{marginRight: "5px"}} />
{"Deleted"}
</>

) : (
<>
<VisibilityOffIcon style={{marginRight: "5px"}} />
{ "Deleted"}
</>

)}
</Button>
</Grid>
</Grid>
);
Expand All @@ -258,7 +284,11 @@ export const SearchTabCredentialsPanel = (props) =>{
const [search, setSearch] = React.useState("");
const [searchField, setSearchField] = React.useState("Account");
const me = props.me;

const showDeleted = React.useRef(false);
const onChangeDeletedField = (newShowDeleted) => {
showDeleted.current = newShowDeleted;
onChangeSearchField(searchField);
}
const onChangeSearchField = (field) => {
setSearchField(field);
switch(field){
Expand Down Expand Up @@ -330,6 +360,7 @@ export const SearchTabCredentialsPanel = (props) =>{
offset: offset,
fetchLimit: fetchLimit,
account: "%" + search + "%",
deleted: showDeleted.current
}})
}
const onRealmSearch = ({search, offset}) => {
Expand All @@ -340,6 +371,7 @@ export const SearchTabCredentialsPanel = (props) =>{
offset: offset,
fetchLimit: fetchLimit,
realm: "%" + search + "%",
deleted: showDeleted.current
}})
}
const onCredentialSearch = ({search, offset}) => {
Expand All @@ -350,6 +382,7 @@ export const SearchTabCredentialsPanel = (props) =>{
offset: offset,
fetchLimit: fetchLimit,
credential: "%" + search + "%",
deleted: showDeleted.current
}})
}
const onCommentSearch = ({search, offset}) => {
Expand All @@ -364,6 +397,7 @@ export const SearchTabCredentialsPanel = (props) =>{
offset: offset,
fetchLimit: fetchLimit,
comment: "%" + new_search + "%",
deleted: showDeleted.current
}})
}
const onTagSearch = ({search, offset}) => {
Expand All @@ -378,6 +412,7 @@ export const SearchTabCredentialsPanel = (props) =>{
offset: offset,
fetchLimit: fetchLimit,
tag: "%" + new_search + "%",
deleted: showDeleted.current
}})
}
const onChangePage = (event, value) => {
Expand Down Expand Up @@ -435,6 +470,7 @@ export const SearchTabCredentialsPanel = (props) =>{
onRealmSearch={onRealmSearch} onCredentialSearch={onCredentialSearch}
onCommentSearch={onCommentSearch} changeSearchParam={props.changeSearchParam}
onTagSearch={onTagSearch} onNewCredential={onNewCredential}
onChangeDeletedField={onChangeDeletedField}
/>
<div style={{overflowY: "auto", flexGrow: 1}}>
{credentialaData.length > 0 ? (
Expand Down
2 changes: 1 addition & 1 deletion MythicReactUI/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {snackActions} from './components/utilities/Snackbar';
import jwt_decode from 'jwt-decode';
import {meState} from './cache';

export const mythicUIVersion = "0.2.30";
export const mythicUIVersion = "0.2.31";

let fetchingNewToken = false;

Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3.3.0-rc18
3.3.0-rc19
Loading

0 comments on commit 4bc0e59

Please sign in to comment.