Skip to content

Commit dd15d8f

Browse files
[backend] Improve markings edition control
1 parent af2ab56 commit dd15d8f

File tree

4 files changed

+41
-13
lines changed

4 files changed

+41
-13
lines changed

opencti-platform/opencti-graphql/src/database/middleware.js

+19-1
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ import {
183183
storeLoadById
184184
} from './middleware-loader';
185185
import { checkRelationConsistency, isRelationConsistent } from '../utils/modelConsistency';
186-
import { getEntitiesListFromCache, getEntityFromCache } from './cache';
186+
import { getEntitiesListFromCache, getEntitiesMapFromCache, getEntityFromCache } from './cache';
187187
import { ACTION_TYPE_SHARE, ACTION_TYPE_UNSHARE, createListTask } from '../domain/backgroundTask-common';
188188
import { ENTITY_TYPE_VOCABULARY, vocabularyDefinitions } from '../modules/vocabulary/vocabulary-types';
189189
import { getVocabulariesCategories, getVocabularyCategoryForField, isEntityFieldAnOpenVocabulary, updateElasticVocabularyValue } from '../modules/vocabulary/vocabulary-utils';
@@ -705,6 +705,24 @@ export const validateCreatedBy = async (context, user, createdById) => {
705705
}
706706
};
707707

