Commit ffa729b4edd157870c6a369f0a5ded4f651a66ef
1 parent
e5e8a90c
配置
Showing
9 changed files
with
982 additions
and
8 deletions
CNLiveCMineModule.podspec
| ... | ... | @@ -29,14 +29,33 @@ TODO: Add long description of the pod here. |
| 29 | 29 | # s.social_media_url = 'https://twitter.com/<TWITTER_USERNAME>' |
| 30 | 30 | |
| 31 | 31 | s.ios.deployment_target = '10.0' |
| 32 | - | |
| 33 | - s.source_files = 'CNLiveCMineModule/Classes/**/*' | |
| 32 | + s.prefix_header_contents = '#import "CNLiveCMineModule.h"' | |
| 33 | + s.static_framework = true | |
| 34 | + | |
| 35 | + | |
| 34 | 36 | |
| 35 | 37 | # s.resource_bundles = { |
| 36 | 38 | # 'CNLiveCMineModule' => ['CNLiveCMineModule/Assets/*.png'] |
| 37 | 39 | # } |
| 38 | 40 | |
| 39 | - # s.public_header_files = 'Pod/Classes/**/*.h' | |
| 41 | + s.public_header_files = 'Pod/Classes/**/*.h' | |
| 40 | 42 | # s.frameworks = 'UIKit', 'MapKit' |
| 41 | 43 | # s.dependency 'AFNetworking', '~> 2.3' |
| 44 | + s.dependency 'CNLiveBaseKit' | |
| 45 | + s.dependency 'CNLiveNewTripartiteManagement/YYCategories' | |
| 46 | + s.dependency 'CNLiveNewTripartiteManagement/YYText' | |
| 47 | + s.dependency 'CNLiveNewTripartiteManagement/QMUIKit' | |
| 48 | + s.dependency 'CNLiveNewTripartiteManagement/Masonry' | |
| 49 | + s.dependency 'CNLiveCustomUI' | |
| 50 | + s.dependency 'CNLiveRequestBastKit' | |
| 51 | + s.dependency 'CNLiveBusinessTools' | |
| 52 | + s.dependency 'CNLiveNewTripartiteManagement/SDWebImage' | |
| 53 | + s.dependency 'CNLiveNewTripartiteManagement/MJExtension' | |
| 54 | + s.dependency 'CNLiveBusinessBaseModule' | |
| 55 | + s.dependency 'JXCategoryView' | |
| 56 | + s.dependency 'CNLiveSDK/CNLiveStat' | |
| 57 | + s.dependency 'CNLivePhotoBrowser' | |
| 58 | + s.dependency 'CNLiveNewIMAManagerKit' | |
| 59 | + s.dependency 'libksygpulive' | |
| 42 | 60 | end |
| 61 | + | ... | ... |
CNLiveCMineModule/Classes/Manager/CNLiveCMineDefine.h
0 → 100644
| 1 | +// | |
| 2 | +// CNLiveCMineDefine.h | |
| 3 | +// Pods | |
| 4 | +// | |
| 5 | +// Created by CNLive on 2021/12/21. | |
| 6 | +// | |
| 7 | + | |
| 8 | +#ifndef CNLiveCMineDefine_h | |
| 9 | +#define CNLiveCMineDefine_h | |
| 10 | + | |
| 11 | +#define RGBCOLOR(r,g,b) \ | |
| 12 | +[UIColor colorWithRed:r/256.f green:g/256.f blue:b/256.f alpha:1.f] | |
| 13 | + | |
| 14 | +#define RGBACOLOR(r,g,b,a) \ | |
| 15 | +[UIColor colorWithRed:r/256.f green:g/256.f blue:b/256.f alpha:a] | |
| 16 | + | |
| 17 | +//协议调取方法 | |
| 18 | +#define CNMessageSend(instance,protocol,message) [(id<protocol>)(instance) message] | |
| 19 | + | |
| 20 | + | |
| 21 | +#endif /* CNLiveCMineDefine_h */ | ... | ... |
CNLiveCMineModule/Classes/Manager/CNLiveCMineModule.h
0 → 100644
| 1 | +// | |
| 2 | +// CNLiveCMineModule.h | |
| 3 | +// Pods | |
| 4 | +// | |
| 5 | +// Created by CNLive on 2021/12/21. | |
| 6 | +// | |
| 7 | + | |
| 8 | +#ifndef CNLiveCMineModule_h | |
| 9 | +#define CNLiveCMineModule_h | |
| 10 | + | |
| 11 | +#import <CNLiveBaseKit/CNLiveBaseKit.h> | |
| 12 | +#import "CNLiveCMineDefine.h" | |
| 13 | +#import <YYCategories/YYCategories.h> | |
| 14 | +#import <QMUIKit/QMUIKit.h> | |
| 15 | +#import <Masonry/Masonry.h> | |
| 16 | +#import <SDWebImage/SDWebImage.h> | |
| 17 | +#import <MJExtension/MJExtension.h> | |
| 18 | +#import <CNLiveBusinessTools/CNLiveBusinessTools.h> | |
| 19 | +#import <YYText/YYText.h> | |
| 20 | +#import <CNLiveBusinessBaseModule/CNLiveBusinessBaseModule.h> | |
| 21 | +#import <JXCategoryView/JXCategoryView.h> | |
| 22 | +#import <CNLivePhotoBrowser/UIViewController+CNLivePhotoBrowserStatusBar.h> | |
| 23 | +#import <CNLiveNewIMAManagerKit/CNLiveNewIMAManagerKit.h> | |
| 24 | + | |
| 25 | +#endif /* CNLiveCMineModule_h */ | ... | ... |
CNLiveCMineModule/Classes/Manager/YYKeychain.h
0 → 100644
| 1 | +// | |
| 2 | +// YYKeychain.h | |
| 3 | +// YYKit <https://github.com/ibireme/YYKit> | |
| 4 | +// | |
| 5 | +// Created by ibireme on 14/10/15. | |
| 6 | +// Copyright (c) 2015 ibireme. | |
| 7 | +// | |
| 8 | +// This source code is licensed under the MIT-style license found in the | |
| 9 | +// LICENSE file in the root directory of this source tree. | |
| 10 | +// | |
| 11 | + | |
| 12 | +#import <Foundation/Foundation.h> | |
| 13 | + | |
| 14 | +@class YYKeychainItem; | |
| 15 | + | |
| 16 | +NS_ASSUME_NONNULL_BEGIN | |
| 17 | + | |
| 18 | +/** | |
| 19 | + A wrapper for system keychain API. | |
| 20 | + | |
| 21 | + Inspired by [SSKeychain](https://github.com/soffes/sskeychain) 😜 | |
| 22 | + */ | |
| 23 | +@interface YYKeychain : NSObject | |
| 24 | + | |
| 25 | +#pragma mark - Convenience method for keychain | |
| 26 | +///============================================================================= | |
| 27 | +/// @name Convenience method for keychain | |
| 28 | +///============================================================================= | |
| 29 | + | |
| 30 | +/** | |
| 31 | + Returns the password for a given account and service, or `nil` if not found or | |
| 32 | + an error occurs. | |
| 33 | + | |
| 34 | + @param serviceName The service for which to return the corresponding password. | |
| 35 | + This value must not be nil. | |
| 36 | + | |
| 37 | + @param account The account for which to return the corresponding password. | |
| 38 | + This value must not be nil. | |
| 39 | + | |
| 40 | + @param error On input, a pointer to an error object. If an error occurs, | |
| 41 | + this pointer is set to an actual error object containing the error information. | |
| 42 | + You may specify nil for this parameter if you do not want the error information. | |
| 43 | + See `YYKeychainErrorCode`. | |
| 44 | + | |
| 45 | + @return Password string, or nil when not found or error occurs. | |
| 46 | + */ | |
| 47 | ++ (nullable NSString *)getPasswordForService:(NSString *)serviceName | |
| 48 | + account:(NSString *)account | |
| 49 | + error:(NSError **)error; | |
| 50 | ++ (nullable NSString *)getPasswordForService:(NSString *)serviceName | |
| 51 | + account:(NSString *)account; | |
| 52 | + | |
| 53 | +/** | |
| 54 | + Deletes a password from the Keychain. | |
| 55 | + | |
| 56 | + @param serviceName The service for which to return the corresponding password. | |
| 57 | + This value must not be nil. | |
| 58 | + | |
| 59 | + @param account The account for which to return the corresponding password. | |
| 60 | + This value must not be nil. | |
| 61 | + | |
| 62 | + @param error On input, a pointer to an error object. If an error occurs, | |
| 63 | + this pointer is set to an actual error object containing the error information. | |
| 64 | + You may specify nil for this parameter if you do not want the error information. | |
| 65 | + See `YYKeychainErrorCode`. | |
| 66 | + | |
| 67 | + @return Whether succeed. | |
| 68 | + */ | |
| 69 | ++ (BOOL)deletePasswordForService:(NSString *)serviceName account:(NSString *)account error:(NSError **)error; | |
| 70 | ++ (BOOL)deletePasswordForService:(NSString *)serviceName account:(NSString *)account; | |
| 71 | + | |
| 72 | +/** | |
| 73 | + Insert or update the password for a given account and service. | |
| 74 | + | |
| 75 | + @param password The new password. | |
| 76 | + | |
| 77 | + @param serviceName The service for which to return the corresponding password. | |
| 78 | + This value must not be nil. | |
| 79 | + | |
| 80 | + @param account The account for which to return the corresponding password. | |
| 81 | + This value must not be nil. | |
| 82 | + | |
| 83 | + @param error On input, a pointer to an error object. If an error occurs, | |
| 84 | + this pointer is set to an actual error object containing the error information. | |
| 85 | + You may specify nil for this parameter if you do not want the error information. | |
| 86 | + See `YYKeychainErrorCode`. | |
| 87 | + | |
| 88 | + @return Whether succeed. | |
| 89 | + */ | |
| 90 | ++ (BOOL)setPassword:(NSString *)password | |
| 91 | + forService:(NSString *)serviceName | |
| 92 | + account:(NSString *)account | |
| 93 | + error:(NSError **)error; | |
| 94 | ++ (BOOL)setPassword:(NSString *)password | |
| 95 | + forService:(NSString *)serviceName | |
| 96 | + account:(NSString *)account; | |
| 97 | + | |
| 98 | + | |
| 99 | +#pragma mark - Full query for keychain (SQL-like) | |
| 100 | +///============================================================================= | |
| 101 | +/// @name Full query for keychain (SQL-like) | |
| 102 | +///============================================================================= | |
| 103 | + | |
| 104 | +/** | |
| 105 | + Insert an item into keychain. | |
| 106 | + | |
| 107 | + @discussion The service,account,password is required. If there's item exist | |
| 108 | + already, an error occurs and insert fail. | |
| 109 | + | |
| 110 | + @param item The item to insert. | |
| 111 | + | |
| 112 | + @param error On input, a pointer to an error object. If an error occurs, | |
| 113 | + this pointer is set to an actual error object containing the error information. | |
| 114 | + You may specify nil for this parameter if you do not want the error information. | |
| 115 | + See `YYKeychainErrorCode`. | |
| 116 | + | |
| 117 | + @return Whether succeed. | |
| 118 | + */ | |
| 119 | ++ (BOOL)insertItem:(YYKeychainItem *)item error:(NSError **)error; | |
| 120 | ++ (BOOL)insertItem:(YYKeychainItem *)item; | |
| 121 | + | |
| 122 | +/** | |
| 123 | + Update item in keychain. | |
| 124 | + | |
| 125 | + @discussion The service,account,password is required. If there's no item exist | |
| 126 | + already, an error occurs and insert fail. | |
| 127 | + | |
| 128 | + @param item The item to insert. | |
| 129 | + | |
| 130 | + @param error On input, a pointer to an error object. If an error occurs, | |
| 131 | + this pointer is set to an actual error object containing the error information. | |
| 132 | + You may specify nil for this parameter if you do not want the error information. | |
| 133 | + See `YYKeychainErrorCode`. | |
| 134 | + | |
| 135 | + @return Whether succeed. | |
| 136 | + */ | |
| 137 | ++ (BOOL)updateItem:(YYKeychainItem *)item error:(NSError **)error; | |
| 138 | ++ (BOOL)updateItem:(YYKeychainItem *)item; | |
| 139 | + | |
| 140 | +/** | |
| 141 | + Delete items from keychain. | |
| 142 | + | |
| 143 | + @discussion The service,account,password is required. If there's item exist | |
| 144 | + already, an error occurs and insert fail. | |
| 145 | + | |
| 146 | + @param item The item to update. | |
| 147 | + | |
| 148 | + @param error On input, a pointer to an error object. If an error occurs, | |
| 149 | + this pointer is set to an actual error object containing the error information. | |
| 150 | + You may specify nil for this parameter if you do not want the error information. | |
| 151 | + See `YYKeychainErrorCode`. | |
| 152 | + | |
| 153 | + @return Whether succeed. | |
| 154 | + */ | |
| 155 | ++ (BOOL)deleteItem:(YYKeychainItem *)item error:(NSError **)error; | |
| 156 | ++ (BOOL)deleteItem:(YYKeychainItem *)item; | |
| 157 | + | |
| 158 | +/** | |
| 159 | + Find an item from keychain. | |
| 160 | + | |
| 161 | + @discussion The service,account is optinal. It returns only one item if there | |
| 162 | + exist multi. | |
| 163 | + | |
| 164 | + @param item The item for query. | |
| 165 | + | |
| 166 | + @param error On input, a pointer to an error object. If an error occurs, | |
| 167 | + this pointer is set to an actual error object containing the error information. | |
| 168 | + You may specify nil for this parameter if you do not want the error information. | |
| 169 | + See `YYKeychainErrorCode`. | |
| 170 | + | |
| 171 | + @return An item or nil. | |
| 172 | + */ | |
| 173 | ++ (nullable YYKeychainItem *)selectOneItem:(YYKeychainItem *)item error:(NSError **)error; | |
| 174 | ++ (nullable YYKeychainItem *)selectOneItem:(YYKeychainItem *)item; | |
| 175 | + | |
| 176 | +/** | |
| 177 | + Find all items matches the query. | |
| 178 | + | |
| 179 | + @discussion The service,account is optinal. It returns all item matches by the | |
| 180 | + query. | |
| 181 | + | |
| 182 | + @param item The item for query. | |
| 183 | + | |
| 184 | + @param error On input, a pointer to an error object. If an error occurs, | |
| 185 | + this pointer is set to an actual error object containing the error information. | |
| 186 | + You may specify nil for this parameter if you do not want the error information. | |
| 187 | + See `YYKeychainErrorCode`. | |
| 188 | + | |
| 189 | + @return An array of YYKeychainItem. | |
| 190 | + */ | |
| 191 | ++ (nullable NSArray<YYKeychainItem *> *)selectItems:(YYKeychainItem *)item error:(NSError **)error; | |
| 192 | ++ (nullable NSArray<YYKeychainItem *> *)selectItems:(YYKeychainItem *)item; | |
| 193 | + | |
| 194 | +@end | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | +#pragma mark - Const | |
| 200 | + | |
| 201 | +/** | |
| 202 | + Error code in YYKeychain API. | |
| 203 | + */ | |
| 204 | +typedef NS_ENUM (NSUInteger, YYKeychainErrorCode) { | |
| 205 | + YYKeychainErrorUnimplemented = 1, ///< Function or operation not implemented. | |
| 206 | + YYKeychainErrorIO, ///< I/O error (bummers) | |
| 207 | + YYKeychainErrorOpWr, ///< File already open with with write permission. | |
| 208 | + YYKeychainErrorParam, ///< One or more parameters passed to a function where not valid. | |
| 209 | + YYKeychainErrorAllocate, ///< Failed to allocate memory. | |
| 210 | + YYKeychainErrorUserCancelled, ///< User cancelled the operation. | |
| 211 | + YYKeychainErrorBadReq, ///< Bad parameter or invalid state for operation. | |
| 212 | + YYKeychainErrorInternalComponent, ///< Internal... | |
| 213 | + YYKeychainErrorNotAvailable, ///< No keychain is available. You may need to restart your computer. | |
| 214 | + YYKeychainErrorDuplicateItem, ///< The specified item already exists in the keychain. | |
| 215 | + YYKeychainErrorItemNotFound, ///< The specified item could not be found in the keychain. | |
| 216 | + YYKeychainErrorInteractionNotAllowed, ///< User interaction is not allowed. | |
| 217 | + YYKeychainErrorDecode, ///< Unable to decode the provided data. | |
| 218 | + YYKeychainErrorAuthFailed, ///< The user name or passphrase you entered is not. | |
| 219 | +}; | |
| 220 | + | |
| 221 | + | |
| 222 | +/** | |
| 223 | + When query to return the item's data, the error | |
| 224 | + errSecInteractionNotAllowed will be returned if the item's data is not | |
| 225 | + available until a device unlock occurs. | |
| 226 | + */ | |
| 227 | +typedef NS_ENUM (NSUInteger, YYKeychainAccessible) { | |
| 228 | + YYKeychainAccessibleNone = 0, ///< no value | |
| 229 | + | |
| 230 | + /** Item data can only be accessed | |
| 231 | + while the device is unlocked. This is recommended for items that only | |
| 232 | + need be accesible while the application is in the foreground. Items | |
| 233 | + with this attribute will migrate to a new device when using encrypted | |
| 234 | + backups. */ | |
| 235 | + YYKeychainAccessibleWhenUnlocked, | |
| 236 | + | |
| 237 | + /** Item data can only be | |
| 238 | + accessed once the device has been unlocked after a restart. This is | |
| 239 | + recommended for items that need to be accesible by background | |
| 240 | + applications. Items with this attribute will migrate to a new device | |
| 241 | + when using encrypted backups.*/ | |
| 242 | + YYKeychainAccessibleAfterFirstUnlock, | |
| 243 | + | |
| 244 | + /** Item data can always be accessed | |
| 245 | + regardless of the lock state of the device. This is not recommended | |
| 246 | + for anything except system use. Items with this attribute will migrate | |
| 247 | + to a new device when using encrypted backups.*/ | |
| 248 | + YYKeychainAccessibleAlways, | |
| 249 | + | |
| 250 | + /** Item data can | |
| 251 | + only be accessed while the device is unlocked. This class is only | |
| 252 | + available if a passcode is set on the device. This is recommended for | |
| 253 | + items that only need to be accessible while the application is in the | |
| 254 | + foreground. Items with this attribute will never migrate to a new | |
| 255 | + device, so after a backup is restored to a new device, these items | |
| 256 | + will be missing. No items can be stored in this class on devices | |
| 257 | + without a passcode. Disabling the device passcode will cause all | |
| 258 | + items in this class to be deleted.*/ | |
| 259 | + YYKeychainAccessibleWhenPasscodeSetThisDeviceOnly, | |
| 260 | + | |
| 261 | + /** Item data can only | |
| 262 | + be accessed while the device is unlocked. This is recommended for items | |
| 263 | + that only need be accesible while the application is in the foreground. | |
| 264 | + Items with this attribute will never migrate to a new device, so after | |
| 265 | + a backup is restored to a new device, these items will be missing. */ | |
| 266 | + YYKeychainAccessibleWhenUnlockedThisDeviceOnly, | |
| 267 | + | |
| 268 | + /** Item data can | |
| 269 | + only be accessed once the device has been unlocked after a restart. | |
| 270 | + This is recommended for items that need to be accessible by background | |
| 271 | + applications. Items with this attribute will never migrate to a new | |
| 272 | + device, so after a backup is restored to a new device these items will | |
| 273 | + be missing.*/ | |
| 274 | + YYKeychainAccessibleAfterFirstUnlockThisDeviceOnly, | |
| 275 | + | |
| 276 | + /** Item data can always | |
| 277 | + be accessed regardless of the lock state of the device. This option | |
| 278 | + is not recommended for anything except system use. Items with this | |
| 279 | + attribute will never migrate to a new device, so after a backup is | |
| 280 | + restored to a new device, these items will be missing.*/ | |
| 281 | + YYKeychainAccessibleAlwaysThisDeviceOnly, | |
| 282 | +}; | |
| 283 | + | |
| 284 | +/** | |
| 285 | + Whether the item in question can be synchronized. | |
| 286 | + */ | |
| 287 | +typedef NS_ENUM (NSUInteger, YYKeychainQuerySynchronizationMode) { | |
| 288 | + | |
| 289 | + /** Default, Don't care for synchronization */ | |
| 290 | + YYKeychainQuerySynchronizationModeAny = 0, | |
| 291 | + | |
| 292 | + /** Is not synchronized */ | |
| 293 | + YYKeychainQuerySynchronizationModeNo, | |
| 294 | + | |
| 295 | + /** To add a new item which can be synced to other devices, or to obtain | |
| 296 | + synchronized results from a query*/ | |
| 297 | + YYKeychainQuerySynchronizationModeYes, | |
| 298 | +} NS_AVAILABLE_IOS (7_0); | |
| 299 | + | |
| 300 | + | |
| 301 | +#pragma mark - Item | |
| 302 | + | |
| 303 | +/** | |
| 304 | + Wrapper for keychain item/query. | |
| 305 | + */ | |
| 306 | +@interface YYKeychainItem : NSObject <NSCopying> | |
| 307 | + | |
| 308 | +@property (nullable, nonatomic, copy) NSString *service; ///< kSecAttrService | |
| 309 | +@property (nullable, nonatomic, copy) NSString *account; ///< kSecAttrAccount | |
| 310 | +@property (nullable, nonatomic, copy) NSData *passwordData; ///< kSecValueData | |
| 311 | +@property (nullable, nonatomic, copy) NSString *password; ///< shortcut for `passwordData` | |
| 312 | +@property (nullable, nonatomic, copy) id <NSCoding> passwordObject; ///< shortcut for `passwordData` | |
| 313 | + | |
| 314 | +@property (nullable, nonatomic, copy) NSString *label; ///< kSecAttrLabel | |
| 315 | +@property (nullable, nonatomic, copy) NSNumber *type; ///< kSecAttrType (FourCC) | |
| 316 | +@property (nullable, nonatomic, copy) NSNumber *creater; ///< kSecAttrCreator (FourCC) | |
| 317 | +@property (nullable, nonatomic, copy) NSString *comment; ///< kSecAttrComment | |
| 318 | +@property (nullable, nonatomic, copy) NSString *descr; ///< kSecAttrDescription | |
| 319 | +@property (nullable, nonatomic, readonly, strong) NSDate *modificationDate; ///< kSecAttrModificationDate | |
| 320 | +@property (nullable, nonatomic, readonly, strong) NSDate *creationDate; ///< kSecAttrCreationDate | |
| 321 | +@property (nullable, nonatomic, copy) NSString *accessGroup; ///< kSecAttrAccessGroup | |
| 322 | + | |
| 323 | +@property (nonatomic) YYKeychainAccessible accessible; ///< kSecAttrAccessible | |
| 324 | +@property (nonatomic) YYKeychainQuerySynchronizationMode synchronizable NS_AVAILABLE_IOS(7_0); ///< kSecAttrSynchronizable | |
| 325 | + | |
| 326 | +@end | |
| 327 | + | |
| 328 | +NS_ASSUME_NONNULL_END | ... | ... |
CNLiveCMineModule/Classes/Manager/YYKeychain.m
0 → 100644
| 1 | +// | |
| 2 | +// YYKeychain.m | |
| 3 | +// YYKit <https://github.com/ibireme/YYKit> | |
| 4 | +// | |
| 5 | +// Created by ibireme on 14/10/15. | |
| 6 | +// Copyright (c) 2015 ibireme. | |
| 7 | +// | |
| 8 | +// This source code is licensed under the MIT-style license found in the | |
| 9 | +// LICENSE file in the root directory of this source tree. | |
| 10 | +// | |
| 11 | + | |
| 12 | +#import "YYKeychain.h" | |
| 13 | +#import "UIDevice+YYAdd.h" | |
| 14 | +//#import "YYKitMacro.h" | |
| 15 | +#import <Security/Security.h> | |
| 16 | + | |
| 17 | + | |
| 18 | +static YYKeychainErrorCode YYKeychainErrorCodeFromOSStatus(OSStatus status) { | |
| 19 | + switch (status) { | |
| 20 | + case errSecUnimplemented: return YYKeychainErrorUnimplemented; | |
| 21 | + case errSecIO: return YYKeychainErrorIO; | |
| 22 | + case errSecOpWr: return YYKeychainErrorOpWr; | |
| 23 | + case errSecParam: return YYKeychainErrorParam; | |
| 24 | + case errSecAllocate: return YYKeychainErrorAllocate; | |
| 25 | + case errSecUserCanceled: return YYKeychainErrorUserCancelled; | |
| 26 | + case errSecBadReq: return YYKeychainErrorBadReq; | |
| 27 | + case errSecInternalComponent: return YYKeychainErrorInternalComponent; | |
| 28 | + case errSecNotAvailable: return YYKeychainErrorNotAvailable; | |
| 29 | + case errSecDuplicateItem: return YYKeychainErrorDuplicateItem; | |
| 30 | + case errSecItemNotFound: return YYKeychainErrorItemNotFound; | |
| 31 | + case errSecInteractionNotAllowed: return YYKeychainErrorInteractionNotAllowed; | |
| 32 | + case errSecDecode: return YYKeychainErrorDecode; | |
| 33 | + case errSecAuthFailed: return YYKeychainErrorAuthFailed; | |
| 34 | + default: return 0; | |
| 35 | + } | |
| 36 | +} | |
| 37 | + | |
| 38 | +static NSString *YYKeychainErrorDesc(YYKeychainErrorCode code) { | |
| 39 | + switch (code) { | |
| 40 | + case YYKeychainErrorUnimplemented: | |
| 41 | + return @"Function or operation not implemented."; | |
| 42 | + case YYKeychainErrorIO: | |
| 43 | + return @"I/O error (bummers)"; | |
| 44 | + case YYKeychainErrorOpWr: | |
| 45 | + return @"ile already open with with write permission."; | |
| 46 | + case YYKeychainErrorParam: | |
| 47 | + return @"One or more parameters passed to a function where not valid."; | |
| 48 | + case YYKeychainErrorAllocate: | |
| 49 | + return @"Failed to allocate memory."; | |
| 50 | + case YYKeychainErrorUserCancelled: | |
| 51 | + return @"User canceled the operation."; | |
| 52 | + case YYKeychainErrorBadReq: | |
| 53 | + return @"Bad parameter or invalid state for operation."; | |
| 54 | + case YYKeychainErrorInternalComponent: | |
| 55 | + return @"Inrernal Component"; | |
| 56 | + case YYKeychainErrorNotAvailable: | |
| 57 | + return @"No keychain is available. You may need to restart your computer."; | |
| 58 | + case YYKeychainErrorDuplicateItem: | |
| 59 | + return @"The specified item already exists in the keychain."; | |
| 60 | + case YYKeychainErrorItemNotFound: | |
| 61 | + return @"The specified item could not be found in the keychain."; | |
| 62 | + case YYKeychainErrorInteractionNotAllowed: | |
| 63 | + return @"User interaction is not allowed."; | |
| 64 | + case YYKeychainErrorDecode: | |
| 65 | + return @"Unable to decode the provided data."; | |
| 66 | + case YYKeychainErrorAuthFailed: | |
| 67 | + return @"The user name or passphrase you entered is not"; | |
| 68 | + default: | |
| 69 | + break; | |
| 70 | + } | |
| 71 | + return nil; | |
| 72 | +} | |
| 73 | + | |
| 74 | +static NSString *YYKeychainAccessibleStr(YYKeychainAccessible e) { | |
| 75 | + switch (e) { | |
| 76 | + case YYKeychainAccessibleWhenUnlocked: | |
| 77 | + return (__bridge NSString *)(kSecAttrAccessibleWhenUnlocked); | |
| 78 | + case YYKeychainAccessibleAfterFirstUnlock: | |
| 79 | + return (__bridge NSString *)(kSecAttrAccessibleAfterFirstUnlock); | |
| 80 | + case YYKeychainAccessibleAlways: | |
| 81 | + return (__bridge NSString *)(kSecAttrAccessibleAlways); | |
| 82 | + case YYKeychainAccessibleWhenPasscodeSetThisDeviceOnly: | |
| 83 | + return (__bridge NSString *)(kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly); | |
| 84 | + case YYKeychainAccessibleWhenUnlockedThisDeviceOnly: | |
| 85 | + return (__bridge NSString *)(kSecAttrAccessibleWhenUnlockedThisDeviceOnly); | |
| 86 | + case YYKeychainAccessibleAfterFirstUnlockThisDeviceOnly: | |
| 87 | + return (__bridge NSString *)(kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly); | |
| 88 | + case YYKeychainAccessibleAlwaysThisDeviceOnly: | |
| 89 | + return (__bridge NSString *)(kSecAttrAccessibleAlwaysThisDeviceOnly); | |
| 90 | + default: | |
| 91 | + return nil; | |
| 92 | + } | |
| 93 | +} | |
| 94 | + | |
| 95 | +static YYKeychainAccessible YYKeychainAccessibleEnum(NSString *s) { | |
| 96 | + if ([s isEqualToString:(__bridge NSString *)kSecAttrAccessibleWhenUnlocked]) | |
| 97 | + return YYKeychainAccessibleWhenUnlocked; | |
| 98 | + if ([s isEqualToString:(__bridge NSString *)kSecAttrAccessibleAfterFirstUnlock]) | |
| 99 | + return YYKeychainAccessibleAfterFirstUnlock; | |
| 100 | + if ([s isEqualToString:(__bridge NSString *)kSecAttrAccessibleAlways]) | |
| 101 | + return YYKeychainAccessibleAlways; | |
| 102 | + if ([s isEqualToString:(__bridge NSString *)kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly]) | |
| 103 | + return YYKeychainAccessibleWhenPasscodeSetThisDeviceOnly; | |
| 104 | + if ([s isEqualToString:(__bridge NSString *)kSecAttrAccessibleWhenUnlockedThisDeviceOnly]) | |
| 105 | + return YYKeychainAccessibleWhenUnlockedThisDeviceOnly; | |
| 106 | + if ([s isEqualToString:(__bridge NSString *)kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly]) | |
| 107 | + return YYKeychainAccessibleAfterFirstUnlockThisDeviceOnly; | |
| 108 | + if ([s isEqualToString:(__bridge NSString *)kSecAttrAccessibleAlwaysThisDeviceOnly]) | |
| 109 | + return YYKeychainAccessibleAlwaysThisDeviceOnly; | |
| 110 | + return YYKeychainAccessibleNone; | |
| 111 | +} | |
| 112 | + | |
| 113 | +static id YYKeychainQuerySynchonizationID(YYKeychainQuerySynchronizationMode mode) { | |
| 114 | + switch (mode) { | |
| 115 | + case YYKeychainQuerySynchronizationModeAny: | |
| 116 | + return (__bridge id)(kSecAttrSynchronizableAny); | |
| 117 | + case YYKeychainQuerySynchronizationModeNo: | |
| 118 | + return (__bridge id)kCFBooleanFalse; | |
| 119 | + case YYKeychainQuerySynchronizationModeYes: | |
| 120 | + return (__bridge id)kCFBooleanTrue; | |
| 121 | + default: | |
| 122 | + return (__bridge id)(kSecAttrSynchronizableAny); | |
| 123 | + } | |
| 124 | +} | |
| 125 | + | |
| 126 | +static YYKeychainQuerySynchronizationMode YYKeychainQuerySynchonizationEnum(NSNumber *num) { | |
| 127 | + if ([num isEqualToNumber:@NO]) return YYKeychainQuerySynchronizationModeNo; | |
| 128 | + if ([num isEqualToNumber:@YES]) return YYKeychainQuerySynchronizationModeYes; | |
| 129 | + return YYKeychainQuerySynchronizationModeAny; | |
| 130 | +} | |
| 131 | + | |
| 132 | +@interface YYKeychainItem () | |
| 133 | +@property (nonatomic, readwrite, strong) NSDate *modificationDate; | |
| 134 | +@property (nonatomic, readwrite, strong) NSDate *creationDate; | |
| 135 | +@end | |
| 136 | + | |
| 137 | +@implementation YYKeychainItem | |
| 138 | + | |
| 139 | + | |
| 140 | +- (void)setPasswordObject:(id <NSCoding> )object { | |
| 141 | + self.passwordData = [NSKeyedArchiver archivedDataWithRootObject:object]; | |
| 142 | +} | |
| 143 | + | |
| 144 | +- (id <NSCoding> )passwordObject { | |
| 145 | + if ([self.passwordData length]) { | |
| 146 | + return [NSKeyedUnarchiver unarchiveObjectWithData:self.passwordData]; | |
| 147 | + } | |
| 148 | + return nil; | |
| 149 | +} | |
| 150 | + | |
| 151 | +- (void)setPassword:(NSString *)password { | |
| 152 | + self.passwordData = [password dataUsingEncoding:NSUTF8StringEncoding]; | |
| 153 | +} | |
| 154 | + | |
| 155 | +- (NSString *)password { | |
| 156 | + if ([self.passwordData length]) { | |
| 157 | + return [[NSString alloc] initWithData:self.passwordData encoding:NSUTF8StringEncoding]; | |
| 158 | + } | |
| 159 | + return nil; | |
| 160 | +} | |
| 161 | + | |
| 162 | +- (NSMutableDictionary *)queryDic { | |
| 163 | + NSMutableDictionary *dic = [NSMutableDictionary new]; | |
| 164 | + | |
| 165 | + dic[(__bridge id)kSecClass] = (__bridge id)kSecClassGenericPassword; | |
| 166 | + | |
| 167 | + if (self.account) dic[(__bridge id)kSecAttrAccount] = self.account; | |
| 168 | + if (self.service) dic[(__bridge id)kSecAttrService] = self.service; | |
| 169 | + | |
| 170 | + if (![UIDevice currentDevice].isSimulator) { | |
| 171 | + // Remove the access group if running on the iPhone simulator. | |
| 172 | + // | |
| 173 | + // Apps that are built for the simulator aren't signed, so there's no keychain access group | |
| 174 | + // for the simulator to check. This means that all apps can see all keychain items when run | |
| 175 | + // on the simulator. | |
| 176 | + // | |
| 177 | + // If a SecItem contains an access group attribute, SecItemAdd and SecItemUpdate on the | |
| 178 | + // simulator will return -25243 (errSecNoAccessForItem). | |
| 179 | + // | |
| 180 | + // The access group attribute will be included in items returned by SecItemCopyMatching, | |
| 181 | + // which is why we need to remove it before updating the item. | |
| 182 | + if (self.accessGroup) dic[(__bridge id)kSecAttrAccessGroup] = self.accessGroup; | |
| 183 | + } | |
| 184 | + | |
| 185 | + if (kiOS7Later) { | |
| 186 | + dic[(__bridge id)kSecAttrSynchronizable] = YYKeychainQuerySynchonizationID(self.synchronizable); | |
| 187 | + } | |
| 188 | + | |
| 189 | + return dic; | |
| 190 | +} | |
| 191 | + | |
| 192 | +- (NSMutableDictionary *)dic { | |
| 193 | + NSMutableDictionary *dic = [NSMutableDictionary new]; | |
| 194 | + | |
| 195 | + dic[(__bridge id)kSecClass] = (__bridge id)kSecClassGenericPassword; | |
| 196 | + | |
| 197 | + if (self.account) dic[(__bridge id)kSecAttrAccount] = self.account; | |
| 198 | + if (self.service) dic[(__bridge id)kSecAttrService] = self.service; | |
| 199 | + if (self.label) dic[(__bridge id)kSecAttrLabel] = self.label; | |
| 200 | + | |
| 201 | + if (![UIDevice currentDevice].isSimulator) { | |
| 202 | + // Remove the access group if running on the iPhone simulator. | |
| 203 | + // | |
| 204 | + // Apps that are built for the simulator aren't signed, so there's no keychain access group | |
| 205 | + // for the simulator to check. This means that all apps can see all keychain items when run | |
| 206 | + // on the simulator. | |
| 207 | + // | |
| 208 | + // If a SecItem contains an access group attribute, SecItemAdd and SecItemUpdate on the | |
| 209 | + // simulator will return -25243 (errSecNoAccessForItem). | |
| 210 | + // | |
| 211 | + // The access group attribute will be included in items returned by SecItemCopyMatching, | |
| 212 | + // which is why we need to remove it before updating the item. | |
| 213 | + if (self.accessGroup) dic[(__bridge id)kSecAttrAccessGroup] = self.accessGroup; | |
| 214 | + } | |
| 215 | + | |
| 216 | + if (kiOS7Later) { | |
| 217 | + dic[(__bridge id)kSecAttrSynchronizable] = YYKeychainQuerySynchonizationID(self.synchronizable); | |
| 218 | + } | |
| 219 | + | |
| 220 | + if (self.accessible) dic[(__bridge id)kSecAttrAccessible] = YYKeychainAccessibleStr(self.accessible); | |
| 221 | + if (self.passwordData) dic[(__bridge id)kSecValueData] = self.passwordData; | |
| 222 | + if (self.type) dic[(__bridge id)kSecAttrType] = self.type; | |
| 223 | + if (self.creater) dic[(__bridge id)kSecAttrCreator] = self.creater; | |
| 224 | + if (self.comment) dic[(__bridge id)kSecAttrComment] = self.comment; | |
| 225 | + if (self.descr) dic[(__bridge id)kSecAttrDescription] = self.descr; | |
| 226 | + | |
| 227 | + return dic; | |
| 228 | +} | |
| 229 | + | |
| 230 | +- (instancetype)initWithDic:(NSDictionary *)dic { | |
| 231 | + if (dic.count == 0) return nil; | |
| 232 | + self = self.init; | |
| 233 | + | |
| 234 | + self.service = dic[(__bridge id)kSecAttrService]; | |
| 235 | + self.account = dic[(__bridge id)kSecAttrAccount]; | |
| 236 | + self.passwordData = dic[(__bridge id)kSecValueData]; | |
| 237 | + self.label = dic[(__bridge id)kSecAttrLabel]; | |
| 238 | + self.type = dic[(__bridge id)kSecAttrType]; | |
| 239 | + self.creater = dic[(__bridge id)kSecAttrCreator]; | |
| 240 | + self.comment = dic[(__bridge id)kSecAttrComment]; | |
| 241 | + self.descr = dic[(__bridge id)kSecAttrDescription]; | |
| 242 | + self.modificationDate = dic[(__bridge id)kSecAttrModificationDate]; | |
| 243 | + self.creationDate = dic[(__bridge id)kSecAttrCreationDate]; | |
| 244 | + self.accessGroup = dic[(__bridge id)kSecAttrAccessGroup]; | |
| 245 | + self.accessible = YYKeychainAccessibleEnum(dic[(__bridge id)kSecAttrAccessible]); | |
| 246 | + self.synchronizable = YYKeychainQuerySynchonizationEnum(dic[(__bridge id)kSecAttrSynchronizable]); | |
| 247 | + | |
| 248 | + return self; | |
| 249 | +} | |
| 250 | + | |
| 251 | +- (id)copyWithZone:(NSZone *)zone { | |
| 252 | + YYKeychainItem *item = [YYKeychainItem new]; | |
| 253 | + item.service = self.service; | |
| 254 | + item.account = self.account; | |
| 255 | + item.passwordData = self.passwordData; | |
| 256 | + item.label = self.label; | |
| 257 | + item.type = self.type; | |
| 258 | + item.creater = self.creater; | |
| 259 | + item.comment = self.comment; | |
| 260 | + item.descr = self.descr; | |
| 261 | + item.modificationDate = self.modificationDate; | |
| 262 | + item.creationDate = self.creationDate; | |
| 263 | + item.accessGroup = self.accessGroup; | |
| 264 | + item.accessible = self.accessible; | |
| 265 | + item.synchronizable = self.synchronizable; | |
| 266 | + return item; | |
| 267 | +} | |
| 268 | + | |
| 269 | +- (NSString *)description { | |
| 270 | + NSMutableString *str = @"".mutableCopy; | |
| 271 | + [str appendString:@"YYKeychainItem:{\n"]; | |
| 272 | + if (self.service) [str appendFormat:@" service:%@,\n", self.service]; | |
| 273 | + if (self.account) [str appendFormat:@" service:%@,\n", self.account]; | |
| 274 | + if (self.password) [str appendFormat:@" service:%@,\n", self.password]; | |
| 275 | + if (self.label) [str appendFormat:@" service:%@,\n", self.label]; | |
| 276 | + if (self.type) [str appendFormat:@" service:%@,\n", self.type]; | |
| 277 | + if (self.creater) [str appendFormat:@" service:%@,\n", self.creater]; | |
| 278 | + if (self.comment) [str appendFormat:@" service:%@,\n", self.comment]; | |
| 279 | + if (self.descr) [str appendFormat:@" service:%@,\n", self.descr]; | |
| 280 | + if (self.modificationDate) [str appendFormat:@" service:%@,\n", self.modificationDate]; | |
| 281 | + if (self.creationDate) [str appendFormat:@" service:%@,\n", self.creationDate]; | |
| 282 | + if (self.accessGroup) [str appendFormat:@" service:%@,\n", self.accessGroup]; | |
| 283 | + [str appendString:@"}"]; | |
| 284 | + return str; | |
| 285 | +} | |
| 286 | + | |
| 287 | +@end | |
| 288 | + | |
| 289 | + | |
| 290 | + | |
| 291 | +@implementation YYKeychain | |
| 292 | + | |
| 293 | ++ (NSString *)getPasswordForService:(NSString *)serviceName | |
| 294 | + account:(NSString *)account | |
| 295 | + error:(NSError **)error { | |
| 296 | + if (!serviceName || !account) { | |
| 297 | + if (error) *error = [YYKeychain errorWithCode:errSecParam]; | |
| 298 | + return nil; | |
| 299 | + } | |
| 300 | + | |
| 301 | + YYKeychainItem *item = [YYKeychainItem new]; | |
| 302 | + item.service = serviceName; | |
| 303 | + item.account = account; | |
| 304 | + YYKeychainItem *result = [self selectOneItem:item error:error]; | |
| 305 | + return result.password; | |
| 306 | +} | |
| 307 | + | |
| 308 | ++ (nullable NSString *)getPasswordForService:(NSString *)serviceName | |
| 309 | + account:(NSString *)account { | |
| 310 | + return [self getPasswordForService:serviceName account:account error:NULL]; | |
| 311 | +} | |
| 312 | + | |
| 313 | ++ (BOOL)deletePasswordForService:(NSString *)serviceName | |
| 314 | + account:(NSString *)account | |
| 315 | + error:(NSError **)error { | |
| 316 | + if (!serviceName || !account) { | |
| 317 | + if (error) *error = [YYKeychain errorWithCode:errSecParam]; | |
| 318 | + return NO; | |
| 319 | + } | |
| 320 | + | |
| 321 | + YYKeychainItem *item = [YYKeychainItem new]; | |
| 322 | + item.service = serviceName; | |
| 323 | + item.account = account; | |
| 324 | + return [self deleteItem:item error:error]; | |
| 325 | +} | |
| 326 | + | |
| 327 | ++ (BOOL)deletePasswordForService:(NSString *)serviceName account:(NSString *)account { | |
| 328 | + return [self deletePasswordForService:serviceName account:account error:NULL]; | |
| 329 | +} | |
| 330 | + | |
| 331 | ++ (BOOL)setPassword:(NSString *)password | |
| 332 | + forService:(NSString *)serviceName | |
| 333 | + account:(NSString *)account | |
| 334 | + error:(NSError **)error { | |
| 335 | + if (!password || !serviceName || !account) { | |
| 336 | + if (error) *error = [YYKeychain errorWithCode:errSecParam]; | |
| 337 | + return NO; | |
| 338 | + } | |
| 339 | + YYKeychainItem *item = [YYKeychainItem new]; | |
| 340 | + item.service = serviceName; | |
| 341 | + item.account = account; | |
| 342 | + YYKeychainItem *result = [self selectOneItem:item error:NULL]; | |
| 343 | + if (result) { | |
| 344 | + result.password = password; | |
| 345 | + return [self updateItem:result error:error]; | |
| 346 | + } else { | |
| 347 | + item.password = password; | |
| 348 | + return [self insertItem:item error:error]; | |
| 349 | + } | |
| 350 | +} | |
| 351 | + | |
| 352 | ++ (BOOL)setPassword:(NSString *)password | |
| 353 | + forService:(NSString *)serviceName | |
| 354 | + account:(NSString *)account { | |
| 355 | + return [self setPassword:password forService:serviceName account:account error:NULL]; | |
| 356 | +} | |
| 357 | + | |
| 358 | ++ (BOOL)insertItem:(YYKeychainItem *)item error:(NSError **)error { | |
| 359 | + if (!item.service || !item.account || !item.passwordData) { | |
| 360 | + if (error) *error = [YYKeychain errorWithCode:errSecParam]; | |
| 361 | + return NO; | |
| 362 | + } | |
| 363 | + | |
| 364 | + NSMutableDictionary *query = [item dic]; | |
| 365 | + OSStatus status = status = SecItemAdd((__bridge CFDictionaryRef)query, NULL); | |
| 366 | + if (status != errSecSuccess) { | |
| 367 | + if (error) *error = [YYKeychain errorWithCode:status]; | |
| 368 | + return NO; | |
| 369 | + } | |
| 370 | + | |
| 371 | + return YES; | |
| 372 | +} | |
| 373 | + | |
| 374 | ++ (BOOL)insertItem:(YYKeychainItem *)item { | |
| 375 | + return [self insertItem:item error:NULL]; | |
| 376 | +} | |
| 377 | + | |
| 378 | ++ (BOOL)updateItem:(YYKeychainItem *)item error:(NSError **)error { | |
| 379 | + if (!item.service || !item.account || !item.passwordData) { | |
| 380 | + if (error) *error = [YYKeychain errorWithCode:errSecParam]; | |
| 381 | + return NO; | |
| 382 | + } | |
| 383 | + | |
| 384 | + NSMutableDictionary *query = [item queryDic]; | |
| 385 | + NSMutableDictionary *update = [item dic]; | |
| 386 | + [update removeObjectForKey:(__bridge id)kSecClass]; | |
| 387 | + if (!query || !update) return NO; | |
| 388 | + OSStatus status = status = SecItemUpdate((__bridge CFDictionaryRef)query, (__bridge CFDictionaryRef)update); | |
| 389 | + if (status != errSecSuccess) { | |
| 390 | + if (error) *error = [YYKeychain errorWithCode:status]; | |
| 391 | + return NO; | |
| 392 | + } | |
| 393 | + | |
| 394 | + return YES; | |
| 395 | +} | |
| 396 | + | |
| 397 | ++ (BOOL)updateItem:(YYKeychainItem *)item { | |
| 398 | + return [self updateItem:item error:NULL]; | |
| 399 | +} | |
| 400 | + | |
| 401 | ++ (BOOL)deleteItem:(YYKeychainItem *)item error:(NSError **)error { | |
| 402 | + if (!item.service || !item.account) { | |
| 403 | + if (error) *error = [YYKeychain errorWithCode:errSecParam]; | |
| 404 | + return NO; | |
| 405 | + } | |
| 406 | + | |
| 407 | + NSMutableDictionary *query = [item dic]; | |
| 408 | + OSStatus status = SecItemDelete((__bridge CFDictionaryRef)query); | |
| 409 | + if (status != errSecSuccess) { | |
| 410 | + if (error) *error = [YYKeychain errorWithCode:status]; | |
| 411 | + return NO; | |
| 412 | + } | |
| 413 | + | |
| 414 | + return YES; | |
| 415 | +} | |
| 416 | + | |
| 417 | ++ (BOOL)deleteItem:(YYKeychainItem *)item { | |
| 418 | + return [self deleteItem:item error:NULL]; | |
| 419 | +} | |
| 420 | + | |
| 421 | ++ (YYKeychainItem *)selectOneItem:(YYKeychainItem *)item error:(NSError **)error { | |
| 422 | + if (!item.service || !item.account) { | |
| 423 | + if (error) *error = [YYKeychain errorWithCode:errSecParam]; | |
| 424 | + return nil; | |
| 425 | + } | |
| 426 | + | |
| 427 | + NSMutableDictionary *query = [item dic]; | |
| 428 | + query[(__bridge id)kSecMatchLimit] = (__bridge id)kSecMatchLimitOne; | |
| 429 | + query[(__bridge id)kSecReturnAttributes] = @YES; | |
| 430 | + query[(__bridge id)kSecReturnData] = @YES; | |
| 431 | + | |
| 432 | + OSStatus status; | |
| 433 | + CFTypeRef result = NULL; | |
| 434 | + status = SecItemCopyMatching((__bridge CFDictionaryRef)query, &result); | |
| 435 | + if (status != errSecSuccess) { | |
| 436 | + if (error) *error = [[self class] errorWithCode:status]; | |
| 437 | + return nil; | |
| 438 | + } | |
| 439 | + if (!result) return nil; | |
| 440 | + | |
| 441 | + NSDictionary *dic = nil; | |
| 442 | + if (CFGetTypeID(result) == CFDictionaryGetTypeID()) { | |
| 443 | + dic = (__bridge NSDictionary *)(result); | |
| 444 | + } else if (CFGetTypeID(result) == CFArrayGetTypeID()){ | |
| 445 | + dic = [(__bridge NSArray *)(result) firstObject]; | |
| 446 | + if (![dic isKindOfClass:[NSDictionary class]]) dic = nil; | |
| 447 | + } | |
| 448 | + if (!dic.count) return nil; | |
| 449 | + return [[YYKeychainItem alloc] initWithDic:dic]; | |
| 450 | +} | |
| 451 | + | |
| 452 | ++ (YYKeychainItem *)selectOneItem:(YYKeychainItem *)item { | |
| 453 | + return [self selectOneItem:item error:NULL]; | |
| 454 | +} | |
| 455 | + | |
| 456 | ++ (NSArray *)selectItems:(YYKeychainItem *)item error:(NSError **)error { | |
| 457 | + NSMutableDictionary *query = [item dic]; | |
| 458 | + query[(__bridge id)kSecMatchLimit] = (__bridge id)kSecMatchLimitAll; | |
| 459 | + query[(__bridge id)kSecReturnAttributes] = @YES; | |
| 460 | + query[(__bridge id)kSecReturnData] = @YES; | |
| 461 | + | |
| 462 | + OSStatus status; | |
| 463 | + CFTypeRef result = NULL; | |
| 464 | + status = SecItemCopyMatching((__bridge CFDictionaryRef)query, &result); | |
| 465 | + if (status != errSecSuccess && error != NULL) { | |
| 466 | + *error = [[self class] errorWithCode:status]; | |
| 467 | + return nil; | |
| 468 | + } | |
| 469 | + | |
| 470 | + NSMutableArray *res = [NSMutableArray new]; | |
| 471 | + NSDictionary *dic = nil; | |
| 472 | + if (CFGetTypeID(result) == CFDictionaryGetTypeID()) { | |
| 473 | + dic = (__bridge NSDictionary *)(result); | |
| 474 | + YYKeychainItem *item = [[YYKeychainItem alloc] initWithDic:dic]; | |
| 475 | + if (item) [res addObject:item]; | |
| 476 | + } else if (CFGetTypeID(result) == CFArrayGetTypeID()){ | |
| 477 | + for (NSDictionary *dic in (__bridge NSArray *)(result)) { | |
| 478 | + YYKeychainItem *item = [[YYKeychainItem alloc] initWithDic:dic]; | |
| 479 | + if (item) [res addObject:item]; | |
| 480 | + } | |
| 481 | + } | |
| 482 | + | |
| 483 | + return res; | |
| 484 | +} | |
| 485 | + | |
| 486 | ++ (NSArray *)selectItems:(YYKeychainItem *)item { | |
| 487 | + return [self selectItems:item error:NULL]; | |
| 488 | +} | |
| 489 | + | |
| 490 | ++ (NSError *)errorWithCode:(OSStatus)osCode { | |
| 491 | + YYKeychainErrorCode code = YYKeychainErrorCodeFromOSStatus(osCode); | |
| 492 | + NSString *desc = YYKeychainErrorDesc(code); | |
| 493 | + NSDictionary *userInfo = desc ? @{ NSLocalizedDescriptionKey : desc } : nil; | |
| 494 | + return [NSError errorWithDomain:@"com.ibireme.yykit.keychain" code:code userInfo:userInfo]; | |
| 495 | +} | |
| 496 | + | |
| 497 | +@end | ... | ... |
CNLiveCMineModule/Classes/ReplaceMe.m deleted
100644 → 0
Example/CNLiveCMineModule.xcodeproj/project.pbxproj
| ... | ... | @@ -208,6 +208,7 @@ |
| 208 | 208 | 6003F587195388D20070C39A /* Frameworks */, |
| 209 | 209 | 6003F588195388D20070C39A /* Resources */, |
| 210 | 210 | 49D4349E8CEBA15A719A01F8 /* [CP] Embed Pods Frameworks */, |
| 211 | + B325211E0D87340E247D54B4 /* [CP] Copy Pods Resources */, | |
| 211 | 212 | ); |
| 212 | 213 | buildRules = ( |
| 213 | 214 | ); |
| ... | ... | @@ -328,17 +329,97 @@ |
| 328 | 329 | ); |
| 329 | 330 | inputPaths = ( |
| 330 | 331 | "${PODS_ROOT}/Target Support Files/Pods-CNLiveCMineModule_Example/Pods-CNLiveCMineModule_Example-frameworks.sh", |
| 331 | - "${BUILT_PRODUCTS_DIR}/CNLiveCMineModule/CNLiveCMineModule.framework", | |
| 332 | + "${BUILT_PRODUCTS_DIR}/AFNetworking/AFNetworking.framework", | |
| 333 | + "${BUILT_PRODUCTS_DIR}/CNLiveBaseKit/CNLiveBaseKit.framework", | |
| 334 | + "${BUILT_PRODUCTS_DIR}/CNLiveBeeHive/CNLiveBeeHive.framework", | |
| 335 | + "${BUILT_PRODUCTS_DIR}/CNLiveBusinessBaseModule/CNLiveBusinessBaseModule.framework", | |
| 336 | + "${BUILT_PRODUCTS_DIR}/CNLiveBusinessTools/CNLiveBusinessTools.framework", | |
| 337 | + "${BUILT_PRODUCTS_DIR}/CNLiveCacheManagerKit/CNLiveCacheManagerKit.framework", | |
| 338 | + "${BUILT_PRODUCTS_DIR}/CNLiveCommonCategory/CNLiveCommonCategory.framework", | |
| 339 | + "${BUILT_PRODUCTS_DIR}/CNLiveCustomUI/CNLiveCustomUI.framework", | |
| 340 | + "${BUILT_PRODUCTS_DIR}/CNLiveEnvironment/CNLiveEnvironment.framework", | |
| 341 | + "${BUILT_PRODUCTS_DIR}/CNLiveNewTripartiteManagement/CNLiveNewTripartiteManagement.framework", | |
| 342 | + "${BUILT_PRODUCTS_DIR}/CNLiveRequestBastKit/CNLiveRequestBastKit.framework", | |
| 343 | + "${BUILT_PRODUCTS_DIR}/CNLiveUserManagement/CNLiveUserManagement.framework", | |
| 344 | + "${BUILT_PRODUCTS_DIR}/FMDB/FMDB.framework", | |
| 345 | + "${BUILT_PRODUCTS_DIR}/GPUImage/GPUImage.framework", | |
| 346 | + "${BUILT_PRODUCTS_DIR}/JXCategoryView/JXCategoryView.framework", | |
| 347 | + "${BUILT_PRODUCTS_DIR}/MJExtension/MJExtension.framework", | |
| 348 | + "${BUILT_PRODUCTS_DIR}/MJRefresh/MJRefresh.framework", | |
| 349 | + "${BUILT_PRODUCTS_DIR}/Masonry/Masonry.framework", | |
| 350 | + "${BUILT_PRODUCTS_DIR}/QMUIKit/QMUIKit.framework", | |
| 351 | + "${BUILT_PRODUCTS_DIR}/SDWebImage/SDWebImage.framework", | |
| 352 | + "${PODS_ROOT}/TXIMSDK_iOS/ImSDK.framework", | |
| 353 | + "${BUILT_PRODUCTS_DIR}/YBImageBrowser/YBImageBrowser.framework", | |
| 354 | + "${BUILT_PRODUCTS_DIR}/YYAsyncLayer/YYAsyncLayer.framework", | |
| 355 | + "${BUILT_PRODUCTS_DIR}/YYCache/YYCache.framework", | |
| 356 | + "${BUILT_PRODUCTS_DIR}/YYCategories/YYCategories.framework", | |
| 357 | + "${BUILT_PRODUCTS_DIR}/YYDispatchQueuePool/YYDispatchQueuePool.framework", | |
| 358 | + "${BUILT_PRODUCTS_DIR}/YYImage/YYImage.framework", | |
| 359 | + "${BUILT_PRODUCTS_DIR}/YYKeyboardManager/YYKeyboardManager.framework", | |
| 360 | + "${BUILT_PRODUCTS_DIR}/YYModel/YYModel.framework", | |
| 361 | + "${BUILT_PRODUCTS_DIR}/YYText/YYText.framework", | |
| 362 | + "${BUILT_PRODUCTS_DIR}/YYWebImage/YYWebImage.framework", | |
| 363 | + "${BUILT_PRODUCTS_DIR}/libksygpulive/libksygpulive.framework", | |
| 332 | 364 | ); |
| 333 | 365 | name = "[CP] Embed Pods Frameworks"; |
| 334 | 366 | outputPaths = ( |
| 335 | - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/CNLiveCMineModule.framework", | |
| 367 | + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/AFNetworking.framework", | |
| 368 | + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/CNLiveBaseKit.framework", | |
| 369 | + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/CNLiveBeeHive.framework", | |
| 370 | + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/CNLiveBusinessBaseModule.framework", | |
| 371 | + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/CNLiveBusinessTools.framework", | |
| 372 | + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/CNLiveCacheManagerKit.framework", | |
| 373 | + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/CNLiveCommonCategory.framework", | |
| 374 | + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/CNLiveCustomUI.framework", | |
| 375 | + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/CNLiveEnvironment.framework", | |
| 376 | + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/CNLiveNewTripartiteManagement.framework", | |
| 377 | + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/CNLiveRequestBastKit.framework", | |
| 378 | + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/CNLiveUserManagement.framework", | |
| 379 | + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FMDB.framework", | |
| 380 | + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GPUImage.framework", | |
| 381 | + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/JXCategoryView.framework", | |
| 382 | + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MJExtension.framework", | |
| 383 | + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MJRefresh.framework", | |
| 384 | + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Masonry.framework", | |
| 385 | + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/QMUIKit.framework", | |
| 386 | + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SDWebImage.framework", | |
| 387 | + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ImSDK.framework", | |
| 388 | + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/YBImageBrowser.framework", | |
| 389 | + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/YYAsyncLayer.framework", | |
| 390 | + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/YYCache.framework", | |
| 391 | + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/YYCategories.framework", | |
| 392 | + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/YYDispatchQueuePool.framework", | |
| 393 | + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/YYImage.framework", | |
| 394 | + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/YYKeyboardManager.framework", | |
| 395 | + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/YYModel.framework", | |
| 396 | + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/YYText.framework", | |
| 397 | + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/YYWebImage.framework", | |
| 398 | + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/libksygpulive.framework", | |
| 336 | 399 | ); |
| 337 | 400 | runOnlyForDeploymentPostprocessing = 0; |
| 338 | 401 | shellPath = /bin/sh; |
| 339 | 402 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-CNLiveCMineModule_Example/Pods-CNLiveCMineModule_Example-frameworks.sh\"\n"; |
| 340 | 403 | showEnvVarsInLog = 0; |
| 341 | 404 | }; |
| 405 | + B325211E0D87340E247D54B4 /* [CP] Copy Pods Resources */ = { | |
| 406 | + isa = PBXShellScriptBuildPhase; | |
| 407 | + buildActionMask = 2147483647; | |
| 408 | + files = ( | |
| 409 | + ); | |
| 410 | + inputPaths = ( | |
| 411 | + "${PODS_ROOT}/Target Support Files/Pods-CNLiveCMineModule_Example/Pods-CNLiveCMineModule_Example-resources.sh", | |
| 412 | + "${PODS_CONFIGURATION_BUILD_DIR}/CNLivePhotoBrowser/CNLivePhotoBrowser.bundle", | |
| 413 | + ); | |
| 414 | + name = "[CP] Copy Pods Resources"; | |
| 415 | + outputPaths = ( | |
| 416 | + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/CNLivePhotoBrowser.bundle", | |
| 417 | + ); | |
| 418 | + runOnlyForDeploymentPostprocessing = 0; | |
| 419 | + shellPath = /bin/sh; | |
| 420 | + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-CNLiveCMineModule_Example/Pods-CNLiveCMineModule_Example-resources.sh\"\n"; | |
| 421 | + showEnvVarsInLog = 0; | |
| 422 | + }; | |
| 342 | 423 | F05AA9CF5A8C99DE74173316 /* [CP] Check Pods Manifest.lock */ = { |
| 343 | 424 | isa = PBXShellScriptBuildPhase; |
| 344 | 425 | buildActionMask = 2147483647; | ... | ... |
Example/CNLiveCMineModule/CNLIVEAppDelegate.h
| ... | ... | @@ -7,9 +7,9 @@ |
| 7 | 7 | // |
| 8 | 8 | |
| 9 | 9 | @import UIKit; |
| 10 | +#import <CNLiveBusinessBaseModule/CNLiveBusinessBaseModule.h> | |
| 10 | 11 | |
| 11 | -@interface CNLIVEAppDelegate : UIResponder <UIApplicationDelegate> | |
| 12 | +@interface CNLIVEAppDelegate : BaseAppDelegate <UIApplicationDelegate> | |
| 12 | 13 | |
| 13 | -@property (strong, nonatomic) UIWindow *window; | |
| 14 | 14 | |
| 15 | 15 | @end | ... | ... |
Example/Podfile
| 1 | 1 | use_frameworks! |
| 2 | 2 | |
| 3 | -platform :ios, '9.0' | |
| 3 | +platform :ios, '10.0' | |
| 4 | +source 'http://bj.gitlab.cnlive.com/ios-team/CNLiveRepos.git' | |
| 5 | +source 'https://mirrors.tuna.tsinghua.edu.cn/git/CocoaPods/Specs.git' | |
| 6 | +source 'http://bj.gitlab.cnlive.com/DSIOSTeam/DSSpecRepos.git' | |
| 4 | 7 | |
| 5 | 8 | target 'CNLiveCMineModule_Example' do |
| 6 | 9 | pod 'CNLiveCMineModule', :path => '../' | ... | ... |