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 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
@@ -0,0 +1,5 @@
1
+ .DS_Store
2
+ .repl_history
3
+ build-*
4
+ build
5
+ xcuserdata
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
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in guard-motion.gemspec
4
+ gemspec
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 [![Build Status](https://travis-ci.org/mordaroso/carabiner.png)](https://travis-ci.org/mordaroso/carabiner)
2
+
3
+ Rubymotion wrapper for the easy access to the keychain.
4
+
5
+ ![Carabiners](http://upload.wikimedia.org/wikipedia/commons/2/2e/Cheap_carabiners.JPG)
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
@@ -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
@@ -0,0 +1,6 @@
1
+ class SettingsController < UIViewController
2
+ def loadView
3
+ self.view = SettingsView.alloc.init
4
+ self.view.setNeedsDisplay
5
+ end
6
+ end
@@ -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,5 @@
1
+ require 'bubble-wrap/core'
2
+
3
+ require 'motion-require'
4
+
5
+ Motion::Require.all(Dir.glob(File.expand_path('../carabiner/**/*.rb', __FILE__)))
@@ -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,3 @@
1
+ module Carabiner
2
+ VERSION = "0.0.2-alpha1"
3
+ end
@@ -0,0 +1,2 @@
1
+ mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles
2
+ cp ./scripts/travis/profile/* ~/Library/MobileDevice/Provisioning\ Profiles/
@@ -0,0 +1 @@
1
+ rm -f ~/Library/MobileDevice/Provisioning\ Profiles/*
data/spec/main_spec.rb ADDED
@@ -0,0 +1,9 @@
1
+ describe "Application 'keychain_example'" do
2
+ before do
3
+ @app = UIApplication.sharedApplication
4
+ end
5
+
6
+ it "has one window" do
7
+ @app.windows.size.should == 1
8
+ end
9
+ end
@@ -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.1
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-09 00:00:00.000000000 Z
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: '0'
129
+ version: 1.3.1
87
130
  requirements: []
88
131
  rubyforge_project:
89
- rubygems_version: 1.8.23
132
+ rubygems_version: 2.1.3
90
133
  signing_key:
91
- specification_version: 3
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: