diff --git a/.bazelrc b/.bazelrc index b083e61ee8..0e438514fd 100644 --- a/.bazelrc +++ b/.bazelrc @@ -22,6 +22,15 @@ build --spawn_strategy=standalone build --strategy=SwiftCompile=standalone build --define RULES_SWIFT_BUILD_DUMMY_WORKER=1 +build:swift_profile --jobs=1 +build:swift_profile --local_cpu_resources=1 +build:swift_profile --features=-swift.enable_batch_mode +build:swift_profile --experimental_ui_max_stdouterr_bytes=104857600 +build:swift_profile --@build_bazel_rules_swift//swift:copt=-Xfrontend +build:swift_profile --@build_bazel_rules_swift//swift:copt=-debug-time-function-bodies +build:swift_profile --@build_bazel_rules_swift//swift:copt=-Xfrontend +build:swift_profile --@build_bazel_rules_swift//swift:copt=-debug-time-expression-type-checking + common:index_build --experimental_convenience_symlinks=ignore common:index_build --bes_backend= --bes_results_url= common:index_build --nolegacy_important_outputs diff --git a/.gitignore b/.gitignore index 3b9c2f5f79..100cdd7947 100644 --- a/.gitignore +++ b/.gitignore @@ -77,3 +77,4 @@ spm-files xcode-files .bsp/** /.claude/ +/buildbox/* diff --git a/build-system/Make/GenerateProfiles.py b/build-system/Make/GenerateProfiles.py index 0992d95a82..df51eb6f1f 100644 --- a/build-system/Make/GenerateProfiles.py +++ b/build-system/Make/GenerateProfiles.py @@ -5,40 +5,165 @@ import shutil import tempfile import plistlib import argparse +import subprocess +import base64 from BuildEnvironment import run_executable_with_output, check_run_system -def get_certificate_base64(): - certificate_data = run_executable_with_output('security', arguments=['find-certificate', '-c', 'Apple Distribution: Telegram FZ-LLC (C67CF9S4VU)', '-p']) - certificate_data = certificate_data.replace('-----BEGIN CERTIFICATE-----', '') - certificate_data = certificate_data.replace('-----END CERTIFICATE-----', '') - certificate_data = certificate_data.replace('\n', '') - return certificate_data +def setup_temp_keychain(p12_path, p12_password=''): + """Create a temporary keychain and import the p12 certificate.""" + keychain_name = 'generate-profiles-temp.keychain' + keychain_password = 'temp123' + + # Delete if exists + run_executable_with_output('security', arguments=['delete-keychain', keychain_name], check_result=False) + + # Create keychain + run_executable_with_output('security', arguments=[ + 'create-keychain', '-p', keychain_password, keychain_name + ], check_result=True) + + # Add to search list + existing = run_executable_with_output('security', arguments=['list-keychains', '-d', 'user']) + run_executable_with_output('security', arguments=[ + 'list-keychains', '-d', 'user', '-s', keychain_name, existing.replace('"', '') + ], check_result=True) + + # Unlock and set settings + run_executable_with_output('security', arguments=['set-keychain-settings', keychain_name]) + run_executable_with_output('security', arguments=[ + 'unlock-keychain', '-p', keychain_password, keychain_name + ]) + + # Import p12 + run_executable_with_output('security', arguments=[ + 'import', p12_path, '-k', keychain_name, '-P', p12_password, + '-T', '/usr/bin/codesign', '-T', '/usr/bin/security' + ], check_result=True) + + # Set partition list for access + run_executable_with_output('security', arguments=[ + 'set-key-partition-list', '-S', 'apple-tool:,apple:', '-k', keychain_password, keychain_name + ], check_result=True) + + return keychain_name -def process_provisioning_profile(source, destination, certificate_data): +def cleanup_temp_keychain(keychain_name): + """Remove the temporary keychain.""" + run_executable_with_output('security', arguments=['delete-keychain', keychain_name], check_result=False) + + +def get_signing_identity_from_p12(p12_path, p12_password=''): + """Extract the common name (signing identity) from the p12 certificate.""" + proc = subprocess.Popen( + ['openssl', 'pkcs12', '-in', p12_path, '-passin', 'pass:' + p12_password, '-nokeys', '-legacy'], + stdout=subprocess.PIPE, stderr=subprocess.PIPE + ) + cert_pem, _ = proc.communicate() + + proc2 = subprocess.Popen( + ['openssl', 'x509', '-noout', '-subject', '-nameopt', 'oneline,-esc_msb'], + stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE + ) + subject, _ = proc2.communicate(cert_pem) + subject = subject.decode('utf-8').strip() + + # Parse CN from subject line like: subject= C = AE, O = ..., CN = Some Name + if 'CN = ' in subject: + cn = subject.split('CN = ')[-1].split(',')[0].strip() + return cn + + return None + + +def get_certificate_base64_from_p12(p12_path, p12_password=''): + """Extract the certificate as base64 from p12 file.""" + # Extract certificate in PEM format + proc = subprocess.Popen( + ['openssl', 'pkcs12', '-in', p12_path, '-passin', 'pass:' + p12_password, '-nokeys', '-legacy'], + stdout=subprocess.PIPE, stderr=subprocess.PIPE + ) + cert_pem, _ = proc.communicate() + + # Convert to DER format + proc2 = subprocess.Popen( + ['openssl', 'x509', '-outform', 'DER'], + stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE + ) + cert_der, _ = proc2.communicate(cert_pem) + + return base64.b64encode(cert_der).decode('utf-8') + + +def process_provisioning_profile(source, destination, certificate_data, signing_identity, keychain_name): parsed_plist = run_executable_with_output('security', arguments=['cms', '-D', '-i', source], check_result=True) parsed_plist_file = tempfile.mktemp() with open(parsed_plist_file, 'w+') as file: file.write(parsed_plist) - run_executable_with_output('plutil', arguments=['-remove', 'DeveloperCertificates.0', parsed_plist_file]) + # Remove all existing developer certificates + while True: + result = run_executable_with_output('plutil', arguments=['-remove', 'DeveloperCertificates.0', parsed_plist_file], check_result=False) + if result is None or 'Could not' in str(result) or result == '': + # Check if the removal actually failed by trying to extract + check = run_executable_with_output('plutil', arguments=['-extract', 'DeveloperCertificates.0', 'raw', parsed_plist_file], check_result=False) + if check is None or 'Could not' in str(check): + break + + # Insert the new certificate run_executable_with_output('plutil', arguments=['-insert', 'DeveloperCertificates.0', '-data', certificate_data, parsed_plist_file]) + + # Remove the DER-Encoded-Profile (signature) run_executable_with_output('plutil', arguments=['-remove', 'DER-Encoded-Profile', parsed_plist_file]) - run_executable_with_output('security', arguments=['cms', '-S', '-N', 'Apple Distribution: Telegram FZ-LLC (C67CF9S4VU)', '-i', parsed_plist_file, '-o', destination]) + # Sign with the certificate from the temporary keychain + run_executable_with_output('security', arguments=[ + 'cms', '-S', '-k', keychain_name, '-N', signing_identity, '-i', parsed_plist_file, '-o', destination + ], check_result=True) os.unlink(parsed_plist_file) -def generate_provisioning_profiles(source_path, destination_path): - certificate_data = get_certificate_base64() +def generate_provisioning_profiles(source_path, destination_path, certs_path): + p12_path = os.path.join(certs_path, 'SelfSigned.p12') - if not os.path.exists(destination_path): - print('{} does not exits'.format(destination_path)) + if not os.path.exists(p12_path): + print('{} does not exist'.format(p12_path)) sys.exit(1) - for file_name in os.listdir(source_path): - if file_name.endswith('.mobileprovision'): - process_provisioning_profile(source=source_path + '/' + file_name, destination=destination_path + '/' + file_name, certificate_data=certificate_data) + if not os.path.exists(destination_path): + print('{} does not exist'.format(destination_path)) + sys.exit(1) + + # Extract certificate info from p12 + p12_password = '' # fake-codesigning uses empty password + certificate_data = get_certificate_base64_from_p12(p12_path, p12_password) + signing_identity = get_signing_identity_from_p12(p12_path, p12_password) + + if not signing_identity: + print('Could not extract signing identity from {}'.format(p12_path)) + sys.exit(1) + + print('Using signing identity: {}'.format(signing_identity)) + + # Setup temporary keychain with the certificate + keychain_name = setup_temp_keychain(p12_path, p12_password) + + try: + for file_name in os.listdir(source_path): + if file_name.endswith('.mobileprovision'): + print('Processing {}'.format(file_name)) + process_provisioning_profile( + source=os.path.join(source_path, file_name), + destination=os.path.join(destination_path, file_name), + certificate_data=certificate_data, + signing_identity=signing_identity, + keychain_name=keychain_name + ) + print('Done. Generated {} profiles.'.format( + len([f for f in os.listdir(destination_path) if f.endswith('.mobileprovision')]) + )) + finally: + cleanup_temp_keychain(keychain_name) diff --git a/build-system/Make/Make.py b/build-system/Make/Make.py index b64eeb5ccd..93b6a56da8 100644 --- a/build-system/Make/Make.py +++ b/build-system/Make/Make.py @@ -46,6 +46,7 @@ class BazelCommandLine: self.show_actions = False self.enable_sandbox = False self.disable_provisioning_profiles = False + self.profile_swift = False self.common_args = [ # https://docs.bazel.build/versions/master/command-line-reference.html @@ -143,6 +144,9 @@ class BazelCommandLine: def set_disable_provisioning_profiles(self): self.disable_provisioning_profiles = True + def set_profile_swift(self, value): + self.profile_swift = value + def set_configuration(self, configuration): if configuration == 'debug_arm64': self.configuration_args = [ @@ -300,6 +304,8 @@ class BazelCommandLine: ] combined_arguments += self.configuration_args + if self.profile_swift: + combined_arguments += ['--config=swift_profile'] print('TelegramBuild: running') print(subprocess.list2cmdline(combined_arguments)) @@ -620,6 +626,7 @@ def build(bazel, arguments): bazel_command_line.set_continue_on_error(arguments.continueOnError) bazel_command_line.set_show_actions(arguments.showActions) bazel_command_line.set_enable_sandbox(arguments.sandbox) + bazel_command_line.set_profile_swift(arguments.profileSwift) bazel_command_line.set_split_swiftmodules(arguments.enableParallelSwiftmoduleGeneration) @@ -972,6 +979,12 @@ if __name__ == '__main__': help='Generate .swiftmodule files in parallel to building modules, can speed up compilation on multi-core ' 'systems. ' ) + buildParser.add_argument( + '--profileSwift', + action='store_true', + default=False, + help='Enable single-core Swift compile profiling flags.' + ) buildParser.add_argument( '--target', type=str, @@ -1063,6 +1076,13 @@ if __name__ == '__main__': type=str, help='Path to the destination directory.' ) + generate_profiles_build_parser.add_argument( + '--certsPath', + required=False, + type=str, + default='build-system/fake-codesigning/certs', + help='Path to the directory containing SelfSigned.p12 certificate.' + ) remote_upload_testflight_parser = subparsers.add_parser('remote-deploy-testflight', help='Build the app using a remote environment.') remote_upload_testflight_parser.add_argument( @@ -1304,7 +1324,7 @@ if __name__ == '__main__': additional_codesigning_output_path=remote_input_path ) - GenerateProfiles.generate_provisioning_profiles(source_path=remote_input_path + '/profiles', destination_path=args.destination) + GenerateProfiles.generate_provisioning_profiles(source_path=remote_input_path + '/profiles', destination_path=args.destination, certs_path=args.certsPath) elif args.commandName == 'remote-deploy-testflight': env = os.environ if 'APPSTORE_CONNECT_USERNAME' not in env: diff --git a/build-system/bazel-rules/sourcekit-bazel-bsp b/build-system/bazel-rules/sourcekit-bazel-bsp index 21edd49ba4..fb08c7e64a 160000 --- a/build-system/bazel-rules/sourcekit-bazel-bsp +++ b/build-system/bazel-rules/sourcekit-bazel-bsp @@ -1 +1 @@ -Subproject commit 21edd49ba4db756cc54b104b6b7eb7137801e8c4 +Subproject commit fb08c7e64a421df645dad8963f7f52a9af3f2ecb diff --git a/build-system/fake-codesigning/BroadcastUpload.mobileprovision b/build-system/fake-codesigning/BroadcastUpload.mobileprovision deleted file mode 100644 index 76d68f7932..0000000000 Binary files a/build-system/fake-codesigning/BroadcastUpload.mobileprovision and /dev/null differ diff --git a/build-system/fake-codesigning/profiles/BroadcastUpload.mobileprovision b/build-system/fake-codesigning/profiles/BroadcastUpload.mobileprovision new file mode 100644 index 0000000000..25a2a4e9b2 Binary files /dev/null and b/build-system/fake-codesigning/profiles/BroadcastUpload.mobileprovision differ diff --git a/build-system/fake-codesigning/profiles/Intents.mobileprovision b/build-system/fake-codesigning/profiles/Intents.mobileprovision index 2c3dbc97ff..5d1026994d 100644 Binary files a/build-system/fake-codesigning/profiles/Intents.mobileprovision and b/build-system/fake-codesigning/profiles/Intents.mobileprovision differ diff --git a/build-system/fake-codesigning/profiles/NotificationContent.mobileprovision b/build-system/fake-codesigning/profiles/NotificationContent.mobileprovision index 4a550cb1c7..1f3b13bf1a 100644 Binary files a/build-system/fake-codesigning/profiles/NotificationContent.mobileprovision and b/build-system/fake-codesigning/profiles/NotificationContent.mobileprovision differ diff --git a/build-system/fake-codesigning/profiles/NotificationService.mobileprovision b/build-system/fake-codesigning/profiles/NotificationService.mobileprovision index aff76a794c..809c9c8a53 100644 Binary files a/build-system/fake-codesigning/profiles/NotificationService.mobileprovision and b/build-system/fake-codesigning/profiles/NotificationService.mobileprovision differ diff --git a/build-system/fake-codesigning/profiles/Share.mobileprovision b/build-system/fake-codesigning/profiles/Share.mobileprovision index 5f45bc81be..cc40fa6a2a 100644 Binary files a/build-system/fake-codesigning/profiles/Share.mobileprovision and b/build-system/fake-codesigning/profiles/Share.mobileprovision differ diff --git a/build-system/fake-codesigning/profiles/Telegram.mobileprovision b/build-system/fake-codesigning/profiles/Telegram.mobileprovision index 18336d85be..0db3e47c70 100644 Binary files a/build-system/fake-codesigning/profiles/Telegram.mobileprovision and b/build-system/fake-codesigning/profiles/Telegram.mobileprovision differ diff --git a/build-system/fake-codesigning/profiles/WatchApp.mobileprovision b/build-system/fake-codesigning/profiles/WatchApp.mobileprovision index 7996879fbe..b766d12ea6 100644 Binary files a/build-system/fake-codesigning/profiles/WatchApp.mobileprovision and b/build-system/fake-codesigning/profiles/WatchApp.mobileprovision differ diff --git a/build-system/fake-codesigning/profiles/WatchExtension.mobileprovision b/build-system/fake-codesigning/profiles/WatchExtension.mobileprovision index 3bf56c09fb..43d092ffcc 100644 Binary files a/build-system/fake-codesigning/profiles/WatchExtension.mobileprovision and b/build-system/fake-codesigning/profiles/WatchExtension.mobileprovision differ diff --git a/build-system/fake-codesigning/profiles/Widget.mobileprovision b/build-system/fake-codesigning/profiles/Widget.mobileprovision index dfdc9cd48a..e578d141d8 100644 Binary files a/build-system/fake-codesigning/profiles/Widget.mobileprovision and b/build-system/fake-codesigning/profiles/Widget.mobileprovision differ