cocoapods-keys 0.9.5 → 1.0.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 54dc28574496b098df76d5fbb5fb61c09cb66839
4
- data.tar.gz: 6037257545de31f6c89d62b740732c8174cdf3d7
3
+ metadata.gz: 43e284067bd4672be8b813d0f5590572156eabda
4
+ data.tar.gz: 42960e0f836c6b72f6e8a34869346e0c1ada5b00
5
5
  SHA512:
6
- metadata.gz: 177cba97497cb4433c09e2606d2f1a9bdfb2af384bc0bd1d54f479927fcec670c26d7601fdc0c1decc56119443231b8c74d4582a6429665b1ae0ff8c8fda51a1
7
- data.tar.gz: 73b33ac99ab1fa60b8be9639bb922bc213e2b7190e6bcaa70b8bc470b01090eeb740eb872a9fb97321b972c6e14c438986da3a7e975701cd2660f23eff33a8ac
6
+ metadata.gz: f6de3d8e783506b471617ed1b67f385376734ce85f606996f1d11b17273513a77a0cff78992aace1501b38c3a419676b7e181bc1596dfac104badffa2fa0b758
7
+ data.tar.gz: ab271fdb4dc0027451ae75f3e36f9097a691c3b6a30020f0b1d21b01e40bf338c2897116cc32ad02bf5718a9ec1434409a0868b8cca27261febc832cca0acfec
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- cocoapods-keys (0.9.0)
4
+ cocoapods-keys (1.0.0)
5
5
  osx_keychain
6
6
 
7
7
  GEM
data/README.md CHANGED
@@ -14,7 +14,7 @@ Requires CocoaPods 0.34+.
14
14
 
