1 Commits

Author SHA1 Message Date
61095a379f 处理网络 2026-02-03 20:22:28 +08:00
4 changed files with 62 additions and 21 deletions

View File

@@ -20,6 +20,10 @@ NS_ASSUME_NONNULL_BEGIN
+ (NSString *)signWithParams:(NSDictionary<NSString *, NSString *> *)params + (NSString *)signWithParams:(NSDictionary<NSString *, NSString *> *)params
secret:(NSString *)secret; secret:(NSString *)secret;
/// 获取签名原始拼接字符串HMAC 前的明文)
+ (NSString *)signSourceStringWithParams:(NSDictionary<NSString *, NSString *> *)params
secret:(NSString *)secret;
/// 秒级时间戳(字符串) /// 秒级时间戳(字符串)
+ (NSString *)currentTimestamp; + (NSString *)currentTimestamp;
@@ -29,4 +33,3 @@ NS_ASSUME_NONNULL_BEGIN
@end @end
NS_ASSUME_NONNULL_END NS_ASSUME_NONNULL_END

View File

@@ -12,10 +12,16 @@
+ (NSString *)urlEncode:(NSString *)value { + (NSString *)urlEncode:(NSString *)value {
if (!value) return @""; if (!value) return @"";
// Swift .urlQueryAllowed // application/x-www-form-urlencoded
NSCharacterSet *allowed = [NSCharacterSet URLQueryAllowedCharacterSet]; NSMutableCharacterSet *allowed = [NSMutableCharacterSet alphanumericCharacterSet];
[allowed addCharactersInString:@"-._*"];
NSString *encoded = [value stringByAddingPercentEncodingWithAllowedCharacters:allowed]; NSString *encoded = [value stringByAddingPercentEncodingWithAllowedCharacters:allowed];
return encoded ?: value; if (!encoded) {
return value;
}
// +URLEncoder
encoded = [encoded stringByReplacingOccurrencesOfString:@"%20" withString:@"+"];
return encoded;
} }
+ (NSString *)hmacSHA256:(NSString *)data secret:(NSString *)secret { + (NSString *)hmacSHA256:(NSString *)data secret:(NSString *)secret {
@@ -41,6 +47,12 @@
+ (NSString *)signWithParams:(NSDictionary<NSString *, NSString *> *)params + (NSString *)signWithParams:(NSDictionary<NSString *, NSString *> *)params
secret:(NSString *)secret { secret:(NSString *)secret {
NSString *dataString = [self signSourceStringWithParams:params secret:secret];
return [self hmacSHA256:dataString secret:secret];
}
+ (NSString *)signSourceStringWithParams:(NSDictionary<NSString *, NSString *> *)params
secret:(NSString *)secret {
// 1. & sign // 1. & sign
NSMutableDictionary<NSString *, NSString *> *filtered = [NSMutableDictionary dictionary]; NSMutableDictionary<NSString *, NSString *> *filtered = [NSMutableDictionary dictionary];
@@ -62,15 +74,11 @@
[components addObject:part]; [components addObject:part];
} }
NSString *encodedSecret = [self urlEncode:secret]; NSString *encodedSecret = [self urlEncode:secret ?: @""];
NSString *secretPart = [NSString stringWithFormat:@"secret=%@", encodedSecret]; NSString *secretPart = [NSString stringWithFormat:@"secret=%@", encodedSecret];
[components addObject:secretPart]; [components addObject:secretPart];
NSString *dataString = [components componentsJoinedByString:@"&"]; return [components componentsJoinedByString:@"&"];
// 4. HMAC-SHA256
NSString *sign = [self hmacSHA256:dataString secret:secret];
return sign;
} }
+ (NSString *)currentTimestamp { + (NSString *)currentTimestamp {
@@ -89,4 +97,3 @@
} }
@end @end

View File

