Skip to content

Commit

Permalink
squashed
Browse files Browse the repository at this point in the history
  • Loading branch information
ValentinBouzinFiligran committed Oct 16, 2024
1 parent 0b6da6a commit 1c40ec7
Show file tree
Hide file tree
Showing 13 changed files with 85 additions and 23 deletions.
1 change: 1 addition & 0 deletions opencti-platform/opencti-front/lang/back/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,7 @@
"Observable content": "Observierbarer Inhalt",
"Observable description": "Observable Beschreibung",
"Observables": "Observables",
"Observables values": "Observable Werte",
"Opened connection": "Geöffnete Verbindung",
"Operating System": "Betriebssystem",
"Operation": "Operation",
Expand Down
1 change: 1 addition & 0 deletions opencti-platform/opencti-front/lang/back/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,7 @@
"Observable content": "Observable content",
"Observable description": "Observable description",
"Observables": "Observables",
"Observables values": "Observables values",
"Opened connection": "Opened connection",
"Operating System": "Operating System",
"Operation": "Operation",
Expand Down
1 change: 1 addition & 0 deletions opencti-platform/opencti-front/lang/back/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,7 @@
"Observable content": "Contenido observable",
"Observable description": "Descripción observable",
"Observables": "Observables",
"Observables values": "Valores observables",
"Opened connection": "Conexión abierta",
"Operating System": "Sistema Operativo",
"Operation": "Operación",
Expand Down
1 change: 1 addition & 0 deletions opencti-platform/opencti-front/lang/back/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,7 @@
"Observable content": "Contenu observable",
"Observable description": "Description de l'observable",
"Observables": "Observables",
"Observables values": "Valeurs observables",
"Opened connection": "Connexion ouverte",
"Operating System": "Système d'exploitation",
"Operation": "Opération",
Expand Down
1 change: 1 addition & 0 deletions opencti-platform/opencti-front/lang/back/ja.json
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,7 @@
"Observable content": "観測可能な内容",
"Observable description": "観測可能な記述",
"Observables": "観測可能なもの",
"Observables values": "観測値",
"Opened connection": "オープン接続",
"Operating System": "インストールされているソフトウェア",
"Operation": "操作",
Expand Down
1 change: 1 addition & 0 deletions opencti-platform/opencti-front/lang/back/ko.json
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,7 @@
"Observable content": "관찰 가능 내용",
"Observable description": "관찰 가능 설명",
"Observables": "관찰 가능 항목",
"Observables values": "관측값",
"Opened connection": "열린 연결",
"Operating System": "운영체제",
"Operation": "작업",
Expand Down
1 change: 1 addition & 0 deletions opencti-platform/opencti-front/lang/back/zh.json
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,7 @@
"Observable content": "可观测内容",
"Observable description": "可观察描述",
"Observables": "可观测",
"Observables values": "观测值",
"Opened connection": "打开的连接",
"Operating System": "操作系统",
"Operation": "操作",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import moment from 'moment';
import { getObservableValuesFromPattern } from 'src/modules/indicator/indicator-domain';
import { buildKillChainPhases, buildMITREExtensions, buildStixDomain, cleanObject, convertToStixDate } from '../../database/stix-converter';
import { STIX_EXT_MITRE, STIX_EXT_OCTI } from '../../types/stix-extensions';
import type { StixIndicator, StoreEntityIndicator } from './indicator-types';
Expand Down Expand Up @@ -27,7 +28,8 @@ const convertIndicatorToStix = (instance: StoreEntityIndicator): StixIndicator =
...indicator.extensions[STIX_EXT_OCTI],
detection: instance.x_opencti_detection,
score: instance.x_opencti_score,
main_observable_type: instance.x_opencti_main_observable_type
main_observable_type: instance.x_opencti_main_observable_type,
observables_values: getObservableValuesFromPattern(instance.pattern),
}),
[STIX_EXT_MITRE]: buildMITREExtensions(instance)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,16 @@ export const promoteIndicatorToObservables = async (context: AuthContext, user:

export const getObservableValuesFromPattern = (pattern: string) => extractObservablesFromIndicatorPattern(pattern);

const getFormattedPattern = async (context: AuthContext, user: AuthUser, pattern_type: string, pattern: string) => {
const patternType = pattern_type.toLowerCase();
const formattedPattern = cleanupIndicatorPattern(patternType, pattern);
const check = await checkIndicatorSyntax(context, user, patternType, formattedPattern);
if (check === false) {
throw FunctionalError(`Indicator of type ${pattern_type} is not correctly formatted.`);
}
return formattedPattern;
};

export const addIndicator = async (context: AuthContext, user: AuthUser, indicator: IndicatorAddInput) => {
let observableType: string = isEmptyField(indicator.x_opencti_main_observable_type) ? 'Unknown' : indicator.x_opencti_main_observable_type as string;
if (observableType === 'File') {
Expand All @@ -221,19 +231,15 @@ export const addIndicator = async (context: AuthContext, user: AuthUser, indicat
if (isKnownObservable && !isStixCyberObservable(observableType)) {
throw FunctionalError(`Observable type ${observableType} is not supported.`);
}
// check indicator syntax
const patternType = indicator.pattern_type.toLowerCase();
const formattedPattern = cleanupIndicatorPattern(patternType, indicator.pattern);
const check = await checkIndicatorSyntax(context, user, patternType, formattedPattern);
if (check === false) {
throw FunctionalError(`Indicator of type ${indicator.pattern_type} is not correctly formatted.`);
}

const indicatorBaseScore = indicator.x_opencti_score ?? 50;
const isDecayActivated = await isModuleActivated('INDICATOR_DECAY_MANAGER');
// find default decay rule (even if decay is not activated, it is used to compute default validFrom and validUntil)
const decayRule = await findDecayRuleForIndicator(context, observableType);
const { validFrom, validUntil, revoked, validPeriod } = await computeValidPeriod(indicator, decayRule.decay_lifetime);
const extractedObservableValues = getObservableValuesFromPattern(formattedPattern);

const formattedPattern = await getFormattedPattern(context, user, indicator.pattern_type, indicator.pattern);

const indicatorToCreate = R.pipe(
R.dissoc('createObservables'),
R.dissoc('basedOn'),
Expand All @@ -244,8 +250,8 @@ export const addIndicator = async (context: AuthContext, user: AuthUser, indicat
R.assoc('valid_from', validFrom.toISOString()),
R.assoc('valid_until', validUntil.toISOString()),
R.assoc('revoked', revoked),
R.assoc('x_opencti_observables_values', extractedObservableValues)
)(indicator);

let finalIndicatorToCreate;
if (isDecayActivated && !revoked) {
const indicatorDecayRule = {
Expand Down Expand Up @@ -310,17 +316,6 @@ export const indicatorEditField = async (context: AuthContext, user: AuthUser, i
throw FunctionalError('Cannot edit the field, Indicator cannot be found.');
}

const foundPattern = finalInput.find((item) => item.key === 'pattern');
if (!indicator.x_opencti_observables_values || foundPattern) {
const patternType = indicator.pattern_type.toLowerCase();
const formattedPattern = cleanupIndicatorPattern(patternType, foundPattern?.value ? foundPattern?.value[0] : indicator.pattern);
const check = await checkIndicatorSyntax(context, user, patternType, formattedPattern);
if (check === false) {
throw FunctionalError(`Indicator of type ${indicator.pattern_type} is not correctly formatted.`);
}
const extractedObservableValues = getObservableValuesFromPattern(formattedPattern);
finalInput.push({ key: 'x_opencti_observables_values', value: [...extractedObservableValues] });
}
// validation check because according to STIX 2.1 specification the valid_until must be greater than the valid_from
let { valid_from, valid_until } = indicator;
input.forEach((e) => {
Expand All @@ -330,6 +325,14 @@ export const indicatorEditField = async (context: AuthContext, user: AuthUser, i
if (new Date(valid_until) <= new Date(valid_from)) {
throw ValidationError('The valid until date must be greater than the valid from date', 'valid_from');
}

const foundPattern = finalInput.find((item) => item.key === 'pattern');
if (!indicator.x_opencti_observables_values || foundPattern) {
const formattedPattern = await getFormattedPattern(context, user, indicator.pattern_type, foundPattern?.value ? foundPattern?.value[0] : indicator.pattern);
const extractedObservableValues = getObservableValuesFromPattern(formattedPattern);
finalInput.push({ key: 'x_opencti_observables_values', value: [...extractedObservableValues] });
}

const scoreEditInput = input.find((e) => e.key === 'x_opencti_score');
if (scoreEditInput) {
if (indicator.decay_applied_rule && !scoreEditInput.value.includes(indicator.decay_base_score)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@ import {
findById,
getDecayChartData,
getDecayDetails,
getObservableValuesFromPattern,
indicatorEditField,
indicatorsDistributionByEntity,
indicatorsNumber,
indicatorsNumberByEntity,
indicatorsTimeSeries,
indicatorsTimeSeriesByEntity,
observablesPaginated
observablesPaginated,
} from './indicator-domain';
import {
stixDomainObjectAddRelation,
Expand Down Expand Up @@ -53,6 +54,7 @@ const indicatorResolvers: Resolvers = {
observables: (indicator, args, context) => observablesPaginated<any>(context, context.user, indicator.id, args),
decayLiveDetails: (indicator, _, context) => getDecayDetails(context, context.user, indicator),
decayChartData: (indicator, _, context) => getDecayChartData(context, context.user, indicator),
x_opencti_observables_values: (indicator) => getObservableValuesFromPattern(indicator.pattern),
},
Mutation: {
indicatorAdd: (_, { input }, context) => addIndicator(context, context.user, input),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ const INDICATOR_DEFINITION: ModuleDefinition<StoreEntityIndicator, StixIndicator
{ name: 'x_opencti_score', label: 'Score', type: 'numeric', precision: 'integer', mandatoryType: 'customizable', editDefault: true, multiple: false, upsert: true, isFilterable: true },
{ name: 'x_opencti_detection', label: 'Is detected', type: 'boolean', mandatoryType: 'no', editDefault: false, multiple: false, upsert: true, isFilterable: true },
{ name: 'x_opencti_main_observable_type', label: 'Main observable type', type: 'string', format: 'short', mandatoryType: 'external', editDefault: true, multiple: false, upsert: true, isFilterable: true },
{ name: 'x_opencti_observables_values', label: 'Observables values', type: 'object', format: 'flat', mandatoryType: 'no', editDefault: false, multiple: true, upsert: true, isFilterable: false },
{ name: 'x_mitre_platforms', label: 'Platforms', type: 'string', format: 'short', mandatoryType: 'customizable', editDefault: true, multiple: true, upsert: true, isFilterable: true },
{
name: 'decay_next_reaction_date',
Expand Down
6 changes: 6 additions & 0 deletions opencti-platform/opencti-graphql/src/types/store.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,11 @@ interface StoreCommonConnection<T extends BasicStoreCommon> {
pageInfo: PageInfo;
}

interface ObservablesValuesType {
type: string;
value: string;
}

interface BasicStoreEntity extends BasicStoreCommon {
id: string;
name: string;
Expand Down Expand Up @@ -329,6 +334,7 @@ interface BasicStoreEntity extends BasicStoreCommon {
x_opencti_epss_score: number;
x_opencti_epss_percentile: number;
x_opencti_main_observable_type: string;
x_opencti_observables_values: Array<ObservablesValuesType>;
x_opencti_lastname: string;
x_opencti_firstname: string;
x_opencti_inferences: Array<StoreRule> | undefined;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ const READ_QUERY = gql`
name
description
toStix
x_opencti_observables_values {
type
value
}
decay_base_score
decay_base_score_date
decay_applied_rule {
Expand Down Expand Up @@ -82,6 +86,10 @@ const CREATE_QUERY = gql`
id
name
description
x_opencti_observables_values {
type
value
}
observables {
edges {
node {
Expand Down Expand Up @@ -119,6 +127,10 @@ describe('Indicator resolver standard behavior', () => {
expect(indicator.data?.indicatorAdd).toBeDefined();
expect(indicator.data?.indicatorAdd.name).toEqual(indicatorForTestName);
expect(indicator.data?.indicatorAdd.observables.edges.length).toEqual(0);
expect(indicator.data?.indicatorAdd.x_opencti_observables_values).toBeDefined();
const observablesValues = indicator.data?.indicatorAdd.x_opencti_observables_values;
expect(observablesValues?.[0].type).toEqual('Domain-Name');
expect(observablesValues?.[0].value).toEqual('www.payah.rest');
firstIndicatorInternalId = indicator.data?.indicatorAdd.id;
});
it('should indicator with same name be created also (no upsert) (see issues/5819)', async () => {
Expand All @@ -138,6 +150,10 @@ describe('Indicator resolver standard behavior', () => {
expect(indicator.data?.indicatorAdd).toBeDefined();
expect(indicator.data?.indicatorAdd.name).toEqual(indicatorForTestName);
expect(indicator.data?.indicatorAdd.observables.edges.length).toEqual(0);
expect(indicator.data?.indicatorAdd.x_opencti_observables_values).toBeDefined();
const observablesValues = indicator.data?.indicatorAdd.x_opencti_observables_values;
expect(observablesValues?.[0].type).toEqual('Domain-Name');
expect(observablesValues?.[0].value).toEqual('www.test2.rest');
expect(indicator.data?.indicatorAdd.id, 'A new indicator should be created, if not it is an upsert and it is a bug').not.toEqual(firstIndicatorInternalId);
secondIndicatorInternalId = indicator.data?.indicatorAdd.id;
});
Expand All @@ -160,6 +176,10 @@ describe('Indicator resolver standard behavior', () => {
expect(indicator.data?.indicatorAdd).toBeDefined();
expect(indicator.data?.indicatorAdd.name).toEqual(`New name for ${indicatorForTestName}`);
expect(indicator.data?.indicatorAdd.observables.edges.length).toEqual(0);
expect(indicator.data?.indicatorAdd.x_opencti_observables_values).toBeDefined();
const observablesValues = indicator.data?.indicatorAdd.x_opencti_observables_values;
expect(observablesValues?.[0].type).toEqual('Domain-Name');
expect(observablesValues?.[0].value).toEqual('www.payah.rest');
expect(indicator.data?.indicatorAdd.id).toEqual(firstIndicatorInternalId);
expect(indicator.data?.indicatorAdd.id).toEqual(firstIndicatorInternalId);
});
Expand Down Expand Up @@ -218,6 +238,29 @@ describe('Indicator resolver standard behavior', () => {
});
expect(queryResult.data?.indicatorFieldPatch.name).toEqual('Indicator - test');
});
// skipped until sync tests fixed
it.skip('should update indicator observables values on pattern edit', async () => {
const UPDATE_QUERY = gql`
mutation IndicatorFieldPatch($id: ID!, $input: [EditInput!]!) {
indicatorFieldPatch(id: $id, input: $input) {
id
name
x_opencti_observables_values {
type
value
}
}
}
`;
const queryResult = await queryAsAdminWithSuccess({
query: UPDATE_QUERY,
variables: { id: firstIndicatorInternalId, input: { key: 'pattern', value: ['[domain-name:value = \'www.payah.test\']'] } },
});
expect(queryResult.data?.indicatorFieldPatch.x_opencti_observables_values).toBeDefined();
const observablesValues = queryResult.data?.indicatorFieldPatch.x_opencti_observables_values;
expect(observablesValues?.[0].type).toEqual('Domain-Name');
expect(observablesValues?.[0].value).toEqual('www.payah.test');
});
it('should context patch indicator', async () => {
const CONTEXT_PATCH_QUERY = gql`
mutation IndicatorContextPatch($id: ID!, $input: EditContext) {
Expand Down

0 comments on commit 1c40ec7

Please sign in to comment.