2525// THE SOFTWARE.
2626
2727import UIKit
28- import KeychainAccess
2928
3029/**
3130 The class for using Studyplus.
@@ -78,6 +77,9 @@ final public class Studyplus {
7877
7978 private let accessTokenStoreKey : String = " accessToken "
8079 private let usernameStoreKey : String = " username "
80+ private var serviceName : String {
81+ return " Studyplus_iOS_SDK_ \( consumerKey) "
82+ }
8183
8284 /// Opens the login screen by invoking the Studyplus application.
8385 /// If Studyplus app is not installed, open the Studyplus page in AppStore.
@@ -94,13 +96,7 @@ final public class Studyplus {
9496 ///
9597 /// Studyplusアプリとの連携を解除します。
9698 public func logout( ) {
97-
98- let chain = keychain ( )
99- do {
100- try chain. remove ( usernameStoreKey)
101- try chain. remove ( accessTokenStoreKey)
102- } catch {
103- }
99+ deleteKey ( )
104100 }
105101
106102 /// Returns to whether or not it is connected with Studyplus application.
@@ -118,12 +114,22 @@ final public class Studyplus {
118114 ///
119115 /// - Returns: accessToken
120116 public func accessToken( ) -> String ? {
121-
122- do {
123- return try keychain ( ) . get ( accessTokenStoreKey)
124- } catch {
117+ let query = [
118+ kSecClass: kSecClassGenericPassword,
119+ kSecAttrService: serviceName,
120+ kSecAttrSynchronizable: kSecAttrSynchronizableAny,
121+ kSecMatchLimit: kSecMatchLimitOne,
122+ kSecReturnData: true ,
123+ kSecAttrAccount: accessTokenStoreKey
124+ ] as CFDictionary
125+
126+ var item : CFTypeRef ?
127+ let status = SecItemCopyMatching ( query, & item)
128+ guard status == errSecSuccess, let data = item as? Data else {
125129 return nil
126130 }
131+
132+ return String ( data: data, encoding: . utf8)
127133 }
128134
129135 /// Username of Studyplus account. It is set when the auth or login is successful.
@@ -132,12 +138,22 @@ final public class Studyplus {
132138 ///
133139 /// - Returns: username
134140 public func username( ) -> String ? {
135-
136- do {
137- return try keychain ( ) . get ( usernameStoreKey)
138- } catch {
141+ let query = [
142+ kSecClass: kSecClassGenericPassword,
143+ kSecAttrService: serviceName,
144+ kSecAttrSynchronizable: kSecAttrSynchronizableAny,
145+ kSecMatchLimit: kSecMatchLimitOne,
146+ kSecReturnData: true ,
147+ kSecAttrAccount: usernameStoreKey
148+ ] as CFDictionary
149+
150+ var item : CFTypeRef ?
151+ let status = SecItemCopyMatching ( query, & item)
152+ guard status == errSecSuccess, let data = item as? Data else {
139153 return nil
140154 }
155+
156+ return String ( data: data, encoding: . utf8)
141157 }
142158
143159 /// Posts a new study record to Studyplus.
@@ -148,7 +164,9 @@ final public class Studyplus {
148164 /// - studyRecord: see StudyplusRecord
149165 /// - success: callback when success to post the studyRecord
150166 /// - failure: callback when failure to post the studyRecord
151- public func post( studyRecord: StudyplusRecord , success: @escaping ( ) -> Void , failure: @escaping ( _ error: StudyplusError ) -> Void ) {
167+ public func post( studyRecord: StudyplusRecord ,
168+ success: @escaping ( ) -> Void ,
169+ failure: @escaping ( _ error: StudyplusError ) -> Void ) {
152170
153171 guard StudyplusRecord . durationRange ~= Int ( studyRecord. duration) else {
154172 failure ( . postRecordFailed)
@@ -204,19 +222,36 @@ final public class Studyplus {
204222
205223 switch appDelegateUrl. pathComponents [ 1 ] {
206224 case " success " :
207-
208- let accessToken : String = appDelegateUrl. pathComponents [ 2 ] . trimmingCharacters ( in: . whitespacesAndNewlines)
209- let username : String = appDelegateUrl. pathComponents [ 3 ] . trimmingCharacters ( in: . whitespacesAndNewlines)
210-
211- let chain = keychain ( )
212- do {
213- try chain. set ( accessToken, key: accessTokenStoreKey)
214- try chain. set ( username, key: usernameStoreKey)
225+ let accessToken : Data = appDelegateUrl
226+ . pathComponents [ 2 ]
227+ . trimmingCharacters ( in: . whitespacesAndNewlines)
228+ . data ( using: . utf8, allowLossyConversion: false ) !
229+ let username : Data = appDelegateUrl
230+ . pathComponents [ 3 ]
231+ . trimmingCharacters ( in: . whitespacesAndNewlines)
232+ . data ( using: . utf8, allowLossyConversion: false ) !
233+
234+ deleteKey ( )
235+ let statusAccessToken = SecItemAdd ( [
236+ kSecClass: kSecClassGenericPassword,
237+ kSecAttrService: serviceName,
238+ kSecAttrSynchronizable: kSecAttrSynchronizableAny,
239+ kSecAttrAccount: accessTokenStoreKey,
240+ kSecValueData: accessToken
241+ ] as CFDictionary , nil )
242+ let statusUsername = SecItemAdd ( [
243+ kSecClass: kSecClassGenericPassword,
244+ kSecAttrService: serviceName,
245+ kSecAttrSynchronizable: kSecAttrSynchronizableAny,
246+ kSecAttrAccount: usernameStoreKey,
247+ kSecValueData: username
248+ ] as CFDictionary , nil )
249+
250+ if statusAccessToken == noErr && statusUsername == noErr {
215251 delegate? . studyplusDidSuccessToLogin ( )
216- } catch {
252+ } else {
217253 delegate? . studyplusDidFailToLogin ( error: . unknownReason( " Could not access Keychain. " ) )
218254 }
219-
220255 case " fail " :
221256
222257 if let errorCode: Int = Int ( appDelegateUrl. pathComponents [ 2 ] ) {
@@ -231,7 +266,7 @@ final public class Studyplus {
231266
232267 default :
233268 #if DEBUG
234- print ( " StudyplusSDK: Unknown format: \( appDelegateUrl. absoluteString) " )
269+ print ( " StudyplusSDK: Unknown format: \( appDelegateUrl. absoluteString) " )
235270 #endif
236271 return false
237272 }
@@ -290,11 +325,6 @@ final public class Studyplus {
290325 self . consumerSecret = consumerSecret
291326 }
292327
293- private func keychain( ) -> Keychain {
294- let serviceName : String = " Studyplus_iOS_SDK_ \( consumerKey) "
295- return Keychain ( service: serviceName)
296- }
297-
298328 private func openStudyplus( command: String ) {
299329
300330 guard UIApplication . shared. canOpenURL ( URL ( string: " studyplus:// " ) !) else {
@@ -335,4 +365,12 @@ final public class Studyplus {
335365
336366 return true
337367 }
368+
369+ private func deleteKey( ) {
370+ SecItemDelete ( [
371+ kSecClass: kSecClassGenericPassword,
372+ kSecAttrService: serviceName,
373+ kSecAttrSynchronizable: kSecAttrSynchronizableAny
374+ ] as CFDictionary )
375+ }
338376}
0 commit comments