cocoapods-keys 0.5.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +3 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +23 -0
- data/LICENSE.txt +22 -0
- data/README.md +84 -0
- data/Rakefile +1 -0
- data/cocoapods_keys.gemspec +24 -0
- data/lib/cocoapods_keys.rb +3 -0
- data/lib/cocoapods_plugin.rb +3 -0
- data/lib/installer.rb +43 -0
- data/lib/key_master.rb +134 -0
- data/lib/keyring.rb +42 -0
- data/lib/keyring_liberator.rb +46 -0
- data/lib/name_whisperer.rb +44 -0
- data/lib/plugin.rb +8 -0
- data/lib/pod/command/keys.rb +19 -0
- data/lib/pod/command/keys/list.rb +55 -0
- data/lib/pod/command/keys/set.rb +64 -0
- metadata +109 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 8f23dba489a19e3db03b86ae34dd3ae84f9093a0
|
4
|
+
data.tar.gz: fe7c56f4c93c86636906a8133de150a1d3dafc9a
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 8296b115b402a664ad3afc3402eb9d1490219e75506570afc82a5404f9acce206c4e6a2228120ce9cf274c28858454fe62b7ea0b656e8666f9b34474a8f0f806
|
7
|
+
data.tar.gz: 26b57d67e5b1bbd521b858db1a398182091107a3aecdfc1faae4ca62bc6748de6b9196791609801d29518b7d537f5084c40892d81178776ef3cb87f9903af434
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
cocoapods-keys (0.5.2)
|
5
|
+
osx_keychain
|
6
|
+
|
7
|
+
GEM
|
8
|
+
remote: https://rubygems.org/
|
9
|
+
specs:
|
10
|
+
RubyInline (3.12.3)
|
11
|
+
ZenTest (~> 4.3)
|
12
|
+
ZenTest (4.10.1)
|
13
|
+
osx_keychain (1.0.0)
|
14
|
+
RubyInline (~> 3)
|
15
|
+
rake (10.3.2)
|
16
|
+
|
17
|
+
PLATFORMS
|
18
|
+
ruby
|
19
|
+
|
20
|
+
DEPENDENCIES
|
21
|
+
bundler (~> 1.3)
|
22
|
+
cocoapods-keys!
|
23
|
+
rake
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Orta Therox <orta.therox@gmail.com>
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
A key value store for enviroment and application keys.
|
2
|
+
|
3
|
+
Its good security practice to keep production keys out of developer hands. CocoaPods-keys makes it easy to have per-user config settings stored securely in the developer's keychain, and not in the application source. It is a plugin that once installed will run on every `pod install` or `pod update`.
|
4
|
+
|
5
|
+
## Requirements
|
6
|
+
|
7
|
+
Requires CocoaPods 0.34+.
|
8
|
+
|
9
|
+
## Installation
|
10
|
+
|
11
|
+
$ gem install cocoapods-keys
|
12
|
+
|
13
|
+
## How it works
|
14
|
+
|
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
|
+
|
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.
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
You can save keys on a per-project basis by running the command:
|
22
|
+
|
23
|
+
$ pod keys set KEY VALUE
|
24
|
+
|
25
|
+
You can list all known keys by running:
|
26
|
+
|
27
|
+
$ pod keys
|
28
|
+
|
29
|
+
For example:
|
30
|
+
|
31
|
+
``` sh
|
32
|
+
$ cd MyApplication
|
33
|
+
$ pod keys set "NetworkAPIToken" "AH2ZMiraGQbyUd9GkNTNfWEdxlwXcmHciEOH"
|
34
|
+
Saved NetworkAPIToken to MyApplication.
|
35
|
+
|
36
|
+
$ pod keys set "AnalyticsToken" "6TYKGVCn7sBSBFpwfSUCclzDoSBtEXw7"
|
37
|
+
Saved AnalyticsToken to MyApplication.
|
38
|
+
|
39
|
+
$ pod keys
|
40
|
+
Keys for MyApplication
|
41
|
+
├ NetworkAPIToken - AH2ZMiraGQbyUd9GkNTNfWEdxlwXcmHciEOH
|
42
|
+
└ AnalyticsToken - 6TYKGVCn7sBSBFpwfSUCclzDoSBtEXw7
|
43
|
+
|
44
|
+
GIFs - /Users/orta/dev/mac/GIFs
|
45
|
+
└ redditAPIToken & mixpanelAPIToken
|
46
|
+
```
|
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:
|
49
|
+
|
50
|
+
``` objc
|
51
|
+
|
52
|
+
#import "ORAppDelegate.h"
|
53
|
+
#import <CocoaPods-Keys/MyApplicationKeys.h>
|
54
|
+
#import <ARAnalytics/ARAnalytics.h>
|
55
|
+
|
56
|
+
@implementation ORAppDelegate
|
57
|
+
|
58
|
+
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
|
59
|
+
{
|
60
|
+
MyApplicationKeys *keys = [[MyApplicationKeys alloc] init];
|
61
|
+
[ARAnalytics setupWithAnalytics:@{
|
62
|
+
ARGoogleAnalyticsID : keys.analyticsToken;
|
63
|
+
}];
|
64
|
+
}
|
65
|
+
|
66
|
+
@end
|
67
|
+
|
68
|
+
```
|
69
|
+
|
70
|
+
#### Security
|
71
|
+
|
72
|
+
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).
|
73
|
+
|
74
|
+
> Putting this in the context of, "should you be storing keys in software", is more appropriate. Many companies do this. It's never a good idea.
|
75
|
+
|
76
|
+
> When developers do that, other developers can use debuggers and string searching commands to extract those keys from the running application. There are numerous talks on how to do that, but leave that as an exercise to the reader to find those talks.
|
77
|
+
|
78
|
+
> Many people believe that obfuscating these keys in code will help. It usually won't because you can just run a debugger and find the fully functional keys.
|
79
|
+
|
80
|
+
So in summary, the ideal way to store keys is to not store keys. In reality though most Apps embed keys, and this does that and adds some rudimentary obfuscation to the keys. A well motivated app cracker could probably extract this within a few minutes however.
|
81
|
+
|
82
|
+
#### Thanks
|
83
|
+
|
84
|
+
This was built with a lot of help from [@segiddins](https://github.com/segiddins).
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'bundler/gem_tasks'
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'cocoapods_keys.rb'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "cocoapods-keys"
|
8
|
+
spec.version = CocoaPodsKeys::VERSION
|
9
|
+
spec.authors = ["Orta Therox", 'Samuel E. Giddins']
|
10
|
+
spec.email = ["orta.therox@gmail.com", 'segiddins@segiddins.me']
|
11
|
+
spec.description = %q{A key value store for environment settings in Cocoa Apps.}
|
12
|
+
spec.summary = %q{CocoaPods Keys will store sensitive data in your Mac's keychain. Then on running pod install they will be installed into your app's source code via the Pods library.}
|
13
|
+
spec.homepage = "https://github.com/cocoapods/cocoapods-keys"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_runtime_dependency "osx_keychain"
|
22
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
23
|
+
spec.add_development_dependency "rake"
|
24
|
+
end
|
data/lib/installer.rb
ADDED
@@ -0,0 +1,43 @@
|
|
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', 'CocoaPods-Keys')
|
20
|
+
interface_file = File.join(keys_headers_folder, key_master.name + '.h')
|
21
|
+
implementation_file = File.join(keys_folder, key_master.name + '.m')
|
22
|
+
Dir.mkdir keys_folder unless Dir.exists? keys_folder
|
23
|
+
Dir.mkdir keys_headers_folder unless Dir.exists? keys_headers_folder
|
24
|
+
File.open(interface_file, 'w') { |f| f.write(key_master.interface) }
|
25
|
+
File.open(implementation_file, 'w') { |f| f.write(key_master.implementation) }
|
26
|
+
|
27
|
+
project = Xcodeproj::Project.open File.join(@sandbox_root, 'Pods.xcodeproj')
|
28
|
+
|
29
|
+
group = project.new_group('Keys')
|
30
|
+
group.new_file(interface_file)
|
31
|
+
implementation = group.new_file(implementation_file)
|
32
|
+
|
33
|
+
pods_target = project.targets.detect { |t| t.name == 'Pods' }
|
34
|
+
unless pods_target
|
35
|
+
pods_target = project.targets.detect { |t| t.name == 'Pods-' + keyring.name }
|
36
|
+
end
|
37
|
+
pods_target.add_file_references [implementation]
|
38
|
+
|
39
|
+
project.save
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
data/lib/key_master.rb
ADDED
@@ -0,0 +1,134 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
3
|
+
module CocoaPodsKeys
|
4
|
+
class KeyMaster
|
5
|
+
|
6
|
+
attr_accessor :name, :interface, :implementation
|
7
|
+
|
8
|
+
def initialize(keyring)
|
9
|
+
@keys = Hash[keyring.keychain_data.map { |(key, value)| [key[0].downcase + key[1..-1], value] }]
|
10
|
+
@name = keyring.code_name + 'Keys'
|
11
|
+
@used_indexes = Set.new
|
12
|
+
@indexed_keys = {}
|
13
|
+
@data = generate_data
|
14
|
+
@interface = generate_interface
|
15
|
+
@implementation = generate_implementation
|
16
|
+
end
|
17
|
+
|
18
|
+
def generate_data
|
19
|
+
|
20
|
+
# Generate a base64 hash string that is ~25 times the length of all keys
|
21
|
+
|
22
|
+
@data_length = @keys.values.map(&:length).reduce(:+) * (20 + rand(10))
|
23
|
+
data = `head -c #{@data_length} /dev/random | base64 | head -c #{@data_length}`
|
24
|
+
length = data.length
|
25
|
+
|
26
|
+
# Swap the characters within the hashed string with the characters from
|
27
|
+
# the keyring values. Then store that index in a index-ed copy of the values.
|
28
|
+
|
29
|
+
@keys.each do |key, value|
|
30
|
+
@indexed_keys[key] = []
|
31
|
+
|
32
|
+
value.chars.each_with_index do |char, char_index|
|
33
|
+
loop do
|
34
|
+
|
35
|
+
index = rand data.length
|
36
|
+
unless @used_indexes.include?(index)
|
37
|
+
data[index] = char
|
38
|
+
|
39
|
+
@used_indexes << index
|
40
|
+
@indexed_keys[key][char_index] = index
|
41
|
+
break
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
data
|
49
|
+
end
|
50
|
+
|
51
|
+
def generate_interface
|
52
|
+
erb = <<-SOURCE
|
53
|
+
//
|
54
|
+
// Generated by CocoaPods-Keys
|
55
|
+
// on #{Time.now.strftime("%d/%m/%Y")}
|
56
|
+
// For more information see https://github.com/cocoapods/cocoapods-keys
|
57
|
+
//
|
58
|
+
|
59
|
+
#import <Foundation/NSString.h>
|
60
|
+
|
61
|
+
@interface <%= @name %> : NSObject
|
62
|
+
<% @keys.each do |key, value| %>
|
63
|
+
- (NSString *)<%= key %>;<% end %>
|
64
|
+
|
65
|
+
@end
|
66
|
+
SOURCE
|
67
|
+
|
68
|
+
render_erb(erb)
|
69
|
+
end
|
70
|
+
|
71
|
+
def generate_implementation
|
72
|
+
require 'digest'
|
73
|
+
|
74
|
+
erb = <<-SOURCE
|
75
|
+
//
|
76
|
+
// Generated by CocoaPods-Keys
|
77
|
+
// on #{Time.now.strftime("%d/%m/%Y")}
|
78
|
+
// For more information see https://github.com/cocoapods/cocoapods-keys
|
79
|
+
//
|
80
|
+
|
81
|
+
#import <objc/runtime.h>
|
82
|
+
#import "<%= @name %>.h"
|
83
|
+
|
84
|
+
#pragma clang diagnostic push
|
85
|
+
#pragma clang diagnostic ignored "-Wincomplete-implementation"
|
86
|
+
|
87
|
+
@implementation <%= @name %>
|
88
|
+
|
89
|
+
#pragma clang diagnostic pop
|
90
|
+
|
91
|
+
+ (BOOL)resolveInstanceMethod:(SEL)name
|
92
|
+
{
|
93
|
+
NSString *key = NSStringFromSelector(name);
|
94
|
+
NSString * (*implementation)(<%= name %> *, SEL) = NULL;
|
95
|
+
<% @keys.each do |key, value| %>
|
96
|
+
if ([key isEqualToString:@"<%= key %>"]) {
|
97
|
+
implementation = _podKeys<%= Digest::MD5.hexdigest(key) %>;
|
98
|
+
}
|
99
|
+
<% end %>
|
100
|
+
if (!implementation) {
|
101
|
+
return [super resolveInstanceMethod:name];
|
102
|
+
}
|
103
|
+
|
104
|
+
return class_addMethod([self class], name, (IMP)implementation, "@@:");
|
105
|
+
}
|
106
|
+
<% @keys.each do |key, value| %>
|
107
|
+
static NSString *_podKeys<%= Digest::MD5.hexdigest(key) %>(<%= name %> *self, SEL _cmd)
|
108
|
+
{
|
109
|
+
char cString[<%= @indexed_keys[key].length + 1 %>] = { <%= key_data_arrays[key] %>, '\\0' };
|
110
|
+
return [NSString stringWithCString:cString encoding:NSUTF8StringEncoding];
|
111
|
+
}
|
112
|
+
<% end %>
|
113
|
+
|
114
|
+
static char <%= name %>Data[<%= @data_length %>] = "<%= @data %>";
|
115
|
+
|
116
|
+
@end
|
117
|
+
SOURCE
|
118
|
+
|
119
|
+
render_erb(erb)
|
120
|
+
end
|
121
|
+
|
122
|
+
:private
|
123
|
+
|
124
|
+
def render_erb(erb)
|
125
|
+
require 'erb'
|
126
|
+
ERB.new(erb).result(binding)
|
127
|
+
end
|
128
|
+
|
129
|
+
def key_data_arrays
|
130
|
+
Hash[@indexed_keys.map {|key, value| [key, value.map { |i| name + "Data[#{i}]" }.join(', ')]}]
|
131
|
+
end
|
132
|
+
|
133
|
+
end
|
134
|
+
end
|
data/lib/keyring.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
require "osx_keychain"
|
2
|
+
|
3
|
+
module CocoaPodsKeys
|
4
|
+
class Keyring
|
5
|
+
attr_accessor :keys, :path, :name
|
6
|
+
|
7
|
+
def initialize(name, path, keys=[])
|
8
|
+
@name = name
|
9
|
+
@path = path
|
10
|
+
@keys = keys
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.from_hash(hash)
|
14
|
+
new(hash["name"], hash["path"], hash["keys"])
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_hash
|
18
|
+
{ "keys" => @keys, "path" => @path, "name" => @name }
|
19
|
+
end
|
20
|
+
|
21
|
+
def code_name
|
22
|
+
name.split(/[^a-zA-Z0-9_-]/).map { |s| s[0].upcase + s[1..-1] }.join('')
|
23
|
+
end
|
24
|
+
|
25
|
+
def save(key, value)
|
26
|
+
keychain = OSXKeychain.new
|
27
|
+
keychain[keychain_prefix + name, key] = value
|
28
|
+
end
|
29
|
+
|
30
|
+
def keychain_data
|
31
|
+
keychain = OSXKeychain.new
|
32
|
+
Hash[
|
33
|
+
@keys.map { |key| [key, keychain[keychain_prefix + name, key]] }
|
34
|
+
]
|
35
|
+
end
|
36
|
+
|
37
|
+
def keychain_prefix
|
38
|
+
"cocoapods-keys-"
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require "digest"
|
2
|
+
require "yaml"
|
3
|
+
require "pathname"
|
4
|
+
|
5
|
+
module CocoaPodsKeys
|
6
|
+
class KeyringLiberator
|
7
|
+
|
8
|
+
# Gets given a gives back a Keyring for the project
|
9
|
+
# by basically parsing it out of ~/.cocoapods/keys/"pathMD5".yml
|
10
|
+
|
11
|
+
def self.keys_dir
|
12
|
+
Pathname.new("~/.cocoapods/keys/").expand_path.to_s
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.yaml_path_for_path(path)
|
16
|
+
sha = Digest::MD5.hexdigest(path)
|
17
|
+
File.join(keys_dir, sha + '.yml')
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.get_keyring(path)
|
21
|
+
get_keyring_at_path(yaml_path_for_path(path))
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.save_keyring(keyring)
|
25
|
+
`mkdir -p #{keys_dir}`
|
26
|
+
|
27
|
+
File.open(yaml_path_for_path(keyring.path), 'w') {|f| f.write(YAML::dump(keyring.to_hash)) }
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.get_all_keyrings()
|
31
|
+
return [] unless Dir.exist? keys_dir
|
32
|
+
rings = []
|
33
|
+
Dir.glob(keys_dir + "/*.yml").each do |path|
|
34
|
+
rings << get_keyring_at_path(path)
|
35
|
+
end
|
36
|
+
rings
|
37
|
+
end
|
38
|
+
|
39
|
+
:private
|
40
|
+
|
41
|
+
def self.get_keyring_at_path(path)
|
42
|
+
Keyring.from_hash(YAML.load(File.read(path))) if File.exist?(path)
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'cocoapods'
|
2
|
+
|
3
|
+
module CocoaPodsKeys
|
4
|
+
class NameWhisperer
|
5
|
+
|
6
|
+
def self.get_project_name()
|
7
|
+
podfile = Pod::Podfile.from_file("Podfile") rescue nil
|
8
|
+
if podfile
|
9
|
+
user_xcodeproj = xcodeproj_from_podfile(podfile)
|
10
|
+
end
|
11
|
+
user_xcodeproj ||= self.search_folders_for_xcodeproj
|
12
|
+
user_xcodeproj.gsub(".xcodeproj", "")
|
13
|
+
end
|
14
|
+
|
15
|
+
:private
|
16
|
+
|
17
|
+
def self.xcodeproj_from_podfile(podfile)
|
18
|
+
if podfile.target_definition_list.length > 0
|
19
|
+
return podfile.target_definition_list[0].user_project_path
|
20
|
+
end
|
21
|
+
nil
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.search_folders_for_xcodeproj
|
25
|
+
xcodeprojects = Dir.glob("**/**/*.xcodeproj")
|
26
|
+
if xcodeprojects.length == 1
|
27
|
+
Pathname.new(xcodeprojects[0]).basename.to_s
|
28
|
+
else
|
29
|
+
error_message = (xcodeprojects.length > 1) ? "found too many" : "couldn't find any"
|
30
|
+
puts "Hello there, we " + error_message + " xcodeprojects. Please give a name for this project."
|
31
|
+
|
32
|
+
answer = ""
|
33
|
+
loop do
|
34
|
+
print " > "
|
35
|
+
answer = STDIN.gets.chomp
|
36
|
+
break if answer.length > 0
|
37
|
+
end
|
38
|
+
answer
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
data/lib/plugin.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
module Pod
|
2
|
+
class Command
|
3
|
+
|
4
|
+
class Keys < Command
|
5
|
+
require 'pod/command/keys/list'
|
6
|
+
require 'pod/command/keys/set'
|
7
|
+
|
8
|
+
self.summary = "A key value store for environment settings in Cocoa Apps."
|
9
|
+
|
10
|
+
self.description = <<-DESC
|
11
|
+
CocoaPods Keys will store sensitive data in your Mac's keychain. Then on running pod install they will be installed into your app's source code via the Pods library.
|
12
|
+
DESC
|
13
|
+
|
14
|
+
self.abstract_command = true
|
15
|
+
self.default_subcommand = 'list'
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'keyring_liberator'
|
2
|
+
|
3
|
+
module Pod
|
4
|
+
class Command
|
5
|
+
class Keys
|
6
|
+
|
7
|
+
class List < Keys
|
8
|
+
self.summary = "Lists all known keys and values."
|
9
|
+
|
10
|
+
self.description = <<-DESC
|
11
|
+
Shows all the current keys and values for your current working directory.
|
12
|
+
|
13
|
+
Also lists all known projects with variable stores.
|
14
|
+
DESC
|
15
|
+
|
16
|
+
def run
|
17
|
+
# List all settings for current app
|
18
|
+
this_keyring = CocoaPodsKeys::KeyringLiberator.get_keyring(Dir.getwd)
|
19
|
+
if this_keyring
|
20
|
+
display_current_keyring this_keyring
|
21
|
+
end
|
22
|
+
|
23
|
+
# List all known bundle ids
|
24
|
+
|
25
|
+
all_keyrings = CocoaPodsKeys::KeyringLiberator.get_all_keyrings()
|
26
|
+
all_keyrings.each do |keyring|
|
27
|
+
display_keyring(keyring) if keyring.path != this_keyring.path
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def display_current_keyring(keyring)
|
32
|
+
puts "Keys for #{keyring.name}"
|
33
|
+
data = keyring.keychain_data
|
34
|
+
data.each_with_index do |(key, value), index|
|
35
|
+
prefix = (index == data.length - 1) ? " └ ": " ├ "
|
36
|
+
puts prefix + " #{key} - #{ value}"
|
37
|
+
end
|
38
|
+
puts ""
|
39
|
+
end
|
40
|
+
|
41
|
+
def display_keyring(keyring)
|
42
|
+
puts "#{keyring.name} - #{keyring.path}"
|
43
|
+
if keyring.keys.length == 1
|
44
|
+
puts " └ " + keyring.keys[0]
|
45
|
+
else
|
46
|
+
puts " └ " + keyring.keys[0...-1].join(" ") + " & " + keyring.keys[-1]
|
47
|
+
end
|
48
|
+
puts ""
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require "keyring_liberator"
|
2
|
+
require "name_whisperer"
|
3
|
+
|
4
|
+
module Pod
|
5
|
+
class Command
|
6
|
+
class Keys
|
7
|
+
|
8
|
+
class Set < Keys
|
9
|
+
self.summary = "A set values for keys."
|
10
|
+
|
11
|
+
self.description = <<-DESC
|
12
|
+
Save a environment key to be added to your project on the next pod install.
|
13
|
+
|
14
|
+
If a third argument is given then that will be used as the project name if
|
15
|
+
you need to skip the project naming process.
|
16
|
+
DESC
|
17
|
+
|
18
|
+
self.arguments = [CLAide::Argument.new('key', true),
|
19
|
+
CLAide::Argument.new('value', true),
|
20
|
+
CLAide::Argument.new('project_name', false)]
|
21
|
+
|
22
|
+
def initialize(argv)
|
23
|
+
@key_name = argv.shift_argument
|
24
|
+
@key_value = argv.shift_argument
|
25
|
+
@project_name = argv.shift_argument
|
26
|
+
super
|
27
|
+
end
|
28
|
+
|
29
|
+
def validate!
|
30
|
+
super
|
31
|
+
verify_podfile_exists!
|
32
|
+
help! "A key name is required to save." unless @key_name
|
33
|
+
help! "A value is required for the key." unless @key_value
|
34
|
+
end
|
35
|
+
|
36
|
+
def run
|
37
|
+
# set a key to a folder id in ~/.cocoapods/keys
|
38
|
+
# info "Saving into the keychain."
|
39
|
+
|
40
|
+
keyring = current_keyring
|
41
|
+
keyring.keys << @key_name
|
42
|
+
CocoaPodsKeys::KeyringLiberator.save_keyring keyring
|
43
|
+
|
44
|
+
keyring.save @key_name, @key_value
|
45
|
+
|
46
|
+
puts "Saved #{@key_name} to #{keyring.name}."
|
47
|
+
end
|
48
|
+
|
49
|
+
def current_keyring
|
50
|
+
current_dir = Dir.getwd
|
51
|
+
keyring = CocoaPodsKeys::KeyringLiberator.get_keyring current_dir
|
52
|
+
|
53
|
+
unless keyring
|
54
|
+
name = @name || CocoaPodsKeys::NameWhisperer.get_project_name
|
55
|
+
keyring = CocoaPodsKeys::Keyring.new(name, current_dir, [])
|
56
|
+
end
|
57
|
+
|
58
|
+
keyring
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
metadata
ADDED
@@ -0,0 +1,109 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: cocoapods-keys
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.5.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Orta Therox
|
8
|
+
- Samuel E. Giddins
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2014-09-15 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: osx_keychain
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - '>='
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: '0'
|
21
|
+
type: :runtime
|
22
|
+
prerelease: false
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - '>='
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: '0'
|
28
|
+
- !ruby/object:Gem::Dependency
|
29
|
+
name: bundler
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - ~>
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: '1.3'
|
35
|
+
type: :development
|
36
|
+
prerelease: false
|
37
|
+
version_requirements: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - ~>
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: '1.3'
|
42
|
+
- !ruby/object:Gem::Dependency
|
43
|
+
name: rake
|
44
|
+
requirement: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - '>='
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: '0'
|
49
|
+
type: :development
|
50
|
+
prerelease: false
|
51
|
+
version_requirements: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - '>='
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '0'
|
56
|
+
description: A key value store for environment settings in Cocoa Apps.
|
57
|
+
email:
|
58
|
+
- orta.therox@gmail.com
|
59
|
+
- segiddins@segiddins.me
|
60
|
+
executables: []
|
61
|
+
extensions: []
|
62
|
+
extra_rdoc_files: []
|
63
|
+
files:
|
64
|
+
- .gitignore
|
65
|
+
- Gemfile
|
66
|
+
- Gemfile.lock
|
67
|
+
- LICENSE.txt
|
68
|
+
- README.md
|
69
|
+
- Rakefile
|
70
|
+
- cocoapods_keys.gemspec
|
71
|
+
- lib/cocoapods_keys.rb
|
72
|
+
- lib/cocoapods_plugin.rb
|
73
|
+
- lib/installer.rb
|
74
|
+
- lib/key_master.rb
|
75
|
+
- lib/keyring.rb
|
76
|
+
- lib/keyring_liberator.rb
|
77
|
+
- lib/name_whisperer.rb
|
78
|
+
- lib/plugin.rb
|
79
|
+
- lib/pod/command/keys.rb
|
80
|
+
- lib/pod/command/keys/list.rb
|
81
|
+
- lib/pod/command/keys/set.rb
|
82
|
+
homepage: https://github.com/cocoapods/cocoapods-keys
|
83
|
+
licenses:
|
84
|
+
- MIT
|
85
|
+
metadata: {}
|
86
|
+
post_install_message:
|
87
|
+
rdoc_options: []
|
88
|
+
require_paths:
|
89
|
+
- lib
|
90
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
91
|
+
requirements:
|
92
|
+
- - '>='
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: '0'
|
95
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
96
|
+
requirements:
|
97
|
+
- - '>='
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
version: '0'
|
100
|
+
requirements: []
|
101
|
+
rubyforge_project:
|
102
|
+
rubygems_version: 2.0.6
|
103
|
+
signing_key:
|
104
|
+
specification_version: 4
|
105
|
+
summary: CocoaPods Keys will store sensitive data in your Mac's keychain. Then on
|
106
|
+
running pod install they will be installed into your app's source code via the Pods
|
107
|
+
library.
|
108
|
+
test_files: []
|
109
|
+
has_rdoc:
|