carabiner 0.0.1 → 0.0.2.pre.alpha1
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.
- checksums.yaml +15 -0
- data/.gitignore +5 -0
- data/.travis.yml +12 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +51 -0
- data/LICENSE +22 -0
- data/README.md +13 -0
- data/Rakefile +16 -0
- data/app/app_delegate.rb +13 -0
- data/app/controllers/settings_controller.rb +6 -0
- data/app/models/user.rb +25 -0
- data/app/views/settings_view.rb +61 -0
- data/carabiner.gemspec +24 -0
- data/lib/carabiner.rb +5 -0
- data/lib/carabiner/keychain_return_code_exception.rb +48 -0
- data/lib/carabiner/password_keychain_item.rb +160 -0
- data/lib/carabiner/version.rb +3 -0
- data/scripts/travis/add-key.sh +2 -0
- data/scripts/travis/profile/4A8AC2EE-F24B-4F4E-A6F0-67F9BC46B924.mobileprovision +0 -0
- data/scripts/travis/remove-key.sh +1 -0
- data/spec/main_spec.rb +9 -0
- data/spec/models/keychain_return_code_exception_spec.rb +39 -0
- data/spec/models/password_keychain_item_spec.rb +28 -0
- data/spec/models/user_spec.rb +30 -0
- metadata +64 -17
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
YzQ1NTdlZmFiNWU5ZDc2OWM2YWIwNzlhNjMwMGZiYzZiYjA2OGY4Ng==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
NzBkZjEwNDJhNTEyYjM3OTUxOTc5MTcxYmZkMDg2NTE2MzM4MTRjNQ==
|
7
|
+
SHA512:
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
OTc0OGIwYmZiNjA3MzA2ZjRkZGQ4ZWJhMTkxMDRhMGE4NmYyMjU2ZGI0ODMz
|
10
|
+
MWQ1NGI5YWJlZDU2Nzc4NThkM2Y2NWEwMDg0ODMxYzM0N2FlZTQ3YzY2ZjM1
|
11
|
+
MjUyOWJmNmE1ZTliMWY0ZWJiNzJkMzVmY2JmYzYyMWEyYWNkOGU=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
NGM4YTE2NzViMzVkNTQyZGFiYzFlNjMwYWRkYTI1YTg0MjA2NzRkYThlZGQ5
|
14
|
+
Yjc5Yzk1MjFhNGFkNmI1MjExMjhmMmYyNDMyOWIxZTA5ZGNjNWUzZGE3Njkz
|
15
|
+
YzY3YjI1OTA5ZTc4OTViMWZmNDMxYjJiYzcwOGQ4OTFmMjIwNTA=
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
language: objective-c
|
2
|
+
install: bundle install
|
3
|
+
script: bundle exec rake spec
|
4
|
+
before_script:
|
5
|
+
- chmod 777 ./scripts/travis/add-key.sh
|
6
|
+
- ./scripts/travis/add-key.sh
|
7
|
+
after_script:
|
8
|
+
- chmod 777 ./scripts/travis/remove-key.sh
|
9
|
+
- ./scripts/travis/remove-key.sh
|
10
|
+
env:
|
11
|
+
global:
|
12
|
+
secure: Usy8ZlZSUKzHUEtxR6zcWhG7c7OnynTn85+L0jjgrMZYw1AOFOmSjttfvfci8/f312YpUXOayBOOtE3U6B0TSbSbs7IwPlf76ZW7ZYa7SyE+BAsdS1E97IwpVL7DhKs17ZZl+6Ln9IJpHuZGF5N4RG9ItPzCQs0IGhRSGE32iNk=
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
carabiner (0.0.1)
|
5
|
+
bubble-wrap
|
6
|
+
motion-require (~> 0.0.3)
|
7
|
+
rake
|
8
|
+
|
9
|
+
GEM
|
10
|
+
remote: https://rubygems.org/
|
11
|
+
specs:
|
12
|
+
bubble-wrap (1.3.0)
|
13
|
+
coderay (1.0.9)
|
14
|
+
ffi (1.9.0)
|
15
|
+
formatador (0.2.4)
|
16
|
+
guard (1.8.2)
|
17
|
+
formatador (>= 0.2.4)
|
18
|
+
listen (>= 1.0.0)
|
19
|
+
lumberjack (>= 1.0.2)
|
20
|
+
pry (>= 0.9.10)
|
21
|
+
thor (>= 0.14.6)
|
22
|
+
guard-motion (0.1.2)
|
23
|
+
guard (>= 1.1.0)
|
24
|
+
rake (>= 0.9)
|
25
|
+
listen (1.3.1)
|
26
|
+
rb-fsevent (>= 0.9.3)
|
27
|
+
rb-inotify (>= 0.9)
|
28
|
+
rb-kqueue (>= 0.2)
|
29
|
+
lumberjack (1.0.4)
|
30
|
+
method_source (0.8.2)
|
31
|
+
motion-require (0.0.7)
|
32
|
+
pry (0.9.12.2)
|
33
|
+
coderay (~> 1.0.5)
|
34
|
+
method_source (~> 0.8)
|
35
|
+
slop (~> 3.4)
|
36
|
+
rake (10.1.0)
|
37
|
+
rb-fsevent (0.9.3)
|
38
|
+
rb-inotify (0.9.1)
|
39
|
+
ffi (>= 0.5.0)
|
40
|
+
rb-kqueue (0.2.0)
|
41
|
+
ffi (>= 0.5.0)
|
42
|
+
slop (3.4.6)
|
43
|
+
thor (0.18.1)
|
44
|
+
|
45
|
+
PLATFORMS
|
46
|
+
ruby
|
47
|
+
|
48
|
+
DEPENDENCIES
|
49
|
+
bundler
|
50
|
+
carabiner!
|
51
|
+
guard-motion
|
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Fabio Kuhn
|
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,13 @@
|
|
1
|
+
# Carabiner [](https://travis-ci.org/mordaroso/carabiner)
|
2
|
+
|
3
|
+
Rubymotion wrapper for the easy access to the keychain.
|
4
|
+
|
5
|
+

