Add check for Bank of Brazil security module to Windows Flutter Doctor validators (#141135)

Add a warning to Flutter Doctor if Topaz OFD is found as a process on
the system.
The protection module used by the Bank of Brazil has been identified as
causing build failures when using VS with CMake for Windows (see
https://github.com/flutter/flutter/issues/121366#issuecomment-1845703728).
Disabling the software allows the build to succeed again.

If a running process is found by `flutter doctor` whose path contains
`Topaz OFD\Warsaw\core.exe`, a warning message is generated to convey
this.

Addresses https://github.com/flutter/flutter/issues/121366

## Pre-launch Checklist

- [x] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [x] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [x] I read and followed the [Flutter Style Guide], including [Features
we expect every widget to implement].
- [ ] I signed the [CLA].
- [x] I listed at least one issue that this PR fixes in the description
above.
- [x] I updated/added relevant documentation (doc comments with `///`).
- [x] I added new tests to check the change I am making, or this PR is
[test-exempt].
- [x] All existing and new tests are passing.

If you need help, consider asking for advice on the #hackers-new channel
on [Discord].

<!-- Links -->
[Contributor Guide]:
https://github.com/flutter/flutter/wiki/Tree-hygiene#overview
[Tree Hygiene]: https://github.com/flutter/flutter/wiki/Tree-hygiene
[test-exempt]:
https://github.com/flutter/flutter/wiki/Tree-hygiene#tests
[Flutter Style Guide]:
https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo
[Features we expect every widget to implement]:
https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#features-we-expect-every-widget-to-implement
[CLA]: https://cla.developers.google.com/
[flutter/tests]: https://github.com/flutter/tests
[breaking change policy]:
https://github.com/flutter/flutter/wiki/Tree-hygiene#handling-breaking-changes
[Discord]: https://github.com/flutter/flutter/wiki/Chat

---------

Co-authored-by: Elias Yishak <42216813+eliasyishak@users.noreply.github.com>
Co-authored-by: Loïc Sharma <737941+loic-sharma@users.noreply.github.com>
This commit is contained in:
yaakovschectman 2024-01-18 12:32:49 -05:00 committed by GitHub
parent c479109e75
commit 3123d98132
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 135 additions and 6 deletions

View file

@ -142,6 +142,7 @@ class _DefaultDoctorValidatorsProvider implements DoctorValidatorsProvider {
if (platform.isWindows)
WindowsVersionValidator(
operatingSystemUtils: globals.os,
processLister: ProcessLister(globals.processManager),
),
if (androidWorkflow!.appliesToHostPlatform)
GroupedValidator(<DoctorValidator>[androidValidator!, androidLicenseValidator!]),

View file

@ -2,6 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:process/process.dart';
import '../base/io.dart';
import '../base/os.dart';
import '../doctor_validator.dart';
@ -16,14 +19,44 @@ const List<String> kUnsupportedVersions = <String>[
/// (ie. 10.5.4123)
const String kWindowsOSVersionSemVerPattern = r'([0-9]+)\.([0-9]+)\.([0-9\.]+)';
/// Regex pattern for identifying a running instance of the Topaz OFD process.
/// This is a known process that interferes with the build toolchain.
/// See https://github.com/flutter/flutter/issues/121366
const String kCoreProcessPattern = r'Topaz\s+OFD\\Warsaw\\core\.exe';
/// Validator for supported Windows host machine operating system version.
class WindowsVersionValidator extends DoctorValidator {
const WindowsVersionValidator({
required OperatingSystemUtils operatingSystemUtils,
required ProcessLister processLister,
}) : _operatingSystemUtils = operatingSystemUtils,
_processLister = processLister,
super('Windows Version');
final OperatingSystemUtils _operatingSystemUtils;
final ProcessLister _processLister;
Future<ValidationResult> _topazScan() async {
final ProcessResult getProcessesResult = await _processLister.getProcessesWithPath();
if (getProcessesResult.exitCode != 0) {
return const ValidationResult(ValidationType.missing, <ValidationMessage>[ValidationMessage.hint('Get-Process failed to complete')]);
}
final RegExp topazRegex = RegExp(kCoreProcessPattern, caseSensitive: false, multiLine: true);
final String processes = getProcessesResult.stdout as String;
final bool topazFound = topazRegex.hasMatch(processes);
if (topazFound) {
return const ValidationResult(
ValidationType.missing,
<ValidationMessage>[
ValidationMessage.hint(
'The Topaz OFD Security Module was detected on your machine. '
'You may need to disable it to build Flutter applications.',
),
],
);
}
return const ValidationResult(ValidationType.success, <ValidationMessage>[]);
}
@override
Future<ValidationResult> validate() async {
@ -34,12 +67,26 @@ class WindowsVersionValidator extends DoctorValidator {
// Use the string split method to extract the major version
// and check against the [kUnsupportedVersions] list
final ValidationType windowsVersionStatus;
final String statusInfo;
ValidationType windowsVersionStatus;
final List<ValidationMessage> messages = <ValidationMessage>[];
String statusInfo;
if (matches.length == 1 &&
!kUnsupportedVersions.contains(matches.elementAt(0).group(1))) {
windowsVersionStatus = ValidationType.success;
statusInfo = 'Installed version of Windows is version 10 or higher';
// Check if the Topaz OFD security module is running, and warn the user if it is.
// See https://github.com/flutter/flutter/issues/121366
final List<ValidationResult> subResults = <ValidationResult>[
await _topazScan(),
];
for (final ValidationResult subResult in subResults) {
if (subResult.type != ValidationType.success) {
statusInfo = 'Problem detected with Windows installation';
windowsVersionStatus = ValidationType.partial;
messages.addAll(subResult.messages);
}
}
} else {
windowsVersionStatus = ValidationType.missing;
statusInfo =
@ -48,8 +95,19 @@ class WindowsVersionValidator extends DoctorValidator {
return ValidationResult(
windowsVersionStatus,
const <ValidationMessage>[],
messages,
statusInfo: statusInfo,
);
}
}
class ProcessLister {
ProcessLister(this.processManager);
final ProcessManager processManager;
Future<ProcessResult> getProcessesWithPath() async {
const String argument = 'Get-Process | Format-List Path';
return processManager.run(<String>['powershell', '-command', argument]);
}
}

View file

@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter_tools/src/base/io.dart';
import 'package:flutter_tools/src/base/os.dart';
import 'package:flutter_tools/src/doctor_validator.dart';
import 'package:flutter_tools/src/windows/windows_version_validator.dart';
@ -19,6 +20,29 @@ class FakeValidOperatingSystemUtils extends Fake
final String name;
}
class FakeProcessLister extends Fake implements ProcessLister {
FakeProcessLister({required this.result, this.exitCode = 0});
final String result;
final int exitCode;
@override
Future<ProcessResult> getProcessesWithPath() async {
return ProcessResult(0, exitCode, result, null);
}
}
FakeProcessLister ofdRunning() {
return FakeProcessLister(result: r'Path: "C:\Program Files\Topaz OFD\Warsaw\core.exe"');
}
FakeProcessLister ofdNotRunning() {
return FakeProcessLister(result: r'Path: "C:\Program Files\Google\Chrome\Application\chrome.exe');
}
FakeProcessLister failure() {
return FakeProcessLister(result: r'Path: "C:\Program Files\Google\Chrome\Application\chrome.exe', exitCode: 10);
}
/// The expected validation result object for
/// a passing windows version test
const ValidationResult validWindows10ValidationResult = ValidationResult(
@ -35,12 +59,32 @@ const ValidationResult invalidWindowsValidationResult = ValidationResult(
statusInfo: 'Unable to confirm if installed Windows version is 10 or greater',
);
const ValidationResult ofdFoundRunning = ValidationResult(
ValidationType.partial,
<ValidationMessage>[
ValidationMessage.hint(
'The Topaz OFD Security Module was detected on your machine. '
'You may need to disable it to build Flutter applications.',
),
],
statusInfo: 'Problem detected with Windows installation',
);
const ValidationResult getProcessFailed = ValidationResult(
ValidationType.partial,
<ValidationMessage>[
ValidationMessage.hint('Get-Process failed to complete'),
],
statusInfo: 'Problem detected with Windows installation',
);
void main() {
testWithoutContext('Successfully running windows version check on windows 10',
() async {
final WindowsVersionValidator windowsVersionValidator =
WindowsVersionValidator(
operatingSystemUtils: FakeValidOperatingSystemUtils());
operatingSystemUtils: FakeValidOperatingSystemUtils(),
processLister: ofdNotRunning());
final ValidationResult result = await windowsVersionValidator.validate();
@ -56,7 +100,8 @@ void main() {
final WindowsVersionValidator windowsVersionValidator =
WindowsVersionValidator(
operatingSystemUtils: FakeValidOperatingSystemUtils(
'Microsoft Windows [versão 10.0.22621.1105]'));
'Microsoft Windows [versão 10.0.22621.1105]'),
processLister: ofdNotRunning());
final ValidationResult result = await windowsVersionValidator.validate();
@ -70,7 +115,8 @@ void main() {
final WindowsVersionValidator windowsVersionValidator =
WindowsVersionValidator(
operatingSystemUtils: FakeValidOperatingSystemUtils(
'Microsoft Windows [Version 8.0.22621.1105]'));
'Microsoft Windows [Version 8.0.22621.1105]'),
processLister: ofdNotRunning());
final ValidationResult result = await windowsVersionValidator.validate();
@ -99,4 +145,28 @@ OS 版本: 10.0.22621 暂缺 Build 22621
expect(matches.length, 5,
reason: 'There should be only 5 matches for the pattern provided');
});
testWithoutContext('Successfully checks for Topaz OFD when it is running', () async {
final WindowsVersionValidator validator =
WindowsVersionValidator(
operatingSystemUtils: FakeValidOperatingSystemUtils(),
processLister: ofdRunning());
final ValidationResult result = await validator.validate();
expect(result.type, ofdFoundRunning.type, reason: 'The ValidationResult type should be the same (partial)');
expect(result.statusInfo, ofdFoundRunning.statusInfo, reason: 'The ValidationResult statusInfo should be the same');
expect(result.messages.length, 1, reason: 'The ValidationResult should have precisely 1 message');
expect(result.messages[0].message, ofdFoundRunning.messages[0].message, reason: 'The ValidationMessage message should be the same');
});
testWithoutContext('Reports failure of Get-Process', () async {
final WindowsVersionValidator validator =
WindowsVersionValidator(
operatingSystemUtils: FakeValidOperatingSystemUtils(),
processLister: failure());
final ValidationResult result = await validator.validate();
expect(result.type, getProcessFailed.type, reason: 'The ValidationResult type should be the same (partial)');
expect(result.statusInfo, getProcessFailed.statusInfo, reason: 'The ValidationResult statusInfo should be the same');
expect(result.messages.length, 1, reason: 'The ValidationResult should have precisely 1 message');
expect(result.messages[0].message, getProcessFailed.messages[0].message, reason: 'The ValidationMessage message should be the same');
});
}