boxen 0.8.1 → 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.
data/.gitignore CHANGED
@@ -8,3 +8,4 @@
8
8
  /boxen-*.gem
9
9
  /log
10
10
  /puppet
11
+ /script/Boxen.dSYM
data/boxen.gemspec CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |gem|
4
4
  gem.name = "boxen"
5
- gem.version = "0.8.1"
5
+ gem.version = "1.0.0"
6
6
  gem.authors = ["John Barnette", "Will Farrington"]
7
7
  gem.email = ["jbarnette@github.com", "wfarr@github.com"]
8
8
  gem.description = "Manage Mac development boxes with love (and Puppet)."
data/lib/boxen/config.rb CHANGED
@@ -1,7 +1,9 @@
1
+ require "boxen/keychain"
2
+ require "boxen/project"
1
3
  require "fileutils"
2
4
  require "json"
3
5
  require "octokit"
4
- require "boxen/project"
6
+ require "shellwords"
5
7
 
6
8
  module Boxen
7
9
 
@@ -9,13 +11,6 @@ module Boxen
9
11
  # args, environment variables, config files, or the keychain.
10
12
 
11
13
  class Config
12
-
13
- # The service name to use when loading/saving config in the Keychain.
14
-
15
- KEYCHAIN_SERVICE = "Boxen"
16
-
17
- # Load config. Yields config if `block` is given.
18
-
19
14
  def self.load(&block)
20
15
  new do |config|
21
16
  file = "#{config.homedir}/config/boxen/defaults.json"
@@ -30,13 +25,9 @@ module Boxen
30
25
  end
31
26
  end
32
27
 
33
- cmd = "/usr/bin/security find-generic-password " +
34
- "-a #{config.user} -s '#{KEYCHAIN_SERVICE}' -w 2>/dev/null"
35
-
36
- password = `#{cmd}`.strip
37
- password = nil unless $?.success?
38
-
39
- config.password = password
28
+ keychain = Boxen::Keychain.new config.user
29
+ config.password = keychain.password
30
+ config.token = keychain.token
40
31
 
41
32
  yield config if block_given?
42
33
  end
@@ -56,7 +47,6 @@ module Boxen
56
47
  :repodir => config.repodir,
57
48
  :reponame => config.reponame,
58
49
  :srcdir => config.srcdir,
59
- :token => config.token,
60
50
  :user => config.user
61
51
  }
62
52
 
@@ -67,12 +57,9 @@ module Boxen
67
57
  f.write JSON.generate Hash[attrs.reject { |k, v| v.nil? }]
68
58
  end
69
59
 
70
- cmd = ["security", "add-generic-password",
71
- "-a", config.user, "-s", KEYCHAIN_SERVICE, "-U", "-w", config.password]
72
-
73
- unless system *cmd
74
- raise Boxen::Error, "Can't save config in the Keychain."
75
- end
60
+ keychain = Boxen::Keychain.new config.user
61
+ keychain.password = config.password
62
+ keychain.token = config.token
76
63
 
77
64
  config
78
65
  end
