objc-obfuscator 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. checksums.yaml +6 -14
  2. data/bin/objc-obfuscator +5 -0
  3. data/lib/objc-obfuscator.rb +6 -0
  4. data/lib/objc-obfuscator/cli.rb +64 -0
  5. data/lib/objc-obfuscator/integrator.rb +59 -0
  6. data/lib/objc-obfuscator/obfuscator.rb +52 -0
  7. data/lib/objc-obfuscator/stringencryptor.rb +33 -0
  8. data/spec/encryptor_spec.rb +0 -0
  9. data/spec/integrator_spec.rb +17 -0
  10. data/spec/string_encryptor_spec.rb +36 -0
  11. data/spec/support/sample_project/Podfile +1 -0
  12. data/spec/support/sample_project/TestProject/TestProject.xcodeproj/project.pbxproj +459 -0
  13. data/spec/support/sample_project/TestProject/TestProject.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
  14. data/spec/support/sample_project/TestProject/TestProject.xcodeproj/project.xcworkspace/xcuserdata/dune.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  15. data/spec/support/sample_project/TestProject/TestProject.xcodeproj/xcuserdata/dune.xcuserdatad/xcschemes/TestProject.xcscheme +96 -0
  16. data/spec/support/sample_project/TestProject/TestProject.xcodeproj/xcuserdata/dune.xcuserdatad/xcschemes/xcschememanagement.plist +27 -0
  17. data/spec/support/sample_project/TestProject/TestProject/FWTAppDelegate.h +15 -0
  18. data/spec/support/sample_project/TestProject/TestProject/FWTAppDelegate.m +49 -0
  19. data/spec/support/sample_project/TestProject/TestProject/Images.xcassets/AppIcon.appiconset/Contents.json +53 -0
  20. data/spec/support/sample_project/TestProject/TestProject/Images.xcassets/LaunchImage.launchimage/Contents.json +51 -0
  21. data/spec/support/sample_project/TestProject/TestProject/TestProject-Info.plist +45 -0
  22. data/spec/support/sample_project/TestProject/TestProject/TestProject-Prefix.pch +16 -0
  23. data/spec/support/sample_project/TestProject/TestProject/en.lproj/InfoPlist.strings +2 -0
  24. data/spec/support/sample_project/TestProject/TestProject/main.m +18 -0
  25. data/spec/support/sample_project/TestProject/TestProjectTests/TestProjectTests-Info.plist +22 -0
  26. data/spec/support/sample_project/TestProject/TestProjectTests/TestProjectTests.m +34 -0
  27. data/spec/support/sample_project/TestProject/TestProjectTests/en.lproj/InfoPlist.strings +2 -0
  28. metadata +124 -8
  29. data/lib/obfuscator.rb +0 -46
checksums.yaml CHANGED
@@ -1,15 +1,7 @@
1
1
  ---