708+
/**
709+
* Verify that the Entity in Marking is one of user allowed
710+
* @param context
711+
* @param user
712+
* @param markingId
713+
*/
714+
export const validateMarking = async (context, user, markingId) => {
715+
if (isBypassUser(user)) {
716+
return;
717+
}
718+
const markings = await getEntitiesMapFromCache(context, SYSTEM_USER, ENTITY_TYPE_MARKING_DEFINITION);
719+
const userMarking = (user.allowed_marking || []).map((m) => markings.get(m.internal_id)).filter((m) => isNotEmptyField(m));
720+
const userMarkingIds = userMarking.map((marking) => extractIdsFromStoreObject(marking)).flat();
721+
if (!userMarkingIds.includes(markingId)) {
722+
throw FunctionalError('User trying to create the data has missing markings', { id: markingId });
723+
}
724+
};
725+
708726
const inputResolveRefs = async (context, user, input, type, entitySetting) => {
709727
const inputResolveRefsFn = async () => {
710728
const fetchingIds = [];

opencti-platform/opencti-graphql/src/domain/stixDomainObject.js

+13-6
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ import {
99
timeSeriesEntities,
1010
updateAttribute,
1111
updateAttributeFromLoadedWithRefs,
12-
validateCreatedBy
12+
validateCreatedBy,
13+
validateMarking
1314
} from '../database/middleware';
1415
import { listAllToEntitiesThroughRelations, listEntities, listEntitiesThroughRelationsPaginated, storeLoadById } from '../database/middleware-loader';
1516
import { elCount, elFindByIds } from '../database/engine';
@@ -25,7 +26,7 @@ import {
2526
isStixDomainObjectLocation,
2627
isStixDomainObjectThreatActor
2728
} from '../schema/stixDomainObject';
28-
import { ABSTRACT_STIX_CYBER_OBSERVABLE, ABSTRACT_STIX_DOMAIN_OBJECT, buildRefRelationKey, INPUT_MARKINGS } from '../schema/general';
29+
import { ABSTRACT_STIX_CYBER_OBSERVABLE, ABSTRACT_STIX_DOMAIN_OBJECT, buildRefRelationKey, INPUT_CREATED_BY, INPUT_MARKINGS } from '../schema/general';
2930
import { RELATION_CREATED_BY, RELATION_OBJECT_ASSIGNEE, } from '../schema/stixRefRelationship';
3031
import { askEntityExport, askListExport, exportTransformFilters } from './stix';
3132
import { RELATION_BASED_ON } from '../schema/stixCoreRelationship';
@@ -202,12 +203,19 @@ export const stixDomainObjectEditField = async (context, user, stixObjectId, inp
202203
if (!stixDomainObject) {
203204
throw FunctionalError('Cannot edit the field, Stix-Domain-Object cannot be found.');
204205
}
205-
206-
const createdByKey = input.find((inputData) => inputData.key === 'createdBy');
206+
// Validate specific relations, created by and markings
207+
const markingsInput = input.find((inputData) => inputData.key === INPUT_MARKINGS);
208+
if (markingsInput && markingsInput.value?.length > 0) {
209+
for (let index = 0; index < markingsInput.value.length; index += 1) {
210+
const markingId = markingsInput.value[index];
211+
await validateMarking(context, user, markingId);
212+
}
213+
}
214+
const createdByKey = input.find((inputData) => inputData.key === INPUT_CREATED_BY);
207215
if (createdByKey && createdByKey.value?.length > 0) {
208216
await validateCreatedBy(context, user, createdByKey.value[0]);
209217
}
210-
218+
// Start the element edition
211219
const { element: updatedElem } = await updateAttribute(context, user, stixObjectId, ABSTRACT_STIX_DOMAIN_OBJECT, input, opts);
212220
// If indicator is score patched, we also patch the score of all observables attached to the indicator
213221
if (stixDomainObject.entity_type === ENTITY_TYPE_INDICATOR && input.key === 'x_opencti_score') {
@@ -245,7 +253,6 @@ export const stixDomainObjectFileEdit = async (context, user, sdoId, { id, order
245253
const { [INPUT_MARKINGS]: markingInput, ...nonResolvedFile } = f;
246254
return nonResolvedFile;
247255
});
248-
249256
const { element: updatedElement } = await updateAttributeFromLoadedWithRefs(context, user, stixDomainObject, { key: 'x_opencti_files', value: nonResolvedFiles });
250257
return notify(BUS_TOPICS[ABSTRACT_STIX_DOMAIN_OBJECT].EDIT_TOPIC, updatedElement, user);
251258
};

opencti-platform/opencti-graphql/src/domain/stixObjectOrStixRelationship.ts

+8-5
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ import { READ_PLATFORM_INDICES, UPDATE_OPERATION_ADD, UPDATE_OPERATION_REMOVE }
33
import { type EntityOptions, storeLoadById } from '../database/middleware-loader';
44
import { ABSTRACT_STIX_OBJECT, ABSTRACT_STIX_REF_RELATIONSHIP, ABSTRACT_STIX_RELATIONSHIP } from '../schema/general';
55
import { FunctionalError, UnsupportedError } from '../config/errors';
6-
import { isStixRefRelationship, RELATION_CREATED_BY } from '../schema/stixRefRelationship';
7-
import { listThings, storeLoadByIdWithRefs, transformPatchToInput, updateAttributeFromLoadedWithRefs, validateCreatedBy } from '../database/middleware';
6+
import { isStixRefRelationship, RELATION_CREATED_BY, RELATION_OBJECT_MARKING } from '../schema/stixRefRelationship';
7+
import { listThings, storeLoadByIdWithRefs, transformPatchToInput, updateAttributeFromLoadedWithRefs, validateCreatedBy, validateMarking } from '../database/middleware';
88
import { notify } from '../database/redis';
99
import { BUS_TOPICS } from '../config/conf';
1010
import type { AuthContext, AuthUser } from '../types/user';
@@ -51,12 +51,15 @@ export const stixObjectOrRelationshipAddRefRelation = async (
5151
type: string,
5252
opts = {}
5353
): Promise<any> => { // TODO remove any when all resolvers in ts
54-
const to = await findById(context, user, input.toId);
55-
54+
// Validate specific relations, created by and markings
55+
if (input.relationship_type === RELATION_OBJECT_MARKING) {
56+
await validateMarking(context, user, input.toId);
57+
}
5658
if (input.relationship_type === RELATION_CREATED_BY) {
5759
await validateCreatedBy(context, user, input.toId);
5860
}
59-
61+
// Add the relationship with patching
62+
const to = await findById(context, user, input.toId);
6063
const patchedFrom = await patchElementWithRefRelationships(context, user, stixObjectOrRelationshipId, type, input.relationship_type, [input.toId], UPDATE_OPERATION_ADD, opts);
6164
const { element: refRelation } = await buildRelationData(context, user, { from: patchedFrom, to, relationship_type: input.relationship_type });
6265
await notify(BUS_TOPICS[type as BusTopicsKeyType].EDIT_TOPIC, refRelation, user);

opencti-platform/opencti-graphql/tests/02-integration/01-database/disseminationList-test.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,4 @@ describe('Create dissemination list', () => {
3434
const id = await deleteDisseminationList(testContext, TEST_DISSEMINATION_USER_SET, data.id);
3535
expect(id, 'List deleted').toBe(data.id);
3636
});
37-
});
37+
});

0 commit comments

Comments
 (0)