yakg 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (118) hide show
  1. data/Gemfile +3 -1
  2. data/Gemfile.lock +19 -21
  3. data/VERSION +1 -1
  4. data/lib/yakg/backend/macos-keychain.rb +226 -0
  5. data/lib/yakg/backend/netrc-fallback.rb +41 -0
  6. data/lib/yakg/backend.rb +6 -215
  7. data/lib/yakg.rb +8 -0
  8. data/vendor/gems/Gemfile +4 -0
  9. data/vendor/gems/Gemfile.lock +13 -0
  10. data/vendor/gems/installit.sh +33 -0
  11. data/vendor/gems/ruby/1.8/gems/corefoundation-0.2.0/CHANGELOG +12 -0
  12. data/vendor/gems/ruby/1.8/gems/corefoundation-0.2.0/LICENSE +8 -0
  13. data/vendor/gems/ruby/1.8/gems/corefoundation-0.2.0/README.md +40 -0
  14. data/vendor/gems/ruby/1.8/gems/corefoundation-0.2.0/lib/corefoundation/array.rb +123 -0
  15. data/vendor/gems/ruby/1.8/gems/corefoundation-0.2.0/lib/corefoundation/base.rb +197 -0
  16. data/vendor/gems/ruby/1.8/gems/corefoundation-0.2.0/lib/corefoundation/boolean.rb +25 -0
  17. data/vendor/gems/ruby/1.8/gems/corefoundation-0.2.0/lib/corefoundation/data.rb +42 -0
  18. data/vendor/gems/ruby/1.8/gems/corefoundation-0.2.0/lib/corefoundation/date.rb +32 -0
  19. data/vendor/gems/ruby/1.8/gems/corefoundation-0.2.0/lib/corefoundation/dictionary.rb +114 -0
  20. data/vendor/gems/ruby/1.8/gems/corefoundation-0.2.0/lib/corefoundation/extensions.rb +158 -0
  21. data/vendor/gems/ruby/1.8/gems/corefoundation-0.2.0/lib/corefoundation/null.rb +11 -0
  22. data/vendor/gems/ruby/1.8/gems/corefoundation-0.2.0/lib/corefoundation/number.rb +98 -0
  23. data/vendor/gems/ruby/1.8/gems/corefoundation-0.2.0/lib/corefoundation/string.rb +91 -0
  24. data/vendor/gems/ruby/1.8/gems/corefoundation-0.2.0/lib/corefoundation/version.rb +4 -0
  25. data/vendor/gems/ruby/1.8/gems/corefoundation-0.2.0/lib/corefoundation.rb +13 -0
  26. data/vendor/gems/ruby/1.8/gems/corefoundation-0.2.0/spec/array_spec.rb +92 -0
  27. data/vendor/gems/ruby/1.8/gems/corefoundation-0.2.0/spec/boolean_spec.rb +24 -0
  28. data/vendor/gems/ruby/1.8/gems/corefoundation-0.2.0/spec/data_spec.rb +30 -0
  29. data/vendor/gems/ruby/1.8/gems/corefoundation-0.2.0/spec/date_spec.rb +25 -0
  30. data/vendor/gems/ruby/1.8/gems/corefoundation-0.2.0/spec/dictionary_spec.rb +81 -0
  31. data/vendor/gems/ruby/1.8/gems/corefoundation-0.2.0/spec/extensions_spec.rb +127 -0
  32. data/vendor/gems/ruby/1.8/gems/corefoundation-0.2.0/spec/null_spec.rb +7 -0
  33. data/vendor/gems/ruby/1.8/gems/corefoundation-0.2.0/spec/number_spec.rb +52 -0
  34. data/vendor/gems/ruby/1.8/gems/corefoundation-0.2.0/spec/spec_helper.rb +10 -0
  35. data/vendor/gems/ruby/1.8/gems/corefoundation-0.2.0/spec/string_spec.rb +48 -0
  36. data/vendor/gems/ruby/1.8/gems/ffi-1.8.1/.require_paths +3 -0
  37. data/vendor/gems/ruby/1.8/gems/ffi-1.8.1/COPYING +674 -0
  38. data/vendor/gems/ruby/1.8/gems/ffi-1.8.1/COPYING.LESSER +165 -0
  39. data/vendor/gems/ruby/1.8/gems/ffi-1.8.1/History.txt +1 -0
  40. data/vendor/gems/ruby/1.8/gems/ffi-1.8.1/LICENSE +14 -0
  41. data/vendor/gems/ruby/1.8/gems/ffi-1.8.1/README.md +109 -0
  42. data/vendor/gems/ruby/1.8/gems/ffi-1.8.1/Rakefile +219 -0
  43. data/vendor/gems/ruby/1.8/gems/ffi-1.8.1/ffi.gemspec +22 -0
  44. data/vendor/gems/ruby/1.8/gems/ffi-1.8.1/gen/Rakefile +30 -0
  45. data/vendor/gems/ruby/1.8/gems/ffi-1.8.1/gen/log +1 -0
  46. data/vendor/gems/ruby/1.8/gems/ffi-1.8.1/lib/ffi/autopointer.rb +184 -0
  47. data/vendor/gems/ruby/1.8/gems/ffi-1.8.1/lib/ffi/buffer.rb +4 -0
  48. data/vendor/gems/ruby/1.8/gems/ffi-1.8.1/lib/ffi/callback.rb +4 -0
  49. data/vendor/gems/ruby/1.8/gems/ffi-1.8.1/lib/ffi/enum.rb +162 -0
  50. data/vendor/gems/ruby/1.8/gems/ffi-1.8.1/lib/ffi/errno.rb +33 -0
  51. data/vendor/gems/ruby/1.8/gems/ffi-1.8.1/lib/ffi/ffi.iml +11 -0
  52. data/vendor/gems/ruby/1.8/gems/ffi-1.8.1/lib/ffi/ffi.rb +33 -0
  53. data/vendor/gems/ruby/1.8/gems/ffi-1.8.1/lib/ffi/io.rb +52 -0
  54. data/vendor/gems/ruby/1.8/gems/ffi-1.8.1/lib/ffi/library.rb +489 -0
  55. data/vendor/gems/ruby/1.8/gems/ffi-1.8.1/lib/ffi/managedstruct.rb +55 -0
  56. data/vendor/gems/ruby/1.8/gems/ffi-1.8.1/lib/ffi/memorypointer.rb +1 -0
  57. data/vendor/gems/ruby/1.8/gems/ffi-1.8.1/lib/ffi/platform/arm-linux/types.conf +104 -0
  58. data/vendor/gems/ruby/1.8/gems/ffi-1.8.1/lib/ffi/platform/i386-cygwin/types.conf +3 -0
  59. data/vendor/gems/ruby/1.8/gems/ffi-1.8.1/lib/ffi/platform/i386-darwin/types.conf +100 -0
  60. data/vendor/gems/ruby/1.8/gems/ffi-1.8.1/lib/ffi/platform/i386-freebsd/types.conf +152 -0
  61. data/vendor/gems/ruby/1.8/gems/ffi-1.8.1/lib/ffi/platform/i386-linux/types.conf +103 -0
  62. data/vendor/gems/ruby/1.8/gems/ffi-1.8.1/lib/ffi/platform/i386-netbsd/types.conf +126 -0
  63. data/vendor/gems/ruby/1.8/gems/ffi-1.8.1/lib/ffi/platform/i386-openbsd/types.conf +126 -0
  64. data/vendor/gems/ruby/1.8/gems/ffi-1.8.1/lib/ffi/platform/i386-solaris/types.conf +122 -0
  65. data/vendor/gems/ruby/1.8/gems/ffi-1.8.1/lib/ffi/platform/i386-windows/types.conf +105 -0
  66. data/vendor/gems/ruby/1.8/gems/ffi-1.8.1/lib/ffi/platform/i486-gnu/types.conf +107 -0
  67. data/vendor/gems/ruby/1.8/gems/ffi-1.8.1/lib/ffi/platform/ia64-linux/types.conf +104 -0
  68. data/vendor/gems/ruby/1.8/gems/ffi-1.8.1/lib/ffi/platform/mips-linux/types.conf +102 -0
  69. data/vendor/gems/ruby/1.8/gems/ffi-1.8.1/lib/ffi/platform/mipsel-linux/types.conf +102 -0
  70. data/vendor/gems/ruby/1.8/gems/ffi-1.8.1/lib/ffi/platform/powerpc-aix/types.conf +180 -0
  71. data/vendor/gems/ruby/1.8/gems/ffi-1.8.1/lib/ffi/platform/powerpc-darwin/types.conf +100 -0
  72. data/vendor/gems/ruby/1.8/gems/ffi-1.8.1/lib/ffi/platform/powerpc-linux/types.conf +100 -0
  73. data/vendor/gems/ruby/1.8/gems/ffi-1.8.1/lib/ffi/platform/s390-linux/types.conf +102 -0
  74. data/vendor/gems/ruby/1.8/gems/ffi-1.8.1/lib/ffi/platform/s390x-linux/types.conf +102 -0
  75. data/vendor/gems/ruby/1.8/gems/ffi-1.8.1/lib/ffi/platform/sparc-linux/types.conf +102 -0
  76. data/vendor/gems/ruby/1.8/gems/ffi-1.8.1/lib/ffi/platform/sparc-solaris/types.conf +128 -0
  77. data/vendor/gems/ruby/1.8/gems/ffi-1.8.1/lib/ffi/platform/sparcv9-solaris/types.conf +128 -0
  78. data/vendor/gems/ruby/1.8/gems/ffi-1.8.1/lib/ffi/platform/x86_64-darwin/types.conf +100 -0
  79. data/vendor/gems/ruby/1.8/gems/ffi-1.8.1/lib/ffi/platform/x86_64-freebsd/types.conf +128 -0
  80. data/vendor/gems/ruby/1.8/gems/ffi-1.8.1/lib/ffi/platform/x86_64-linux/types.conf +102 -0
  81. data/vendor/gems/ruby/1.8/gems/ffi-1.8.1/lib/ffi/platform/x86_64-netbsd/types.conf +126 -0
  82. data/vendor/gems/ruby/1.8/gems/ffi-1.8.1/lib/ffi/platform/x86_64-openbsd/types.conf +126 -0
  83. data/vendor/gems/ruby/1.8/gems/ffi-1.8.1/lib/ffi/platform/x86_64-solaris/types.conf +122 -0
  84. data/vendor/gems/ruby/1.8/gems/ffi-1.8.1/lib/ffi/platform/x86_64-windows/types.conf +27 -0
  85. data/vendor/gems/ruby/1.8/gems/ffi-1.8.1/lib/ffi/platform.rb +139 -0
  86. data/vendor/gems/ruby/1.8/gems/ffi-1.8.1/lib/ffi/pointer.rb +122 -0
  87. data/vendor/gems/ruby/1.8/gems/ffi-1.8.1/lib/ffi/struct.rb +356 -0
  88. data/vendor/gems/ruby/1.8/gems/ffi-1.8.1/lib/ffi/struct_layout_builder.rb +211 -0
  89. data/vendor/gems/ruby/1.8/gems/ffi-1.8.1/lib/ffi/tools/const_generator.rb +229 -0
  90. data/vendor/gems/ruby/1.8/gems/ffi-1.8.1/lib/ffi/tools/generator.rb +60 -0
  91. data/vendor/gems/ruby/1.8/gems/ffi-1.8.1/lib/ffi/tools/generator_task.rb +36 -0
  92. data/vendor/gems/ruby/1.8/gems/ffi-1.8.1/lib/ffi/tools/struct_generator.rb +194 -0
  93. data/vendor/gems/ruby/1.8/gems/ffi-1.8.1/lib/ffi/tools/types_generator.rb +135 -0
  94. data/vendor/gems/ruby/1.8/gems/ffi-1.8.1/lib/ffi/types.rb +177 -0
  95. data/vendor/gems/ruby/1.8/gems/ffi-1.8.1/lib/ffi/union.rb +32 -0
  96. data/vendor/gems/ruby/1.8/gems/ffi-1.8.1/lib/ffi/variadic.rb +65 -0
  97. data/vendor/gems/ruby/1.8/gems/ffi-1.8.1/lib/ffi/version.rb +4 -0
  98. data/vendor/gems/ruby/1.8/gems/ffi-1.8.1/lib/ffi.rb +28 -0
  99. data/vendor/gems/ruby/1.8/gems/ffi-1.8.1/lib/ffi_c.bundle +0 -0
  100. data/vendor/gems/ruby/1.8/gems/ffi-1.8.1/libtest/Benchmark.c +52 -0
  101. data/vendor/gems/ruby/1.8/gems/ffi-1.8.1/libtest/BoolTest.c +31 -0
  102. data/vendor/gems/ruby/1.8/gems/ffi-1.8.1/libtest/BufferTest.c +31 -0
  103. data/vendor/gems/ruby/1.8/gems/ffi-1.8.1/libtest/ClosureTest.c +190 -0
  104. data/vendor/gems/ruby/1.8/gems/ffi-1.8.1/libtest/EnumTest.c +34 -0
  105. data/vendor/gems/ruby/1.8/gems/ffi-1.8.1/libtest/FunctionTest.c +58 -0
  106. data/vendor/gems/ruby/1.8/gems/ffi-1.8.1/libtest/GNUmakefile +149 -0
  107. data/vendor/gems/ruby/1.8/gems/ffi-1.8.1/libtest/GlobalVariable.c +62 -0
  108. data/vendor/gems/ruby/1.8/gems/ffi-1.8.1/libtest/LastErrorTest.c +21 -0
  109. data/vendor/gems/ruby/1.8/gems/ffi-1.8.1/libtest/NumberTest.c +132 -0
  110. data/vendor/gems/ruby/1.8/gems/ffi-1.8.1/libtest/PointerTest.c +63 -0
  111. data/vendor/gems/ruby/1.8/gems/ffi-1.8.1/libtest/ReferenceTest.c +23 -0
  112. data/vendor/gems/ruby/1.8/gems/ffi-1.8.1/libtest/StringTest.c +34 -0
  113. data/vendor/gems/ruby/1.8/gems/ffi-1.8.1/libtest/StructTest.c +240 -0
  114. data/vendor/gems/ruby/1.8/gems/ffi-1.8.1/libtest/UnionTest.c +43 -0
  115. data/vendor/gems/ruby/1.8/gems/ffi-1.8.1/libtest/VariadicTest.c +62 -0
  116. data/vendor/gems/ruby/1.8/specifications/corefoundation-0.2.0.gemspec +44 -0
  117. data/vendor/gems/ruby/1.8/specifications/ffi-1.8.1.gemspec +43 -0
  118. metadata +115 -3