|
6
|
+
|
7
|
+
**This gem is still under heavy development and will be released soon. Please be paitent.**
|
8
|
+
|
9
|
+
## TODOs
|
10
|
+
|
11
|
+
* Better error handling
|
12
|
+
* Code Documentation
|
13
|
+
* README
|
data/Rakefile
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
$:.unshift("/Library/RubyMotion/lib")
|
2
|
+
require 'motion/project/template/ios'
|
3
|
+
|
4
|
+
$:.unshift("./lib/")
|
5
|
+
require './lib/carabiner'
|
6
|
+
|
7
|
+
Motion::Project::App.setup do |app|
|
8
|
+
# Use `rake config' to see complete project settings.
|
9
|
+
app.name = 'KeychainExample'
|
10
|
+
|
11
|
+
app.frameworks += ['Security']
|
12
|
+
|
13
|
+
app.entitlements['keychain-access-groups'] = [
|
14
|
+
app.seed_id + '.' + app.identifier
|
15
|
+
]
|
16
|
+
end
|
data/app/app_delegate.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
class AppDelegate
|
2
|
+
def application(application, didFinishLaunchingWithOptions:launchOptions)
|
3
|
+
@window = UIWindow.alloc.initWithFrame(UIScreen.mainScreen.bounds)
|
4
|
+
@window.rootViewController = SettingsController.alloc.init
|
5
|
+
@window.rootViewController.wantsFullScreenLayout = true
|
6
|
+
@window.makeKeyAndVisible
|
7
|
+
return true
|
8
|
+
end
|
9
|
+
|
10
|
+
def user
|
11
|
+
@user ||= User.new
|
12
|
+
end
|
13
|
+
end
|
data/app/models/user.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
class User
|
2
|
+
attr_accessor :username, :password
|
3
|
+
|
4
|
+
def initialize
|
5
|
+
@keychain = Carabiner::PasswordKeychainItem.new 'ExampleAppLoginData'
|
6
|
+
load
|
7
|
+
end
|
8
|
+
|
9
|
+
def save
|
10
|
+
@keychain.account = username
|
11
|
+
@keychain.password = password
|
12
|
+
@keychain.save!
|
13
|
+
end
|
14
|
+
|
15
|
+
def load
|
16
|
+
self.username = @keychain.account
|
17
|
+
self.password = @keychain.password
|
18
|
+
end
|
19
|
+
|
20
|
+
def reset
|
21
|
+
self.username = ''
|
22
|
+
self.password = ''
|
23
|
+
@keychain.reset!
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
class SettingsView < UIView
|
2
|
+
|
3
|
+
def initWithFrame(rect)
|
4
|
+
if super
|
5
|
+
self.backgroundColor = UIColor.groupTableViewBackgroundColor
|
6
|
+
@user = UIApplication.sharedApplication.delegate.user
|
7
|
+
drawUsername
|
8
|
+
drawPassword
|
9
|
+
drawButton
|
10
|
+
end
|
11
|
+
self
|
12
|
+
end
|
13
|
+
|
14
|
+
def drawUsername
|
15
|
+
@username = UITextField.alloc.initWithFrame CGRectMake(40, 30, 240, 30)
|
16
|
+
@username.setBorderStyle UITextBorderStyleRoundedRect
|
17
|
+
@username.placeholder = 'Username'
|
18
|
+
@username.text = @user.username
|
19
|
+
@username.setReturnKeyType UIReturnKeyDone
|
20
|
+
@username.addTarget self, action: 'textFieldFinished', forControlEvents:UIControlEventEditingDidEndOnExit
|
21
|
+
|
22
|
+
addSubview @username
|
23
|
+
end
|
24
|
+
|
25
|
+
def drawPassword
|
26
|
+
@password = UITextField.alloc.initWithFrame CGRectMake(40, 75, 240, 30)
|
27
|
+
@password.setBorderStyle UITextBorderStyleRoundedRect
|
28
|
+
@password.placeholder = 'Password'
|
29
|
+
@password.text = @user.password
|
30
|
+
@password.setSecureTextEntry true
|
31
|
+
@password.setReturnKeyType UIReturnKeyDone
|
32
|
+
@password.addTarget self, action: 'textFieldFinished', forControlEvents:UIControlEventEditingDidEndOnExit
|
33
|
+
|
34
|
+
addSubview @password
|
35
|
+
end
|
36
|
+
|
37
|
+
def drawButton
|
38
|
+
@saveButton = UIButton.buttonWithType UIButtonTypeRoundedRect
|
39
|
+
@saveButton.setFrame CGRectMake(80, 130, 160, 40)
|
40
|
+
@saveButton.setTitle "Save", forState: UIControlStateNormal
|
41
|
+
|
42
|
+
pointer = Pointer.new(:object)
|
43
|
+
|
44
|
+
@saveButton.addTarget self, action:'saveSettings', forControlEvents: UIControlEventTouchUpInside
|
45
|
+
|
46
|
+
addSubview @saveButton
|
47
|
+
end
|
48
|
+
|
49
|
+
def textFieldFinished
|
50
|
+
self.endEditing true
|
51
|
+
end
|
52
|
+
|
53
|
+
def saveSettings
|
54
|
+
@user.username = @username.text
|
55
|
+
@user.password = @password.text
|
56
|
+
@user.save
|
57
|
+
|
58
|
+
@saveButton.setTitle "Saved", forState: UIControlStateNormal
|
59
|
+
self.endEditing true
|
60
|
+
end
|
61
|
+
end
|
data/carabiner.gemspec
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/carabiner/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["mordaroso"]
|
6
|
+
gem.email = ["mordaroso@gmail.com"]
|
7
|
+
gem.homepage = 'http://rubygems.org/gems/carabiner'
|
8
|
+
gem.summary = 'Rubymotion wrapper for the keychain'
|
9
|
+
gem.description = 'Easy access to the ios keychain'
|
10
|
+
|
11
|
+
gem.files = `git ls-files`.split($\)
|
12
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
13
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
14
|
+
gem.name = "carabiner"
|
15
|
+
gem.require_paths = ["lib"]
|
16
|
+
gem.version = Carabiner::VERSION
|
17
|
+
|
18
|
+
gem.add_dependency 'rake'
|
19
|
+
gem.add_dependency 'bubble-wrap'
|
20
|
+
gem.add_dependency 'motion-require', '~> 0.0.3'
|
21
|
+
|
22
|
+
gem.add_development_dependency 'bundler'
|
23
|
+
gem.add_development_dependency 'guard-motion'
|
24
|
+
end
|
data/lib/carabiner.rb
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
module Carabiner
|
2
|
+
class KeychainReturnCodeException < Exception
|
3
|
+
|
4
|
+
attr_accessor :return_code
|
5
|
+
|
6
|
+
RETURN_CODES = {
|
7
|
+
ErrSecSuccess => {:constant_name => 'ErrSecSuccess', :message => "No error."},
|
8
|
+
ErrSecUnimplemented => {:constant_name => 'ErrSecUnimplemented', :message => "Function or operation not implemented."},
|
9
|
+
ErrSecParam => {:constant_name => 'ErrSecParam', :message => "One or more parameters passed to the function were not valid."},
|
10
|
+
ErrSecAllocate => {:constant_name => 'ErrSecAllocate', :message => "Failed to allocate memory."},
|
11
|
+
ErrSecNotAvailable => {:constant_name => 'ErrSecNotAvailable', :message => "No trust results are available."},
|
12
|
+
ErrSecAuthFailed => {:constant_name => 'ErrSecAuthFailed', :message => "Authorization/Authentication failed."},
|
13
|
+
ErrSecDuplicateItem => {:constant_name => 'ErrSecDuplicateItem', :message => "The item already exists."},
|
14
|
+
ErrSecItemNotFound => {:constant_name => 'ErrSecItemNotFound', :message => "The item cannot be found."},
|
15
|
+
ErrSecInteractionNotAllowed => {:constant_name => 'ErrSecInteractionNotAllowed', :message => "Interaction with the Security Server is not allowed."},
|
16
|
+
ErrSecDecode => {:constant_name => 'ErrSecDecode', :message => "Unable to decode the provided data."}
|
17
|
+
}
|
18
|
+
|
19
|
+
def initialize message, return_code
|
20
|
+
@return_code = return_code
|
21
|
+
super message
|
22
|
+
end
|
23
|
+
|
24
|
+
def message
|
25
|
+
super + "\nReturn Code: #{constant_name} (#{return_message})"
|
26
|
+
end
|
27
|
+
|
28
|
+
def return_message
|
29
|
+
if return_code_item
|
30
|
+
return_code_item[:message]
|
31
|
+
else
|
32
|
+
"Keychain return code #{return_code} unknown."
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def constant_name
|
37
|
+
if return_code_item
|
38
|
+
return_code_item[:constant_name]
|
39
|
+
else
|
40
|
+
return_code.to_s
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def return_code_item
|
45
|
+
RETURN_CODES[return_code]
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,160 @@
|
|
1
|
+
module Carabiner
|
2
|
+
class PasswordKeychainItem
|
3
|
+
|
4
|
+
attr_accessor :generic_password_query
|
5
|
+
|
6
|
+
# These are the default constants and their respective types,
|
7
|
+
# available for the kSecClassGenericPassword Keychain Item class:
|
8
|
+
#
|
9
|
+
# See the header file Security/SecItem.h for more details.
|
10
|
+
ATTRIBUTES = {
|
11
|
+
:access_group => KSecAttrAccessGroup,
|
12
|
+
:creation_time => KSecAttrCreationDate,
|
13
|
+
:modifaction_date => KSecAttrModificationDate,
|
14
|
+
:description => KSecAttrDescription,
|
15
|
+
:comment => KSecAttrComment,
|
16
|
+
:creator => KSecAttrCreator,
|
17
|
+
:type => KSecAttrType,
|
18
|
+
:label => KSecAttrLabel,
|
19
|
+
:is_invisible => KSecAttrIsInvisible,
|
20
|
+
:is_negative => KSecAttrIsNegative,
|
21
|
+
:account => KSecAttrAccount,
|
22
|
+
:service => KSecAttrService,
|
23
|
+
:generic => KSecAttrGeneric,
|
24
|
+
:password => KSecValueData
|
25
|
+
}
|
26
|
+
|
27
|
+
ATTRIBUTES.keys.each do |key|
|
28
|
+
attr_accessor key
|
29
|
+
end
|
30
|
+
|
31
|
+
NoErr = 0
|
32
|
+
|
33
|
+
def initialize identifier, accessGroup = nil
|
34
|
+
self.generic_password_query = {}
|
35
|
+
generic_password_query[KSecClass] = KSecClassGenericPassword
|
36
|
+
generic_password_query[KSecAttrGeneric] = identifier
|
37
|
+
|
38
|
+
if !accessGroup.nil? && !Device.simulator?
|
39
|
+
generic_password_query[KSecAttrAccessGroup] = accessGroup
|
40
|
+
end
|
41
|
+
|
42
|
+
generic_password_query[KSecMatchLimit] = KSecMatchLimitOne
|
43
|
+
generic_password_query[KSecReturnAttributes] = KCFBooleanTrue
|
44
|
+
|
45
|
+
tempQuery = NSDictionary.dictionaryWithDictionary generic_password_query
|
46
|
+
outDictionaryPtr = Pointer.new(:object)
|
47
|
+
|
48
|
+
if !(SecItemCopyMatching(tempQuery, outDictionaryPtr) == NoErr)
|
49
|
+
reset!
|
50
|
+
self.generic = identifier
|
51
|
+
|
52
|
+
if !accessGroup.nil? && !Device.simulator?
|
53
|
+
generic_password_query[KSecAttrAccessGroup] = accessGroup
|
54
|
+
end
|
55
|
+
else
|
56
|
+
self.keychain_item_data = secItemFormatToDictionary(outDictionaryPtr[0])
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def reset!
|
61
|
+
delete! unless keychain_item_data.empty?
|
62
|
+
self.account = ''
|
63
|
+
self.label = ''
|
64
|
+
self.description = ''
|
65
|
+
self.password = ''
|
66
|
+
true
|
67
|
+
end
|
68
|
+
|
69
|
+
def save!
|
70
|
+
writeToKeychain
|
71
|
+
true
|
72
|
+
end
|
73
|
+
|
74
|
+
def delete!
|
75
|
+
tempDictionary = dictionaryToSecItemFormat(keychain_item_data)
|
76
|
+
result = SecItemDelete(tempDictionary)
|
77
|
+
if result != NoErr && result != ErrSecItemNotFound
|
78
|
+
raise KeychainReturnCodeException.new "Problem deleting current dictionary.", result
|
79
|
+
end
|
80
|
+
self.keychain_item_data = {}
|
81
|
+
true
|
82
|
+
end
|
83
|
+
|
84
|
+
def self.key_accepted? key
|
85
|
+
ATTRIBUTES.values.include? key
|
86
|
+
end
|
87
|
+
|
88
|
+
private
|
89
|
+
|
90
|
+
def keychain_item_data
|
91
|
+
ATTRIBUTES.keys.inject({}) do |memo, getter_name|
|
92
|
+
constant = ATTRIBUTES[getter_name]
|
93
|
+
value = send(getter_name)
|
94
|
+
memo[constant] = value if value
|
95
|
+
memo
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def keychain_item_data=(hash)
|
100
|
+
ATTRIBUTES.each do |getter_name, constant|
|
101
|
+
send("#{getter_name}=", hash[constant])
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def dictionaryToSecItemFormat dictionaryToConvert
|
106
|
+
returnDictionary = NSMutableDictionary.dictionaryWithDictionary dictionaryToConvert
|
107
|
+
returnDictionary[KSecClass] = KSecClassGenericPassword
|
108
|
+
passwordString = dictionaryToConvert[KSecValueData]
|
109
|
+
|
110
|
+
returnDictionary[KSecValueData] = passwordString.dataUsingEncoding(NSUTF8StringEncoding)
|
111
|
+
returnDictionary
|
112
|
+
end
|
113
|
+
|
114
|
+
def secItemFormatToDictionary dictionaryToConvert
|
115
|
+
returnDictionary = NSMutableDictionary.dictionaryWithDictionary dictionaryToConvert
|
116
|
+
returnDictionary[KSecReturnData] = KCFBooleanTrue
|
117
|
+
returnDictionary[KSecClass] = KSecClassGenericPassword
|
118
|
+
|
119
|
+
passwordDataPtr = Pointer.new(:object)
|
120
|
+
|
121
|
+
result = SecItemCopyMatching(returnDictionary, passwordDataPtr)
|
122
|
+
if result == NoErr
|
123
|
+
returnDictionary.delete KSecReturnData
|
124
|
+
passwordData = passwordDataPtr[0]
|
125
|
+
password = NSString.alloc.initWithBytes(passwordData.bytes, length: passwordData.length, encoding: NSUTF8StringEncoding)
|
126
|
+
returnDictionary[KSecValueData] = password
|
127
|
+
else
|
128
|
+
raise KeychainReturnCodeException.new "Serious error, no matching item found in the keychain.", result
|
129
|
+
end
|
130
|
+
|
131
|
+
returnDictionary
|
132
|
+
end
|
133
|
+
|
134
|
+
def writeToKeychain
|
135
|
+
attributesPtr = Pointer.new(:object)
|
136
|
+
if SecItemCopyMatching(generic_password_query, attributesPtr) == NoErr
|
137
|
+
query = NSMutableDictionary.dictionaryWithDictionary attributesPtr[0]
|
138
|
+
|
139
|
+
query[KSecClass] = generic_password_query[KSecClass]
|
140
|
+
attributes_to_update = dictionaryToSecItemFormat keychain_item_data
|
141
|
+
attributes_to_update.delete_if { |key, value| !self.class.key_accepted? key }
|
142
|
+
|
143
|
+
if Device.simulator?
|
144
|
+
attributes_to_update.delete KSecAttrAccessGroup
|
145
|
+
end
|
146
|
+
|
147
|
+
result = SecItemUpdate(query, attributes_to_update)
|
148
|
+
unless result == NoErr
|
149
|
+
raise KeychainReturnCodeException.new "Couldn't update the Keychain Item.", result
|
150
|
+
end
|
151
|
+
else
|
152
|
+
result = SecItemAdd(dictionaryToSecItemFormat(keychain_item_data), nil)
|
153
|
+
unless result == NoErr
|
154
|
+
raise KeychainReturnCodeException.new "Couldn't add the Keychain Item.", result
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
end
|
160
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
rm -f ~/Library/MobileDevice/Provisioning\ Profiles/*
|
data/spec/main_spec.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
module Carabiner
|
2
|
+
describe KeychainReturnCodeException do
|
3
|
+
describe 'known return value' do
|
4
|
+
before do
|
5
|
+
@exception = KeychainReturnCodeException.new "custom message", ErrSecNotAvailable
|
6
|
+
end
|
7
|
+
|
8
|
+
it 'has return_message' do
|
9
|
+
@exception.return_message.should == 'No trust results are available.'
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'has constant_name' do
|
13
|
+
@exception.constant_name.should == 'ErrSecNotAvailable'
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'has descriptive error message' do
|
17
|
+
@exception.message.should == "custom message\nReturn Code: ErrSecNotAvailable (No trust results are available.)"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe 'unknown return value' do
|
22
|
+
before do
|
23
|
+
@exception = KeychainReturnCodeException.new "custom message", 999
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'has return_message' do
|
27
|
+
@exception.return_message.should == 'Keychain return code 999 unknown.'
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'has constant_name' do
|
31
|
+
@exception.constant_name.should == '999'
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'has descriptive error message' do
|
35
|
+
@exception.message.should == "custom message\nReturn Code: 999 (Keychain return code 999 unknown.)"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Carabiner
|
2
|
+
describe PasswordKeychainItem do
|
3
|
+
before do
|
4
|
+
@item = PasswordKeychainItem.new 'TestPasswordItem'
|
5
|
+
@item.password = 'secret'
|
6
|
+
@item.account = 'Test'
|
7
|
+
@item.save!
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'initialize attributes' do
|
11
|
+
new_item = PasswordKeychainItem.new 'TestPasswordItem'
|
12
|
+
new_item.account.should == 'Test'
|
13
|
+
new_item.password.should == 'secret'
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'reset!' do
|
17
|
+
@item.reset!
|
18
|
+
@item.account.should == ''
|
19
|
+
@item.password.should == ''
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'delete!' do
|
23
|
+
@item.delete!
|
24
|
+
@item.account.should == nil
|
25
|
+
@item.password.should == nil
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
describe "User" do
|
2
|
+
before do
|
3
|
+
@user = User.new
|
4
|
+
@user.username = 'Username'
|
5
|
+
@user.password = 'Secret'
|
6
|
+
@user.save
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should save username and password" do
|
10
|
+
@user.username = 'New Username'
|
11
|
+
@user.password = 'New Secret'
|
12
|
+
@user.save
|
13
|
+
|
14
|
+
@user.username.should == 'New Username'
|
15
|
+
@user.password.should == 'New Secret'
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should load username and password" do
|
19
|
+
@second_user_object = User.new
|
20
|
+
@user.username.should == 'Username'
|
21
|
+
@user.password.should == 'Secret'
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should reset information" do
|
25
|
+
@user.reset
|
26
|
+
@user.load
|
27
|
+
@user.username.should == ''
|
28
|
+
@user.username.should == ''
|
29
|
+
end
|
30
|
+
end
|
metadata
CHANGED
@@ -1,20 +1,18 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: carabiner
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
5
|
-
prerelease:
|
4
|
+
version: 0.0.2.pre.alpha1
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- mordaroso
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date: 2013-09-
|
11
|
+
date: 2013-09-16 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: rake
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
16
|
requirements:
|
19
17
|
- - ! '>='
|
20
18
|
- !ruby/object:Gem::Version
|
@@ -22,15 +20,41 @@ dependencies:
|
|
22
20
|
type: :runtime
|
23
21
|
prerelease: false
|
24
22
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
23
|
requirements:
|
27
24
|
- - ! '>='
|
28
25
|
- !ruby/object:Gem::Version
|
29
26
|
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: bubble-wrap
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ! '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ! '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: motion-require
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ~>
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 0.0.3
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 0.0.3
|
30
55
|
- !ruby/object:Gem::Dependency
|
31
56
|
name: bundler
|
32
57
|
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
58
|
requirements:
|
35
59
|
- - ! '>='
|
36
60
|
- !ruby/object:Gem::Version
|
@@ -38,7 +62,6 @@ dependencies:
|
|
38
62
|
type: :development
|
39
63
|
prerelease: false
|
40
64
|
version_requirements: !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
65
|
requirements:
|
43
66
|
- - ! '>='
|
44
67
|
- !ruby/object:Gem::Version
|
@@ -46,7 +69,6 @@ dependencies:
|
|
46
69
|
- !ruby/object:Gem::Dependency
|
47
70
|
name: guard-motion
|
48
71
|
requirement: !ruby/object:Gem::Requirement
|
49
|
-
none: false
|
50
72
|
requirements:
|
51
73
|
- - ! '>='
|
52
74
|
- !ruby/object:Gem::Version
|
@@ -54,7 +76,6 @@ dependencies:
|
|
54
76
|
type: :development
|
55
77
|
prerelease: false
|
56
78
|
version_requirements: !ruby/object:Gem::Requirement
|
57
|
-
none: false
|
58
79
|
requirements:
|
59
80
|
- - ! '>='
|
60
81
|
- !ruby/object:Gem::Version
|
@@ -65,30 +86,56 @@ email:
|
|
65
86
|
executables: []
|
66
87
|
extensions: []
|
67
88
|
extra_rdoc_files: []
|
68
|
-
files:
|
89
|
+
files:
|
90
|
+
- .gitignore
|
91
|
+
- .travis.yml
|
92
|
+
- Gemfile
|
93
|
+
- Gemfile.lock
|
94
|
+
- LICENSE
|
95
|
+
- README.md
|
96
|
+
- Rakefile
|
97
|
+
- app/app_delegate.rb
|
98
|
+
- app/controllers/settings_controller.rb
|
99
|
+
- app/models/user.rb
|
100
|
+
- app/views/settings_view.rb
|
101
|
+
- carabiner.gemspec
|
102
|
+
- lib/carabiner.rb
|
103
|
+
- lib/carabiner/keychain_return_code_exception.rb
|
104
|
+
- lib/carabiner/password_keychain_item.rb
|
105
|
+
- lib/carabiner/version.rb
|
106
|
+
- scripts/travis/add-key.sh
|
107
|
+
- scripts/travis/profile/4A8AC2EE-F24B-4F4E-A6F0-67F9BC46B924.mobileprovision
|
108
|
+
- scripts/travis/remove-key.sh
|
109
|
+
- spec/main_spec.rb
|
110
|
+
- spec/models/keychain_return_code_exception_spec.rb
|
111
|
+
- spec/models/password_keychain_item_spec.rb
|
112
|
+
- spec/models/user_spec.rb
|
69
113
|
homepage: http://rubygems.org/gems/carabiner
|
70
114
|
licenses: []
|
115
|
+
metadata: {}
|
71
116
|
post_install_message:
|
72
117
|
rdoc_options: []
|
73
118
|
require_paths:
|
74
119
|
- lib
|
75
120
|
required_ruby_version: !ruby/object:Gem::Requirement
|
76
|
-
none: false
|
77
121
|
requirements:
|
78
122
|
- - ! '>='
|
79
123
|
- !ruby/object:Gem::Version
|
80
124
|
version: '0'
|
81
125
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
82
|
-
none: false
|
83
126
|
requirements:
|
84
|
-
- - ! '
|
127
|
+
- - ! '>'
|
85
128
|
- !ruby/object:Gem::Version
|
86
|
-
version:
|
129
|
+
version: 1.3.1
|
87
130
|
requirements: []
|
88
131
|
rubyforge_project:
|
89
|
-
rubygems_version: 1.
|
132
|
+
rubygems_version: 2.1.3
|
90
133
|
signing_key:
|
91
|
-
specification_version:
|
134
|
+
specification_version: 4
|
92
135
|
summary: Rubymotion wrapper for the keychain
|
93
|
-
test_files:
|
136
|
+
test_files:
|
137
|
+
- spec/main_spec.rb
|
138
|
+
- spec/models/keychain_return_code_exception_spec.rb
|
139
|
+
- spec/models/password_keychain_item_spec.rb
|
140
|
+
- spec/models/user_spec.rb
|
94
141
|
has_rdoc:
|