2020-02-05 20:36:07 +00:00
|
|
|
// Copyright 2014 The Flutter Authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
|
|
// found in the LICENSE file.
|
|
|
|
|
2021-01-14 18:40:29 +00:00
|
|
|
import 'dart:io';
|
2020-02-05 20:36:07 +00:00
|
|
|
import 'package:path/path.dart' as path;
|
|
|
|
|
2021-01-14 18:40:29 +00:00
|
|
|
String get repoRoot => path.normalize(path.join(path.dirname(Platform.script.toFilePath()), '..', '..'));
|
|
|
|
String get cacheDirectory => path.normalize(path.join(repoRoot, 'bin', 'cache'));
|
|
|
|
|
|
|
|
/// Check mime-type of file at [filePath] to determine if it is binary
|
|
|
|
bool isBinary(String filePath) {
|
|
|
|
final ProcessResult result = Process.runSync(
|
|
|
|
'file',
|
|
|
|
<String>[
|
|
|
|
'--mime-type',
|
|
|
|
'-b', // is binary
|
|
|
|
filePath,
|
|
|
|
],
|
|
|
|
);
|
|
|
|
return (result.stdout as String).contains('application/x-mach-binary');
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Find every binary file in the given [rootDirectory]
|
|
|
|
List<String> findBinaryPaths([String rootDirectory]) {
|
|
|
|
rootDirectory ??= cacheDirectory;
|
|
|
|
final ProcessResult result = Process.runSync(
|
|
|
|
'find',
|
|
|
|
<String>[
|
|
|
|
rootDirectory,
|
|
|
|
'-type',
|
|
|
|
'f',
|
|
|
|
'-perm',
|
|
|
|
'+111', // is executable
|
|
|
|
],
|
2020-02-05 20:36:07 +00:00
|
|
|
);
|
2021-01-14 18:40:29 +00:00
|
|
|
final List<String> allFiles = (result.stdout as String).split('\n').where((String s) => s.isNotEmpty).toList();
|
|
|
|
return allFiles.where(isBinary).toList();
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Given the path to a stamp file, read the contents.
|
|
|
|
///
|
|
|
|
/// Will throw if the file doesn't exist.
|
|
|
|
String readStamp(String filePath) {
|
|
|
|
final File file = File(filePath);
|
|
|
|
if (!file.existsSync()) {
|
|
|
|
throw 'Error! Stamp file $filePath does not exist!';
|
|
|
|
}
|
|
|
|
return file.readAsStringSync().trim();
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Return whether or not the flutter cache is up to date.
|
|
|
|
bool checkCacheIsCurrent() {
|
|
|
|
try {
|
|
|
|
final String dartSdkStamp = readStamp(path.join(cacheDirectory, 'engine-dart-sdk.stamp'));
|
|
|
|
final String engineVersion = readStamp(path.join(repoRoot, 'bin', 'internal', 'engine.version'));
|
|
|
|
return dartSdkStamp == engineVersion;
|
|
|
|
} catch (e) {
|
|
|
|
print(e);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
List<String> get binariesWithEntitlements => List<String>.unmodifiable(<String>[
|
|
|
|
'ideviceinfo',
|
|
|
|
'idevicename',
|
|
|
|
'idevicescreenshot',
|
|
|
|
'idevicesyslog',
|
|
|
|
'libimobiledevice.6.dylib',
|
|
|
|
'libplist.3.dylib',
|
|
|
|
'iproxy',
|
|
|
|
'libusbmuxd.4.dylib',
|
|
|
|
'libssl.1.0.0.dylib',
|
|
|
|
'libcrypto.1.0.0.dylib',
|
|
|
|
'libzip.5.0.dylib',
|
|
|
|
'libzip.5.dylib',
|
|
|
|
'gen_snapshot',
|
|
|
|
'dart',
|
|
|
|
'flutter_tester',
|
|
|
|
'gen_snapshot_arm64',
|
|
|
|
'gen_snapshot_armv7',
|
|
|
|
]);
|
|
|
|
|
|
|
|
List<String> get expectedEntitlements => List<String>.unmodifiable(<String>[
|
|
|
|
'com.apple.security.cs.allow-jit',
|
|
|
|
'com.apple.security.cs.allow-unsigned-executable-memory',
|
|
|
|
'com.apple.security.cs.allow-dyld-environment-variables',
|
|
|
|
'com.apple.security.network.client',
|
|
|
|
'com.apple.security.network.server',
|
|
|
|
'com.apple.security.cs.disable-library-validation',
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
|
|
/// Check if the binary has the expected entitlements.
|
|
|
|
bool hasExpectedEntitlements(String binaryPath) {
|
|
|
|
try {
|
|
|
|
final ProcessResult entitlementResult = Process.runSync(
|
|
|
|
'codesign',
|
|
|
|
<String>[
|
|
|
|
'--display',
|
|
|
|
'--entitlements',
|
|
|
|
':-',
|
|
|
|
binaryPath,
|
|
|
|
],
|
|
|
|
);
|
|
|
|
|
|
|
|
if (entitlementResult.exitCode != 0) {
|
|
|
|
print('The `codesign --entitlements` command failed with exit code ${entitlementResult.exitCode}:\n'
|
|
|
|
'${entitlementResult.stderr}\n');
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool passes = true;
|
|
|
|
final String output = entitlementResult.stdout as String;
|
|
|
|
for (final String entitlement in expectedEntitlements) {
|
|
|
|
final bool entitlementExpected = binariesWithEntitlements.contains(path.basename(binaryPath));
|
|
|
|
if (output.contains(entitlement) != entitlementExpected) {
|
|
|
|
print('File "$binaryPath" ${entitlementExpected ? 'does not have expected' : 'has unexpected'} entitlement $entitlement.');
|
|
|
|
passes = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return passes;
|
|
|
|
} catch (e) {
|
|
|
|
print(e);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void main() {
|
|
|
|
if (!Platform.isMacOS) {
|
|
|
|
print('Error! Expected operating system "macos", actual operating system '
|
|
|
|
'is: "${Platform.operatingSystem}"');
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!checkCacheIsCurrent()) {
|
|
|
|
print(
|
|
|
|
'Warning! Your cache is either not present or not matching your flutter\n'
|
|
|
|
'version. Run a `flutter` command to update your cache, and re-try this\n'
|
|
|
|
'test.');
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
final List<String> unsignedBinaries = <String>[];
|
|
|
|
final List<String> wrongEntitlementBinaries = <String>[];
|
|
|
|
for (final String binaryPath in findBinaryPaths(cacheDirectory)) {
|
|
|
|
print('Verifying the code signature of $binaryPath');
|
|
|
|
final ProcessResult codeSignResult = Process.runSync(
|
|
|
|
'codesign',
|
|
|
|
<String>[
|
|
|
|
'-vvv',
|
|
|
|
binaryPath,
|
|
|
|
],
|
|
|
|
);
|
|
|
|
if (codeSignResult.exitCode != 0) {
|
|
|
|
unsignedBinaries.add(binaryPath);
|
|
|
|
print('File "$binaryPath" does not appear to be codesigned.\n'
|
|
|
|
'The `codesign` command failed with exit code ${codeSignResult.exitCode}:\n'
|
|
|
|
'${codeSignResult.stderr}\n');
|
|
|
|
continue;
|
|
|
|
} else {
|
|
|
|
print('Verifying entitlements of $binaryPath');
|
|
|
|
if (!hasExpectedEntitlements(binaryPath)) {
|
|
|
|
wrongEntitlementBinaries.add(binaryPath);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (unsignedBinaries.isNotEmpty) {
|
|
|
|
print('Found ${unsignedBinaries.length} unsigned binaries:');
|
|
|
|
unsignedBinaries.forEach(print);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (wrongEntitlementBinaries.isNotEmpty) {
|
|
|
|
print('Found ${wrongEntitlementBinaries.length} binaries with unexpected entitlements:');
|
|
|
|
wrongEntitlementBinaries.forEach(print);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (unsignedBinaries.isNotEmpty) {
|
|
|
|
// TODO(jmagman): Also exit if `wrongEntitlementBinaries.isNotEmpty` after https://github.com/flutter/flutter/issues/46704 is done.
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
print('Verified that binaries are codesigned and have expected entitlements.');
|
2020-02-05 20:36:07 +00:00
|
|
|
}
|