■ ■ ■ ■ ■ ■
opencti-platform/opencti-graphql/src/graphql/sseMiddleware.js
| skipped 78 lines |
79 | 79 | | return filterRefs; |
80 | 80 | | }; |
81 | 81 | | |
82 | | - | const isInstanceAccessible = async (context, user, instance, filterCache, filters = {}) => { |
83 | | - | // Check if user have correct access rights. |
84 | | - | const isUserHaveAccessToElement = await isUserCanAccessStixElement(context, user, instance); |
85 | | - | if (!isUserHaveAccessToElement) { |
86 | | - | return false; |
87 | | - | } |
88 | | - | // When apply extra filters if needed. |
89 | | - | if (isNotEmptyField(filters)) { |
90 | | - | // Pre-filter transformation to handle specific frontend format |
91 | | - | const adaptedFilters = adaptFiltersFrontendFormat(filters); |
92 | | - | // User is granted, but we still need to apply filters if needed |
93 | | - | const filterEntries = Object.entries(adaptedFilters); |
94 | | - | for (let index = 0; index < filterEntries.length; index += 1) { |
95 | | - | const [type, { operator, values }] = filterEntries[index]; |
96 | | - | // Markings filtering |
97 | | - | if (type === MARKING_FILTER) { |
98 | | - | if (values.length === 0) { |
99 | | - | return true; |
100 | | - | } |
101 | | - | const markings = instance.object_marking_refs || []; |
102 | | - | if (values.length > 0 && markings.length === 0) { |
103 | | - | return false; |
104 | | - | } |
105 | | - | const filterMarkingRefs = await filterCacheResolver(values, filterCache); |
106 | | - | const found = filterMarkingRefs.some((r) => markings.includes(r)); |
107 | | - | if (!found) { |
108 | | - | return false; |
109 | | - | } |
110 | | - | } |
111 | | - | // Entity type filtering |
112 | | - | if (type === TYPE_FILTER) { |
113 | | - | const instanceType = instance.extensions[STIX_EXT_OCTI].type; |
114 | | - | const instanceAllTypes = [instanceType, ...getParentTypes(instanceType)]; |
115 | | - | let found = false; |
116 | | - | if (values.length === 0) { |
117 | | - | found = true; |
118 | | - | } else { |
119 | | - | // eslint-disable-next-line no-restricted-syntax |
120 | | - | for (const filter of values) { |
121 | | - | if (instanceAllTypes.includes(filter.id)) { |
122 | | - | found = true; |
123 | | - | } |
124 | | - | } |
125 | | - | } |
126 | | - | if (!found) { |
127 | | - | return false; |
128 | | - | } |
129 | | - | } |
130 | | - | // Workflow |
131 | | - | if (type === WORKFLOW_FILTER) { |
132 | | - | const workflowId = instance.extensions[STIX_EXT_OCTI].workflow_id; |
133 | | - | const found = values.includes(workflowId); |
134 | | - | if (!found) { |
135 | | - | return false; |
136 | | - | } |
137 | | - | } |
138 | | - | // Creator filtering |
139 | | - | if (type === CREATOR_FILTER) { |
140 | | - | if (values.length === 0) { |
141 | | - | return true; |
142 | | - | } |
143 | | - | if (values.length > 0 && instance.created_by_ref === undefined) { |
144 | | - | return false; |
145 | | - | } |
146 | | - | const filterCreationRefs = await filterCacheResolver(values, filterCache); |
147 | | - | const found = filterCreationRefs.includes(instance.created_by_ref); |
148 | | - | if (!found) { |
149 | | - | return false; |
150 | | - | } |
151 | | - | } |
152 | | - | // Labels filtering |
153 | | - | if (type === LABEL_FILTER) { |
154 | | - | const labels = [...(instance.labels ?? []), ...(instance.extensions[STIX_EXT_OCTI_SCO]?.labels ?? [])]; |
155 | | - | const found = values.map((v) => v.value).some((r) => labels.includes(r)); |
156 | | - | if (!found) { |
157 | | - | return false; |
158 | | - | } |
159 | | - | } |
160 | | - | // Boolean filtering |
161 | | - | if (type === REVOKED_FILTER || type === DETECTION_FILTER) { |
162 | | - | const { id } = R.head(values); |
163 | | - | const found = (id === 'true') === instance.revoked; |
164 | | - | if (!found) { |
165 | | - | return false; |
166 | | - | } |
167 | | - | } |
168 | | - | // Numeric filtering |
169 | | - | if (type === SCORE_FILTER || type === CONFIDENCE_FILTER) { |
170 | | - | const { id } = R.head(values); |
171 | | - | let found = false; |
172 | | - | const numeric = parseInt(id, 10); |
173 | | - | switch (operator) { |
174 | | - | case 'lt': |
175 | | - | found = instance[type] < numeric; |
176 | | - | break; |
177 | | - | case 'lte': |
178 | | - | found = instance[type] <= numeric; |
179 | | - | break; |
180 | | - | case 'gt': |
181 | | - | found = instance[type] > numeric; |
182 | | - | break; |
183 | | - | case 'gte': |
184 | | - | found = instance[type] >= numeric; |
185 | | - | break; |
186 | | - | default: |
187 | | - | found = instance[type] === numeric; |
188 | | - | } |
189 | | - | if (!found) { |
190 | | - | return false; |
191 | | - | } |
192 | | - | } |
193 | | - | // String filtering |
194 | | - | if (type === PATTERN_FILTER) { |
195 | | - | const { id } = R.head(values); |
196 | | - | const found = id === instance[type]; |
197 | | - | if (!found) { |
198 | | - | return false; |
199 | | - | } |
200 | | - | } |
201 | | - | } |
202 | | - | } |
203 | | - | return true; |
204 | | - | }; |
205 | | - | |
206 | 82 | | const createBroadcastClient = (channel) => { |
207 | 83 | | let lastHeartbeat; |
208 | 84 | | return { |
| skipped 154 lines |
363 | 239 | | return; |
364 | 240 | | } |
365 | 241 | | const { client } = createSseChannel(req, res); |
366 | | - | const filterCache = new LRU({ max: MAX_CACHE_SIZE, ttl: MAX_CACHE_TIME }); |
367 | 242 | | const processor = createStreamProcessor(sessionUser, sessionUser.user_email, false, async (elements, lastEventId) => { |
368 | 243 | | // Process the event messages |
369 | 244 | | for (let index = 0; index < elements.length; index += 1) { |
370 | 245 | | const { id: eventId, event, data } = elements[index]; |
371 | | - | const instanceAccessible = await isInstanceAccessible(context, sessionUser, data.data, filterCache); |
| 246 | + | const instanceAccessible = await isUserCanAccessStixElement(context, sessionUser, data.data); |
372 | 247 | | if (instanceAccessible) { |
373 | 248 | | client.sendEvent(eventId, event, data); |
374 | 249 | | } |
| skipped 483 lines |