Skip to content

Commit 8b96a58

Browse files
feat[backend](updated filters and rules): added initial load service
1 parent f72e468 commit 8b96a58

File tree

1 file changed

+209
-0
lines changed

1 file changed

+209
-0
lines changed
Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
package com.park.utmstack.service;
2+
3+
import com.park.utmstack.config.Constants;
4+
import com.park.utmstack.domain.correlation.config.UtmDataTypes;
5+
import com.park.utmstack.domain.correlation.rules.UtmCorrelationRules;
6+
import com.park.utmstack.domain.logstash_filter.UtmLogstashFilter;
7+
import com.park.utmstack.repository.correlation.config.UtmDataTypesRepository;
8+
import com.park.utmstack.repository.correlation.rules.UtmCorrelationRulesRepository;
9+
import com.park.utmstack.repository.logstash_filter.UtmLogstashFilterRepository;
10+
import com.park.utmstack.service.correlation.rules.UtmCorrelationRulesService;
11+
import com.park.utmstack.service.dto.correlation.AdversaryType;
12+
import com.park.utmstack.service.dto.correlation.UtmCorrelationRulesDTO;
13+
import com.park.utmstack.service.dto.correlation.UtmCorrelationRulesMapper;
14+
import lombok.Data;
15+
import lombok.RequiredArgsConstructor;
16+
import org.slf4j.Logger;
17+
import org.slf4j.LoggerFactory;
18+
import org.springframework.boot.CommandLineRunner;
19+
import org.springframework.stereotype.Service;
20+
import org.springframework.transaction.annotation.Transactional;
21+
import org.yaml.snakeyaml.Yaml;
22+
23+
import java.io.IOException;
24+
import java.nio.file.Files;
25+
import java.nio.file.Path;
26+
import java.nio.file.Paths;
27+
import java.time.Instant;
28+
import java.util.*;
29+
import java.util.stream.Collectors;
30+
import java.util.stream.Stream;
31+
32+
@Service
33+
@RequiredArgsConstructor
34+
public class DefinitionSyncService implements CommandLineRunner {
35+
36+
private final Logger log = LoggerFactory.getLogger(DefinitionSyncService.class);
37+
38+
private final UtmLogstashFilterRepository filterRepository;
39+
private final UtmCorrelationRulesRepository rulesRepository;
40+
private final UtmDataTypesRepository dataTypesRepository;
41+
private final UtmCorrelationRulesService rulesService;
42+
private final UtmCorrelationRulesMapper rulesMapper;
43+
44+
@Override
45+
@Transactional
46+
public void run(String... args) {
47+
log.info("Starting definition sync from filesystem...");
48+
syncFilters();
49+
syncRules();
50+
log.info("Definition sync completed.");
51+
}
52+
53+
private void syncFilters() {
54+
Path filtersPath = Paths.get(".",Constants.APP_FILTER_DEFINITIONS);
55+
if (!Files.exists(filtersPath) || !Files.isDirectory(filtersPath)) {
56+
log.warn("Filters directory not found: {}", Constants.APP_FILTER_DEFINITIONS);
57+
return;
58+
}
59+
60+
try (Stream<Path> paths = Files.walk(filtersPath)) {
61+
paths.filter(path -> Files.isRegularFile(path) && isYamlFile(path)).forEach(path -> {
62+
String moduleName = getFileNameWithoutExtension(path);
63+
try {
64+
String content = Files.readString(path);
65+
Optional<UtmLogstashFilter> filterOpt = filterRepository.findOneByModuleName(moduleName);
66+
67+
if (filterOpt.isPresent()) {
68+
UtmLogstashFilter filter = filterOpt.get();
69+
if (!content.equals(filter.getLogstashFilter())) {
70+
log.info("Updating existing filter for module: {}", moduleName);
71+
filter.setLogstashFilter(content);
72+
filter.setUpdatedAt(Instant.now());
73+
filterRepository.save(filter);
74+
}
75+
} else {
76+
log.info("Inserting new filter for module: {}", moduleName);
77+
UtmLogstashFilter filter = new UtmLogstashFilter();
78+
filter.setModuleName(moduleName);
79+
filter.setFilterName(moduleName + " Filter");
80+
filter.setLogstashFilter(content);
81+
filter.setSystemOwner(true);
82+
filter.setActive(true);
83+
filter.setUpdatedAt(Instant.now());
84+
85+
// Try to find a matching data type
86+
Optional<UtmDataTypes> dataType = dataTypesRepository.findOneByDataType(moduleName.toLowerCase());
87+
if (dataType.isPresent()) {
88+
filter.setDatatype(dataType.get());
89+
}
90+
91+
filterRepository.save(filter);
92+
}
93+
} catch (IOException e) {
94+
log.error("Error reading filter file {}: {}", path, e.getMessage());
95+
}
96+
});
97+
} catch (IOException e) {
98+
log.error("Error listing filters directory: {}", e.getMessage());
99+
}
100+
}
101+
102+
private void syncRules() {
103+
Path rulesPath = Paths.get(".",Constants.APP_RULE_DEFINITIONS);
104+
if (!Files.exists(rulesPath) || !Files.isDirectory(rulesPath)) {
105+
log.warn("Rules directory not found: {}", Constants.APP_RULE_DEFINITIONS);
106+
return;
107+
}
108+
109+
Yaml yaml = new Yaml();
110+
try (Stream<Path> paths = Files.walk(rulesPath)) {
111+
112+
paths.filter(path -> Files.isRegularFile(path) && isYamlFile(path)).forEach(path -> {
113+
try {
114+
String content = Files.readString(path);
115+
RuleYaml ruleYaml = yaml.loadAs(content, RuleYaml.class);
116+
if (ruleYaml == null || ruleYaml.getName() == null) {
117+
log.warn("Skipping invalid rule file: {}", path);
118+
return;
119+
}
120+
121+
Optional<UtmCorrelationRules> ruleOpt = rulesRepository.findOneByRuleName(ruleYaml.getName());
122+
UtmCorrelationRulesDTO ruleDto = new UtmCorrelationRulesDTO();
123+
124+
if (ruleOpt.isPresent()) {
125+
ruleDto.setId(ruleOpt.get().getId());
126+
} else {
127+
ruleDto.setId(rulesRepository.getNextId());
128+
}
129+
130+
ruleDto.setName(ruleYaml.getName());
131+
ruleDto.setCategory(ruleYaml.getCategory());
132+
ruleDto.setTechnique(ruleYaml.getTechnique());
133+
ruleDto.setAdversary(ruleYaml.getAdversary() != null ? ruleYaml.getAdversary() : AdversaryType.origin);
134+
ruleDto.setDescription(ruleYaml.getDescription());
135+
ruleDto.setReferences(ruleYaml.getReferences());
136+
ruleDto.setDefinition(ruleYaml.getWhere());
137+
ruleDto.setGroupBy(ruleYaml.getGroupBy());
138+
ruleDto.setDeduplicateBy(ruleYaml.getDeduplicateBy());
139+
ruleDto.setAfterEvents(ruleYaml.getAfterEvents());
140+
ruleDto.setSystemOwner(true);
141+
ruleDto.setRuleActive(true);
142+
143+
if (ruleYaml.getImpact() != null) {
144+
ruleDto.setConfidentiality(ruleYaml.getImpact().getConfidentiality());
145+
ruleDto.setIntegrity(ruleYaml.getImpact().getIntegrity());
146+
ruleDto.setAvailability(ruleYaml.getImpact().getAvailability());
147+
}
148+
149+
// Map dataTypes strings to UtmDataTypes entities
150+
if (ruleYaml.getDataTypes() != null) {
151+
Set<UtmDataTypes> dataTypes = ruleYaml.getDataTypes().stream()
152+
.map(dtName -> dataTypesRepository.findOneByDataType(dtName.toLowerCase()))
153+
.filter(Optional::isPresent)
154+
.map(Optional::get)
155+
.collect(Collectors.toSet());
156+
ruleDto.setDataTypes(dataTypes);
157+
}
158+
159+
UtmCorrelationRules entity = rulesMapper.toEntity(ruleDto);
160+
if (ruleOpt.isPresent()) {
161+
rulesService.updateRule(entity);
162+
163+
} else {
164+
rulesService.save(entity);
165+
}
166+
167+
} catch (Exception e) {
168+
log.error("Error processing rule file {}: {}", path, e.getMessage());
169+
}
170+
});
171+
} catch (IOException e) {
172+
log.error("Error walking rules directory: {}", e.getMessage());
173+
}
174+
}
175+
176+
private boolean isYamlFile(Path path) {
177+
String fileName = path.getFileName().toString().toLowerCase();
178+
return fileName.endsWith(".yaml") || fileName.endsWith(".yml");
179+
}
180+
181+
private String getFileNameWithoutExtension(Path path) {
182+
String fileName = path.getFileName().toString();
183+
int lastDotIndex = fileName.lastIndexOf('.');
184+
return (lastDotIndex == -1) ? fileName : fileName.substring(0, lastDotIndex);
185+
}
186+
187+
@Data
188+
public static class RuleYaml {
189+
private List<String> dataTypes;
190+
private String name;
191+
private ImpactYaml impact;
192+
private String category;
193+
private String technique;
194+
private AdversaryType adversary;
195+
private String description;
196+
private List<String> references;
197+
private String where;
198+
private List<com.park.utmstack.domain.correlation.rules.SearchRequest> afterEvents;
199+
private List<String> groupBy;
200+
private List<String> deduplicateBy;
201+
}
202+
203+
@Data
204+
public static class ImpactYaml {
205+
private Integer confidentiality;
206+
private Integer integrity;
207+
private Integer availability;
208+
}
209+
}

0 commit comments

Comments
 (0)