Skip to content

Commit

Permalink
[frontend/backend] In XLS mapper, having a way to map "All teams" as …
Browse files Browse the repository at this point in the history
…targets of injects (#1349)
  • Loading branch information
Dimfacion authored Aug 28, 2024
1 parent 12bc4aa commit d823b1a
Show file tree
Hide file tree
Showing 7 changed files with 119 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ public class InjectorContractApi extends RestBehavior {
private final InjectorRepository injectorRepository;

private final InjectorContractRepository injectorContractRepository;

private final InjectorContractService injectorContractService;

@GetMapping("/api/injector_contracts")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package io.openbas.rest.injector_contract;

import io.openbas.database.model.*;
import io.openbas.database.repository.InjectorContractRepository;
import io.openbas.injectors.email.EmailContract;
import io.openbas.injectors.email.EmailInjector;
import io.openbas.injectors.ovh.OvhSmsContract;
import io.openbas.rest.injector_contract.output.InjectorContractOutput;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
Expand All @@ -10,12 +14,16 @@
import lombok.RequiredArgsConstructor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.EventListener;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
Expand All @@ -32,6 +40,28 @@ public class InjectorContractService {
@PersistenceContext
private EntityManager entityManager;

private final InjectorContractRepository injectorContractRepository;

@Value("${openbas.xls.import.mail.enable}")
private boolean mailImportEnabled;

@Value("${openbas.xls.import.sms.enable}")
private boolean smsImportEnabled;

@EventListener(ApplicationReadyEvent.class)
public void initImportAvailableOnStartup() {
List<String> listOfInjectorImportAvailable = new ArrayList<>();
if (mailImportEnabled) listOfInjectorImportAvailable.addAll(Arrays.asList(EmailContract.EMAIL_GLOBAL, EmailContract.EMAIL_DEFAULT));
if (smsImportEnabled) listOfInjectorImportAvailable.add(OvhSmsContract.OVH_DEFAULT);

List<InjectorContract> listInjectorContract = new ArrayList<>();
injectorContractRepository.findAll().spliterator().forEachRemaining(listInjectorContract::add);
listInjectorContract.forEach(injectorContract -> {
injectorContract.setImportAvailable(listOfInjectorImportAvailable.contains(injectorContract.getId()));
});
injectorContractRepository.saveAll(listInjectorContract);
}

public Page<InjectorContractOutput> injectorContracts(
@Nullable final Specification<InjectorContract> specification,
@NotNull final Pageable pageable) {
Expand Down
36 changes: 26 additions & 10 deletions openbas-api/src/main/java/io/openbas/service/InjectService.java
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ private ImportTestSummary importXls(String importId, Scenario scenario, ImportMa
try {
// We open the previously saved file
String tmpdir = System.getProperty("java.io.tmpdir");
java.nio.file.Path file = Files.list(Path.of(tmpdir, pathSeparator, importId, pathSeparator)).findFirst().orElseThrow();
Path file = Files.list(Path.of(tmpdir, pathSeparator, importId, pathSeparator)).findFirst().orElseThrow();

// We open the file and convert it to an apache POI object
InputStream xlsFile = Files.newInputStream(file);
Expand All @@ -300,7 +300,17 @@ private ImportTestSummary importXls(String importId, Scenario scenario, ImportMa
Map<String, Pattern> mapPatternByInjectImport = importMapper
.getInjectImporters().stream().collect(
Collectors.toMap(InjectImporter::getId,
injectImporter -> Pattern.compile(injectImporter.getImportTypeValue())
injectImporter -> Pattern.compile(injectImporter.getImportTypeValue())
));

Map<String, Pattern> mapPatternByAllTeams = importMapper.getInjectImporters().stream()
.flatMap(injectImporter -> injectImporter.getRuleAttributes().stream())
.filter(ruleAttribute -> Objects.equals(ruleAttribute.getName(), "teams"))
.filter(ruleAttribute -> ruleAttribute.getAdditionalConfig() != null && !Strings.isBlank(ruleAttribute.getAdditionalConfig().get("allTeamsValue")))
.collect(
Collectors.toMap(ruleAttribute -> ruleAttribute.getAdditionalConfig().get("allTeamsValue"),
ruleAttribute -> Pattern.compile(ruleAttribute.getAdditionalConfig().get("allTeamsValue")),
(first, second) -> first
));

// We also get the list of teams into a map to be able to get them easily later on
Expand All @@ -321,7 +331,7 @@ private ImportTestSummary importXls(String importId, Scenario scenario, ImportMa

// For each rows of the selected sheet
selectedSheet.rowIterator().forEachRemaining(row -> {
ImportRow rowSummary = importRow(row, importMapper, scenario, mapPatternByInjectImport, mapTeamByName,
ImportRow rowSummary = importRow(row, importMapper, scenario, mapPatternByInjectImport, mapTeamByName, mapPatternByAllTeams,
zoneOffset);
importTestSummary.getImportMessage().addAll(rowSummary.getImportMessages());
if(rowSummary.getInject() != null) {
Expand Down Expand Up @@ -366,7 +376,7 @@ private ImportTestSummary importXls(String importId, Scenario scenario, ImportMa

private ImportRow importRow(Row row, ImportMapper importMapper, Scenario scenario,
Map<String, Pattern> mapPatternByInjectImport, Map<String, Team> mapTeamByName,
ZoneOffset timezoneOffset) {
Map<String, Pattern> mapPatternByAllTeams, ZoneOffset timezoneOffset) {
ImportRow importTestSummary = new ImportRow();
// The column that differenciate the importer is the same for all so we get it right now
int colTypeIdx = CellReference.convertColStringToIndex(importMapper.getInjectTypeColumn());
Expand Down Expand Up @@ -574,10 +584,8 @@ private ImportRow importRow(Row row, ImportMapper importMapper, Scenario scenari
matchingInjectImporter.getRuleAttributes().forEach(ruleAttribute -> {
importTestSummary.getImportMessages().addAll(
addFields(inject, ruleAttribute,
row, mapTeamByName, expectation, importMapper));
row, mapTeamByName, expectation, importMapper, mapPatternByAllTeams));
});
// This is by default at false
inject.setAllTeams(false);
// The user is the one doing the import
inject.setUser(userRepository.findById(currentUser().getId()).orElseThrow());
// No exercise yet
Expand Down Expand Up @@ -630,7 +638,8 @@ private void setAttributeValue(Row row, InjectImporter matchingInjectImporter, S
private List<ImportMessage> addFields(Inject inject, RuleAttribute ruleAttribute,
Row row, Map<String, Team> mapTeamByName,
AtomicReference<InjectExpectation> expectation,
ImportMapper importMapper) {
ImportMapper importMapper,
Map<String, Pattern> mapPatternByAllTeams) {
// If it's a reserved field, it's already taken care of
if(importReservedField.contains(ruleAttribute.getName())) {
return Collections.emptyList();
Expand Down Expand Up @@ -668,8 +677,8 @@ private List<ImportMessage> addFields(Inject inject, RuleAttribute ruleAttribute
case "team":
// If the rule type is on a team field, we split by "+" if there is a concatenation of columns
// and then joins the result, split again by "," and use the list of results to get the teams by their name

List<String> columnValues = new ArrayList<>();
String allTeamsValue = ruleAttribute.getAdditionalConfig() != null ? ruleAttribute.getAdditionalConfig().get("allTeamsValue") : null;
if(ruleAttribute.getColumns() != null) {
columnValues = Arrays.stream(Arrays.stream(ruleAttribute.getColumns().split("\\+"))
.map(column -> getValueAsString(row, column))
Expand All @@ -687,7 +696,14 @@ private List<ImportMessage> addFields(Inject inject, RuleAttribute ruleAttribute
} else {
List<ImportMessage> importMessages = new ArrayList<>();
columnValues.forEach(teamName -> {
if(mapTeamByName.containsKey(teamName)) {
inject.setAllTeams(false);
Matcher allTeamsMatcher = null;
if(mapPatternByAllTeams.get(allTeamsValue) != null) {
allTeamsMatcher = mapPatternByAllTeams.get(allTeamsValue).matcher(teamName);
}
if (allTeamsValue != null && allTeamsMatcher != null && allTeamsMatcher.find()) {
inject.setAllTeams(true);
} else if(mapTeamByName.containsKey(teamName)) {
inject.getTeams().add(mapTeamByName.get(teamName));
} else {
// The team does not exist, we create a new one
Expand Down
3 changes: 3 additions & 0 deletions openbas-api/src/main/resources/application.properties
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,9 @@ openbas.mail.imap.starttls.enable=false
openbas.xtm.opencti.enable=false
openbas.xtm.opencti.url=<opencti-url>
openbas.xtm.opencti.token=<opencti-token>
# XLS Import
openbas.xls.import.mail.enable=true
openbas.xls.import.sms.enable=true

# Injector Caldera config
injector.caldera.enable=true
Expand Down
4 changes: 4 additions & 0 deletions openbas-api/src/test/resources/application.properties
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,10 @@ http.enable=false
# Injector Caldera config
injector.caldera.enable=false

# XLS Import
openbas.xls.import.mail.enable=true
openbas.xls.import.sms.enable=true

#############
# COLLECTORS #
#############
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,36 @@ const RulesContractContent: React.FC<Props> = ({
)}
/>
{rulesFields.map((ruleField, rulesIndex) => {
let cogIcon;
if (ruleField.rule_attribute_name === 'trigger_time') {
cogIcon = <Badge
color="secondary" variant="dot"
invisible={(!methods.getValues(`import_mapper_inject_importers.${index}.inject_importer_rule_attributes.${rulesIndex}.rule_attribute_default_value`)
|| methods.getValues(`import_mapper_inject_importers.${index}.inject_importer_rule_attributes.${rulesIndex}.rule_attribute_default_value`)?.length === 0)
&& (!methods.getValues(`import_mapper_inject_importers.${index}.inject_importer_rule_attributes.${rulesIndex}.rule_attribute_additional_config.timePattern`)
|| methods.getValues(`import_mapper_inject_importers.${index}.inject_importer_rule_attributes.${rulesIndex}.rule_attribute_additional_config`)?.timePattern?.length === 0)}
>
<CogOutline />
</Badge>;
} else if (ruleField.rule_attribute_name === 'teams') {
cogIcon = <Badge
color="secondary" variant="dot"
invisible={(!methods.getValues(`import_mapper_inject_importers.${index}.inject_importer_rule_attributes.${rulesIndex}.rule_attribute_default_value`)
|| methods.getValues(`import_mapper_inject_importers.${index}.inject_importer_rule_attributes.${rulesIndex}.rule_attribute_default_value`)?.length === 0)
&& (!methods.getValues(`import_mapper_inject_importers.${index}.inject_importer_rule_attributes.${rulesIndex}.rule_attribute_additional_config.allTeamsValue`)
|| methods.getValues(`import_mapper_inject_importers.${index}.inject_importer_rule_attributes.${rulesIndex}.rule_attribute_additional_config`)?.allTeamsValue?.length === 0)}
>
<CogOutline />
</Badge>;
} else {
cogIcon = <Badge
color="secondary" variant="dot"
invisible={!methods.getValues(`import_mapper_inject_importers.${index}.inject_importer_rule_attributes.${rulesIndex}.rule_attribute_default_value`)
|| methods.getValues(`import_mapper_inject_importers.${index}.inject_importer_rule_attributes.${rulesIndex}.rule_attribute_default_value`)?.length === 0}
>
<CogOutline />
</Badge>;
}
return (
<div key={ruleField.id} style={{ marginTop: 20 }}>
<div className={classes.rulesArray}>
Expand Down Expand Up @@ -261,26 +291,7 @@ const RulesContractContent: React.FC<Props> = ({
color="primary"
onClick={() => handleDefaultValueOpen(rulesIndex)}
>
{(ruleField.rule_attribute_name === 'trigger_time')
? (
<Badge
color="secondary" variant="dot"
invisible={(!methods.getValues(`import_mapper_inject_importers.${index}.inject_importer_rule_attributes.${rulesIndex}.rule_attribute_default_value`)
|| methods.getValues(`import_mapper_inject_importers.${index}.inject_importer_rule_attributes.${rulesIndex}.rule_attribute_default_value`)?.length === 0)
&& (!methods.getValues(`import_mapper_inject_importers.${index}.inject_importer_rule_attributes.${rulesIndex}.rule_attribute_additional_config.timePattern`)
|| methods.getValues(`import_mapper_inject_importers.${index}.inject_importer_rule_attributes.${rulesIndex}.rule_attribute_additional_config`)?.timePattern?.length === 0)}
>
<CogOutline />
</Badge>
) : (
<Badge
color="secondary" variant="dot"
invisible={!methods.getValues(`import_mapper_inject_importers.${index}.inject_importer_rule_attributes.${rulesIndex}.rule_attribute_default_value`)
|| methods.getValues(`import_mapper_inject_importers.${index}.inject_importer_rule_attributes.${rulesIndex}.rule_attribute_default_value`)?.length === 0}
>
<CogOutline />
</Badge>)
}
{cogIcon}
</IconButton>
</div>
{currentRuleIndex !== null
Expand Down Expand Up @@ -320,6 +331,27 @@ const RulesContractContent: React.FC<Props> = ({
</Tooltip>
</div>
}
{currentRuleIndex === rulesFields.findIndex((r) => r.rule_attribute_name === 'teams')
&& <div style={{ display: 'flex', alignItems: 'end', gap: '8px' }}>
<TextField
label={t('All teams value')}
fullWidth
style={{ marginTop: 10 }}
inputProps={methods.register(`import_mapper_inject_importers.${index}.inject_importer_rule_attributes.${currentRuleIndex}.rule_attribute_additional_config.allTeamsValue`)}
/>
<Tooltip
title={t(
'Value that signifies all teams are targeted. A regex can be used.',
)}
>
<InformationOutline
fontSize="medium"
color="primary"
style={{ cursor: 'default' }}
/>
</Tooltip>
</div>
}
</DialogContent>
<DialogActions>
<Button onClick={handleDefaultValueClose} autoFocus>
Expand Down
3 changes: 3 additions & 0 deletions openbas-front/src/utils/Localization.js
Original file line number Diff line number Diff line change
Expand Up @@ -1285,6 +1285,7 @@ const i18n = {
// Inject test
'Inject test has been sent, you can view test logs details on ': 'Le test de l\'inject a été envoyé, vous pouvez visualiser les logs de test sur ',
'its dedicated page.': 'sa page dédiée',
'Value that signifies that all teams are targeted. A regex can be used.': 'Valeur indiquant que l\'injecteur s\'applique à toutes les équipes. Il est possible d\'utiliser une expression régulière.',
},
zh: {
'Email address': 'email地址',
Expand Down Expand Up @@ -2501,6 +2502,7 @@ const i18n = {
// Platform Banner
'IMAP service is not responding, your injectors may be impacted.': 'IMAP service is not responding, your injectors may be impacted.',
'Executor Caldera is not responding, your exercises may be impacted.': 'Executor Caldera is not responding, your exercises may be impacted.',
'Value that signifies that all teams are targeted. A regex can be used.': 'Value that signifies that all teams are targeted. A regex can be used.',
},
en: {
openbas_email: 'Email',
Expand Down Expand Up @@ -2619,6 +2621,7 @@ const i18n = {
// Platform Banner
'IMAP service is not responding, your injectors may be impacted.': 'IMAP service is not responding, your injectors may be impacted.',
'Executor Caldera is not responding, your exercises may be impacted.': 'Executor Caldera is not responding, your exercises may be impacted.',
'Value that signifies that all teams are targeted. A regex can be used.': 'Value that signifies that all teams are targeted. A regex can be used.',
},
},
};
Expand Down

0 comments on commit d823b1a

Please sign in to comment.