Browse files

Added

[git-p4: depot-paths = "//src/osx_keychain/dev/": change = 5491]
  • Loading branch information...
0 parents commit a87aaeaf58e73a9892b930d5c07ff31fe4cc8ff1 @zenspider zenspider committed Oct 16, 2009
Showing with 252 additions and 0 deletions.
  1. +24 −0 .autotest
  2. +6 −0 History.txt
  3. +8 −0 Manifest.txt
  4. +52 −0 README.txt
  5. +16 −0 Rakefile
  6. +18 −0 bin/osx_keychain
  7. +113 −0 lib/osx_keychain.rb
  8. +15 −0 test/test_osx_keychain.rb
24 .autotest
@@ -0,0 +1,24 @@
+# -*- ruby -*-
+
+require 'autotest/restart'
+
+Autotest.add_hook :initialize do |at|
+ at.testlib = "minitest/autorun"
+# at.extra_files << "../some/external/dependency.rb"
+#
+# at.libs << ":../some/external"
+#
+# at.add_exception 'vendor'
+#
+# at.add_mapping(/dependency.rb/) do |f, _|
+# at.files_matching(/test_.*rb$/)
+# end
+#
+# %w(TestA TestB).each do |klass|
+# at.extra_class_map[klass] = "test/test_misc.rb"
+# end
+end
+
+# Autotest.add_hook :run_command do |at|
+# system "rake build"
+# end
6 History.txt
@@ -0,0 +1,6 @@
+=== 1.0.0 / 2009-10-16
+
+* 1 major enhancement
+
+ * Birthday!
+
8 Manifest.txt
@@ -0,0 +1,8 @@
+.autotest
+History.txt
+Manifest.txt
+README.txt
+Rakefile
+bin/osx_keychain
+lib/osx_keychain.rb
+test/test_osx_keychain.rb
52 README.txt
@@ -0,0 +1,52 @@
+= osx_keychain
+
+* http://rubyforge.org/projects/seattlerb
+
+== DESCRIPTION:
+
+Provides API and a command line tool to Access the OS X Keychain. The
+command line tool isn't actually useful (use `security` instead), but
+demonstrates the usage quite well.
+
+== FEATURES/PROBLEMS:
+
+* Very simple hash-like access to the OS X keychain.
+
+== SYNOPSIS:
+
+ keychain = OSXKeychain.new
+ keychain[service, username] = password
+ p keychain[service, username]
+
+== REQUIREMENTS:
+
+* RubyInline
+
+== INSTALL:
+
+* sudo gem install osx_keychain
+
+== LICENSE:
+
+(The MIT License)
+
+Copyright (c) Ryan Davis, seattle.rb
+
+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:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+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.
16 Rakefile
@@ -0,0 +1,16 @@
+# -*- ruby -*-
+
+require 'rubygems'
+require 'hoe'
+
+Hoe.plugin :seattlerb
+
+Hoe.spec 'osx_keychain' do
+ developer 'Ryan Davis', 'ryand-ruby@zenspider.com'
+
+ extra_deps << ['RubyInline', '~> 3']
+
+ self.rubyforge_name = 'seattlerb'
+end
+
+# vim: syntax=ruby
18 bin/osx_keychain
@@ -0,0 +1,18 @@
+#!/usr/bin/env ruby
+
+require 'osx_keychain'
+
+keychain = OSXKeychain.new
+
+action = ARGV.shift
+
+abort "usage: #{File.basename $0} (get|set) service [user] [pass]" unless action
+
+case action
+when "get" then
+ p keychain[ARGV.shift, ARGV.shift]
+when "set" then
+ keychain[ARGV.shift, ARGV.shift] = ARGV.shift
+else
+ warn "unknown command: #{action}"
+end
113 lib/osx_keychain.rb
@@ -0,0 +1,113 @@
+#!/usr/bin/ruby -w
+
+require 'rubygems'
+require 'inline'
+
+class OSXKeychain
+ VERSION = '1.0.0'
+
+ def []= service, username, password
+ set(service, username, password)
+ end
+
+ def [] service, username = nil
+ get(service, username)
+ end
+
+ inline :C do |builder|
+ builder.include '<Security/Security.h>'
+
+ builder.add_link_flags %w[-lc]
+
+ builder.add_link_flags %w[-framework Security
+ -framework CoreFoundation
+ -framework CoreServices]
+
+ builder.c <<-EOC
+ VALUE get(char * service, VALUE _username) {
+ char *username = RTEST(_username) ? StringValueCStr(_username) : NULL;
+ OSStatus status;
+ UInt32 length;
+ CFArrayRef keychains = NULL;
+ void *data;
+ VALUE result = Qnil;
+
+ status = SecKeychainCopySearchList(&keychains);
+
+ if (status)
+ rb_raise(rb_eRuntimeError,
+ "can't access keychains, Authorization failed: %d", status);
+
+ status = SecKeychainFindGenericPassword(keychains,
+ strlen(service), service,
+ username ? strlen(username) : 0, username,
+ &length, &data, NULL);
+
+ if (status == errSecItemNotFound)
+ status = SecKeychainFindInternetPassword(keychains,
+ strlen(service), service,
+ 0, NULL,
+ username ? strlen(username) : 0, username,
+ 0, NULL, 0, kSecProtocolTypeAny, kSecAuthenticationTypeAny,
+ &length, &data, NULL);
+
+ switch (status) {
+ case 0:
+ result = rb_str_new(data, length);
+ SecKeychainItemFreeContent(NULL, data);
+ break;
+ case errSecItemNotFound:
+ // do nothing, return nil password
+ break;
+ default:
+ rb_raise(rb_eRuntimeError, "Can't fetch password from system");
+ break;
+ }
+
+ CFRelease(keychains);
+
+ return result;
+ }
+ EOC
+
+ builder.c <<-EOC
+ void set(char * service, char * username, char * password) {
+ OSStatus status;
+ SecKeychainRef keychain;
+ SecKeychainItemRef item;
+
+ status = SecKeychainOpen("login.keychain",&keychain);
+
+ if (status)
+ rb_raise(rb_eRuntimeError,
+ "can't access keychains, Authorization failed: %d", status);
+
+ status = SecKeychainFindGenericPassword(keychain,
+ strlen(service), service,
+ username == NULL ? 0 : strlen(username), username,
+ 0, NULL, &item);
+
+ switch (status) {
+ case 0:
+ status = SecKeychainItemModifyAttributesAndData(item, NULL,
+ strlen(password), password);
+ CFRelease(item);
+ break;
+ case errSecItemNotFound:
+ status = SecKeychainAddGenericPassword(keychain,
+ strlen(service), service,
+ username == NULL ? 0 : strlen(username), username,
+ strlen(password), password,
+ NULL);
+ break;
+ default:
+ rb_raise(rb_eRuntimeError, "Can't fetch password from system");
+ break;
+ }
+
+ if (status)
+ rb_raise(rb_eRuntimeError, "Can't store password in Keychain");
+ }
+ EOC
+ end
+end
15 test/test_osx_keychain.rb
@@ -0,0 +1,15 @@
+require "minitest/autorun"
+require "osx_keychain"
+
+class TestOsxKeychain < MiniTest::Unit::TestCase
+ def test_sanity
+ keychain = OSXKeychain.new
+
+ serv, user, pass = %w[osx_keychain_test username password]
+
+ keychain[serv, user] = pass
+
+ assert_equal pass, keychain[serv, user]
+ assert_equal pass, keychain[serv]
+ end
+end

0 comments on commit a87aaea

Please sign in to comment.