2
- !binary "U0hBMQ==":
3
- metadata.gz: !binary |-
4
- NTE2ZmNmOTAzOWQ2NDMzNDljYThiN2I0NWM1NDRiYWEyM2EwYzdiMw==
5
- data.tar.gz: !binary |-
6
- NDg1YjVlZGZmNDg1YTJkOGZjNDk5ZGVlODk2NWUzYmI5MTg1ODU0Mg==
7
- !binary "U0hBNTEy":
8
- metadata.gz: !binary |-
9
- YWU4YzIzYmQ2ZDRlODRjMzJlYzY1OGVhNTZmYWJmYmI1YjVjYWVhYWUwNmQw
10
- M2E3ZGU5NjM0ZDEwNzAzZjllZDg5ZmY5NDNjZTU3OTQ4ZTg1ZWZkMmQxZmU4
11
- MmI1NTQ0ZWQ5YWI5YWRkZTE4MzQ5NjI1MDJmN2RkYWVjZTRlYjU=
12
- data.tar.gz: !binary |-
13
- ZmY3ZjQ4MjJkZGVlN2MwZGVmMjU1YTU0MzZhNmU4NGVhNzQ1ZmU0NGY2NGQz
14
- ODY4ZmY3NDY2OTUxNWVmNmNkNDhjYzg5MTk0ZTBiYTRmMjIwODljMGY1MmY3
15
- NjYzMDIzYTY2YWNjMDJhYTZiMWYzZmMwZmZmZDYwYzkwZGVkZjQ=
2
+ SHA1:
3
+ metadata.gz: 8ca7ae76fa6cbd837fa588b5fca5385d16cdc533
4
+ data.tar.gz: 005a9d1d2c5a9a2a778a1881c4296fe2fcbb9a63
5
+ SHA512:
6
+ metadata.gz: 72de6e59f6e359d26f293eeb97ad08036b7ad0fc87db410f31034ef30cbf6a9fa327f41500b796636fa194e60847dbd760693b71e825c82d755309c20fd8b0a5
7
+ data.tar.gz: 27561859c13e993aaf455968f0adaae75217b965bf527aeaedb84e3997b248f9607799f62b6f69874a9c27723618a60e590dcf3abe312bce3bc526c8064122c1
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'objc-obfuscator'
4
+
5
+ Objc_Obfuscator::CLI.start(ARGV)
@@ -0,0 +1,6 @@
1
+ require 'objc-obfuscator/obfuscator'
2
+ require 'objc-obfuscator/stringencryptor'
3
+ require 'objc-obfuscator/cli'
4
+
5
+ module Objc_Obfuscator
6
+ end
@@ -0,0 +1,64 @@
1
+ require 'thor'
2
+ require 'objc-obfuscator/obfuscator'
3
+ require 'objc-obfuscator/integrator'
4
+
5
+
6
+ module Objc_Obfuscator
7
+ class CLI < Thor
8
+
9
+ include Objc_Obfuscator::Obfuscator
10
+ include Objc_Obfuscator::Integrator
11
+ include Thor::Actions
12
+
13
+ desc 'obfuscate [ENCRYPTION_KEY] [FILE_NAMES]', "Obfuscate one or more files using a string as the encryption key."
14
+ long_desc <<-LONGDESC
15
+ The app will scan the files for an occurence of an NSString with the keyword
16
+ '__obfuscated' and replace the character of the string with the base64 encoding
17
+ of the the encrypted string using AES256-cbc and the encryption string specified
18
+ as a parameter.
19
+ LONGDESC
20
+ option :backup,
21
+ :type => :boolean,
22
+ :default => true,
23
+ :desc => 'Saves the original files as a .bak file'
24
+ def obfuscate(key, *file_paths)
25
+
26
+ raise Thor::Error, 'A valid key and file should be provided' if key.empty? || file_paths.empty?
27
+
28
+ file_paths.each do |file_path|
29
+ unless File.exist? file_path
30
+ say_status :warning, "File #{file_path} not found!", :yellow
31
+ else
32
+ Dir.mktmpdir { |tmp_dir| obfuscate_file file_path, tmp_dir, key, options[:backup] }
33
+ end
34
+ end
35
+ end
36
+
37
+ desc 'integrate [PROJECT_FILE]', "Integrate Objc Obfuscator with the Xcode project at PROJECT_FILE."
38
+ long_desc <<-LONGDESC
39
+ Obfuscate build phases will be added to the Xcode project and a Podfile augmented with
40
+ the required library to decode such strings. It requires a valid cocoapods project.
41
+ LONGDESC
42
+ option :podfile,
43
+ :type => :string,
44
+ :default => '',
45
+ :desc => 'Path for the Podfile. Default: same as the project file'
46
+ option :target,
47
+ :type => :string,
48
+ :default => '',
49
+ :desc => 'Xcode project containing the "compile source" build phase. Default: the first target on the list.'
50
+ def integrate(project_path)
51
+ raise Thor::Error, 'A valid project file should be specified' unless File.exist?(project_path)
52
+
53
+ podfile_path = File.join File.dirname(project_path), './Podfile'
54
+ unless options[:podfile].empty?
55
+ podfile_path = options[:podfile]
56
+ end
57
+ raise Thor::Error, 'The project must be using cocoapods' unless File.exist?(podfile_path)
58
+
59
+ integrate_xcode project_path, podfile_path, options[:target]
60
+
61
+ end
62
+
63
+ end
64
+ end
@@ -0,0 +1,59 @@
1
+ require 'thor'
2
+ require 'xcodeproj'
3
+
4
+ module Objc_Obfuscator
5
+ module Integrator
6
+ def integrate_xcode(project_path, podfile_path, target_name)
7
+ project = Xcodeproj::Project.open project_path
8
+
9
+ main_target = project.targets.first
10
+
11
+ unless target_name.empty?
12
+ main_target = project.targets.select { |a| (a.name == target_name) }.first
13
+ end
14
+
15
+ raise Thor::Error, 'Cannot find the specified target' unless main_target
16
+
17
+ phase_obf = project.new('PBXShellScriptBuildPhase')
18
+ phase_obf.name = "Obfuscate strings"
19
+ phase_obf.shell_path = '/bin/bash'
20
+ phase_obf.shell_script = <<-SCRIPT
21
+ if [ -f "$HOME/.rvm/scripts/rvm" ];
22
+ then
23
+ source $HOME/.rvm/scripts/rvm
24
+ rvm rvmrc trust
25
+ rvm rvmrc load
26
+ fi
27
+ find ${SRCROOT} -name "*.h" -exec objc-obfuscator obfuscate {} \\;
28
+ find ${SRCROOT} -name "*.m" -exec objc-obfuscator obfuscate {} \\;
29
+ SCRIPT
30
+
31
+ phase_unobf = project.new('PBXShellScriptBuildPhase')
32
+ phase_unobf.name = "Unobfuscate strings"
33
+ phase_unobf.shell_path = '/bin/bash'
34
+ phase_unobf.shell_script = <<-SCRIPT
35
+ find ${SRCROOT} -name "*.bak" -exec bash -c 'mv -f "$1" "${1%.bak}"' _ {} \\;
36
+ SCRIPT
37
+
38
+ build_source_phase_idx = main_target.build_phases.index main_target.source_build_phase
39
+ obf_phase_idx = build_source_phase_idx
40
+
41
+ main_target.build_phases.insert obf_phase_idx, phase_obf
42
+
43
+ phase_unobf_idx = build_source_phase_idx+2
44
+ if(phase_unobf_idx >= main_target.build_phases.size)
45
+ main_target.build_phases << phase_unobf
46
+ else
47
+ main_target.build_phases.insert phase_unobf_idx, phase_unobf
48
+ end
49
+
50
+ project.save
51
+
52
+ if File.readlines(podfile_path).grep(/objc_obfuscator/).size == 0
53
+ File.open(podfile_path, 'a') {|f| f.write('pod "FWTObfuscator"') }
54
+ end
55
+
56
+ say_status :info, 'The project has been correctly update. Please run "pod install" to install the required pods', :blue
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,52 @@
1
+ require 'thor'
2
+
3
+
4
+ module Objc_Obfuscator
5
+ module Obfuscator
6
+ def obfuscate_file(filepath, tmp_dir, key, backup=true)
7
+ keyword = '__obfuscated'
8
+ objc_string_regex = /@"(.*)"\s*;/
9
+
10
+ encryptor = Objc_Obfuscator::StringEncryptor.new key
11
+
12
+ source_file_path = filepath
13
+ temp_file_path = File.join tmp_dir, "#{File.basename(source_file_path)}.bak"
14
+
15
+ File.delete(temp_file_path) if File.exist?(temp_file_path)
16
+
17
+ source_file = File.open(source_file_path, 'r')
18
+ dest_file = File.open(temp_file_path, 'w')
19
+
20
+ file_changed = false
21
+ say_status :info, "Processing file: #{source_file_path}", :blue
22
+ while !source_file.eof?
23
+ line = source_file.readline
24
+ if line.include? keyword
25
+ unencrypted_string = line.scan(objc_string_regex).last.first
26
+ if unencrypted_string.empty?
27
+ say_status :warning, "Found an occurrence of #{keyword} but there's no obj-string there: \"#{line}\""
28
+ else
29
+ say_status :info, "Found occurrence of __obfuscated string: '#{unencrypted_string}'."
30
+ encrypted_string = encryptor.encrypt unencrypted_string
31
+ line.slice! keyword # remove keyword
32
+ line = line.gsub(unencrypted_string, encrypted_string) # replace the unencrypted with the encrypted
33
+ file_changed = true
34
+ end
35
+ end
36
+ dest_file.puts line
37
+ end
38
+ source_file.close
39
+ dest_file.close
40
+
41
+ if file_changed
42
+ if backup
43
+ FileUtils.mv source_file_path, "#{source_file_path}.bak"
44
+ else
45
+ File.delete source_file_path
46
+ end
47
+ FileUtils.mv temp_file_path, source_file_path
48
+ end
49
+ end
50
+
51
+ end
52
+ end
@@ -0,0 +1,33 @@
1
+ require 'encryptor'
2
+ require 'base64'
3
+
4
+ module Objc_Obfuscator
5
+ class StringEncryptor
6
+ attr_reader :last_iv
7
+ attr_reader :last_salt
8
+ attr_accessor :key
9
+
10
+ class EncryptorError < StandardError
11
+
12
+ end
13
+
14
+ def initialize(key)
15
+ @key = key
16
+ end
17
+
18
+ def encrypt(unencrypted_string)
19
+ raise EncryptorError::Error "FATAL: Can't encrypt with an empty key" if key.empty?
20
+ return '' if unencrypted_string.empty?
21
+ salt = Time.now.to_i.to_s
22
+ iv = OpenSSL::Cipher::Cipher.new('aes-256-cbc').random_iv
23
+ Encryptor.default_options.merge!(:key => key , :iv => iv, :salt => salt)
24
+
25
+ encrypted_string = Base64.strict_encode64 unencrypted_string.encrypt
26
+ @last_iv = Base64.strict_encode64 iv
27
+ @last_salt = Base64.strict_encode64 salt
28
+
29
+ "#{encrypted_string}-#{last_iv}-#{last_salt}"
30
+
31
+ end
32
+ end
33
+ end
File without changes
@@ -0,0 +1,17 @@
1
+ require 'objc-obfuscator/integrator'
2
+ require 'fileutils'
3
+
4
+ describe "StringEncryptor" do
5
+ include ObjC_Obfuscator::Integrator
6
+
7
+ # before do
8
+ # @encryptor = Objc_Obfuscator::StringEncryptor.new 'mySecretKey'
9
+ # end
10
+
11
+ it "integrates the encryptor with xcode" do
12
+ Dir.mktmpdir do |dir|
13
+ FileUtils.cp_r 'spec/support/sample_project', dir
14
+ project_path = File.join dir, 'sample_project', 'TestProject', 'TestProject.xcodeproj'
15
+ podfile_path = File.join dir, 'sample_project', 'Podfile'
16
+ end
17
+ end
@@ -0,0 +1,36 @@
1
+ require 'objc-obfuscator/stringencryptor'
2
+ require 'encryptor'
3
+ require 'base64'
4
+
5
+
6
+ describe "StringEncryptor" do
7
+
8
+ before do
9
+ @encryptor = Objc_Obfuscator::StringEncryptor.new 'mySecretKey'
10
+ end
11
+
12
+ it "encrypts a string into a concatenated base64 format (enc-iv-salt)" do
13
+ unencrypted_string = 'MySecretSecretString'
14
+ encrypted_string = @encryptor.encrypt unencrypted_string
15
+ components = encrypted_string.split '-'
16
+ encrypted_payload = Base64.strict_decode64 components[0]
17
+ iv = components[1]
18
+ salt = components[2]
19
+ @encryptor.last_iv.should eq(iv)
20
+ @encryptor.last_salt.should eq(salt)
21
+ iv = Base64.strict_decode64 iv
22
+ salt = Base64.strict_decode64 salt
23
+
24
+ Encryptor.decrypt(:value => encrypted_payload, :key => 'mySecretKey', :iv => iv, :salt => salt).should eq(unencrypted_string)
25
+ end
26
+
27
+ it "fails with empty key" do
28
+ @encryptor.key = ''
29
+ expect { @encryptor.encrypt 'mystring' }.to raise_error
30
+ end
31
+
32
+ it "doesn't fail with empty string" do
33
+ @encryptor.encrypt('').should eq('')
34
+ end
35
+
36
+ end
@@ -0,0 +1 @@
1
+ # sample podfile
@@ -0,0 +1,459 @@
1
+ // !$*UTF8*$!
2
+ {
3
+ archiveVersion = 1;
4
+ classes = {
5
+ };
6
+ objectVersion = 46;
7
+ objects = {
8
+
9
+ /* Begin PBXBuildFile section */
10
+ B71EE897189665D800C6B549 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B71EE896189665D800C6B549 /* Foundation.framework */; };
11
+ B71EE899189665D800C6B549 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B71EE898189665D800C6B549 /* CoreGraphics.framework */; };
12
+ B71EE89B189665D800C6B549 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B71EE89A189665D800C6B549 /* UIKit.framework */; };
13
+ B71EE8A1189665D800C6B549 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = B71EE89F189665D800C6B549 /* InfoPlist.strings */; };
14
+ B71EE8A3189665D800C6B549 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = B71EE8A2189665D800C6B549 /* main.m */; };
15
+ B71EE8A7189665D800C6B549 /* FWTAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = B71EE8A6189665D800C6B549 /* FWTAppDelegate.m */; };
16
+ B71EE8A9189665D800C6B549 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B71EE8A8189665D800C6B549 /* Images.xcassets */; };
17
+ B71EE8B0189665D800C6B549 /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B71EE8AF189665D800C6B549 /* XCTest.framework */; };
18
+ B71EE8B1189665D800C6B549 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B71EE896189665D800C6B549 /* Foundation.framework */; };
19
+ B71EE8B2189665D800C6B549 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B71EE89A189665D800C6B549 /* UIKit.framework */; };
20
+ B71EE8BA189665D800C6B549 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = B71EE8B8189665D800C6B549 /* InfoPlist.strings */; };
21
+ B71EE8BC189665D800C6B549 /* TestProjectTests.m in Sources */ = {isa = PBXBuildFile; fileRef = B71EE8BB189665D800C6B549 /* TestProjectTests.m */; };
22
+ /* End PBXBuildFile section */
23
+
24
+ /* Begin PBXContainerItemProxy section */
25
+ B71EE8B3189665D800C6B549 /* PBXContainerItemProxy */ = {
26
+ isa = PBXContainerItemProxy;
27
+ containerPortal = B71EE88B189665D800C6B549 /* Project object */;
28
+ proxyType = 1;
29
+ remoteGlobalIDString = B71EE892189665D800C6B549;
30
+ remoteInfo = TestProject;
31
+ };
32
+ /* End PBXContainerItemProxy section */
33
+
34
+ /* Begin PBXFileReference section */
35
+ B71EE893189665D800C6B549 /* TestProject.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TestProject.app; sourceTree = BUILT_PRODUCTS_DIR; };
36
+ B71EE896189665D800C6B549 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
37
+ B71EE898189665D800C6B549 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
38
+ B71EE89A189665D800C6B549 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
39
+ B71EE89E189665D800C6B549 /* TestProject-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "TestProject-Info.plist"; sourceTree = "<group>"; };
40
+ B71EE8A0189665D800C6B549 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
41
+ B71EE8A2189665D800C6B549 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
42
+ B71EE8A4189665D800C6B549 /* TestProject-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "TestProject-Prefix.pch"; sourceTree = "<group>"; };
43
+ B71EE8A5189665D800C6B549 /* FWTAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FWTAppDelegate.h; sourceTree = "<group>"; };
44
+ B71EE8A6189665D800C6B549 /* FWTAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FWTAppDelegate.m; sourceTree = "<group>"; };
45
+ B71EE8A8189665D800C6B549 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
46
+ B71EE8AE189665D800C6B549 /* TestProjectTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = TestProjectTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
47
+ B71EE8AF189665D800C6B549 /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; };
48
+ B71EE8B7189665D800C6B549 /* TestProjectTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "TestProjectTests-Info.plist"; sourceTree = "<group>"; };
49
+ B71EE8B9189665D800C6B549 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
50
+ B71EE8BB189665D800C6B549 /* TestProjectTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TestProjectTests.m; sourceTree = "<group>"; };
51
+ /* End PBXFileReference section */
52
+
53
+ /* Begin PBXFrameworksBuildPhase section */
54
+ B71EE890189665D800C6B549 /* Frameworks */ = {
55
+ isa = PBXFrameworksBuildPhase;
56
+ buildActionMask = 2147483647;
57
+ files = (
58
+ B71EE899189665D800C6B549 /* CoreGraphics.framework in Frameworks */,
59
+ B71EE89B189665D800C6B549 /* UIKit.framework in Frameworks */,
60
+ B71EE897189665D800C6B549 /* Foundation.framework in Frameworks */,
61
+ );
62
+ runOnlyForDeploymentPostprocessing = 0;
63
+ };
64
+ B71EE8AB189665D800C6B549 /* Frameworks */ = {
65
+ isa = PBXFrameworksBuildPhase;
66
+ buildActionMask = 2147483647;
67
+ files = (
68
+ B71EE8B0189665D800C6B549 /* XCTest.framework in Frameworks */,
69
+ B71EE8B2189665D800C6B549 /* UIKit.framework in Frameworks */,
70
+ B71EE8B1189665D800C6B549 /* Foundation.framework in Frameworks */,
71
+ );
72
+ runOnlyForDeploymentPostprocessing = 0;
73
+ };
74
+ /* End PBXFrameworksBuildPhase section */
75
+
76
+ /* Begin PBXGroup section */
77
+ B71EE88A189665D800C6B549 = {
78
+ isa = PBXGroup;
79
+ children = (
80
+ B71EE89C189665D800C6B549 /* TestProject */,
81
+ B71EE8B5189665D800C6B549 /* TestProjectTests */,
82
+ B71EE895189665D800C6B549 /* Frameworks */,
83
+ B71EE894189665D800C6B549 /* Products */,
84
+ );
85
+ sourceTree = "<group>";
86
+ };
87
+ B71EE894189665D800C6B549 /* Products */ = {
88
+ isa = PBXGroup;
89
+ children = (
90
+ B71EE893189665D800C6B549 /* TestProject.app */,
91
+ B71EE8AE189665D800C6B549 /* TestProjectTests.xctest */,
92
+ );
93
+ name = Products;
94
+ sourceTree = "<group>";
95
+ };
96
+ B71EE895189665D800C6B549 /* Frameworks */ = {
97
+ isa = PBXGroup;
98
+ children = (
99
+ B71EE896189665D800C6B549 /* Foundation.framework */,
100
+ B71EE898189665D800C6B549 /* CoreGraphics.framework */,
101
+ B71EE89A189665D800C6B549 /* UIKit.framework */,
102
+ B71EE8AF189665D800C6B549 /* XCTest.framework */,
103
+ );
104
+ name = Frameworks;
105
+ sourceTree = "<group>";
106
+ };
107
+ B71EE89C189665D800C6B549 /* TestProject */ = {
108
+ isa = PBXGroup;
109
+ children = (
110
+ B71EE8A5189665D800C6B549 /* FWTAppDelegate.h */,
111
+ B71EE8A6189665D800C6B549 /* FWTAppDelegate.m */,
112
+ B71EE8A8189665D800C6B549 /* Images.xcassets */,
113
+ B71EE89D189665D800C6B549 /* Supporting Files */,
114
+ );
115
+ path = TestProject;
116
+ sourceTree = "<group>";
117
+ };
118
+ B71EE89D189665D800C6B549 /* Supporting Files */ = {
119
+ isa = PBXGroup;
120
+ children = (
121
+ B71EE89E189665D800C6B549 /* TestProject-Info.plist */,
122
+ B71EE89F189665D800C6B549 /* InfoPlist.strings */,
123
+ B71EE8A2189665D800C6B549 /* main.m */,
124
+ B71EE8A4189665D800C6B549 /* TestProject-Prefix.pch */,
125
+ );
126
+ name = "Supporting Files";
127
+ sourceTree = "<group>";
128
+ };
129
+ B71EE8B5189665D800C6B549 /* TestProjectTests */ = {
130
+ isa = PBXGroup;
131
+ children = (
132
+ B71EE8BB189665D800C6B549 /* TestProjectTests.m */,
133
+ B71EE8B6189665D800C6B549 /* Supporting Files */,
134
+ );
135
+ path = TestProjectTests;
136
+ sourceTree = "<group>";
137
+ };
138
+ B71EE8B6189665D800C6B549 /* Supporting Files */ = {
139
+ isa = PBXGroup;
140
+ children = (
141
+ B71EE8B7189665D800C6B549 /* TestProjectTests-Info.plist */,
142
+ B71EE8B8189665D800C6B549 /* InfoPlist.strings */,
143
+ );
144
+ name = "Supporting Files";
145
+ sourceTree = "<group>";
146
+ };
147
+ /* End PBXGroup section */
148
+
149
+ /* Begin PBXNativeTarget section */
150
+ B71EE892189665D800C6B549 /* TestProject */ = {
151
+ isa = PBXNativeTarget;
152
+ buildConfigurationList = B71EE8BF189665D800C6B549 /* Build configuration list for PBXNativeTarget "TestProject" */;
153
+ buildPhases = (
154
+ B71EE88F189665D800C6B549 /* Sources */,
155
+ B71EE890189665D800C6B549 /* Frameworks */,
156
+ B71EE891189665D800C6B549 /* Resources */,
157
+ );
158
+ buildRules = (
159
+ );
160
+ dependencies = (
161
+ );
162
+ name = TestProject;
163
+ productName = TestProject;
164
+ productReference = B71EE893189665D800C6B549 /* TestProject.app */;
165
+ productType = "com.apple.product-type.application";
166
+ };
167
+ B71EE8AD189665D800C6B549 /* TestProjectTests */ = {
168
+ isa = PBXNativeTarget;
169
+ buildConfigurationList = B71EE8C2189665D800C6B549 /* Build configuration list for PBXNativeTarget "TestProjectTests" */;
170
+ buildPhases = (
171
+ B71EE8AA189665D800C6B549 /* Sources */,
172
+ B71EE8AB189665D800C6B549 /* Frameworks */,
173
+ B71EE8AC189665D800C6B549 /* Resources */,
174
+ );
175
+ buildRules = (
176
+ );
177
+ dependencies = (
178
+ B71EE8B4189665D800C6B549 /* PBXTargetDependency */,
179
+ );
180
+ name = TestProjectTests;
181
+ productName = TestProjectTests;
182
+ productReference = B71EE8AE189665D800C6B549 /* TestProjectTests.xctest */;
183
+ productType = "com.apple.product-type.bundle.unit-test";
184
+ };
185
+ /* End PBXNativeTarget section */
186
+
187
+ /* Begin PBXProject section */
188
+ B71EE88B189665D800C6B549 /* Project object */ = {
189
+ isa = PBXProject;
190
+ attributes = {
191
+ CLASSPREFIX = FWT;
192
+ LastUpgradeCheck = 0500;
193
+ ORGANIZATIONNAME = "Future Workshops";
194
+ TargetAttributes = {
195
+ B71EE8AD189665D800C6B549 = {
196
+ TestTargetID = B71EE892189665D800C6B549;
197
+ };
198
+ };
199
+ };
200
+ buildConfigurationList = B71EE88E189665D800C6B549 /* Build configuration list for PBXProject "TestProject" */;
201
+ compatibilityVersion = "Xcode 3.2";
202
+ developmentRegion = English;
203
+ hasScannedForEncodings = 0;
204
+ knownRegions = (
205
+ en,
206
+ );
207
+ mainGroup = B71EE88A189665D800C6B549;
208
+ productRefGroup = B71EE894189665D800C6B549 /* Products */;
209
+ projectDirPath = "";
210
+ projectRoot = "";
211
+ targets = (
212
+ B71EE892189665D800C6B549 /* TestProject */,
213
+ B71EE8AD189665D800C6B549 /* TestProjectTests */,
214
+ );
215
+ };
216
+ /* End PBXProject section */
217
+
218
+ /* Begin PBXResourcesBuildPhase section */
219
+ B71EE891189665D800C6B549 /* Resources */ = {
220
+ isa = PBXResourcesBuildPhase;
221
+ buildActionMask = 2147483647;
222
+ files = (
223
+ B71EE8A1189665D800C6B549 /* InfoPlist.strings in Resources */,
224
+ B71EE8A9189665D800C6B549 /* Images.xcassets in Resources */,
225
+ );
226
+ runOnlyForDeploymentPostprocessing = 0;
227
+ };
228
+ B71EE8AC189665D800C6B549 /* Resources */ = {
229
+ isa = PBXResourcesBuildPhase;
230
+ buildActionMask = 2147483647;
231
+ files = (
232
+ B71EE8BA189665D800C6B549 /* InfoPlist.strings in Resources */,
233
+ );
234
+ runOnlyForDeploymentPostprocessing = 0;
235
+ };
236
+ /* End PBXResourcesBuildPhase section */
237
+
238
+ /* Begin PBXSourcesBuildPhase section */
239
+ B71EE88F189665D800C6B549 /* Sources */ = {
240
+ isa = PBXSourcesBuildPhase;
241
+ buildActionMask = 2147483647;
242
+ files = (
243
+ B71EE8A7189665D800C6B549 /* FWTAppDelegate.m in Sources */,
244
+ B71EE8A3189665D800C6B549 /* main.m in Sources */,
245
+ );
246
+ runOnlyForDeploymentPostprocessing = 0;
247
+ };
248
+ B71EE8AA189665D800C6B549 /* Sources */ = {
249
+ isa = PBXSourcesBuildPhase;
250
+ buildActionMask = 2147483647;
251
+ files = (
252
+ B71EE8BC189665D800C6B549 /* TestProjectTests.m in Sources */,
253
+ );
254
+ runOnlyForDeploymentPostprocessing = 0;
255
+ };
256
+ /* End PBXSourcesBuildPhase section */
257
+
258
+ /* Begin PBXTargetDependency section */
259
+ B71EE8B4189665D800C6B549 /* PBXTargetDependency */ = {
260
+ isa = PBXTargetDependency;
261
+ target = B71EE892189665D800C6B549 /* TestProject */;
262
+ targetProxy = B71EE8B3189665D800C6B549 /* PBXContainerItemProxy */;
263
+ };
264
+ /* End PBXTargetDependency section */
265
+
266
+ /* Begin PBXVariantGroup section */
267
+ B71EE89F189665D800C6B549 /* InfoPlist.strings */ = {
268
+ isa = PBXVariantGroup;
269
+ children = (
270
+ B71EE8A0189665D800C6B549 /* en */,
271
+ );
272
+ name = InfoPlist.strings;
273
+ sourceTree = "<group>";
274
+ };
275
+ B71EE8B8189665D800C6B549 /* InfoPlist.strings */ = {
276
+ isa = PBXVariantGroup;
277
+ children = (
278
+ B71EE8B9189665D800C6B549 /* en */,
279
+ );
280
+ name = InfoPlist.strings;
281
+ sourceTree = "<group>";
282
+ };
283
+ /* End PBXVariantGroup section */
284
+
285
+ /* Begin XCBuildConfiguration section */
286
+ B71EE8BD189665D800C6B549 /* Debug */ = {
287
+ isa = XCBuildConfiguration;
288
+ buildSettings = {
289
+ ALWAYS_SEARCH_USER_PATHS = NO;
290
+ ARCHS = "$(ARCHS_STANDARD_INCLUDING_64_BIT)";
291
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
292
+ CLANG_CXX_LIBRARY = "libc++";
293
+ CLANG_ENABLE_MODULES = YES;
294
+ CLANG_ENABLE_OBJC_ARC = YES;
295
+ CLANG_WARN_BOOL_CONVERSION = YES;
296
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
297
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
298
+ CLANG_WARN_EMPTY_BODY = YES;
299
+ CLANG_WARN_ENUM_CONVERSION = YES;
300
+ CLANG_WARN_INT_CONVERSION = YES;
301
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
302
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
303
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
304
+ COPY_PHASE_STRIP = NO;
305
+ GCC_C_LANGUAGE_STANDARD = gnu99;
306
+ GCC_DYNAMIC_NO_PIC = NO;
307
+ GCC_OPTIMIZATION_LEVEL = 0;
308
+ GCC_PREPROCESSOR_DEFINITIONS = (
309
+ "DEBUG=1",
310
+ "$(inherited)",
311
+ );
312
+ GCC_SYMBOLS_PRIVATE_EXTERN = NO;
313
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
314
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
315
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
316
+ GCC_WARN_UNINITIALIZED_AUTOS = YES;
317
+ GCC_WARN_UNUSED_FUNCTION = YES;
318
+ GCC_WARN_UNUSED_VARIABLE = YES;
319
+ IPHONEOS_DEPLOYMENT_TARGET = 7.0;
320
+ ONLY_ACTIVE_ARCH = YES;
321
+ SDKROOT = iphoneos;
322
+ TARGETED_DEVICE_FAMILY = "1,2";
323
+ };
324
+ name = Debug;
325
+ };
326
+ B71EE8BE189665D800C6B549 /* Release */ = {
327
+ isa = XCBuildConfiguration;
328
+ buildSettings = {
329
+ ALWAYS_SEARCH_USER_PATHS = NO;
330
+ ARCHS = "$(ARCHS_STANDARD_INCLUDING_64_BIT)";
331
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
332
+ CLANG_CXX_LIBRARY = "libc++";
333
+ CLANG_ENABLE_MODULES = YES;
334
+ CLANG_ENABLE_OBJC_ARC = YES;
335
+ CLANG_WARN_BOOL_CONVERSION = YES;
336
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
337
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
338
+ CLANG_WARN_EMPTY_BODY = YES;
339
+ CLANG_WARN_ENUM_CONVERSION = YES;
340
+ CLANG_WARN_INT_CONVERSION = YES;
341
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
342
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
343
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
344
+ COPY_PHASE_STRIP = YES;
345
+ ENABLE_NS_ASSERTIONS = NO;
346
+ GCC_C_LANGUAGE_STANDARD = gnu99;
347
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
348
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
349
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
350
+ GCC_WARN_UNINITIALIZED_AUTOS = YES;
351
+ GCC_WARN_UNUSED_FUNCTION = YES;
352
+ GCC_WARN_UNUSED_VARIABLE = YES;
353
+ IPHONEOS_DEPLOYMENT_TARGET = 7.0;
354
+ SDKROOT = iphoneos;
355
+ TARGETED_DEVICE_FAMILY = "1,2";
356
+ VALIDATE_PRODUCT = YES;
357
+ };
358
+ name = Release;
359
+ };
360
+ B71EE8C0189665D800C6B549 /* Debug */ = {
361
+ isa = XCBuildConfiguration;
362
+ buildSettings = {
363
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
364
+ ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
365
+ GCC_PRECOMPILE_PREFIX_HEADER = YES;
366
+ GCC_PREFIX_HEADER = "TestProject/TestProject-Prefix.pch";
367
+ INFOPLIST_FILE = "TestProject/TestProject-Info.plist";
368
+ PRODUCT_NAME = "$(TARGET_NAME)";
369
+ WRAPPER_EXTENSION = app;
370
+ };
371
+ name = Debug;
372
+ };
373
+ B71EE8C1189665D800C6B549 /* Release */ = {
374
+ isa = XCBuildConfiguration;
375
+ buildSettings = {
376
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
377
+ ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
378
+ GCC_PRECOMPILE_PREFIX_HEADER = YES;
379
+ GCC_PREFIX_HEADER = "TestProject/TestProject-Prefix.pch";
380
+ INFOPLIST_FILE = "TestProject/TestProject-Info.plist";
381
+ PRODUCT_NAME = "$(TARGET_NAME)";
382
+ WRAPPER_EXTENSION = app;
383
+ };
384
+ name = Release;
385
+ };
386
+ B71EE8C3189665D800C6B549 /* Debug */ = {
387
+ isa = XCBuildConfiguration;
388
+ buildSettings = {
389
+ ARCHS = "$(ARCHS_STANDARD_INCLUDING_64_BIT)";
390
+ BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/TestProject.app/TestProject";
391
+ FRAMEWORK_SEARCH_PATHS = (
392
+ "$(SDKROOT)/Developer/Library/Frameworks",
393
+ "$(inherited)",
394
+ "$(DEVELOPER_FRAMEWORKS_DIR)",
395
+ );
396
+ GCC_PRECOMPILE_PREFIX_HEADER = YES;
397
+ GCC_PREFIX_HEADER = "TestProject/TestProject-Prefix.pch";
398
+ GCC_PREPROCESSOR_DEFINITIONS = (
399
+ "DEBUG=1",
400
+ "$(inherited)",
401
+ );
402
+ INFOPLIST_FILE = "TestProjectTests/TestProjectTests-Info.plist";
403
+ PRODUCT_NAME = "$(TARGET_NAME)";
404
+ TEST_HOST = "$(BUNDLE_LOADER)";
405
+ WRAPPER_EXTENSION = xctest;
406
+ };
407
+ name = Debug;
408
+ };
409
+ B71EE8C4189665D800C6B549 /* Release */ = {
410
+ isa = XCBuildConfiguration;
411
+ buildSettings = {
412
+ ARCHS = "$(ARCHS_STANDARD_INCLUDING_64_BIT)";
413
+ BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/TestProject.app/TestProject";
414
+ FRAMEWORK_SEARCH_PATHS = (
415
+ "$(SDKROOT)/Developer/Library/Frameworks",
416
+ "$(inherited)",
417
+ "$(DEVELOPER_FRAMEWORKS_DIR)",
418
+ );
419
+ GCC_PRECOMPILE_PREFIX_HEADER = YES;
420
+ GCC_PREFIX_HEADER = "TestProject/TestProject-Prefix.pch";
421
+ INFOPLIST_FILE = "TestProjectTests/TestProjectTests-Info.plist";
422
+ PRODUCT_NAME = "$(TARGET_NAME)";
423
+ TEST_HOST = "$(BUNDLE_LOADER)";
424
+ WRAPPER_EXTENSION = xctest;
425
+ };
426
+ name = Release;
427
+ };
428
+ /* End XCBuildConfiguration section */
429
+
430
+ /* Begin XCConfigurationList section */
431
+ B71EE88E189665D800C6B549 /* Build configuration list for PBXProject "TestProject" */ = {
432
+ isa = XCConfigurationList;
433
+ buildConfigurations = (
434
+ B71EE8BD189665D800C6B549 /* Debug */,
435
+ B71EE8BE189665D800C6B549 /* Release */,
436
+ );
437
+ defaultConfigurationIsVisible = 0;
438
+ defaultConfigurationName = Release;
439
+ };
440
+ B71EE8BF189665D800C6B549 /* Build configuration list for PBXNativeTarget "TestProject" */ = {
441
+ isa = XCConfigurationList;
442
+ buildConfigurations = (
443
+ B71EE8C0189665D800C6B549 /* Debug */,
444
+ B71EE8C1189665D800C6B549 /* Release */,
445
+ );
446
+ defaultConfigurationIsVisible = 0;
447
+ };
448
+ B71EE8C2189665D800C6B549 /* Build configuration list for PBXNativeTarget "TestProjectTests" */ = {
449
+ isa = XCConfigurationList;
450
+ buildConfigurations = (
451
+ B71EE8C3189665D800C6B549 /* Debug */,
452
+ B71EE8C4189665D800C6B549 /* Release */,
453
+ );
454
+ defaultConfigurationIsVisible = 0;
455
+ };
456
+ /* End XCConfigurationList section */
457
+ };
458
+ rootObject = B71EE88B189665D800C6B549 /* Project object */;
459
+ }