boxen 0.8.1 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/boxen.gemspec +1 -1
- data/lib/boxen/config.rb +9 -22
- data/lib/boxen/keychain.rb +64 -0
- data/script/Boxen +0 -0
- data/script/build-keychain-helper +6 -0
- data/src/keychain-helper.c +67 -0
- data/test/boxen_keychain_test.rb +28 -0
- metadata +9 -3
data/.gitignore
CHANGED
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.
|
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 "
|
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
|
-
|
34
|
-
|
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
|
-
|
71
|
-
|
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,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
|
-
|
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
|