@@ -0,0 +1,64 @@
1
+ require "shellwords"
2
+
3
+ module Boxen
4
+ class Keychain
5
+
6
+ # The keychain proxy we use to provide isolation and a friendly
7
+ # message in security prompts.
8
+
9
+ HELPER = File.expand_path "../../../script/Boxen", __FILE__
10
+
11
+ # The service name to use when loading/saving passwords.
12
+
13
+ PASSWORD_SERVICE = "GitHub Password"
14
+
15
+ # The service name to use when loading/saving API keys.
16
+
17
+ TOKEN_SERVICE = "GitHub API Token"
18
+
19
+ def initialize(login)
20
+ @login = login
21
+ end
22
+
23
+ def password
24
+ get PASSWORD_SERVICE
25
+ end
26
+
27
+ def password=(password)
28
+ set PASSWORD_SERVICE, password
29
+ end
30
+
31
+ def token
32
+ get TOKEN_SERVICE
33
+ end
34
+
35
+ def token=(token)
36
+ set TOKEN_SERVICE, token
37
+ end
38
+
39
+ protected
40
+
41
+ attr_reader :login
42
+
43
+ def get(service)
44
+ cmd = shellescape(HELPER, service, login)
45
+
46
+ result = `#{cmd}`.strip
47
+ $?.success? ? result : nil
48
+ end
49
+
50
+ def set(service, password)
51
+ cmd = shellescape(HELPER, service, login, password)
52
+
53
+ unless system *cmd
54
+ raise Boxen::Error, "Can't save #{service} in the keychain."
55
+ end
56
+
57
+ password
58
+ end
59
+
60
+ def shellescape(*args)
61
+ args.map { |s| Shellwords.shellescape s }.join " "
62
+ end
63
+ end
64
+ end
data/script/Boxen ADDED
Binary file
@@ -0,0 +1,6 @@
1
+ #!/bin/sh
2
+
3
+ set -e
4
+
5
+ cd $(dirname "$0")/..
6
+ cc -g -O2 -Wall -framework Security -o script/Boxen src/keychain-helper.c
@@ -0,0 +1,67 @@
1
+ #include <stdio.h>
2
+ #include <stdlib.h>
3
+ #include <Security/Security.h>
4
+
5
+ int key_exists_p(
6
+ const char *service,
7
+ const char *login,
8
+ SecKeychainItemRef *item
9
+ ) {
10
+ void *buf;
11
+ UInt32 len;
12
+
13
+ OSStatus ret = SecKeychainFindGenericPassword(
14
+ NULL, strlen(service), service, strlen(login), login, &len, &buf, item
15
+ );
16
+
17
+ if (ret == 0) {
18
+ return 0;
19
+ } else {
20
+ fprintf(stderr, "Boxen Keychain Helper: Encountered error code: %d\n", ret);
21
+ return ret;
22
+ }
23
+ }
24
+
25
+ int main(int argc, char **argv) {
26
+ if ((argc < 3) || (argc > 4)) {
27
+ printf("Usage: %s <service> <account> [<password>]\n", argv[0]);
28
+ return 1;
29
+ }
30
+
31
+ const char *service = argv[1];
32
+ const char *login = argv[2];
33
+ const char *password = argc == 4 ? argv[3] : NULL;
34
+
35
+ void *buf;
36
+ UInt32 len;
37
+ SecKeychainItemRef item;
38
+
39
+ if (password != NULL) {
40
+ if (key_exists_p(service, login, &item) == 0) {
41
+ SecKeychainItemDelete(item);
42
+ }
43
+
44
+ OSStatus create_key = SecKeychainAddGenericPassword(
45
+ NULL, strlen(service), service, strlen(login), login, strlen(password),
46
+ password, &item
47
+ );
48
+
49
+ if (create_key != 0) {
50
+ fprintf(stderr, "Boxen Keychain Helper: Encountered error code: %d\n", create_key);
51
+ return 1;
52
+ }
53
+
54
+ } else {
55
+ OSStatus find_key = SecKeychainFindGenericPassword(
56
+ NULL, strlen(service), service, strlen(login), login, &len, &buf, &item);
57
+
58
+ if (find_key != 0) {
59
+ fprintf(stderr, "Boxen Keychain Helper: Encountered error code: %d\n", find_key);
60
+ return 1;
61
+ }
62
+
63
+ fwrite(buf, 1, len, stdout);
64
+ }
65
+
66
+ return 0;
67
+ }
@@ -0,0 +1,28 @@
1
+ require "boxen/test"
2
+ require "boxen/keychain"
3
+
4
+ class BoxenKeychainTest < Boxen::Test
5
+ def setup
6
+ @keychain = Boxen::Keychain.new('test')
7
+ end
8
+
9
+ def test_get_password
10
+ @keychain.expects(:get).with('GitHub Password').returns('foobar')
11
+ assert_equal 'foobar', @keychain.password
12
+ end
13
+
14
+ def test_set_password
15
+ @keychain.expects(:set).with('GitHub Password', 'foobar').returns('foobar')
16
+ assert_equal 'foobar', @keychain.password=('foobar')
17
+ end
18
+
19
+ def test_get_token
20
+ @keychain.expects(:get).with('GitHub API Token').returns('foobar')
21
+ assert_equal 'foobar', @keychain.token
22
+ end
23
+
24
+ def test_set_token
25
+ @keychain.expects(:set).with('GitHub API Token', 'foobar').returns('foobar')
26
+ assert_equal 'foobar', @keychain.token=('foobar')
27
+ end
28
+ end
metadata CHANGED
@@ -3,10 +3,10 @@ name: boxen
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
- - 0
7
- - 8
8
6
  - 1
9
- version: 0.8.1
7
+ - 0
8
+ - 0
9
+ version: 1.0.0
10
10
  platform: ruby
11
11
  authors:
12
12
  - John Barnette
@@ -170,6 +170,7 @@ files:
170
170
  - lib/boxen/hook.rb
171
171
  - lib/boxen/hook/github_issue.rb
172
172
  - lib/boxen/hook/web.rb
173
+ - lib/boxen/keychain.rb
173
174
  - lib/boxen/postflight.rb
174
175
  - lib/boxen/postflight/active.rb
175
176
  - lib/boxen/postflight/env.rb
@@ -189,9 +190,12 @@ files:
189
190
  - lib/boxen/util.rb
190
191
  - lib/facter/boxen.rb
191
192
  - lib/system_timer.rb
193
+ - script/Boxen
192
194
  - script/bootstrap
195
+ - script/build-keychain-helper
193
196
  - script/release
194
197
  - script/tests
198
+ - src/keychain-helper.c
195
199
  - test/boxen/test.rb
196
200
  - test/boxen_check_test.rb
197
201
  - test/boxen_checkout_test.rb
@@ -201,6 +205,7 @@ files:
201
205
  - test/boxen_flags_test.rb
202
206
  - test/boxen_hook_github_issue_test.rb
203
207
  - test/boxen_hook_web_test.rb
208
+ - test/boxen_keychain_test.rb
204
209
  - test/boxen_postflight_active_test.rb
205
210
  - test/boxen_postflight_env_test.rb
206
211
  - test/boxen_preflight_etc_my_cnf_test.rb
@@ -254,6 +259,7 @@ test_files:
254
259
  - test/boxen_flags_test.rb
255
260
  - test/boxen_hook_github_issue_test.rb
256
261
  - test/boxen_hook_web_test.rb
262
+ - test/boxen_keychain_test.rb
257
263
  - test/boxen_postflight_active_test.rb
258
264
  - test/boxen_postflight_env_test.rb
259
265
  - test/boxen_preflight_etc_my_cnf_test.rb