@@ -119,12 +119,7 @@ autoShowBusinessError:NO
return; return;
} }
NSString *encodedContent = NSString *path = API_AI_CHAT_MESSAGE;
[content stringByAddingPercentEncodingWithAllowedCharacters:
[NSCharacterSet URLQueryAllowedCharacterSet]];
NSString *path = [NSString
stringWithFormat:@"%@?content=%@&companionId=%ld", API_AI_CHAT_MESSAGE,
encodedContent ?: @"", (long)companionId];
NSDictionary *params = @{ NSDictionary *params = @{
@"content" : content ?: @"", @"content" : content ?: @"",
@"companionId" : @(companionId) @"companionId" : @(companionId)

View File

@@ -33,6 +33,29 @@ NSErrorDomain const KBNetworkErrorDomain = @"com.company.keyboard.network";
@implementation KBNetworkManager @implementation KBNetworkManager
static NSString *KBSignStringFromObject(id obj) {
if (!obj || obj == (id)kCFNull) {
return nil;
}
if ([obj isKindOfClass:[NSString class]]) {
return (NSString *)obj;
}
if ([obj isKindOfClass:[NSNumber class]]) {
return [(NSNumber *)obj stringValue];
}
if ([obj isKindOfClass:[NSArray class]] || [obj isKindOfClass:[NSDictionary class]]) {
NSJSONWritingOptions options = 0;
if (@available(iOS 11.0, *)) {
options = NSJSONWritingSortedKeys;
}
NSData *data = [NSJSONSerialization dataWithJSONObject:obj options:options error:nil];
if (data.length > 0) {
return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
}
}
return [obj description];
}
+ (instancetype)shared { + (instancetype)shared {
static KBNetworkManager *m; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ m = [KBNetworkManager new]; }); static KBNetworkManager *m; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ m = [KBNetworkManager new]; });
return m; return m;
@@ -73,14 +96,24 @@ NSErrorDomain const KBNetworkErrorDomain = @"com.company.keyboard.network";
signParams[@"nonce"] = nonce; signParams[@"nonce"] = nonce;
// body // body
[bodyParams enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { [bodyParams enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
if ([obj isKindOfClass:[NSString class]]) { NSString *value = KBSignStringFromObject(obj);
signParams[key] = obj; if (value.length == 0) {
} else { return;
signParams[key] = [obj description];
} }
signParams[key] = value;
}]; }];
NSString *signSource = [KBSignUtils signSourceStringWithParams:signParams secret:secret];
NSString *sign = [KBSignUtils signWithParams:signParams secret:secret]; NSString *sign = [KBSignUtils signWithParams:signParams secret:secret];
#if DEBUG
if (signSource.length > 0) {
NSString *secretPart = [NSString stringWithFormat:@"secret=%@", [KBSignUtils urlEncode:secret ?: @""]];
NSString *masked = [signSource stringByReplacingOccurrencesOfString:secretPart withString:@"secret=***"];
KBLOG(@"[KBNetwork] sign source: %@", masked);
KBLOG(@"[KBNetwork] sign value: %@", sign ?: @"");
}
#endif
// //
NSMutableDictionary<NSString *, NSString *> *headers = NSMutableDictionary<NSString *, NSString *> *headers =
[self.defaultHeaders mutableCopy] ?: [NSMutableDictionary dictionary]; [self.defaultHeaders mutableCopy] ?: [NSMutableDictionary dictionary];
@@ -202,6 +235,7 @@ autoShowBusinessError:YES
parameters:(NSDictionary *)parameters parameters:(NSDictionary *)parameters
headers:(NSDictionary<NSString *,NSString *> *)headers headers:(NSDictionary<NSString *,NSString *> *)headers
completion:(KBNetworkDataCompletion)completion { completion:(KBNetworkDataCompletion)completion {
[self getSignWithParare:parameters];
if (!self.isEnabled) { if (!self.isEnabled) {
NSError *e = [NSError errorWithDomain:KBNetworkErrorDomain NSError *e = [NSError errorWithDomain:KBNetworkErrorDomain
code:KBNetworkErrorDisabled code:KBNetworkErrorDisabled
@@ -243,6 +277,7 @@ autoShowBusinessError:YES
completion:(KBNetworkCompletion)completion completion:(KBNetworkCompletion)completion
{ {
NSLog(@"[KBNetworkManager] UPLOAD called, enabled=%d, path=%@", self.isEnabled, path); NSLog(@"[KBNetworkManager] UPLOAD called, enabled=%d, path=%@", self.isEnabled, path);
[self getSignWithParare:@{}];
if (![self ensureEnabled:completion]) return nil; if (![self ensureEnabled:completion]) return nil;
NSString *urlString = [self buildURLStringWithPath:path]; NSString *urlString = [self buildURLStringWithPath:path];
@@ -330,6 +365,7 @@ autoShowBusinessError:YES
parameters:(NSDictionary *)parameters parameters:(NSDictionary *)parameters
headers:(NSDictionary<NSString *, NSString *> *)headers headers:(NSDictionary<NSString *, NSString *> *)headers
completion:(KBNetworkCompletion)completion { completion:(KBNetworkCompletion)completion {
[self getSignWithParare:parameters ?: @{}];
if (!fileURL || !fileURL.isFileURL) { if (!fileURL || !fileURL.isFileURL) {
if (completion) { if (completion) {
NSError *e = [NSError errorWithDomain:KBNetworkErrorDomain NSError *e = [NSError errorWithDomain:KBNetworkErrorDomain