Skip to content

Commit

Permalink
[backend] elementWithTargetTypes filters with not_eq (#6390)
Browse files Browse the repository at this point in the history
  • Loading branch information
Archidoit committed Mar 21, 2024
1 parent 2bd6113 commit 56d9545
Show file tree
Hide file tree
Showing 5 changed files with 65 additions and 14 deletions.
61 changes: 56 additions & 5 deletions opencti-platform/opencti-graphql/src/database/engine.js
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ import {
complexConversionFilterKeys,
COMPUTED_RELIABILITY_FILTER,
IDS_FILTER,
INSTANCE_FILTER_TARGET_TYPES,
INSTANCE_RELATION_TYPES_FILTER,
INSTANCE_REGARDING_OF,
INSTANCE_RELATION_FILTER,
RELATION_FROM_FILTER,
Expand Down Expand Up @@ -2289,9 +2289,60 @@ const completeSpecialFilterKeys = async (context, user, inputFilters) => {
];
finalFilters.push({ key: 'connections', nested, mode: filter.mode });
}
if (filterKey === INSTANCE_FILTER_TARGET_TYPES) {
const nested = [{ key: 'types', operator: filter.operator, values: filter.values }];
finalFilters.push({ key: 'connections', nested, mode: filter.mode });
if (filterKey === INSTANCE_RELATION_TYPES_FILTER) {
// define mode for the filter group
let globalMode = 'or';
if (filter.operator === 'eq' || filter.operator === 'not_nil') {
// relatedType = malware <-> fromType = malware OR toType = malware
// relatedType is not empty <-> fromType is not empty OR toType is not empty
globalMode = 'or';
} else if (filter.operator === 'not_eq' || filter.operator === 'nil') {
// relatedType != malware <-> fromType != malware AND toType != malware
// relatedType is empty <-> fromType is empty AND toType is empty
globalMode = 'and';
} else {
throw Error(`${INSTANCE_RELATION_TYPES_FILTER} filter only support 'eq', 'not_eq', 'nil' and 'not_nil' operators, not ${filter.operator}.`);
}
// define the filter group
if (filter.operator === 'eq' || filter.operator === 'not_eq') {
const filterGroupsForValues = filter.values.map((val) => {
const nestedFrom = [
{ key: 'types', operator: filter.operator, values: [val] },
{ key: 'role', operator: 'wildcard', values: ['*_from'] }
];
const nestedTo = [
{ key: 'types', operator: filter.operator, values: [val] },
{ key: 'role', operator: 'wildcard', values: ['*_to'] }
];
return {
mode: globalMode,
filters: [{ key: 'connections', nested: nestedFrom, mode: filter.mode }, { key: 'connections', nested: nestedTo, mode: filter.mode }],
filterGroups: [],
};
});
finalFilterGroups.push({
mode: filter.mode,
filters: [],
filterGroups: filterGroupsForValues,
});
} else if (filter.operator === 'nil' || filter.operator === 'not_nil') {
const nestedFrom = [
{ key: 'types', operator: filter.operator, values: [] },
{ key: 'role', operator: 'wildcard', values: ['*_from'] }
];
const nestedTo = [
{ key: 'types', operator: filter.operator, values: [] },
{ key: 'role', operator: 'wildcard', values: ['*_to'] }
];
const innerFilters = [{ key: 'connections', nested: nestedFrom, mode: filter.mode }, { key: 'connections', nested: nestedTo, mode: filter.mode }];
console.log('filters', innerFilters);
console.log('filters00', innerFilters[0].nested);
finalFilterGroups.push({
mode: globalMode,
filters: innerFilters,
filterGroups: [],
});
}
}
if (filterKey === RELATION_FROM_ROLE_FILTER || filterKey === RELATION_TO_ROLE_FILTER) {
const side = filterKey === RELATION_FROM_ROLE_FILTER ? 'from' : 'to';
Expand All @@ -2303,7 +2354,7 @@ const completeSpecialFilterKeys = async (context, user, inputFilters) => {
if (filterKey === ALIAS_FILTER) {
finalFilters.push({ ...filter, key: [ATTRIBUTE_ALIASES, ATTRIBUTE_ALIASES_OPENCTI] });
}
} else if (arrayKeys.some((fiterKey) => isObjectAttribute(fiterKey)) && !arrayKeys.some((fiterKey) => fiterKey === 'connections')) {
} else if (arrayKeys.some((filterKey) => isObjectAttribute(filterKey)) && !arrayKeys.some((filterKey) => filterKey === 'connections')) {
if (arrayKeys.length > 1) {
throw UnsupportedError('A filter with these multiple keys is not supported', { keys: arrayKeys });
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {
import { schemaAttributesDefinition } from '../../schema/schema-attributes';
import { ABSTRACT_BASIC_RELATIONSHIP } from '../../schema/general';
import {
INSTANCE_FILTER_TARGET_TYPES,
INSTANCE_RELATION_TYPES_FILTER,
INSTANCE_RELATION_FILTER,
RELATION_FROM_FILTER,
RELATION_FROM_TYPES_FILTER,
Expand Down Expand Up @@ -44,7 +44,7 @@ export const connections: AttributeDefinition = {
},
{ name: 'name', label: 'Name', type: 'string', format: 'short', editDefault: false, mandatoryType: 'no', multiple: true, upsert: true, isFilterable: false },
{ name: 'role', label: 'Role', type: 'string', format: 'short', editDefault: false, mandatoryType: 'no', multiple: true, upsert: true, isFilterable: false },
{ name: 'types', label: 'Types', type: 'string', format: 'short', editDefault: false, mandatoryType: 'no', multiple: true, upsert: true, isFilterable: false, associatedFilterKeys: [{ key: RELATION_FROM_TYPES_FILTER, label: 'Source type' }, { key: RELATION_TO_TYPES_FILTER, label: 'Target type' }, { key: INSTANCE_FILTER_TARGET_TYPES, label: 'Related type' }] },
{ name: 'types', label: 'Types', type: 'string', format: 'short', editDefault: false, mandatoryType: 'no', multiple: true, upsert: true, isFilterable: false, associatedFilterKeys: [{ key: RELATION_FROM_TYPES_FILTER, label: 'Source type' }, { key: RELATION_TO_TYPES_FILTER, label: 'Target type' }, { key: INSTANCE_RELATION_TYPES_FILTER, label: 'Related type' }] },
],
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { STIX_CORE_RELATIONSHIPS } from '../../schema/stixCoreRelationship';
import { connections } from './basicRelationship-registrationAttributes';
import { internalId } from '../../schema/attribute-definition';
import {
INSTANCE_FILTER_TARGET_TYPES,
INSTANCE_RELATION_TYPES_FILTER,
INSTANCE_RELATION_FILTER,
RELATION_FROM_FILTER,
RELATION_FROM_TYPES_FILTER,
Expand All @@ -28,7 +28,7 @@ export const stixCoreRelationshipsAttributes: Array<AttributeDefinition> = [
},
{ name: 'name', label: 'Name', type: 'string', format: 'short', editDefault: false, mandatoryType: 'no', multiple: true, upsert: true, isFilterable: false },
{ name: 'role', label: 'Role', type: 'string', format: 'short', editDefault: false, mandatoryType: 'no', multiple: true, upsert: true, isFilterable: false },
{ name: 'types', label: 'Types', type: 'string', format: 'short', editDefault: false, mandatoryType: 'no', multiple: true, upsert: true, isFilterable: true, associatedFilterKeys: [{ key: RELATION_FROM_TYPES_FILTER, label: 'Source type' }, { key: RELATION_TO_TYPES_FILTER, label: 'Target type' }, { key: INSTANCE_FILTER_TARGET_TYPES, label: 'Related type' }] },
{ name: 'types', label: 'Types', type: 'string', format: 'short', editDefault: false, mandatoryType: 'no', multiple: true, upsert: true, isFilterable: true, associatedFilterKeys: [{ key: RELATION_FROM_TYPES_FILTER, label: 'Source type' }, { key: RELATION_TO_TYPES_FILTER, label: 'Target type' }, { key: INSTANCE_RELATION_TYPES_FILTER, label: 'Related type' }] },
],
},
{ name: 'entity_type', label: 'Entity type', type: 'string', format: 'short', editDefault: false, mandatoryType: 'no', multiple: true, upsert: true, isFilterable: false },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export const RELATION_FROM_ROLE_FILTER = 'fromRole';
export const RELATION_TO_ROLE_FILTER = 'toRole';
export const RELATION_FROM_TYPES_FILTER = 'fromTypes';
export const RELATION_TO_TYPES_FILTER = 'toTypes';
export const INSTANCE_FILTER_TARGET_TYPES = 'elementWithTargetTypes'; // TODO Rename/migrate to fromOrToType
export const INSTANCE_RELATION_TYPES_FILTER = 'elementWithTargetTypes'; // TODO Rename/migrate to fromOrToType
export const CONNECTED_TO_INSTANCE_FILTER = 'connectedToId'; // TODO Rename/migrate to triggerListenId
export const CONNECTED_TO_INSTANCE_SIDE_EVENTS_FILTER = 'connectedToId_sideEvents';

Expand Down Expand Up @@ -75,7 +75,7 @@ export const complexConversionFilterKeys = [
SOURCE_RELIABILITY_FILTER, // reliability of the author
COMPUTED_RELIABILITY_FILTER, // reliability, or reliabilityof the author if no reliability
INSTANCE_RELATION_FILTER, // nested relation for the from or to of a relationship
INSTANCE_FILTER_TARGET_TYPES, // nested relation for the from or type type of a relationship
INSTANCE_RELATION_TYPES_FILTER, // nested relation for the from or type type of a relationship
RELATION_FROM_FILTER, // nested relation for the from of a relationship
RELATION_TO_FILTER, // nested relation for the to of a relationship
RELATION_TO_SIGHTING_FILTER, // nested sigthing relation for the to of a sighting
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import {
ALIAS_FILTER,
CONNECTED_TO_INSTANCE_FILTER,
CONTEXT_OBJECT_LABEL_FILTER,
INSTANCE_FILTER_TARGET_TYPES,
INSTANCE_RELATION_TYPES_FILTER,
INSTANCE_REGARDING_OF,
RELATION_FROM_FILTER,
RELATION_TO_TYPES_FILTER,
Expand Down Expand Up @@ -152,8 +152,8 @@ describe('Filter keys schema generation testing', async () => {
expect(filterDefinition?.label).toEqual('Target type');
expect(filterDefinition?.elementsForFilterValuesSearch.length).toEqual(0);
// 'elementWithTargetTypes' for stix core relationships
filterDefinition = filterKeysSchema.get(ABSTRACT_STIX_CORE_RELATIONSHIP)?.get(INSTANCE_FILTER_TARGET_TYPES);
expect(filterDefinition?.filterKey).toEqual(INSTANCE_FILTER_TARGET_TYPES);
filterDefinition = filterKeysSchema.get(ABSTRACT_STIX_CORE_RELATIONSHIP)?.get(INSTANCE_RELATION_TYPES_FILTER);
expect(filterDefinition?.filterKey).toEqual(INSTANCE_RELATION_TYPES_FILTER);
expect(filterDefinition?.type).toEqual('string');
// 'fromId' for basic relationships: not filterable
filterDefinition = filterKeysSchema.get(ABSTRACT_BASIC_RELATIONSHIP)?.get(RELATION_FROM_FILTER);
Expand Down

0 comments on commit 56d9545

Please sign in to comment.