data/Gemfile CHANGED
@@ -1,4 +1,6 @@
1
1
  source "https://rubygems.org"
2
2
 
3
3
  gemspec
4
- gem "corefoundation", :git => "https://github.com/tmaher/corefoundation.git"
4
+ gem "ffi", "~>1.8.1"
5
+ gem "corefoundation"
6
+ gem "netrc"
data/Gemfile.lock CHANGED
@@ -1,33 +1,29 @@
1
- GIT
2
- remote: https://github.com/tmaher/corefoundation.git
3
- revision: e4cb21a7985577c44cd0aa8f9f17e9b6b6e09141
4
- specs:
5
- corefoundation (0.1.4)
6
- ffi
7
-
8
1
  PATH
9
2
  remote: .
10
3
  specs:
11
- yakg (0.0.2)
4
+ yakg (0.0.3)
12
5
  corefoundation
13
6
  ffi
14
7
 
15
8
  GEM
16
9
  remote: https://rubygems.org/
17
10
  specs:
18
- diff-lcs (1.1.3)
11
+ corefoundation (0.2.0)
12
+ ffi
13
+ diff-lcs (1.2.4)
19
14
  excon (0.16.10)
20
- ffi (1.2.0)
21
- highline (1.6.15)
22
- rake (10.0.2)
23
- rspec (2.12.0)
24
- rspec-core (~> 2.12.0)
25
- rspec-expectations (~> 2.12.0)
26
- rspec-mocks (~> 2.12.0)
27
- rspec-core (2.12.1)
28
- rspec-expectations (2.12.0)
29
- diff-lcs (~> 1.1.3)
30
- rspec-mocks (2.12.0)
15
+ ffi (1.8.1)
16
+ highline (1.6.18)
17
+ netrc (0.7.7)
18
+ rake (10.0.4)
19
+ rspec (2.13.0)
20
+ rspec-core (~> 2.13.0)
21
+ rspec-expectations (~> 2.13.0)
22
+ rspec-mocks (~> 2.13.0)
23
+ rspec-core (2.13.1)
24
+ rspec-expectations (2.13.0)
25
+ diff-lcs (>= 1.1.3, < 2.0)
26
+ rspec-mocks (2.13.1)
31
27
  woof_util (0.0.16)
