Skip to content

Commit

Permalink
замечания на ХХХ.Разрешения.Добавить
Browse files Browse the repository at this point in the history
Тесты + документация
  • Loading branch information
artbear committed Nov 26, 2023
1 parent d96f4af commit c31f92f
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 48 deletions.
13 changes: 13 additions & 0 deletions docs/diagnostics/DisableSafeModeForExternalDataProcessors.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,13 @@
Правило проверяет отключение безопасного режима во внешних отчетах и обработках, подключаемых к подсистеме "
Дополнительные отчеты и обработки" для БСП-совместимых конфигураций.

Также выдается замечание, если добавляются разрешения на специальные
действия - `Разрешение = РаботаВБезопасномРежиме.РазрешениеНаХХХ`

- т.к. в случае файловых баз или клиент-серверных систем без установленных профилей безопасности `БСП` подключает
внешние файлы с отключением безопасного режима
- смотрите пример далее

## Примеры

<!-- В данном разделе приводятся примеры, на которые диагностика срабатывает, а также можно привести пример, как можно исправить ситуацию -->
Expand All @@ -37,6 +44,12 @@
ПараметрыРегистрации.Вставить("БезопасныйРежим", Ложь); // будет выдано замечание
ПараметрыРегистрации.Вставить("БезопасныйРежим", Истина); // замечания не будет
Разрешение = РаботаВБезопасномРежиме.РазрешениеНаИспользованиеПривилегированногоРежима();
ПараметрыРегистрации.Разрешения.Добавить(Разрешение); // будет выдано замечание
ПараметрыРегистрации.Разрешения.Вставить(0, Разрешение); // будет выдано замечание
КоличествоРазрешений = ПараметрыРегистрации.Разрешения.Количество(); // замечания не будет
Возврат ПараметрыРегистрации;
КонецФункции
```
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,38 +64,18 @@ public class DisableSafeModeForExternalDataProcessorsDiagnostic extends Abstract
private static final String SAFE_MODE_PARAMETER = "БЕЗОПАСНЫЙРЕЖИМ";
private static final String SAFE_MODE_PARAMETER_WITH_QUOTES = "\"" + SAFE_MODE_PARAMETER + "\"";
private static final Pattern INSERT_METHOD_PATTERN = CaseInsensitivePattern.compile("вставить|insert");
private static final Pattern ADD_INSERT_METHOD_PATTERN = CaseInsensitivePattern.compile("add|добавить|вставить|insert");
private static final Pattern PERMISSIONS_PATTERN = CaseInsensitivePattern.compile("разрешения");

private final ReferenceIndex referenceIndex;
private final Map<String, List<BSLParserRuleContext>> nodes = new HashMap<>();
private final Map<String, List<BSLParserRuleContext>> safeModeUnsetNodes = new HashMap<>();
private MethodSymbol methodSymbol;
private Optional<String> mainCollection = Optional.empty();
private String returnedVariableNameFromMainMethod = "";

public DisableSafeModeForExternalDataProcessorsDiagnostic(ReferenceIndex referenceIndex) {
this.referenceIndex = referenceIndex;
}

private static boolean isFalseExpression(Optional<BSLParser.ExpressionContext> expressionContext) {
return expressionContext
.map(BSLParser.ExpressionContext::member)
.filter(memberContexts -> !memberContexts.isEmpty())
.map(memberContexts -> memberContexts.get(0))
.map(BSLParser.MemberContext::constValue)
.map(BSLParser.ConstValueContext::FALSE)
.isPresent();
}

private static boolean haveSafeModeText(BSLParser.CallParamContext callParamContext) {
return Optional.of(callParamContext)
.map(BSLParser.CallParamContext::expression)
.map(BSLParser.ExpressionContext::member)
.filter(memberContexts -> !memberContexts.isEmpty())
.map(memberContexts -> memberContexts.get(0))
.map(BSLParser.MemberContext::constValue)
.map(BSLParser.ConstValueContext::string)
.map(BSLParserRuleContext::getText)
.filter(name -> name.equalsIgnoreCase(SAFE_MODE_PARAMETER_WITH_QUOTES))
.isPresent();
}

@Override
public ParseTree visitFile(BSLParser.FileContext ctx) {
processFile(ctx);
Expand All @@ -116,9 +96,9 @@ public void processFile(BSLParser.FileContext ctx) {
return;
}

super.visitFile(ctx); // вычисляю имя возвращаемой переменной в mainCollectionName
if (mainCollection.isPresent() && !nodes.isEmpty()) {
nodes.get(mainCollection.get())
super.visitFile(ctx); // вычисляю имя возвращаемой переменной в returnedVariablesFromMainMethod
if (!returnedVariableNameFromMainMethod.isEmpty() && !safeModeUnsetNodes.isEmpty()) {
safeModeUnsetNodes.get(returnedVariableNameFromMainMethod)
.forEach(diagnosticStorage::addDiagnostic);
}
}
Expand All @@ -132,15 +112,16 @@ private Optional<MethodSymbol> getMainMethodSymbol() {

@Override
public ParseTree visitFunction(BSLParser.FunctionContext ctx) {
// TODO проверить на вхождение range плюс или минус 1
if (Ranges.containsRange(methodSymbol.getRange(), Ranges.create(ctx)) &&
Optional.ofNullable(ctx.funcDeclaration())
if (Ranges.containsRange(methodSymbol.getRange(), Ranges.create(ctx))) {
final var isMainFunction = Optional.ofNullable(ctx.funcDeclaration())
.map(BSLParser.FuncDeclarationContext::subName)
.map(BSLParser.SubNameContext::IDENTIFIER)
.map(ParseTree::getText)
.filter(s -> s.equalsIgnoreCase(MAIN_METHOD_NAME))
.isPresent()) {
return super.visitFunction(ctx);
.isPresent();
if (isMainFunction) {
return super.visitFunction(ctx);
}
}
return null; // нет смысла анализировать другие методы
}
Expand All @@ -152,15 +133,17 @@ public ParseTree visitProcedure(BSLParser.ProcedureContext ctx) {

@Override
public ParseTree visitReturnStatement(BSLParser.ReturnStatementContext ctx) {
// TODO проверить на вхождение range плюс или минус 1
if (mainCollection.isEmpty() && Ranges.containsRange(methodSymbol.getRange(), Ranges.create(ctx))) {
mainCollection = Optional.ofNullable(ctx.expression())
if (returnedVariableNameFromMainMethod.isEmpty()
&& Ranges.containsRange(methodSymbol.getRange(), Ranges.create(ctx))) {

returnedVariableNameFromMainMethod = Optional.ofNullable(ctx.expression())
.map(BSLParser.ExpressionContext::member)
.filter(memberContexts -> !memberContexts.isEmpty())
.map(memberContexts -> memberContexts.get(0))
.map(BSLParser.MemberContext::complexIdentifier)
.map(BSLParser.ComplexIdentifierContext::IDENTIFIER)
.map(ParseTree::getText);
.map(ParseTree::getText)
.orElse("");
}
return null; //нет смысла идти глубже
}
Expand All @@ -185,7 +168,7 @@ public void processAssignment(BSLParser.AssignmentContext ctx) {
.filter(terminalNode1 -> terminalNode1.getText().equalsIgnoreCase(SAFE_MODE_PARAMETER));

if (terminalNodeSafeMode.isPresent() && isFalseExpression(Optional.ofNullable(ctx.expression()))) {
nodes.computeIfAbsent(varName.get(), name -> new ArrayList<>()).add(ctx);
safeModeUnsetNodes.computeIfAbsent(varName.get(), name -> new ArrayList<>()).add(ctx);
}
}

Expand All @@ -202,15 +185,48 @@ public void processCallStatement(BSLParser.CallStatementContext ctx) {
return;
}

final var methodCallContext = Optional.of(ctx)
.map(BSLParser.CallStatementContext::accessCall)
.map(BSLParser.AccessCallContext::methodCall);
final var methodNameContext = methodCallContext
.map(BSLParser.MethodCallContext::methodName)
.filter(methodName -> INSERT_METHOD_PATTERN.matcher(methodName.getText()).matches());
if (methodNameContext.isEmpty()) {
final var callContext = Optional.of(ctx);
if (isPermissionAdding(callContext)) {
safeModeUnsetNodes.computeIfAbsent(varName.get(), name -> new ArrayList<>()).add(ctx);
return;
}

if (isSafeModeUnsetCalling(callContext)) {
safeModeUnsetNodes.computeIfAbsent(varName.get(), name -> new ArrayList<>()).add(ctx);
}
}

private static boolean isFalseExpression(Optional<BSLParser.ExpressionContext> expressionContext) {
return expressionContext
.map(BSLParser.ExpressionContext::member)
.filter(memberContexts -> !memberContexts.isEmpty())
.map(memberContexts -> memberContexts.get(0))
.map(BSLParser.MemberContext::constValue)
.map(BSLParser.ConstValueContext::FALSE)
.isPresent();
}

private static boolean isPermissionAdding(Optional<BSLParser.CallStatementContext> callContext) {
final var isPermissionReferenced = callContext
.map(BSLParser.CallStatementContext::modifier)
.filter(modifierContexts -> !modifierContexts.isEmpty())
.map(modifierContexts -> modifierContexts.get(0))
.map(BSLParser.ModifierContext::accessProperty)
.map(BSLParser.AccessPropertyContext::IDENTIFIER)
.filter(terminalNode -> PERMISSIONS_PATTERN.matcher(terminalNode.getText()).matches())
.isPresent();
if (!isPermissionReferenced) {
return false;
}
return getMethodCallContext(callContext, ADD_INSERT_METHOD_PATTERN)
.isPresent();
}

private static boolean isSafeModeUnsetCalling(Optional<BSLParser.CallStatementContext> callContext) {
final var methodCallContext = getMethodCallContext(callContext, INSERT_METHOD_PATTERN);
if (methodCallContext.isEmpty()) {
return false;
}
final var expressionContext = methodCallContext
.map(BSLParser.MethodCallContext::doCall)
.map(BSLParser.DoCallContext::callParamList)
Expand All @@ -220,8 +236,32 @@ public void processCallStatement(BSLParser.CallStatementContext ctx) {
.map(callParamContexts -> callParamContexts.get(1))
.map(BSLParser.CallParamContext::expression);

if (isFalseExpression(expressionContext)) {
nodes.computeIfAbsent(varName.get(), name -> new ArrayList<>()).add(ctx);
return isFalseExpression(expressionContext);
}

private static Optional<BSLParser.MethodCallContext> getMethodCallContext(Optional<BSLParser.CallStatementContext> callContext, Pattern insertMethodPattern) {
final var methodCallContext = callContext
.map(BSLParser.CallStatementContext::accessCall)
.map(BSLParser.AccessCallContext::methodCall);
final var methodNameContext = methodCallContext
.map(BSLParser.MethodCallContext::methodName)
.filter(methodName -> insertMethodPattern.matcher(methodName.getText()).matches());
if (methodNameContext.isEmpty()) {
return Optional.empty();
}
return methodCallContext;
}

private static boolean haveSafeModeText(BSLParser.CallParamContext callParamContext) {
return Optional.of(callParamContext)
.map(BSLParser.CallParamContext::expression)
.map(BSLParser.ExpressionContext::member)
.filter(memberContexts -> !memberContexts.isEmpty())
.map(memberContexts -> memberContexts.get(0))
.map(BSLParser.MemberContext::constValue)
.map(BSLParser.ConstValueContext::string)
.map(BSLParserRuleContext::getText)
.filter(name -> name.equalsIgnoreCase(SAFE_MODE_PARAMETER_WITH_QUOTES))
.isPresent();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ void test() {
assertThat(diagnostics, true)
.hasRange(5, 4, 47)
.hasRange(7, 4, 58)
.hasSize(2);
.hasRange(12, 4, 56)
.hasRange(13, 4, 59)
.hasSize(4);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@
ПараметрыРегистрации.Вставить("БезопасныйРежим", Ложь); // ошибка
ПараметрыРегистрации.Вставить("БезопасныйРежим", Истина);

Разрешение = РаботаВБезопасномРежиме.РазрешениеНаИспользованиеПривилегированногоРежима();
ПараметрыРегистрации.Очистить(); // нет замечания
ПараметрыРегистрации.Разрешения.Добавить(Разрешение); // ошибка
ПараметрыРегистрации.Разрешения.Вставить(0, Разрешение); // ошибка

Возврат ПараметрыРегистрации;
КонецФункции

Expand Down

0 comments on commit c31f92f

Please sign in to comment.