Proyectos de Subversion Iphone Microlearning

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
// Copyright 2017 Google
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//      http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
 
15
#import "GoogleUtilities/Environment/Public/GoogleUtilities/GULAppEnvironmentUtil.h"
16
 
17
#import <Foundation/Foundation.h>
18
#import <dlfcn.h>
19
#import <mach-o/dyld.h>
20
#import <sys/sysctl.h>
21
#import <sys/utsname.h>
22
#import <objc/runtime.h>
23
 
24
#if TARGET_OS_IOS
25
#import <UIKit/UIKit.h>
26
#endif
27
 
28
/// The encryption info struct and constants are missing from the iPhoneSimulator SDK, but not from
29
/// the iPhoneOS or Mac OS X SDKs. Since one doesn't ever ship a Simulator binary, we'll just
30
/// provide the definitions here.
31
#if TARGET_OS_SIMULATOR && !defined(LC_ENCRYPTION_INFO)
32
#define LC_ENCRYPTION_INFO 0x21
33
struct encryption_info_command {
34
  uint32_t cmd;
35
  uint32_t cmdsize;
36
  uint32_t cryptoff;
37
  uint32_t cryptsize;
38
  uint32_t cryptid;
39
};
40
#endif
41
 
42
@implementation GULAppEnvironmentUtil
43
 
44
/// A key for the Info.plist to enable or disable checking if the App Store is running in a sandbox.
45
/// This will affect your data integrity when using Firebase Analytics, as it will disable some
46
/// necessary checks.
47
static NSString *const kFIRAppStoreReceiptURLCheckEnabledKey =
48
    @"FirebaseAppStoreReceiptURLCheckEnabled";
49
 
50
/// The file name of the sandbox receipt. This is available on iOS >= 8.0
51
static NSString *const kFIRAIdentitySandboxReceiptFileName = @"sandboxReceipt";
52
 
53
/// The following copyright from Landon J. Fuller applies to the isAppEncrypted function.
54
///
55
/// Copyright (c) 2017 Landon J. Fuller <landon@landonf.org>
56
/// All rights reserved.
57
///
58
/// Permission is hereby granted, free of charge, to any person obtaining a copy of this software
59
/// and associated documentation files (the "Software"), to deal in the Software without
60
/// restriction, including without limitation the rights to use, copy, modify, merge, publish,
61
/// distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
62
/// Software is furnished to do so, subject to the following conditions:
63
///
64
/// The above copyright notice and this permission notice shall be included in all copies or
65
/// substantial portions of the Software.
66
///
67
/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
68
/// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
69
/// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
70
/// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
71
/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
72
///
73
/// Comment from <a href="http://iphonedevwiki.net/index.php/Crack_prevention">iPhone Dev Wiki
74
/// Crack Prevention</a>:
75
/// App Store binaries are signed by both their developer and Apple. This encrypts the binary so
76
/// that decryption keys are needed in order to make the binary readable. When iOS executes the
77
/// binary, the decryption keys are used to decrypt the binary into a readable state where it is
78
/// then loaded into memory and executed. iOS can tell the encryption status of a binary via the
79
/// cryptid structure member of LC_ENCRYPTION_INFO MachO load command. If cryptid is a non-zero
80
/// value then the binary is encrypted.
81
///
82
/// 'Cracking' works by letting the kernel decrypt the binary then siphoning the decrypted data into
83
/// a new binary file, resigning, and repackaging. This will only work on jailbroken devices as
84
/// codesignature validation has been removed. Resigning takes place because while the codesignature
85
/// doesn't have to be valid thanks to the jailbreak, it does have to be in place unless you have
86
/// AppSync or similar to disable codesignature checks.
87
///
88
/// More information at <a href="http://landonf.org/2009/02/index.html">Landon Fuller's blog</a>
89
static BOOL IsAppEncrypted() {
90
  const struct mach_header *executableHeader = NULL;
91
  for (uint32_t i = 0; i < _dyld_image_count(); i++) {
92
    const struct mach_header *header = _dyld_get_image_header(i);
93
    if (header && header->filetype == MH_EXECUTE) {
94
      executableHeader = header;
95
      break;
96
    }
97
  }
98
 
99
  if (!executableHeader) {
100
    return NO;
101
  }
102
 
103
  BOOL is64bit = (executableHeader->magic == MH_MAGIC_64);
104
  uintptr_t cursor = (uintptr_t)executableHeader +
105
                     (is64bit ? sizeof(struct mach_header_64) : sizeof(struct mach_header));
106
  const struct segment_command *segmentCommand = NULL;
107
  uint32_t i = 0;
108
 
109
  while (i++ < executableHeader->ncmds) {
110
    segmentCommand = (struct segment_command *)cursor;
111
 
112
    if (!segmentCommand) {
113
      continue;
114
    }
115
 
116
    if ((!is64bit && segmentCommand->cmd == LC_ENCRYPTION_INFO) ||
117
        (is64bit && segmentCommand->cmd == LC_ENCRYPTION_INFO_64)) {
118
      if (is64bit) {
119
        struct encryption_info_command_64 *cryptCmd =
120
            (struct encryption_info_command_64 *)segmentCommand;
121
        return cryptCmd && cryptCmd->cryptid != 0;
122
      } else {
123
        struct encryption_info_command *cryptCmd = (struct encryption_info_command *)segmentCommand;
124
        return cryptCmd && cryptCmd->cryptid != 0;
125
      }
126
    }
127
    cursor += segmentCommand->cmdsize;
128
  }
129
 
130
  return NO;
131
}
132
 