32
28
  excon (~> 0.16.10)
33
29
  highline (~> 1.6.15)
@@ -36,7 +32,9 @@ PLATFORMS
36
32
  ruby
37
33
 
38
34
  DEPENDENCIES
39
- corefoundation!
35
+ corefoundation
36
+ ffi (~> 1.8.1)
37
+ netrc
40
38
  rake
41
39
  rspec
42
40
  woof_util
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.2
1
+ 0.0.3
@@ -0,0 +1,226 @@
1
+ # https://developer.apple.com/library/mac/#documentation/security/Reference/keychainservices/Reference/reference.html
2
+
3
+ Gem.use_paths(nil, Gem.path << Yakg::Misc::VENDOR_GEM_DIR)
4
+ require "ffi"
5
+ require "corefoundation"
6
+
7
+ class Yakg
8
+ module Backend
9
+ module MacosKeychain
10
+
11
+ def self.framework name
12
+ "/System/Library/Frameworks/#{name}.framework/#{name}"
13
+ end
14
+
15
+ class KeychainError < Exception
16
+ end
17
+
18
+ extend FFI::Library
19
+ NULL = FFI::Pointer::NULL
20
+ ffi_lib(FFI::Library::LIBC,
21
+ framework(:CoreFoundation),
22
+ framework(:Security))
23
+
24
+ attach_function :malloc, [:size_t], :pointer
25
+ attach_function :free, [:pointer], :void
26
+ attach_function :CFRelease, [:pointer], :void
27
+
28
+ attach_function(:SecKeychainItemFreeContent,
29
+ [:pointer, :pointer], :uint32)
30
+
31
+ attach_function(:SecKeychainFindGenericPassword,
32
+ [:pointer, :uint32, :string, :uint32, :string,
33
+ :pointer, :pointer, :pointer],
34
+ :uint32)
35
+
36
+ attach_function(:SecKeychainAddGenericPassword,
37
+ [:pointer, :uint32, :string, :uint32, :string,
38
+ :uint32, :pointer, :pointer],
39
+ :uint32)
40
+
41
+ attach_function(:SecKeychainItemDelete, [:pointer], :uint32)
42
+ attach_function(:SecCopyErrorMessageString, [:uint32, :pointer],
43
+ :pointer)
44
+
45
+ attach_function(:SecKeychainItemModifyContent,
46
+ [:pointer, :pointer, :uint32, :string], :uint32)
47
+
48
+ attach_function(:SecKeychainSearchCreateFromAttributes,
49
+ [:pointer, :uint32, :pointer, :pointer], :uint32)
50
+ attach_function(:SecKeychainSearchCopyNext,
51
+ [:pointer, :pointer], :uint32)
52
+ attach_function(:SecKeychainItemCopyAttributesAndData,
53
+ [:pointer, :pointer, :pointer, :pointer,
54
+ :pointer, :pointer], :uint32)
55
+ attach_function(:SecKeychainItemFreeAttributesAndData,
56
+ [:pointer, :pointer], :uint32)
57
+
58
+ def error_message code
59
+ CF::String.new(SecCopyErrorMessageString(code, NULL)).to_s
60
+ end
61
+
62
+ def raise_error? code
63
+ raise KeychainError.new(error_message code) if code != 0
64
+ code
65
+ end
66
+
67
+ def delete acct, svc
68
+ pw_length = FFI::MemoryPointer.new :uint32
69
+ pw_val = FFI::MemoryPointer.new :pointer
70
+ item_ref = FFI::MemoryPointer.new :pointer
71
+ raise_error? SecKeychainFindGenericPassword(NULL, svc.length, svc,
72
+ acct.length, acct,
73
+ pw_length, pw_val,
74
+ item_ref)
75
+ raise_error? SecKeychainItemFreeContent(NULL, pw_val.read_pointer)
76
+ raise_error? SecKeychainItemDelete(item_ref.read_pointer)
77
+ CFRelease item_ref.read_pointer
78
+ true
79
+ end
80
+
81
+ def get acct, svc
82
+ pw_length = FFI::MemoryPointer.new :uint32
83
+ pw_val = FFI::MemoryPointer.new :pointer
84
+ retval = SecKeychainFindGenericPassword(NULL, svc.length, svc,
85
+ acct.length, acct,
86
+ pw_length, pw_val, NULL)
87
+ return nil unless 0 == retval
88
+ pw = pw_val.read_pointer.read_string(pw_length.read_int)
89
+ retval = SecKeychainItemFreeContent(NULL, pw_val.read_pointer)
90
+ return nil unless 0 == retval
91
+
92
+ pw
93
+ end
94
+
95
+ def set acct, value, svc
96
+ pw_length = FFI::MemoryPointer.new :uint32
97
+ pw_val = FFI::MemoryPointer.new :pointer
98
+ item_ref = FFI::MemoryPointer.new :pointer
99
+ retval = SecKeychainFindGenericPassword(NULL, svc.length, svc,
100
+ acct.length, acct,
101
+ pw_length, pw_val, item_ref)
102
+ if retval != 0
103
+ raise_error? SecKeychainAddGenericPassword(NULL, svc.length, svc,
104
+ acct.length, acct,
105
+ value.length, value, NULL)
106
+ else
107
+ raise_error? SecKeychainItemFreeContent(NULL, pw_val.read_pointer)
108
+ raise_error? SecKeychainItemModifyContent(item_ref.read_pointer, NULL,
109
+ value.length, value)
110
+ CFRelease item_ref.read_pointer
111
+ end
112
+ true
113
+ end
114
+
115
+ class SecKeychainAttributeList < FFI::Struct
116
+ layout(:count, :uint32,
117
+ :attr, :pointer)
118
+ end
119
+
120
+ def self.s2i s
121
+ s.unpack("N")[0].to_i
122
+ end
123
+ def s2i s
124
+ s.unpack("N")[0].to_i
125
+ end
126
+
127
+ enum :SecItemAttr, [:kSecCreatiofnDateItemAttr, s2i('cdat'),
128
+ :kSecModDateItemAttr, s2i('mdat'),
129
+ :kSecDescriptionItemAttr, s2i('desc'),
130
+ :kSecCommentItemAttr, s2i('icmt'),
131
+ :kSecCreatorItemAttr, s2i('crtr'),
132
+ :kSecTypeItemAttr, s2i('type'),
133
+ :kSecScriptCodeItemAttr, s2i('scrp'),
134
+ :kSecLabelItemAttr, s2i('labl'),
135
+ :kSecInvisibleItemAttr, s2i('invi'),
136
+ :kSecNegativeItemAttr, s2i('nega'),
137
+ :kSecCustomIconItemAttr, s2i('cusi'),
138
+ :kSecAccountItemAttr, s2i('acct'),
139
+ :kSecServiceItemAttr, s2i('svce'),
140
+ :kSecGenericItemAttr, s2i('gena'),
141
+ :kSecSecurityDomainItemAttr, s2i('sdmn'),
142
+ :kSecServerItemAttr, s2i('srvr'),
143
+ :kSecAuthenticationTypeItemAttr, s2i('atyp'),
144
+ :kSecPortItemAttr, s2i('port'),
145
+ :kSecPathItemAttr, s2i('path'),
146
+ :kSecVolumeItemAttr, s2i('vlme'),
147
+ :kSecAddressItemAttr, s2i('addr'),
148
+ :kSecSignatureItemAttr, s2i('ssig'),
149
+ :kSecProtocolItemAttr, s2i('ptcl'),
150
+ :kSecCertificateType, s2i('ctyp'),
151
+ :kSecCertificateEncoding, s2i('cenc'),
152
+ :kSecCrlType, s2i('crtp'),
153
+ :kSecCrlEncoding, s2i('crnc'),
154
+ :kSecAlias, s2i('alis')
155
+ ]
156
+
157
+ class SecKeychainAttribute < FFI::Struct
158
+ layout(:tag, :SecItemAttr,
159
+ :length, :uint32,
160
+ :data, :pointer)
161
+ end
162
+
163
+ class SecKeychainAttributeInfo < FFI::Struct
164
+ layout(:count, :uint32,
165
+ :tag, :pointer,
166
+ :format, :pointer)
167
+ end
168
+
169
+ def list svc
170
+ search_ref = FFI::MemoryPointer.new :pointer
171
+ found_item = FFI::MemoryPointer.new :pointer
172
+ found_attr_list = FFI::MemoryPointer.new :pointer
173
+ svc_attr = SecKeychainAttribute.new
174
+
175
+ acct_info = SecKeychainAttributeInfo.new
176
+ acct_info[:count] = 1
177
+ acct_info[:tag] = FFI::MemoryPointer.new :uint32
178
+ acct_info[:tag].write_array_of_int [s2i("acct")]
179
+ acct_info[:format] = FFI::MemoryPointer.new :uint32
180
+ acct_info[:format].write_array_of_int [0]
181
+
182
+ svc_attr[:tag] = s2i "svce"
183
+ svc_attr[:length] = svc.length
184
+ svc_attr[:data] = FFI::MemoryPointer.from_string(svc)
185
+
186
+ search_attr_list = SecKeychainAttributeList.new
187
+ search_attr_list[:count] = 1
188
+ search_attr_list[:attr] = svc_attr.pointer
189
+
190
+ raise_error? SecKeychainSearchCreateFromAttributes(NULL,
191
+ s2i("genp"),
192
+ search_attr_list,
193
+ search_ref)
194
+
195
+ acct_names = []
196
+ while true
197
+ retval = SecKeychainSearchCopyNext(search_ref.read_pointer,
198
+ found_item)
199
+ # the magic "no more items" number
200
+ break if retval == 4294941996
201
+ raise_error? retval
202
+
203
+ raise_error? SecKeychainItemCopyAttributesAndData(found_item.read_pointer,
204
+ acct_info,
205
+ NULL,
206
+ found_attr_list,
207
+ NULL, NULL)
208
+ f = SecKeychainAttributeList.new found_attr_list.read_pointer
209
+ next if f[:count] != 1
210
+
211
+ a = SecKeychainAttribute.new f[:attr]
212
+ next if a[:tag] != :kSecAccountItemAttr
213
+
214
+ acct_names.push a[:data].get_string(0, a[:length])
215
+ end
216
+
217
+ raise_error? SecKeychainItemFreeAttributesAndData(found_attr_list.read_pointer,
218
+ NULL)
219
+ CFRelease search_ref.read_pointer
220
+
221
+ acct_names
222
+ end
223
+
224
+ end
225
+ end
226
+ end
@@ -0,0 +1,41 @@
1
+ require "netrc"
2
+
3
+ class Yakg
4
+ module Backend
5
+ module NetrcFallback
6
+
7
+ def set acct, value, svc
8
+ n = Netrc.read
9
+ n["#{svc}/#{acct}"] = [acct, value]
10
+ n.save
11
+ acct
12
+ end
13
+
14
+ def get acct, svc
15
+ n = Netrc.read
16
+ if n["#{svc}/#{acct}"].nil?
17
+ nil
18
+ else
19
+ n["#{svc}/#{acct}"][1]
20
+ end
21
+ end
22
+
23
+ def delete acct, svc
24
+ n = Netrc.read
25
+ n.delete "#{svc}/#{acct}"
26
+ n.save
27
+ true
28
+ end
29
+
30
+ def list svc
31
+ known = []
32
+ Netrc.read.each do |x|
33
+ next unless x[1].match /^#{svc}/
34
+ known.push(x[1].sub(/^#{svc}\//, ""))
35
+ end
36
+ known
37
+ end
38
+
39
+ end
40
+ end
41
+ end
data/lib/yakg/backend.rb CHANGED
@@ -1,220 +1,11 @@
1
- # https://developer.apple.com/library/mac/#documentation/security/Reference/keychainservices/Reference/reference.html
2
- require "ffi"
3
- require "corefoundation"
4
-
5
1
  class Yakg
6
2
  module Backend
7
-
8
- def self.framework name
9
- "/System/Library/Frameworks/#{name}.framework/#{name}"
3
+ if RUBY_PLATFORM.match("-darwin")
4
+ require "yakg/backend/macos-keychain"
5
+ extend Yakg::Backend::MacosKeychain
6
+ else
7
+ require "yakg/backend/netrc-fallback"
8
+ extend Yakg::Backend::NetrcFallback
10
9
  end
11
-
12
- class KeychainError < Exception
13
- end
14
-
15
- extend FFI::Library
16
- NULL = FFI::Pointer::NULL
17
- ffi_lib(FFI::Library::LIBC,
18
- framework(:CoreFoundation),
19
- framework(:Security))
20
-
21
- attach_function :malloc, [:size_t], :pointer
22
- attach_function :free, [:pointer], :void
23
- attach_function :CFRelease, [:pointer], :void
24
-
25
- attach_function(:SecKeychainItemFreeContent,
26
- [:pointer, :pointer], :uint32)
27
-
28
- attach_function(:SecKeychainFindGenericPassword,
29
- [:pointer, :uint32, :string, :uint32, :string,
30
- :pointer, :pointer, :pointer],
31
- :uint32)
32
-
33
- attach_function(:SecKeychainAddGenericPassword,
34
- [:pointer, :uint32, :string, :uint32, :string,
35
- :uint32, :pointer, :pointer],
36
- :uint32)
37
-
38
- attach_function(:SecKeychainItemDelete, [:pointer], :uint32)
39
- attach_function(:SecCopyErrorMessageString, [:uint32, :pointer],
40
- :pointer)
41
-
42
- attach_function(:SecKeychainItemModifyContent,
43
- [:pointer, :pointer, :uint32, :string], :uint32)
44
-
45
- attach_function(:SecKeychainSearchCreateFromAttributes,
46
- [:pointer, :uint32, :pointer, :pointer], :uint32)
47
- attach_function(:SecKeychainSearchCopyNext,
48
- [:pointer, :pointer], :uint32)
49
- attach_function(:SecKeychainItemCopyAttributesAndData,
50
- [:pointer, :pointer, :pointer, :pointer,
51
- :pointer, :pointer], :uint32)
52
- attach_function(:SecKeychainItemFreeAttributesAndData,
53
- [:pointer, :pointer], :uint32)
54
-
55
- def self.error_message code
56
- CF::String.new(SecCopyErrorMessageString(code, NULL)).to_s
57
- end
58
-
59
- def self.raise_error? code
60
- raise KeychainError.new(error_message code) if code != 0
61
- code
62
- end
63
-
64
- def self.delete acct, svc
65
- pw_length = FFI::MemoryPointer.new :uint32
66
- pw_val = FFI::MemoryPointer.new :pointer
67
- item_ref = FFI::MemoryPointer.new :pointer
68
- raise_error? SecKeychainFindGenericPassword(NULL, svc.length, svc,
69
- acct.length, acct,
70
- pw_length, pw_val,
71
- item_ref)
72
- raise_error? SecKeychainItemFreeContent(NULL, pw_val.read_pointer)
73
- raise_error? SecKeychainItemDelete(item_ref.read_pointer)
74
- CFRelease item_ref.read_pointer
75
- true
76
- end
77
-
78
- def self.get acct, svc
79
- pw_length = FFI::MemoryPointer.new :uint32
80
- pw_val = FFI::MemoryPointer.new :pointer
81
- retval = SecKeychainFindGenericPassword(NULL, svc.length, svc,
82
- acct.length, acct,
83
- pw_length, pw_val, NULL)
84
- return nil unless 0 == retval
85
- pw = pw_val.read_pointer.read_string(pw_length.read_int)
86
- retval = SecKeychainItemFreeContent(NULL, pw_val.read_pointer)
87
- return nil unless 0 == retval
88
-
89
- pw
90
- end
91
-
92
- def self.set acct, value, svc
93
- pw_length = FFI::MemoryPointer.new :uint32
94
- pw_val = FFI::MemoryPointer.new :pointer
95
- item_ref = FFI::MemoryPointer.new :pointer
96
- retval = SecKeychainFindGenericPassword(NULL, svc.length, svc,
97
- acct.length, acct,
98
- pw_length, pw_val, item_ref)
99
- if retval != 0
100
- raise_error? SecKeychainAddGenericPassword(NULL, svc.length, svc,
101
- acct.length, acct,
102
- value.length, value, NULL)
103
- else
104
- raise_error? SecKeychainItemFreeContent(NULL, pw_val.read_pointer)
105
- raise_error? SecKeychainItemModifyContent(item_ref.read_pointer, NULL,
106
- value.length, value)
107
- CFRelease item_ref.read_pointer
108
- end
109
- true
110
- end
111
-
112
- class SecKeychainAttributeList < FFI::Struct
113
- layout(:count, :uint32,
114
- :attr, :pointer)
115
- end
116
-
117
- def self.s2i s
118
- s.unpack("N")[0].to_i
119
- end
120
-
121
- enum :SecItemAttr, [:kSecCreatiofnDateItemAttr, s2i('cdat'),
122
- :kSecModDateItemAttr, s2i('mdat'),
123
- :kSecDescriptionItemAttr, s2i('desc'),
124
- :kSecCommentItemAttr, s2i('icmt'),
125
- :kSecCreatorItemAttr, s2i('crtr'),
126
- :kSecTypeItemAttr, s2i('type'),
127
- :kSecScriptCodeItemAttr, s2i('scrp'),
128
- :kSecLabelItemAttr, s2i('labl'),
129
- :kSecInvisibleItemAttr, s2i('invi'),
130
- :kSecNegativeItemAttr, s2i('nega'),
131
- :kSecCustomIconItemAttr, s2i('cusi'),
132
- :kSecAccountItemAttr, s2i('acct'),
133
- :kSecServiceItemAttr, s2i('svce'),
134
- :kSecGenericItemAttr, s2i('gena'),
135
- :kSecSecurityDomainItemAttr, s2i('sdmn'),
136
- :kSecServerItemAttr, s2i('srvr'),
137
- :kSecAuthenticationTypeItemAttr, s2i('atyp'),
138
- :kSecPortItemAttr, s2i('port'),
139
- :kSecPathItemAttr, s2i('path'),
140
- :kSecVolumeItemAttr, s2i('vlme'),
141
- :kSecAddressItemAttr, s2i('addr'),
142
- :kSecSignatureItemAttr, s2i('ssig'),
143
- :kSecProtocolItemAttr, s2i('ptcl'),
144
- :kSecCertificateType, s2i('ctyp'),
145
- :kSecCertificateEncoding, s2i('cenc'),
146
- :kSecCrlType, s2i('crtp'),
147
- :kSecCrlEncoding, s2i('crnc'),
148
- :kSecAlias, s2i('alis')
149
- ]
150
-
151
- class SecKeychainAttribute < FFI::Struct
152
- layout(:tag, :SecItemAttr,
153
- :length, :uint32,
154
- :data, :pointer)
155
- end
156
-
157
- class SecKeychainAttributeInfo < FFI::Struct
158
- layout(:count, :uint32,
159
- :tag, :pointer,
160
- :format, :pointer)
161
- end
162
-
163
-
164
- def self.list svc
165
- search_ref = FFI::MemoryPointer.new :pointer
166
- found_item = FFI::MemoryPointer.new :pointer
167
- found_attr_list = FFI::MemoryPointer.new :pointer
168
- svc_attr = SecKeychainAttribute.new
169
-
170
- acct_info = SecKeychainAttributeInfo.new
171
- acct_info[:count] = 1
172
- acct_info[:tag] = FFI::MemoryPointer.new :uint32
173
- acct_info[:tag].write_array_of_int [s2i("acct")]
174
- acct_info[:format] = FFI::MemoryPointer.new :uint32
175
- acct_info[:format].write_array_of_int [0]
176
-
177
- svc_attr[:tag] = s2i "svce"
178
- svc_attr[:length] = svc.length
179
- svc_attr[:data] = FFI::MemoryPointer.from_string(svc)
180
-
181
- search_attr_list = SecKeychainAttributeList.new
182
- search_attr_list[:count] = 1
183
- search_attr_list[:attr] = svc_attr.pointer
184
-
185
- raise_error? SecKeychainSearchCreateFromAttributes(NULL,
186
- s2i("genp"),
187
- search_attr_list,
188
- search_ref)
189
-
190
- acct_names = []
191
- while true
192
- retval = SecKeychainSearchCopyNext(search_ref.read_pointer,
193
- found_item)
194
- # the magic "no more items" number
195
- break if retval == 4294941996
196
- raise_error? retval
197
-
198
- raise_error? SecKeychainItemCopyAttributesAndData(found_item.read_pointer,
199
- acct_info,
200
- NULL,
201
- found_attr_list,
202
- NULL, NULL)
203
- f = SecKeychainAttributeList.new found_attr_list.read_pointer
204
- next if f[:count] != 1
205
-
206
- a = SecKeychainAttribute.new f[:attr]
207
- next if a[:tag] != :kSecAccountItemAttr
208
-
209
- acct_names.push a[:data].get_string(0, a[:length])
210
- end
211
-
212
- raise_error? SecKeychainItemFreeAttributesAndData(found_attr_list.read_pointer,
213
- NULL)
214
- CFRelease search_ref.read_pointer
215
-
216
- acct_names
217
- end
218
-
219
10
  end
220
11
  end
data/lib/yakg.rb CHANGED
@@ -1,3 +1,11 @@
1
+ class Yakg
2
+ module Misc
3
+ VENDOR_GEM_DIR =
4
+ File.expand_path(File.join(File.dirname(__FILE__),
5
+ "..", "vendor", "gems", "ruby", "1.8"))
6
+ end
7
+ end
8
+
1
9
  require "yakg/backend"
2
10
 
3
11
  class Yakg
@@ -0,0 +1,4 @@
1
+ source "https://rubygems.org/"
2
+
3
+ gem "ffi", "~>1.8.1"
4
+ gem "corefoundation", "~>0.2.0"
@@ -0,0 +1,13 @@
1
+ GEM
2
+ remote: https://rubygems.org/
3
+ specs:
4
+ corefoundation (0.2.0)
5
+ ffi
6
+ ffi (1.8.1)
7
+
8
+ PLATFORMS
9
+ ruby
10
+
11
+ DEPENDENCIES
12
+ corefoundation (~> 0.2.0)
13
+ ffi (~> 1.8.1)
@@ -0,0 +1,33 @@
1
+ #!/bin/bash -x
2
+
3
+ # default mac os path
4
+ export PATH="/usr/bin:/usr/sbin:/bin:/sbin:/usr/local/bin:/usr/local/sbin"
5
+ DIR="$( cd "$( dirname "$0" )" && pwd )" ; cd $DIR
6
+
7
+ if ! [ -r `basename $0 2>/dev/null` ]; then
8
+ echo "FAIL! can't cd to the parent of $0"
9
+ exit 1
10
+ fi
11
+
12
+ if [ -r ruby ] && ! [ -d ruby ]; then
13
+ echo "FAIL! ./ruby exists and is not a directory"
14
+ exit 2
15
+ fi
16
+
17
+ rm -rf Gemfile.lock ruby
18
+ bundle install --path `pwd`
19
+
20
+ FFI_C=`find ruby -type f -name ffi_c.bundle | head -n 1`
21
+ if [ "x${FFI_C}" = "x" ]; then
22
+ echo "FAIL! Couldn't install ffi"
23
+ exit 3
24
+ fi
25
+
26
+ CFRB=`find ruby -type f -name corefoundation.rb | head -n 1`
27
+ if [ "x${CFRB}" = "x" ]; then
28
+ echo "FAIL! Couldn't install corefoundation"
29
+ exit 4
30
+ fi
31
+
32
+ rm -rf ./ruby/*/gems/ffi-*/{ext,spec}
33
+ rm -rf ./ruby/*/cache
@@ -0,0 +1,12 @@
1
+ # Changelog
2
+
3
+
4
+
5
+
6
+ ## 0.2.0 - 2012-12-06
7
+ Add support for ruby 1.8.7 [tmaher]
8
+
9
+
10
+ ## 0.1.4 - 2012-10-16
11
+
12
+ Initial version
@@ -0,0 +1,8 @@
1
+ The MIT License
2
+ Copyright (c) 2012 Frederick Cheung
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5
+
6
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7
+
8
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.