Files
firebase-ios-sdk/FirebaseAppDistribution/Sources/FIRAppDistributionMachO.m
T
16e062c355 Switch App Distribution SDK from AppAuth to FirebaseInstallations (#6126)
* Adding error handling and returning correct error codes

* * Handling auth cancellation a few other error cases

* Adding some logging for EAP (Using NSLogs temporarily. DONOT MERGE)

* Add in a setter for clientID to allow overrides (#5514)

* Add in a setter for clientID to allow overrides

* Update styling

* Adding some result parsing logs

* Fixing code hash logging

* Add FirebaseAppDistribution to ZipBuilder

* * Making sure keychain is accesible after first unlock even if app is backgrounded (#5563)
* Fix auth persistence logging and invalid type casting (#5631)
* Logging app id requesting releases (#5655)

* AppDistribution keychain access fixes (#5683)

* Using the GULKeychainUtils instead of custom keychain utility. Also added better logging

* Updating keychain name and fixing tests

* Code review feedback updates

* Making serviceID unique per app

* Adding gmp app id to the keychain along with the bundle id

* Moving Keychain Utility functions in the AuthPersistence class and deleting the utility class

* Lazy initialize auth state (#5755)

* Lazy initialize auth state

* Making sure we dont log an error is auth state is not persisted in the keychain

* Switch from NSLog to FIRFADLogger (#5756)

* Add FIRLogger
* Switch from NSLog to FIRFADLogger

* * Use FIS Auth for authenticating the tester
* Remove AppAuth and start wiring up interceptor to do sign in

* Extracting registration flow UI in interceptor

* Adding support for iOS 9 and 10

* Create app distribution api service to handle tester api calls. (#6060)

* Pull out calls to the FAD API to make them reuseable

* Fix tests and run styl updates

* Uncomment FIRFADLog Statements

* Use [] accessor rather than . accessor

* Re-running style updates

* Trying to get these checks to pass the first time around

* App distribution signin persist (#6063)

* Pull out calls to the FAD API to make them reuseable

* Fix tests and run styl updates

* Add in UserDefaults storage after a tester has signed in

* Add testing for the main AppDistribution file

* Ran style.sh

* Remove FIRFADLocalStorage and call GULUserDefaults directly. Update tests to stop mocking on teardown.

* Add support for dynamic url schemes and fix two crashes (#6081)

* Add support for dynamic url schemes and fix two crashes

  * Add support for dynamic url schemes in the format appdistribution-<app id without colons>
  * Fix crash when launching an app directly via a URL scheme
  * Fix a crash on iOS 10 simulator caused by calling NSLogv twice
  * Remove uses of NSLog
  * Fix warnings

* Switch encodedAppId to be a class method

* Fix styles

* Create changelog and readme in preparation for release. (#6095)

Just changing markdown files so will not wait for gha checks.

* Change slices property from copy to strong (#6097)

Fix lint warning

* Change error handlers to return bool values instead of void (#6101)

* Mapping sign in flow errors to app distribution errors. Also renaming AppDelegateInterceptor to FIRAppDistributionUIService (#6099)

* Add github action for App Distribution (#6094)

* Updating app distribution deployment target to iOS 9 (#6118)

* Making sure we return granular errors during sign in persistence. Also fixing some naming and comment issues (#6117)

* Encoding colons to dashes in the app id (#6119)

* Move Internal headers to Sources (#6106)

* Move Internal headers to Sources/ folder

* PR feedback

* Remove appDistribution from zip builder

* Respond to code review feedback (#6138)

* Initializing UIWindow using initWithWindowScene for ios 13 and removing UI code from main FIRAppDistribution.m (#6144)

* Initializing UIWindow using initWithWindowScene for ios 13. Also making sure we only reset window in the App delegate if a registration flow is in progress.

* Remove UI code from main class, add unit tests, and clean up UIService

* stylish

* Remove defines in favor of solely 'if (@available(iOS 13.0, *))'

* Respond to code review feedback

Co-authored-by: Cleo Schneider <cleoschneider@google.com>

Co-authored-by: Pranav Rajgopal <pranavrajgopal@google.com>
Co-authored-by: Cleo Schneider <cleoschneider@google.com>
2020-07-28 16:39:29 -04:00

157 lines
5.0 KiB
Objective-C

/*
* Copyright 2019 Google
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#import "FirebaseAppDistribution/Sources/FIRAppDistributionMachO.h"
#import <CommonCrypto/CommonHMAC.h>
#include <mach-o/arch.h>
#import <mach-o/fat.h>
#import <mach-o/loader.h>
#import "FirebaseAppDistribution/Sources/FIRAppDistributionMachOSlice.h"
@interface FIRAppDistributionMachO ()
@property(nonatomic, copy) NSFileHandle* file;
@property(nonatomic, strong) NSMutableArray* slices;
@end
@implementation FIRAppDistributionMachO
- (instancetype)initWithPath:(NSString*)path {
self = [super init];
if (self) {
_file = [NSFileHandle fileHandleForReadingAtPath:path];
_slices = [NSMutableArray new];
[self extractSlices];
}
return self;
}
- (void)extractSlices {
uint32_t magicValue;
struct fat_header fheader;
NSData* data = [self.file readDataOfLength:sizeof(fheader)];
[data getBytes:&fheader length:sizeof(fheader)];
magicValue = CFSwapInt32BigToHost(fheader.magic);
// Check to see if the file is a FAT binary (has multiple architectures)
if (magicValue == FAT_MAGIC) {
uint32_t archCount = CFSwapInt32BigToHost(fheader.nfat_arch);
NSUInteger archOffsets[archCount];
// Gather the offsets for each architecture
for (uint32_t i = 0; i < archCount; i++) {
struct fat_arch arch;
data = [self.file readDataOfLength:sizeof(arch)];
[data getBytes:&arch length:sizeof(arch)];
archOffsets[i] = CFSwapInt32BigToHost(arch.offset);
}
// Iterate the slices based on the offsets we extracted above
for (uint32_t i = 0; i < archCount; i++) {
FIRAppDistributionMachOSlice* slice = [self extractSliceAtOffset:archOffsets[i]];
if (slice) [_slices addObject:slice];
}
} else {
// If the binary is not FAT, we're dealing with a single architecture
FIRAppDistributionMachOSlice* slice = [self extractSliceAtOffset:0];
if (slice) [_slices addObject:slice];
}
}
- (FIRAppDistributionMachOSlice*)extractSliceAtOffset:(NSUInteger)offset {
[self.file seekToFileOffset:offset];
struct mach_header header;
NSData* data = [self.file readDataOfLength:sizeof(header)];
[data getBytes:&header length:sizeof(header)];
uint32_t magicValue = CFSwapInt32BigToHost(header.magic);
// If we didn't read a valid magic value, something is wrong
// Bail out immediately to prevent reading random data
if (magicValue != MH_CIGAM_64 && magicValue != MH_CIGAM) {
return nil;
}
// If the binary is 64-bit, read the reserved bit and discard it
if (magicValue == MH_CIGAM_64) {
uint32_t reserved;
[self.file readDataOfLength:sizeof(reserved)];
}
for (uint32_t i = 0; i < header.ncmds; i++) {
struct load_command lc;
data = [self.file readDataOfLength:sizeof(lc)];
[data getBytes:&lc length:sizeof(lc)];
if (lc.cmd != LC_UUID) {
// Move to the next load command
[self.file seekToFileOffset:[self.file offsetInFile] + lc.cmdsize - sizeof(lc)];
continue;
}
// Re-read the load command, but this time as a UUID command
// so we can easily fetch the UUID
[self.file seekToFileOffset:[self.file offsetInFile] - sizeof(lc)];
struct uuid_command uc;
data = [self.file readDataOfLength:sizeof(uc)];
[data getBytes:&uc length:sizeof(uc)];
NSUUID* uuid = [[NSUUID alloc] initWithUUIDBytes:uc.uuid];
const NXArchInfo* arch = NXGetArchInfoFromCpuType(header.cputype, header.cpusubtype);
return [[FIRAppDistributionMachOSlice alloc] initWithArch:arch uuid:uuid];
}
// If we got here, something is wrong. We iterated the load commands
// and didn't find a UUID load command. This means the binary is corrupt.
return nil;
}
- (NSString*)codeHash {
NSMutableString* prehashedString = [NSMutableString new];
NSArray* sortedSlices =
[_slices sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
return [[obj1 architectureName] compare:[obj2 architectureName]];
}];
for (FIRAppDistributionMachOSlice* slice in sortedSlices) {
[prehashedString appendString:[slice uuidString]];
}
return [self sha1:prehashedString];
}
- (NSString*)sha1:(NSString*)prehashedString {
NSData* data = [prehashedString dataUsingEncoding:NSUTF8StringEncoding];
uint8_t digest[CC_SHA1_DIGEST_LENGTH];
CC_SHA1(data.bytes, (int)data.length, digest);
NSMutableString* hashedString = [NSMutableString stringWithCapacity:CC_SHA1_DIGEST_LENGTH * 2];
for (int i = 0; i < CC_SHA1_DIGEST_LENGTH; i++) [hashedString appendFormat:@"%02x", digest[i]];
return hashedString;
}
@end