carabiner 0.0.2.pre.alpha1 → 0.0.2.pre.alpha2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- YzQ1NTdlZmFiNWU5ZDc2OWM2YWIwNzlhNjMwMGZiYzZiYjA2OGY4Ng==
4
+ MWQ1MTE4MzgxYWRjZjgzMjAyMzFjNWY4NGQ3Nzk1ZDE2YjI4MGZlYQ==
5
5
  data.tar.gz: !binary |-
6
- NzBkZjEwNDJhNTEyYjM3OTUxOTc5MTcxYmZkMDg2NTE2MzM4MTRjNQ==
6
+ MzNjZmNhODRkZTc2NmExMTlhMjU0ZDZlYzFiZDVmN2Q3MDhlNDI1ZA==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- OTc0OGIwYmZiNjA3MzA2ZjRkZGQ4ZWJhMTkxMDRhMGE4NmYyMjU2ZGI0ODMz
10
- MWQ1NGI5YWJlZDU2Nzc4NThkM2Y2NWEwMDg0ODMxYzM0N2FlZTQ3YzY2ZjM1
11
- MjUyOWJmNmE1ZTliMWY0ZWJiNzJkMzVmY2JmYzYyMWEyYWNkOGU=
9
+ ZTViMDU1MGRjMDZjNjYyNzg3YzMxOTYyZjZmODkzNzA3ZWViOTQ1ZjIwNThh
10
+ YzhhZjhmMGNhZjg3ODYyNDdmZjAyNDIyNDE2YWJlNWY1NTg3YjIyMjhmY2Vi
11
+ ZGIzZTQ3NmJlYWI3MzI4MmU4ZDU2MzY0MzU4NzZkY2E3NjVjZDQ=
12
12
  data.tar.gz: !binary |-
13
- NGM4YTE2NzViMzVkNTQyZGFiYzFlNjMwYWRkYTI1YTg0MjA2NzRkYThlZGQ5
14
- Yjc5Yzk1MjFhNGFkNmI1MjExMjhmMmYyNDMyOWIxZTA5ZGNjNWUzZGE3Njkz
15
- YzY3YjI1OTA5ZTc4OTViMWZmNDMxYjJiYzcwOGQ4OTFmMjIwNTA=
13
+ ZWY3YjI3MmYyNDhiMzQ1YTJiNGFiYTQ2Yjc1Mzg1NTk3NGE1ODEwZWJmMmFi
14
+ OWMwZWM2N2QwYjdiZDM1MzgyMGU4YTY3ZTRiNTNiNzFlMWQxMDk0Y2ZhNDJl
15
+ ODFmOTNjZWNiMzE2ZDA1ZTAxNjFhZWFjMGMwOWIwNTBlOGEzYmQ=
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- carabiner (0.0.1)
4
+ carabiner (0.0.2.pre.alpha2)
5
5
  bubble-wrap
6
6
  motion-require (~> 0.0.3)
7
7
  rake
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # Carabiner [![Build Status](https://travis-ci.org/mordaroso/carabiner.png)](https://travis-ci.org/mordaroso/carabiner)
1
+ # Carabiner [![Build Status](https://travis-ci.org/mordaroso/carabiner.png)](https://travis-ci.org/mordaroso/carabiner) [![Gem Version](https://badge.fury.io/rb/carabiner.png)](http://badge.fury.io/rb/carabiner)
2
2
 
3
3
  Rubymotion wrapper for the easy access to the keychain.
4
4
 
@@ -6,8 +6,82 @@ Rubymotion wrapper for the easy access to the keychain.
6
6
 
7
7
  **This gem is still under heavy development and will be released soon. Please be paitent.**
8
8
 
