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,14 +29,33 @@ TODO: Add long description of the pod here. | ||
| 29 | # s.social_media_url = 'https://twitter.com/<TWITTER_USERNAME>' | 29 | # s.social_media_url = 'https://twitter.com/<TWITTER_USERNAME>' |
| 30 | 30 | ||
| 31 | s.ios.deployment_target = '10.0' | 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 | # s.resource_bundles = { | 37 | # s.resource_bundles = { |
| 36 | # 'CNLiveCMineModule' => ['CNLiveCMineModule/Assets/*.png'] | 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 | # s.frameworks = 'UIKit', 'MapKit' | 42 | # s.frameworks = 'UIKit', 'MapKit' |
| 41 | # s.dependency 'AFNetworking', '~> 2.3' | 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 | end | 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,6 +208,7 @@ | ||
| 208 | 6003F587195388D20070C39A /* Frameworks */, | 208 | 6003F587195388D20070C39A /* Frameworks */, |
| 209 | 6003F588195388D20070C39A /* Resources */, | 209 | 6003F588195388D20070C39A /* Resources */, |
| 210 | 49D4349E8CEBA15A719A01F8 /* [CP] Embed Pods Frameworks */, | 210 | 49D4349E8CEBA15A719A01F8 /* [CP] Embed Pods Frameworks */, |
| 211 | + B325211E0D87340E247D54B4 /* [CP] Copy Pods Resources */, | ||
| 211 | ); | 212 | ); |
| 212 | buildRules = ( | 213 | buildRules = ( |
| 213 | ); | 214 | ); |
| @@ -328,17 +329,97 @@ | @@ -328,17 +329,97 @@ | ||
| 328 | ); | 329 | ); |
| 329 | inputPaths = ( | 330 | inputPaths = ( |
| 330 | "${PODS_ROOT}/Target Support Files/Pods-CNLiveCMineModule_Example/Pods-CNLiveCMineModule_Example-frameworks.sh", | 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 | name = "[CP] Embed Pods Frameworks"; | 365 | name = "[CP] Embed Pods Frameworks"; |
| 334 | outputPaths = ( | 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 | runOnlyForDeploymentPostprocessing = 0; | 400 | runOnlyForDeploymentPostprocessing = 0; |
| 338 | shellPath = /bin/sh; | 401 | shellPath = /bin/sh; |
| 339 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-CNLiveCMineModule_Example/Pods-CNLiveCMineModule_Example-frameworks.sh\"\n"; | 402 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-CNLiveCMineModule_Example/Pods-CNLiveCMineModule_Example-frameworks.sh\"\n"; |
| 340 | showEnvVarsInLog = 0; | 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 | F05AA9CF5A8C99DE74173316 /* [CP] Check Pods Manifest.lock */ = { | 423 | F05AA9CF5A8C99DE74173316 /* [CP] Check Pods Manifest.lock */ = { |
| 343 | isa = PBXShellScriptBuildPhase; | 424 | isa = PBXShellScriptBuildPhase; |
| 344 | buildActionMask = 2147483647; | 425 | buildActionMask = 2147483647; |
Example/CNLiveCMineModule/CNLIVEAppDelegate.h
| @@ -7,9 +7,9 @@ | @@ -7,9 +7,9 @@ | ||
| 7 | // | 7 | // |
| 8 | 8 | ||
| 9 | @import UIKit; | 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 | @end | 15 | @end |
Example/Podfile
| 1 | use_frameworks! | 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 | target 'CNLiveCMineModule_Example' do | 8 | target 'CNLiveCMineModule_Example' do |
| 6 | pod 'CNLiveCMineModule', :path => '../' | 9 | pod 'CNLiveCMineModule', :path => '../' |