15
15
  Key names are stored in `~/cocoapods/keys/` and key values in the OS X keychain. When you run `pod install` or `pod update`, an Objective-C class is created with scrambled versions of the keys, making it difficult to just [dump](https://github.com/stefanesser/dumpdecrypted) the contents of the decrypted binary and extract the keys. At runtime, the keys are unscrambled for use in your app.
16
16
 
17
- The generated Objective-C classes are stored in the `Pods/Keys` directory, so if you're checking in your [Pods folder](http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control), just add `Pods/Keys` to your `.gitignore` file.
17
+ The generated Objective-C classes are stored in the `Pods/Keys` directory, so if you're checking in your [Pods folder](http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control), just add `Pods/Keys` to your `.gitignore` file. CocoaPods-Keys supports integration in Swift or Objective-C projects.
18
18
 
19
19
  ## Usage
20
20
 
@@ -45,12 +45,12 @@ For example:
45
45
  └ redditAPIToken & mixpanelAPIToken
46
46
  ```
47
47
 
48
- After the next `pod install` or `pod update` keys will add a new Objective-C class to your Pods xcworkspace. This provides an API to your keys from Cocoa code. For example the application code above would look like:
48
+ After the next `pod install` or `pod update` keys will add a new `Keys` framework to your Pods project. This provides an API to your keys from Cocoa code. For example the application code above would look like:
49
49
 
50
50
  ``` objc
51
51
 
52
52
  #import "ORAppDelegate.h"
53
- #import <CocoaPods-Keys/MyApplicationKeys.h>
53
+ #import <Keys/MyApplicationKeys.h>
54
54
  #import <ARAnalytics/ARAnalytics.h>
55
55
 
56
56
  @implementation ORAppDelegate
@@ -67,6 +67,38 @@ After the next `pod install` or `pod update` keys will add a new Objective-C cla
67
67
 
68
68
  ```
69
69
 
70
+ ## Usage via CocoaPods 0.36
71
+
72
+ Using the new Plugin API in CocoaPods we can automate a lot of the fiddly bits away. You define what keys you want inside your [Podfile](https://github.com/artsy/eidolon/blob/0a9f5947914eb637fd4abf364fa3532b56da3c52/Podfile#L6-L21) and Keys will detect what keys are not yet set. If you need to specify a different project name from the target name, use the key `:target` to specify it.
73
+
74
+ ```
75
+ plugin 'cocoapods-keys', {
76
+ :project => "Eidolon",
77
+ :keys => [
78
+ "ArtsyAPIClientSecret",
79
+ "ArtsyAPIClientKey",
80
+ "HockeyProductionSecret",
81
+ "HockeyBetaSecret",
82
+ "MixpanelProductionAPIClientKey",
83
+ ...
84
+ ]}
85
+ ```
86
+
87
+ Then running `pod install` will prompt for the keys not yet set and you can ensure everyone has the same setup.
88
+
89
+ #### Other commands
90
+
91
+ CocoaPods-keys has 3 other commands:
92
+
93
+ * `pod keys get [key] [optional project]`
94
+ Which will output the value of the key to STDOUT, useful for scripting.
95
+
96
+ * `pod keys rm [key] [optional project]`
97
+ Will remove a key from a project.
98
+
99
+ * `pod keys generate [optional project]`
100
+ Will generate the obfuscated Objective-C keys class (mainly used internally).
101
+
70
102
  #### Security
71
103
 
72
104
  Key security is difficult. Right now even the biggest apps get their keys [leaked](https://threatpost.com/twitter-oauth-api-keys-leaked-030713/77597). This is neatly summed up by John Adams of the Twitter Security Team on [Quora](http://www.quora.com/Twitter-1/How-were-the-Twitter-iPhone-and-Android-OAuth-keys-leaked).
@@ -1,3 +1,3 @@
1
1
  module CocoaPodsKeys
2
- VERSION = "0.9.5"
2
+ VERSION = "1.0.0"
3
3
  end
@@ -21,7 +21,8 @@ module CocoaPodsKeys
21
21
 
22
22
  @data_length = @keys.values.map(&:length).reduce(:+) * (20 + rand(10))
23
23
  data = `head -c #{@data_length} /dev/random | base64 | head -c #{@data_length}`
24
- length = data.length
24
+ data = data + '\\"'
25
+ @data_length = data.length
25
26
 
26
27
  # Swap the characters within the hashed string with the characters from
27
28
  # the keyring values. Then store that index in a index-ed copy of the values.
@@ -32,15 +33,20 @@ module CocoaPodsKeys
32
33
  value.chars.each_with_index do |char, char_index|
33
34
  loop do
34
35
 
35
- index = rand data.length
36
- unless @used_indexes.include?(index)
37
- data[index] = char
38
-
39
- @used_indexes << index
36
+ if char == '"'
37
+ index = data.delete('\\').length - 1
40
38
  @indexed_keys[key][char_index] = index
41
39
  break
40
+ else
41
+ index = rand data.length
42
+ unless @used_indexes.include?(index)
43
+ data[index] = char
44
+
45
+ @used_indexes << index
46
+ @indexed_keys[key][char_index] = index
47
+ break
48
+ end
42
49
  end
43
-
44
50
  end
45
51
  end
46
52
  end
@@ -79,6 +85,7 @@ SOURCE
79
85
  //
80
86
 
81
87
  #import <objc/runtime.h>
88
+ #import <Foundation/NSDictionary.h>
82
89
  #import "<%= @name %>.h"
83
90
 
84
91
  #pragma clang diagnostic push
@@ -121,6 +128,20 @@ static NSString *_podKeys<%= Digest::MD5.hexdigest(key) %>(<%= name %> *self, SE
121
128
 
122
129
  static char <%= name %>Data[<%= @data_length %>] = "<%= @data %>";
123
130
 
131
+ - (NSString *)description
132
+ {
133
+ return [@{
134
+ <%- @keys.each do |key, value| -%>
135
+ @"<%= key %>": self.<%= key %>,
136
+ <%- end -%>
137
+ } description];
138
+ }
139
+
140
+ - (id)debugQuickLookObject
141
+ {
142
+ return [self description];
143
+ }
144
+
124
145
  @end
125
146
  SOURCE
126
147
 
@@ -131,7 +152,7 @@ SOURCE
131
152
 
132
153
  def render_erb(erb)
133
154
  require 'erb'
134
- ERB.new(erb).result(binding)
155
+ ERB.new(erb, nil, '-').result(binding)
135
156
  end
136
157
 
137
158
  def key_data_arrays
@@ -22,21 +22,21 @@ module CocoaPodsKeys
22
22
  name.split(/[^a-zA-Z0-9_]/).map { |s| s[0].upcase + s[1..-1] }.join('')
23
23
  end
24
24
 
25
+ def self.keychain_prefix
26
+ "cocoapods-keys-"
27
+ end
28
+
25
29
  def save(key, value)
26
30
  keychain = OSXKeychain.new
27
- keychain[keychain_prefix + name, key] = value
31
+ keychain[self.class.keychain_prefix + name, key] = value
28
32
  end
29
33
 
30
34
  def keychain_data
31
35
  keychain = OSXKeychain.new
32
36
  Hash[
33
- @keys.map { |key| [key, keychain[keychain_prefix + name, key]] }
37
+ @keys.map { |key| [key, keychain[self.class.keychain_prefix + name, key]] }
34
38
  ]
35
39
  end
36
40
 
37
- def keychain_prefix
38
- "cocoapods-keys-"
39
- end
40
-
41
41
  end
42
42
  end
@@ -20,6 +20,10 @@ module CocoaPodsKeys
20
20
  def self.get_keyring(path)
21
21
  get_keyring_at_path(yaml_path_for_path(path))
22
22
  end
23
+
24
+ def self.get_keyring_named(name)
25
+ self.get_all_keyrings.find { |k| k.name == name }
26
+ end
23
27
 
24
28
  def self.save_keyring(keyring)
25
29
  `mkdir -p #{keys_dir}`
@@ -1,8 +1,72 @@
1
+ require 'cocoapods-core'
2
+
1
3
  module CocoaPodsKeys
4
+ class << self
5
+ def podspec_for_current_project(spec_contents)
6
+ keyring = KeyringLiberator.get_keyring_named(user_options["project"]) || KeyringLiberator.get_keyring(Dir.getwd)
7
+ raise Informative, "Could not load keyring" unless keyring
8
+ key_master = KeyMaster.new(keyring)
9
+
10
+ spec_contents.gsub!(/%%SOURCE_FILES%%/, "#{key_master.name}.{h,m}")
11
+ spec_contents.gsub!(/%%PROJECT_NAME%%/, user_options["project"])
12
+ end
13
+
14
+ def setup
15
+ require 'preinstaller'
16
+
17
+ PreInstaller.new(user_options).setup
18
+ # Add our template podspec (needs to be remote, not local).
19
+ podfile.pod 'Keys', :git => 'https://github.com/ashfurrow/empty-podspec.git'
20
+ end
21
+
22
+ private
23
+
24
+ def podfile
25
+ Pod::Config.instance.podfile
26
+ end
27
+
28
+ def user_options
29
+ podfile.plugins["cocoapods-keys"]
30
+ end
31
+ end
32
+ end
33
+
34
+ module Pod
35
+ class Installer
36
+ alias_method :install_before_cocoapods_keys!, :install!
37
+
38
+ def install!
39
+ CocoaPodsKeys.setup
40
+ install_before_cocoapods_keys!
41
+ end
42
+
43
+ class Analyzer
44
+ class SandboxAnalyzer
45
+ alias_method :pod_state_before_cocoapods_keys, :pod_state
46
+
47
+ def pod_state(pod)
48
+ if pod == 'Keys'
49
+ # return :added if we were, otherwise assume the Keys have :changed since last install, following my mother's "Better Safe than Sorry" principle.
50
+ return :added if pod_added?(pod)
51
+ :changed
52
+ else
53
+ pod_state_before_cocoapods_keys(pod)
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
2
59
 
3
- Pod::HooksManager.register(:post_install) do |options|
4
- require 'installer'
60
+ class Specification
61
+ class << self
62
+ alias_method :from_string_before_cocoapods_keys, :from_string
5
63
 
6
- Installer.new(options.sandbox_root).install!
64
+ def from_string(spec_contents, path, subspec_name = nil)
65
+ if path.to_s.include? "Keys.podspec"
66
+ CocoaPodsKeys.podspec_for_current_project(spec_contents)
67
+ end
68
+ from_string_before_cocoapods_keys(spec_contents, path, subspec_name)
69
+ end
70
+ end
7
71
  end
8
72
  end
@@ -4,6 +4,9 @@ module Pod
4
4
  class Keys < Command
5
5
  require 'pod/command/keys/list'
6
6
  require 'pod/command/keys/set'
7
+ require 'pod/command/keys/get'
8
+ require 'pod/command/keys/rm'
9
+ require 'pod/command/keys/generate'
7
10
 
8
11
  self.summary = "A key value store for environment settings in Cocoa Apps."
9
12
 
@@ -0,0 +1,43 @@
1
+ require 'keyring_liberator'
2
+ require 'key_master'
3
+
4
+ module Pod
5
+ class Command
6
+ class Keys
7
+ class Generate < Keys
8
+ include CocoaPodsKeys
9
+
10
+ self.summary = "Generates the .h and .m files representing the keys."
11
+
12
+ self.description = <<-DESC
13
+ Generates the Objective-C class containing obfuscated keys for the project
14
+ in the current working directory (if it exists). The .h and .m files are
15
+ generated in the current working directory.
16
+ DESC
17
+
18
+ def initialize(argv)
19
+ @project_name = argv.shift_argument
20
+ super
21
+ end
22
+
23
+ def run
24
+ key_master = KeyMaster.new(@keyring)
25
+
26
+ interface_file = key_master.name + '.h'
27
+ implementation_file = key_master.name + '.m'
28
+
29
+ File.write(interface_file, key_master.interface)
30
+ File.write(implementation_file, key_master.implementation)
31
+ end
32
+
33
+ def validate!
34
+ super
35
+ verify_podfile_exists!
36
+
37
+ @keyring = KeyringLiberator.get_keyring_named(@project_name) || KeyringLiberator.get_keyring(Dir.getwd)
38
+ help! "No keys associated with this directory or project name." unless @keyring
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,59 @@
1
+ require "keyring_liberator"
2
+ require "name_whisperer"
3
+
4
+ module Pod
5
+ class Command
6
+ class Keys
7
+
8
+ class Get < Keys
9
+ self.summary = "Print a values of a key."
10
+
11
+ self.description = <<-DESC
12
+ Outputs the value of a key to SDTOUT
13
+
14
+ A second optional operator can be done to force a project name.
15
+ DESC
16
+
17
+ self.arguments = [CLAide::Argument.new('key', true),
18
+ CLAide::Argument.new('project_name', false)]
19
+
20
+ def initialize(argv)
21
+ @key_name = argv.shift_argument
22
+ @project_name = argv.shift_argument
23
+ super
24
+ end
25
+
26
+ def validate!
27
+ super
28
+ verify_podfile_exists!
29
+ help! "A key name is required for lookup." unless @key_name
30
+ end
31
+
32
+ def run
33
+ keyring = get_current_keyring
34
+ if !keyring
35
+ $stderr.puts "Could not find a project for this folder"
36
+ return
37
+ end
38
+
39
+ if keyring.keys.include? @key_name
40
+ data = keyring.keychain_data
41
+ $stderr.puts data[@key_name]
42
+ else
43
+ $stderr.puts "Could not find value"
44
+ end
45
+ end
46
+
47
+ def get_current_keyring
48
+ current_dir = Dir.getwd
49
+ keyring = CocoaPodsKeys::KeyringLiberator.get_keyring current_dir
50
+ if !keyring && @project_name
51
+ return CocoaPodsKeys::KeyringLiberator.get_keyring_named @project_name
52
+ end
53
+ keyring
54
+ end
55
+
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,71 @@
1
+ require "keyring_liberator"
2
+ require "keyring"
3
+ require "name_whisperer"
4
+
5
+ module Pod
6
+ class Command
7
+ class Keys
8
+
9
+ class Rm < Keys
10
+ self.summary = "Remove a key-value pair from a project."
11
+
12
+ self.description = <<-DESC
13
+ Remove a key, and it's value from a project
14
+
15
+ A second optional operator can be done to force a project name.
16
+ DESC
17
+
18
+ self.arguments = [CLAide::Argument.new('key', true), CLAide::Argument.new('project_name', false)]
19
+
20
+ def initialize(argv)
21
+ @key_name = argv.shift_argument
22
+ @project_name = argv.shift_argument
23
+ super
24
+ end
25
+
26
+ def validate!
27
+ super
28
+ verify_podfile_exists!
29
+ help! "A key name is required for lookup." unless @key_name
30
+ end
31
+
32
+ def run
33
+ keyring = get_current_keyring
34
+ if !keyring
35
+ $stderr.puts "Could not find a project to remove the key from."
36
+ return
37
+ end
38
+
39
+ if keyring.keys.include? @key_name
40
+ keyring.save(@key_name, "")
41
+ keyring.keys.delete @key_name
42
+ CocoaPodsKeys::KeyringLiberator.save_keyring(keyring)
43
+
44
+ prefix = CocoaPodsKeys::Keyring.keychain_prefix
45
+ delete_generic = `security delete-generic-password -a #{@key_name} -l #{prefix+keyring.name} 2>&1`
46
+
47
+ if delete_generic.include? "security: SecKeychainSearchCopyNext: The specified item could not be found in the keychain."
48
+ $stderr.puts "Removed value for #{@key_name}, but could not delete from Keychain."
49
+ elsif delete_generic.include? "password has been deleted."
50
+ $stderr.puts "Removed value for #{@key_name}, and deleted associated key in Keychain."
51
+ else
52
+ $stderr.puts "Removed value for #{@key_name}."
53
+ end
54
+ else
55
+ $stderr.puts "Could not find key named #{@key_name}."
56
+ end
57
+ end
58
+
59
+ def get_current_keyring
60
+ current_dir = Dir.getwd
61
+ keyring = CocoaPodsKeys::KeyringLiberator.get_keyring current_dir
62
+ if !keyring && @project_name
63
+ return CocoaPodsKeys::KeyringLiberator.get_keyring_named @project_name
64
+ end
65
+ keyring
66
+ end
67
+
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,47 @@
1
+ module CocoaPodsKeys
2
+ class PreInstaller
3
+ def initialize(user_options)
4
+ @options = user_options
5
+ end
6
+
7
+ def setup
8
+ require 'key_master'
9
+ require 'keyring_liberator'
10
+ require 'pod/command/keys/set'
11
+
12
+ current_dir = Dir.getwd
13
+ keyring = KeyringLiberator.get_keyring_named(@options["project"]) || KeyringLiberator.get_keyring(current_dir)
14
+ unless keyring
15
+ name = @options["project"] || CocoaPodsKeys::NameWhisperer.get_project_name
16
+ keyring = CocoaPodsKeys::Keyring.new(name, current_dir, [])
17
+ end
18
+
19
+ data = keyring.keychain_data
20
+ has_shown_intro = false
21
+ @options["keys"].each do |key|
22
+ unless data.keys.include? key
23
+
24
+ unless has_shown_intro
25
+ puts "\n CocoaPods-Keys has detected a keys mismatch for your setup."
26
+ has_shown_intro = true
27
+ end
28
+
29
+ puts " What is the key for " + key.green
30
+ answer = ""
31
+ loop do
32
+ print " > "
33
+ answer = STDIN.gets.chomp
34
+ break if answer.length > 0
35
+ end
36
+
37
+ puts ""
38
+ args = CLAide::ARGV.new([key, answer, keyring.name])
39
+ setter = Pod::Command::Keys::Set.new(args)
40
+ setter.run
41
+
42
+ end
43
+ end
44
+
45
+ end
46
+ end
47
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cocoapods-keys
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.5
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Orta Therox
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-11-17 00:00:00.000000000 Z
12
+ date: 2015-02-13 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: osx_keychain
@@ -70,15 +70,18 @@ files:
70
70
  - cocoapods_keys.gemspec
71
71
  - lib/cocoapods_keys.rb
72
72
  - lib/cocoapods_plugin.rb
73
- - lib/installer.rb
74
73
  - lib/key_master.rb
75
74
  - lib/keyring.rb
76
75
  - lib/keyring_liberator.rb
77
76
  - lib/name_whisperer.rb
78
77
  - lib/plugin.rb
79
78
  - lib/pod/command/keys.rb
79
+ - lib/pod/command/keys/generate.rb
80
+ - lib/pod/command/keys/get.rb
80
81
  - lib/pod/command/keys/list.rb
82
+ - lib/pod/command/keys/rm.rb
81
83
  - lib/pod/command/keys/set.rb
84
+ - lib/preinstaller.rb
82
85
  homepage: https://github.com/cocoapods/cocoapods-keys
83
86
  licenses:
84
87
  - MIT
@@ -1,53 +0,0 @@
1
- module CocoaPodsKeys
2
- class Installer
3
- def initialize(sandbox_root)
4
- @sandbox_root = sandbox_root
5
- end
6
-
7
- def install!
8
- require 'key_master'
9
- require 'keyring_liberator'
10
-
11
- keyring = KeyringLiberator.get_keyring(Dir.getwd)
12
-
13
- return unless keyring
14
-
15
- Pod::UI.section 'Adding keys' do
16
- key_master = KeyMaster.new(keyring)
17
-
18
- keys_folder = File.join(@sandbox_root, 'Keys')
19
- keys_headers_folder = File.join(@sandbox_root, 'Headers', 'Public', 'CocoaPods-Keys')
20
- interface_name = key_master.name + '.h'
21
- interface_file = File.join(keys_headers_folder, interface_name)
22
- implementation_file = File.join(keys_folder, key_master.name + '.m')
23
-
24
- Dir.mkdir keys_folder unless Dir.exists? keys_folder
25
- Dir.mkdir keys_headers_folder unless Dir.exists? keys_headers_folder
26
- File.open(interface_file, 'w') { |f| f.write(key_master.interface) }
27
- File.open(implementation_file, 'w') { |f| f.write(key_master.implementation) }
28
-
29
- project = Xcodeproj::Project.open File.join(@sandbox_root, 'Pods.xcodeproj')
30
-
31
- group = project.new_group('Keys')
32
- interface = group.new_file(interface_file)
33
- implementation = group.new_file(implementation_file)
34
-
35
- pods_target = project.targets.detect { |t| t.name == 'Pods' }
36
- unless pods_target
37
- pods_target = project.targets.detect { |t| t.name == 'Pods-' + keyring.name }
38
- end
39
-
40
- pods_target.add_file_references [implementation]
41
-
42
- # Swift Pod support
43
- if pods_target.product_type == "com.apple.product-type.framework"
44
- pods_target.add_file_references [interface]
45
- header_ref = pods_target.headers_build_phase.files[-1]
46
- header_ref.settings = { "ATTRIBUTES" => ["Public"] }
47
- end
48
-
49
- project.save
50
- end
51
- end
52
- end
53
- end