9
+ ## Installation
10
+
11
+ Install the gem
12
+ ```bash
13
+ gem install carabiner
14
+ ```
15
+
16
+ And add it to your Rakefile
17
+ ```ruby
18
+ require 'carabiner'
19
+ ```
20
+
21
+ Or use [Bundler](http://gembundler.com/) to manage your gem dependencies
22
+ ```ruby
23
+ gem 'carabiner'
24
+ ```
25
+
26
+ ## Usage
27
+
28
+ First add the Security framwork and the entitlement setting to your Rakefile.
29
+
30
+ ```ruby
31
+ app.frameworks += ['Security']
32
+
33
+ app.entitlements['keychain-access-groups'] = [
34
+ app.seed_id + '.' + app.identifier
35
+ ]
36
+ ```
37
+
38
+ Initialize a keychain item with an unique identifier as a finder hash. If it already exists the keychain data will be available otherwise it will set it up.
39
+
40
+ ```ruby
41
+ @item = Carabiner::PasswordItem.new generic: 'YourKeyChainItemIdentifier'
42
+ ```
43
+
44
+ After the initialization you have access to all kSecClassGenericPassword attributes with getter and setter methods.
45
+ *Note: These values are not secure.*
46
+ ```ruby
47
+ @item.access_group # The corresponding value is of type CFStringRef and indicates which access group an item is in.
48
+ @item.creation_time # The corresponding value is of type CFDateRef and represents the date the item was created. Read only.
49
+ @item.modifaction_date # The corresponding value is of type CFDateRef and represents the last time the item was updated. Read only.
50
+ @item.description # The corresponding value is of type CFStringRef and specifies a user-visible string describing this kind of item (for example, "Disk image password").
51
+ @item.comment # The corresponding value is of type CFStringRef and contains the user-editable comment for this item.
52
+ @item.creator # The corresponding value is of type CFNumberRef and represents the item's creator. This number is the unsigned integer representation of a four-character code (for example, 'aCrt').
53
+ @item.type # The corresponding value is of type CFNumberRef and represents the item's type. This number is the unsigned integer representation of a four-character code (for example, 'aTyp').
54
+ @item.label # The corresponding value is of type CFStringRef and contains the user-visible label for this item.
55
+ @item.is_invisible # The corresponding value is of type CFBooleanRef and is kCFBooleanTrue if the item is invisible (that is, should not be displayed).
56
+ @item.is_negative # The corresponding value is of type CFBooleanRef and indicates whether there is a valid password associated with this keychain item. This is useful if your application doesn't want a password for some particular service to be stored in the keychain, but prefers that it always be entered by the user.
57
+ @item.account # The corresponding value is of type CFStringRef and contains an account name. Items of class kSecClassGenericPassword and kSecClassInternetPassword have this attribute.
58
+ @item.service # The corresponding value is a string of type CFStringRef that represents the service associated with this item. Items of class kSecClassGenericPassword have this attribute.
59
+ @item.generic # The corresponding value is of type CFDataRef and contains a user-defined attribute. Items of class kSecClassGenericPassword have this attribute.
60
+ ```
61
+
62
+ Set and get the secure password
63
+ ```ruby
64
+ @item.password = 'secure'
65
+ @item.password
66
+ ```
67
+
68
+ And then save the item to the keychain.
69
+ ```ruby
70
+ @item.save!
71
+ ```
72
+
73
+ To delete the data use ```@item.delete!``` or ```@item.reset!```.
74
+
75
+ ## Documentation
76
+
77
+ See Apples [Keychain Services Reference](https://developer.apple.com/library/mac/documentation/Security/Reference/keychainservices/Reference/reference.html) for more information
78
+
9
79
  ## TODOs
10
80
 
11
- * Better error handling
12
- * Code Documentation
13
- * README
81
+ * Better Documentation
82
+ * OSX Support
83
+ * Secure Notes
84
+ * Certificates
85
+ * Keys
86
+
87
+ Feel free to fork and submit pull requests!
@@ -4,7 +4,7 @@ class AppDelegate
4
4
  @window.rootViewController = SettingsController.alloc.init
5
5
  @window.rootViewController.wantsFullScreenLayout = true
6
6
  @window.makeKeyAndVisible
7
- return true
7
+ true
8
8
  end
9
9
 
10
10
  def user
@@ -2,7 +2,7 @@ class User
2
2
  attr_accessor :username, :password
3
3
 
4
4
  def initialize
5
- @keychain = Carabiner::PasswordKeychainItem.new 'ExampleAppLoginData'
5
+ @keychain = Carabiner::PasswordItem.new :generic => 'ExampleAppLoginData'
6
6
  load
7
7
  end
8
8
 
@@ -0,0 +1,160 @@
1
+ module Carabiner
2
+ class BaseItem
3
+ attr_accessor :query, :persistent, :identifiers
4
+
5
+ def self.attributes(attrs = nil)
6
+ if attrs
7
+ @attributes = attrs
8
+ attr_accessor *attrs.keys
9
+ else
10
+ @attributes ||= {}
11
+ end
12
+ end
13
+
14
+ def self.sec_class sec_class = nil
15
+ @sec_class ||= sec_class
16
+ end
17
+
18
+ NoErr = 0
19
+
20
+ def initialize identifiers
21
+ @identifiers = identifiers
22
+ reset_to_identifiers
23
+
24
+ self.query = data
25
+ query[KSecClass] = self.class.sec_class
26
+
27
+ if BubbleWrap::Device.simulator?
28
+ query.delete(KSecAttrAccessGroup)
29
+ end
30
+
31
+ query[KSecMatchLimit] = KSecMatchLimitOne
32
+ query[KSecReturnAttributes] = KCFBooleanTrue
33
+
34
+ tempQuery = NSDictionary.dictionaryWithDictionary query
35
+ outDictionaryPtr = Pointer.new(:object)
36
+ if !(SecItemCopyMatching(tempQuery, outDictionaryPtr) == NoErr)
37
+ reset!
38
+ self.data = self.data.merge identifiers
39
+ self.persistent = false
40
+
41
+ unless Device.simulator?
42
+ query[KSecAttrAccessGroup] = identifiers[:access_group]
43
+ end
44
+ else
45
+ self.persistent = true
46
+ self.data = secItemFormatToDictionary(outDictionaryPtr[0])
47
+ end
48
+ end
49
+
50
+ def save!
51
+ writeToKeychain
52
+ self.persistent = true
53
+ true
54
+ end
55
+
56
+ def delete!
57
+ if persistent?
58
+ tempDictionary = dictionaryToSecItemFormat(data)
59
+ result = SecItemDelete(tempDictionary)
60
+ if result != NoErr && result != ErrSecItemNotFound
61
+ raise KeychainReturnCodeException.new "Problem deleting current dictionary.", result
62
+ end
63
+ self.persistent = false
64
+ end
65
+ self.data = {}
66
+ true
67
+ end
68
+
69
+ def reset!
70
+ delete! unless data.empty?
71
+ reset_to_identifiers
72
+ true
73
+ end
74
+
75
+ def self.key_accepted? key
76
+ attributes.values.include? key
77
+ end
78
+
79
+ def persistent?
80
+ persistent
81
+ end
82
+
83
+ def data
84
+ self.class.attributes.keys.inject({}) do |memo, getter_name|
85
+ constant = self.class.attributes[getter_name]
86
+ value = send(getter_name)
87
+ memo[constant] = value if value
88
+ memo
89
+ end
90
+ end
91
+
92
+ def data=(hash)
93
+ self.class.attributes.each do |getter_name, constant|
94
+ send("#{getter_name}=", hash[constant])
95
+ end
96
+ end
97
+
98
+ private
99
+
100
+ def reset_to_identifiers
101
+ identifiers.each do |getter_name, value|
102
+ send("#{getter_name}=", value)
103
+ end
104
+ end
105
+
106
+ def dictionaryToSecItemFormat dictionaryToConvert
107
+ returnDictionary = NSMutableDictionary.dictionaryWithDictionary dictionaryToConvert
108
+ returnDictionary[KSecClass] = self.class.sec_class
109
+ passwordString = dictionaryToConvert[KSecValueData]
110
+
111
+ returnDictionary[KSecValueData] = passwordString.dataUsingEncoding(NSUTF8StringEncoding)
112
+ returnDictionary
113
+ end
114
+
115
+ def secItemFormatToDictionary dictionaryToConvert
116
+ returnDictionary = NSMutableDictionary.dictionaryWithDictionary dictionaryToConvert
117
+ returnDictionary[KSecReturnData] = KCFBooleanTrue
118
+ returnDictionary[KSecClass] = self.class.sec_class
119
+
120
+ passwordDataPtr = Pointer.new(:object)
121
+
122
+ result = SecItemCopyMatching(returnDictionary, passwordDataPtr)
123
+ if result == NoErr
124
+ returnDictionary.delete KSecReturnData
125
+ passwordData = passwordDataPtr[0]
126
+ password = NSString.alloc.initWithBytes(passwordData.bytes, length: passwordData.length, encoding: NSUTF8StringEncoding)
127
+ returnDictionary[KSecValueData] = password
128
+ else
129
+ raise KeychainReturnCodeException.new "Serious error, no matching item found in the keychain.", result
130
+ end
131
+
132
+ returnDictionary
133
+ end
134
+
135
+ def writeToKeychain
136
+ attributesPtr = Pointer.new(:object)
137
+ if SecItemCopyMatching(query, attributesPtr) == NoErr
138
+ query = NSMutableDictionary.dictionaryWithDictionary attributesPtr[0]
139
+
140
+ query[KSecClass] = self.class.sec_class
141
+ attributes_to_update = dictionaryToSecItemFormat data
142
+ attributes_to_update.delete_if { |key, value| !self.class.key_accepted? key }
143
+
144
+ if Device.simulator?
145
+ attributes_to_update.delete KSecAttrAccessGroup
146
+ end
147
+
148
+ result = SecItemUpdate(query, attributes_to_update)
149
+ unless result == NoErr
150
+ raise KeychainReturnCodeException.new "Couldn't update the Keychain Item.", result
151
+ end
152
+ else
153
+ result = SecItemAdd(dictionaryToSecItemFormat(data), nil)
154
+ unless result == NoErr
155
+ raise KeychainReturnCodeException.new "Couldn't add the Keychain Item.", result
156
+ end
157
+ end
158
+ end
159
+ end
160
+ end
@@ -0,0 +1,152 @@
1
+ module Carabiner
2
+ class InternetPasswordItem < BaseItem
3
+ # These are the default constants and their respective types,
4
+ # available for the KSecClassInternetPassword Keychain Item class:
5
+ #
6
+ # See the header file Security/SecItem.h for more details.
7
+ attributes({
8
+ # The corresponding value is of type CFStringRef and indicates which access group an item is in. Access groups can be used to share keychain items among two or more applications. For applications to share a keychain item, the applications must have a common access group listed in their keychain-access-groups entitlement, and the application adding the shared item to the keychain must specify this shared access-group name as the value for this key in the dictionary passed to the SecItemAdd function.
9
+ # An application can be a member of any number of access groups. By default, the SecItemUpdate, SecItemDelete, and SecItemCopyMatching functions search all the access groups an application is a member of. Include this key in the search dictionary for these functions to specify which access group is searched.
10
+ # A keychain item can be in only a single access group.
11
+ access_group: KSecAttrAccessGroup,
12
+
13
+ # The corresponding value is of type CFDateRef and represents the date the item was created. Read only.
14
+ creation_time: KSecAttrCreationDate,
15
+
16
+ # The corresponding value is of type CFDateRef and represents the last time the item was updated. Read only.
17
+ modifaction_date: KSecAttrModificationDate,
18
+
19
+ # The corresponding value is of type CFStringRef and specifies a user-visible string describing this kind of item (for example, "Disk image password").
20
+ description: KSecAttrDescription,
21
+
22
+ # The corresponding value is of type CFStringRef and contains the user-editable comment for this item.
23
+ comment: KSecAttrComment,
24
+
25
+ # The corresponding value is of type CFNumberRef and represents the item's creator. This number is the unsigned integer representation of a four-character code (for example, 'aCrt').
26
+ creator: KSecAttrCreator,
27
+
28
+ # The corresponding value is of type CFStringRef and contains the user-visible label for this item.
29
+ type: KSecAttrType,
30
+
31
+ # The corresponding value is of type CFStringRef and contains the user-visible label for this item.
32
+ label: KSecAttrLabel,
33
+
34
+ # The corresponding value is of type CFBooleanRef and is kCFBooleanTrue if the item is invisible (that is, should not be displayed).
35
+ is_invisible: KSecAttrIsInvisible,
36
+
37
+ # The corresponding value is of type CFBooleanRef and indicates whether there is a valid password associated with this keychain item. This is useful if your application doesn't want a password for some particular service to be stored in the keychain, but prefers that it always be entered by the user.
38
+ is_negative: KSecAttrIsNegative,
39
+
40
+ # The corresponding value is of type CFStringRef and contains an account name. Items of class kSecClassGenericPassword and kSecClassInternetPassword have this attribute.
41
+ account: KSecAttrAccount,
42
+
43
+ # The corresponding value is of type CFStringRef and represents the Internet security domain. Items of class kSecClassInternetPassword have this attribute.
44
+ security_domain: KSecAttrSecurityDomain,
45
+
46
+ # The corresponding value is of type CFStringRef and contains the server's domain name or IP address. Items of class kSecClassInternetPassword have this attribute.
47
+ server: KSecAttrServer,
48
+
49
+ # The corresponding value is of type CFNumberRef and denotes the protocol for this item (see “Protocol Values”). Items of class kSecClassInternetPassword have this attribute.
50
+ protocol: KSecAttrProtocol,
51
+
52
+ # The corresponding value is of type CFNumberRef and denotes the authentication scheme for this item (see “Authentication Type Values”).
53
+ authentication_type: KSecAttrAuthenticationType,
54
+
55
+ # The corresponding value is of type CFNumberRef and represents an Internet port number. Items of class kSecClassInternetPassword have this attribute.
56
+ port: KSecAttrPort,
57
+
58
+ # The corresponding value is of type CFStringRef and represents a path, typically the path component of the URL. Items of class kSecClassInternetPassword have this attribute.
59
+ path: KSecAttrPath,
60
+
61
+ # Data attribute key. A persistent reference to a credential can be stored on disk for later use or passed to other processes.
62
+ # The corresponding value is of type CFDataRef. For keys and password items, the data is secret (encrypted) and may require the user to enter a password for access.
63
+ password: KSecValueData
64
+ })
65
+
66
+ sec_class KSecClassInternetPassword
67
+
68
+ def self.authentication_type_values
69
+ {
70
+ ntlm: KSecAttrAuthenticationTypeNTLM,
71
+ msn: KSecAttrAuthenticationTypeMSN,
72
+ dpa: KSecAttrAuthenticationTypeDPA,
73
+ rpa: KSecAttrAuthenticationTypeRPA,
74
+ http_basic: KSecAttrAuthenticationTypeHTTPBasic,
75
+ http_digest: KSecAttrAuthenticationTypeHTTPDigest,
76
+ html_form: KSecAttrAuthenticationTypeHTMLForm,
77
+ default: KSecAttrAuthenticationTypeDefault
78
+ }
79
+ end
80
+
81
+ def self.protocol_values
82
+ {
83
+ ftp: KSecAttrProtocolFTP,
84
+ ftp_account: KSecAttrProtocolFTPAccount,
85
+ http: KSecAttrProtocolHTTP,
86
+ irc: KSecAttrProtocolIRC,
87
+ nntp: KSecAttrProtocolNNTP,
88
+ pop3: KSecAttrProtocolPOP3,
89
+ smtp: KSecAttrProtocolSMTP,
90
+ socks: KSecAttrProtocolSOCKS,
91
+ imap: KSecAttrProtocolIMAP,
92
+ ldap: KSecAttrProtocolLDAP,
93
+ apple_talk: KSecAttrProtocolAppleTalk,
94
+ afp: KSecAttrProtocolAFP,
95
+ telnet: KSecAttrProtocolTelnet,
96
+ ssh: KSecAttrProtocolSSH,
97
+ ftps: KSecAttrProtocolFTPS,
98
+ https: KSecAttrProtocolHTTPS,
99
+ http_proxy: KSecAttrProtocolHTTPProxy,
100
+ https_proxy: KSecAttrProtocolHTTPSProxy,
101
+ ftp_proxy: KSecAttrProtocolFTPProxy,
102
+ smb: KSecAttrProtocolSMB,
103
+ rtsp: KSecAttrProtocolRTSP,
104
+ rtsp_proxy: KSecAttrProtocolRTSPProxy,
105
+ daap: KSecAttrProtocolDAAP,
106
+ eppc: KSecAttrProtocolEPPC,
107
+ ipp: KSecAttrProtocolIPP,
108
+ nntps: KSecAttrProtocolNNTPS,
109
+ ldaps: KSecAttrProtocolLDAPS,
110
+ telnet_s: KSecAttrProtocolTelnetS,
111
+ imaps: KSecAttrProtocolIMAPS,
112
+ ircs: KSecAttrProtocolIRCS,
113
+ pop3_s: KSecAttrProtocolPOP3S
114
+ }
115
+ end
116
+
117
+ def protocol_sym
118
+ self.class.protocol_values.find {|k, v| v == @protocol }.first if @protocol
119
+ end
120
+
121
+ def protocol=(value)
122
+ if self.class.protocol_values.values.include? value
123
+ @protocol = value
124
+ else
125
+ new_protocol = self.class.protocol_values.find {|k, v| k == value }
126
+ @protocol = new_protocol.last if new_protocol
127
+ end
128
+ end
129
+
130
+ def authentication_type_sym
131
+ self.class.authentication_type_values.find {|k, v| v == @authentication_type }.first if @authentication_type
132
+ end
133
+
134
+ def authentication_type=(value)
135
+ if self.class.authentication_type_values.values.include? value
136
+ @authentication_type = value
137
+ else
138
+ new_authentication_type = self.class.authentication_type_values.find {|k, v| k == value }
139
+ @authentication_type = new_authentication_type.last if new_authentication_type
140
+ end
141
+ end
142
+
143
+ def reset!
144
+ super
145
+ self.account = ''
146
+ self.label = ''
147
+ self.description = ''
148
+ self.password = ''
149
+ true
150
+ end
151
+ end
152
+ end
@@ -0,0 +1,67 @@
1
+ module Carabiner
2
+ class PasswordItem < BaseItem
3
+
4
+ # These are the default constants and their respective types,
5
+ # available for the kSecClassGenericPassword Keychain Item class:
6
+ #
7
+ # See the header file Security/SecItem.h for more details.
8
+ attributes({
9
+ # The corresponding value is of type CFStringRef and indicates which access group an item is in. Access groups can be used to share keychain items among two or more applications. For applications to share a keychain item, the applications must have a common access group listed in their keychain-access-groups entitlement, and the application adding the shared item to the keychain must specify this shared access-group name as the value for this key in the dictionary passed to the SecItemAdd function.
10
+ # An application can be a member of any number of access groups. By default, the SecItemUpdate, SecItemDelete, and SecItemCopyMatching functions search all the access groups an application is a member of. Include this key in the search dictionary for these functions to specify which access group is searched.
11
+ # A keychain item can be in only a single access group.
12
+ access_group: KSecAttrAccessGroup,
13
+
14
+ # The corresponding value is of type CFDateRef and represents the date the item was created. Read only.
15
+ creation_time: KSecAttrCreationDate,
16
+
17
+ # The corresponding value is of type CFDateRef and represents the last time the item was updated. Read only.
18
+ modifaction_date: KSecAttrModificationDate,
19
+
20
+ # The corresponding value is of type CFStringRef and specifies a user-visible string describing this kind of item (for example, "Disk image password").
21
+ description: KSecAttrDescription,
22
+
23
+ # The corresponding value is of type CFStringRef and contains the user-editable comment for this item.
24
+ comment: KSecAttrComment,
25
+
26
+ # The corresponding value is of type CFNumberRef and represents the item's creator. This number is the unsigned integer representation of a four-character code (for example, 'aCrt').
27
+ creator: KSecAttrCreator,
28
+
29
+ # The corresponding value is of type CFNumberRef and represents the item's type. This number is the unsigned integer representation of a four-character code (for example, 'aTyp').
30
+ type: KSecAttrType,
31
+
32
+ # The corresponding value is of type CFStringRef and contains the user-visible label for this item.
33
+ label: KSecAttrLabel,
34
+
35
+ # The corresponding value is of type CFBooleanRef and is kCFBooleanTrue if the item is invisible (that is, should not be displayed).
36
+ is_invisible: KSecAttrIsInvisible,
37
+
38
+ # The corresponding value is of type CFBooleanRef and indicates whether there is a valid password associated with this keychain item. This is useful if your application doesn't want a password for some particular service to be stored in the keychain, but prefers that it always be entered by the user.
39
+ is_negative: KSecAttrIsNegative,
40
+
41
+ # The corresponding value is of type CFStringRef and contains an account name. Items of class kSecClassGenericPassword and kSecClassInternetPassword have this attribute.
42
+ account: KSecAttrAccount,
43
+
44
+ # The corresponding value is a string of type CFStringRef that represents the service associated with this item. Items of class kSecClassGenericPassword have this attribute.
45
+ service: KSecAttrService,
46
+
47
+ # The corresponding value is of type CFDataRef and contains a user-defined attribute. Items of class kSecClassGenericPassword have this attribute.
48
+ generic: KSecAttrGeneric,
49
+
50
+ # Data attribute key. A persistent reference to a credential can be stored on disk for later use or passed to other processes.
51
+ # The corresponding value is of type CFDataRef. For keys and password items, the data is secret (encrypted) and may require the user to enter a password for access.
52
+ password: KSecValueData
53
+ })
54
+
55
+ sec_class KSecClassGenericPassword
56
+
57
+ def reset!
58
+ super
59
+ self.account = ''
60
+ self.label = ''
61
+ self.description = ''
62
+ self.password = ''
63
+ true
64
+ end
65
+
66
+ end
67
+ end
@@ -1,3 +1,3 @@
1
1
  module Carabiner
2
- VERSION = "0.0.2-alpha1"
2
+ VERSION = "0.0.2.pre.alpha2"
3
3
  end
@@ -0,0 +1,38 @@
1
+ module Carabiner
2
+ describe InternetPasswordItem do
3
+ before do
4
+ @item = InternetPasswordItem.new :server => 'github.com', :protocol => :https
5
+ @item.password = 'secret'
6
+ @item.account = 'Test'
7
+ @item.authentication_type = :html_form
8
+ @item.save!
9
+ end
10
+
11
+ after do
12
+ @item.delete!
13
+ end
14
+
15
+ it 'initialize attributes' do
16
+ new_item = InternetPasswordItem.new :server => 'github.com', :protocol => :https
17
+ new_item.account.should == 'Test'
18
+ new_item.password.should == 'secret'
19
+ new_item.server.should == 'github.com'
20
+ new_item.protocol_sym.should == :https
21
+ new_item.authentication_type_sym.should == :html_form
22
+ new_item.persistent?.should == true
23
+ end
24
+
25
+ it 'reset!' do
26
+ @item.reset!
27
+ @item.account.should == ''
28
+ @item.password.should == ''
29
+ end
30
+
31
+ it 'delete!' do
32
+ @item.delete!
33
+ @item.account.should == nil
34
+ @item.password.should == nil
35
+ @item.persistent?.should == false
36
+ end
37
+ end
38
+ end
@@ -1,14 +1,18 @@
1
1
  module Carabiner
2
- describe PasswordKeychainItem do
2
+ describe PasswordItem do
3
3
  before do
4
- @item = PasswordKeychainItem.new 'TestPasswordItem'
4
+ @item = PasswordItem.new :generic => 'TestPasswordItem'
5
5
  @item.password = 'secret'
6
6
  @item.account = 'Test'
7
7
  @item.save!
8
8
  end
9
9
 
10
+ after do
11
+ @item.delete!
12
+ end
13
+
10
14
  it 'initialize attributes' do
11
- new_item = PasswordKeychainItem.new 'TestPasswordItem'
15
+ new_item = PasswordItem.new :generic => 'TestPasswordItem'
12
16
  new_item.account.should == 'Test'
13
17
  new_item.password.should == 'secret'
14
18
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: carabiner
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2.pre.alpha1
4
+ version: 0.0.2.pre.alpha2
5
5
  platform: ruby
6
6
  authors:
7
7
  - mordaroso
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-09-16 00:00:00.000000000 Z
11
+ date: 2013-09-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -100,15 +100,18 @@ files:
100
100
  - app/views/settings_view.rb
101
101
  - carabiner.gemspec
102
102
  - lib/carabiner.rb
103
+ - lib/carabiner/base_item.rb
104
+ - lib/carabiner/internet_password_item.rb
103
105
  - lib/carabiner/keychain_return_code_exception.rb
104
- - lib/carabiner/password_keychain_item.rb
106
+ - lib/carabiner/password_item.rb
105
107
  - lib/carabiner/version.rb
106
108
  - scripts/travis/add-key.sh
107
109
  - scripts/travis/profile/4A8AC2EE-F24B-4F4E-A6F0-67F9BC46B924.mobileprovision
108
110
  - scripts/travis/remove-key.sh
109
111
  - spec/main_spec.rb
112
+ - spec/models/internet_password_item_spec.rb
110
113
  - spec/models/keychain_return_code_exception_spec.rb
111
- - spec/models/password_keychain_item_spec.rb
114
+ - spec/models/password_item_spec.rb
112
115
  - spec/models/user_spec.rb
113
116
  homepage: http://rubygems.org/gems/carabiner
114
117
  licenses: []
@@ -135,7 +138,8 @@ specification_version: 4
135
138
  summary: Rubymotion wrapper for the keychain
136
139
  test_files:
137
140
  - spec/main_spec.rb
141
+ - spec/models/internet_password_item_spec.rb
138
142
  - spec/models/keychain_return_code_exception_spec.rb
139
- - spec/models/password_keychain_item_spec.rb
143
+ - spec/models/password_item_spec.rb
140
144
  - spec/models/user_spec.rb
141
145
  has_rdoc:
@@ -1,160 +0,0 @@
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