133
static BOOL HasSCInfoFolder() {
134
#if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_WATCH
135
  NSString *bundlePath = [NSBundle mainBundle].bundlePath;
136
  NSString *scInfoPath = [bundlePath stringByAppendingPathComponent:@"SC_Info"];
137
  return [[NSFileManager defaultManager] fileExistsAtPath:scInfoPath];
138
#elif TARGET_OS_OSX
139
  return NO;
140
#endif
141
}
142
 
143
static BOOL HasEmbeddedMobileProvision() {
144
#if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_WATCH
145
  return [[NSBundle mainBundle] pathForResource:@"embedded" ofType:@"mobileprovision"].length > 0;
146
#elif TARGET_OS_OSX
147
  return NO;
148
#endif
149
}
150
 
151
+ (BOOL)isFromAppStore {
152
  static dispatch_once_t isEncryptedOnce;
153
  static BOOL isEncrypted = NO;
154
 
155
  dispatch_once(&isEncryptedOnce, ^{
156
    isEncrypted = IsAppEncrypted();
157
  });
158
 
159
  if ([GULAppEnvironmentUtil isSimulator]) {
160
    return NO;
161
  }
162
 
163
  // If an app contain the sandboxReceipt file, it means its coming from TestFlight
164
  // This must be checked before the SCInfo Folder check below since TestFlight apps may
165
  // also have an SCInfo folder.
166
  if ([GULAppEnvironmentUtil isAppStoreReceiptSandbox]) {
167
    return NO;
168
  }
169
 
170
  if (HasSCInfoFolder()) {
171
    // When iTunes downloads a .ipa, it also gets a customized .sinf file which is added to the
172
    // main SC_Info directory.
173
    return YES;
174
  }
175
 
176
  // For iOS >= 8.0, iTunesMetadata.plist is moved outside of the sandbox. Any attempt to read
177
  // the iTunesMetadata.plist outside of the sandbox will be rejected by Apple.
178
  // If the app does not contain the embedded.mobileprovision which is stripped out by Apple when
179
  // the app is submitted to store, then it is highly likely that it is from Apple Store.
180
  return isEncrypted && !HasEmbeddedMobileProvision();
181
}
182
 
183
+ (BOOL)isAppStoreReceiptSandbox {
184
  // Since checking the App Store's receipt URL can be memory intensive, check the option in the
185
  // Info.plist if developers opted out of this check.
186
  id enableSandboxCheck =
187
      [[NSBundle mainBundle] objectForInfoDictionaryKey:kFIRAppStoreReceiptURLCheckEnabledKey];
188
  if (enableSandboxCheck && [enableSandboxCheck isKindOfClass:[NSNumber class]] &&
189
      ![enableSandboxCheck boolValue]) {
190
    return NO;
191
  }
192
 
193
  NSURL *appStoreReceiptURL = [NSBundle mainBundle].appStoreReceiptURL;
194
  NSString *appStoreReceiptFileName = appStoreReceiptURL.lastPathComponent;
195
  return [appStoreReceiptFileName isEqualToString:kFIRAIdentitySandboxReceiptFileName];
196
}
197
 
198
+ (BOOL)isSimulator {
199
#if TARGET_OS_SIMULATOR
200
  return YES;
201
#elif TARGET_OS_MACCATALYST
202
  return NO;
203
#elif TARGET_OS_IOS || TARGET_OS_TV
204
  NSString *platform = [GULAppEnvironmentUtil deviceModel];
205
  return [platform isEqual:@"x86_64"] || [platform isEqual:@"i386"];
206
#elif TARGET_OS_OSX
207
  return NO;
208
#endif
209
  return NO;
210
}
211
 
212
+ (NSString *)deviceModel {
213
  static dispatch_once_t once;
214
  static NSString *deviceModel;
215
 
216
#if TARGET_OS_OSX || TARGET_OS_MACCATALYST
217
  dispatch_once(&once, ^{
218
    // The `uname` function only returns x86_64 for Macs. Use `sysctlbyname` instead, but fall back
219
    // to the `uname` function if it fails.
220
    size_t size;
221
    sysctlbyname("hw.model", NULL, &size, NULL, 0);
222
    if (size > 0) {
223
      char *machine = malloc(size);
224
      sysctlbyname("hw.model", machine, &size, NULL, 0);
225
      deviceModel = [NSString stringWithCString:machine encoding:NSUTF8StringEncoding];
226
      free(machine);
227
    } else {
228
      struct utsname systemInfo;
229
      if (uname(&systemInfo) == 0) {
230
        deviceModel = [NSString stringWithUTF8String:systemInfo.machine];
231
      }
232
    }
233
  });
234
#else
235
  dispatch_once(&once, ^{
236
    struct utsname systemInfo;
237
    if (uname(&systemInfo) == 0) {
238
      deviceModel = [NSString stringWithUTF8String:systemInfo.machine];
239
    }
240
  });
241
#endif  // TARGET_OS_OSX || TARGET_OS_MACCATALYST
242
  return deviceModel;
243
}
244
 
245
+ (NSString *)systemVersion {
246
#if TARGET_OS_IOS
247
  return [UIDevice currentDevice].systemVersion;
248
#elif TARGET_OS_OSX || TARGET_OS_TV || TARGET_OS_WATCH
249
  // Assemble the systemVersion, excluding the patch version if it's 0.
250
  NSOperatingSystemVersion osVersion = [NSProcessInfo processInfo].operatingSystemVersion;
251
  NSMutableString *versionString = [[NSMutableString alloc]
252
      initWithFormat:@"%ld.%ld", (long)osVersion.majorVersion, (long)osVersion.minorVersion];
253
  if (osVersion.patchVersion != 0) {
254
    [versionString appendFormat:@".%ld", (long)osVersion.patchVersion];
255
  }
256
  return versionString;
257
#endif
258
}
259
 
260
+ (BOOL)isAppExtension {
261
#if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_WATCH
262
  // Documented by <a href="https://goo.gl/RRB2Up">Apple</a>
263
  BOOL appExtension = [[[NSBundle mainBundle] bundlePath] hasSuffix:@".appex"];
264
  return appExtension;
265
#elif TARGET_OS_OSX
266
  return NO;
267
#endif
268
}
269
 
270
+ (BOOL)isIOS7OrHigher {
271
  return YES;
272
}
273
 
274
+ (BOOL)hasSwiftRuntime {
275
  // The class
276
  // [Swift._SwiftObject](https://github.com/apple/swift/blob/5eac3e2818eb340b11232aff83edfbd1c307fa03/stdlib/public/runtime/SwiftObject.h#L35)
277
  // is a part of Swift runtime, so it should be present if Swift runtime is available.
278
 
279
  BOOL hasSwiftRuntime =
280
      objc_lookUpClass("Swift._SwiftObject") != nil ||
281
      // Swift object class name before
282
      // https://github.com/apple/swift/commit/9637b4a6e11ddca72f5f6dbe528efc7c92f14d01
283
      objc_getClass("_TtCs12_SwiftObject") != nil;
284
 
285
  return hasSwiftRuntime;
286
}
287
 
288
+ (NSString *)applePlatform {
289
  NSString *applePlatform = @"unknown";
290
 
291
  // When a Catalyst app is run on macOS then both `TARGET_OS_MACCATALYST` and `TARGET_OS_IOS` are
292
  // `true`, which means the condition list is order-sensitive.
293
#if TARGET_OS_MACCATALYST
294
  applePlatform = @"maccatalyst";
295
#elif TARGET_OS_IOS
296
#if defined(__IPHONE_14_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 140000
297
  if (@available(iOS 14.0, *)) {
298
    // Early iOS 14 betas do not include isiOSAppOnMac (#6969)
299
    applePlatform = ([[NSProcessInfo processInfo] respondsToSelector:@selector(isiOSAppOnMac)] &&
300
                      [NSProcessInfo processInfo].isiOSAppOnMac) ? @"ios_on_mac" : @"ios";
301
  } else {
302
    applePlatform = @"ios";
303
  }
304
#else // defined(__IPHONE_14_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 140000
305
  applePlatform = @"ios";
306
#endif // defined(__IPHONE_14_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 140000
307
 
308
#elif TARGET_OS_TV
309
  applePlatform = @"tvos";
310
#elif TARGET_OS_OSX
311
  applePlatform = @"macos";
312
#elif TARGET_OS_WATCH
313
  applePlatform = @"watchos";
314
#endif // TARGET_OS_MACCATALYST
315
 
316
  return applePlatform;
317
}
318
 
319
+ (NSString *)deploymentType {
320
#if SWIFT_PACKAGE
321
  NSString *deploymentType = @"swiftpm";
322
#elif FIREBASE_BUILD_CARTHAGE
323
  NSString *deploymentType = @"carthage";
324
#elif FIREBASE_BUILD_ZIP_FILE
325
  NSString *deploymentType = @"zip";
326
#else
327
  NSString *deploymentType = @"cocoapods";
328
#endif
329
 
330
  return deploymentType;
331
}
332
 
333
@end