增加换肤功能

This commit is contained in:
启星
2025-08-14 10:07:49 +08:00
parent f6964c1e89
commit 4f9318d98e
8789 changed files with 978530 additions and 2 deletions

View File

@@ -0,0 +1,35 @@
//
// OSSServiceSignature.h
// AliyunOSSSDK
//
// Created by ws on 2023/12/26.
// Copyright © 2023 aliyun. All rights reserved.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@protocol OSSServiceSignature <NSObject>
@property (nonatomic, copy, readonly) NSString *algorithm;
@property (nonatomic, copy, readonly) NSString *version;
- (NSData *)computeHash:(NSData *)key
data:(NSData *)data;
- (NSString *)computeSignature:(NSString *)key
data:(NSString *)data;
@end
@interface HmacSHA1Signature : NSObject<OSSServiceSignature>
@end
@interface HmacSHA256Signature : NSObject<OSSServiceSignature>
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,89 @@
//
// OSSServiceSignature.m
// AliyunOSSSDK
//
// Created by ws on 2023/12/26.
// Copyright © 2023 aliyun. All rights reserved.
//
#import "OSSServiceSignature.h"
#import <CommonCrypto/CommonHMAC.h>
#import "OSSUtil.h"
#define Version @"1"
#define AlgorithmSHA1 @"HmacSHA1"
#define AlgorithmSHA256 @"HmacSHA256"
@interface HmacSHA1Signature()
@end
@implementation HmacSHA1Signature
- (NSString *)algorithm {
return AlgorithmSHA1;
}
- (NSString *)version {
return Version;
}
- (NSData *)computeHash:(NSData *)key
data:(NSData *)data {
return [self sign:key data:data];
}
- (NSString *)computeSignature:(NSString *)key
data:(NSString *)data {
NSData *secretData = [key dataUsingEncoding:NSUTF8StringEncoding];
NSData *clearTextData = [data dataUsingEncoding:NSUTF8StringEncoding];
NSData *signData = [self sign:secretData data:clearTextData];
return [OSSUtil calBase64WithData:(UTF8Char*)signData.bytes];
}
- (NSData *)sign:(NSData *)key
data:(NSData *)data {
uint8_t input[CC_SHA1_DIGEST_LENGTH];
CCHmac(kCCHmacAlgSHA1, [key bytes], [key length], [data bytes], [data length], input);
return [NSData dataWithBytes:input length:CC_SHA1_DIGEST_LENGTH];
}
@end
@interface HmacSHA256Signature()
@end
@implementation HmacSHA256Signature
//static NSString *Algorithm = @"HmacSHA256";
- (NSString *)algorithm {
return AlgorithmSHA256;
}
- (NSString *)version {
return Version;
}
- (NSData *)computeHash:(NSData *)key
data:(NSData *)data {
return [self sign:key data:data];
}
- (NSString *)computeSignature:(NSString *)key
data:(NSString *)data {
NSData *secretData = [key dataUsingEncoding:NSUTF8StringEncoding];
NSData *clearTextData = [data dataUsingEncoding:NSUTF8StringEncoding];
NSData *signData = [self sign:secretData data:clearTextData];
return [OSSUtil calBase64WithData:(UTF8Char*)signData.bytes];
}
- (NSData *)sign:(NSData *)key
data:(NSData *)data {
uint8_t input[CC_SHA256_DIGEST_LENGTH];
CCHmac(kCCHmacAlgSHA256, [key bytes], [key length], [data bytes], [data length], input);
return [NSData dataWithBytes:input length:CC_SHA256_DIGEST_LENGTH];
}
@end

View File

@@ -0,0 +1,36 @@
//
// SignUtils.h
// AliyunOSSSDK
//
// Created by ws on 2023/12/26.
// Copyright © 2023 aliyun. All rights reserved.
//
#import <Foundation/Foundation.h>
@class OSSAllRequestNeededMessage;
NS_ASSUME_NONNULL_BEGIN
@interface OSSSignUtils : NSObject
+ (NSString *)composeRequestAuthorization:(NSString *)accessKeyId
signature:(NSString *)signature;
+ (NSString *)buildCanonicalString:(NSString *)method
resourcePath:(NSString *)resourcePath
request:(OSSAllRequestNeededMessage *)request
expires:(nullable NSString *)expires;
+ (NSString *)buildCanonicalizedResource:(NSString *)resourcePath
parameters:(NSDictionary *)parameters;
+ (NSString *)buildSignature:(NSString *)secretAccessKey
httpMethod:(NSString *)httpMethod
resourcePath:(NSString *)resourcePath
request:(OSSAllRequestNeededMessage *)request;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,113 @@
//
// SignUtils.m
// AliyunOSSSDK
//
// Created by ws on 2023/12/26.
// Copyright © 2023 aliyun. All rights reserved.
//
#import "OSSSignUtils.h"
#import "OSSDefine.h"
#import "OSSAllRequestNeededMessage.h"
#import "OSSUtil.h"
#import "OSSServiceSignature.h"
@implementation OSSSignUtils
#define NewLine @"\n"
+ (NSString *)composeRequestAuthorization:(NSString *)accessKeyId
signature:(NSString *)signature {
return [NSString stringWithFormat:@"%@%@:%@", OSSAuthorizationPrefix, accessKeyId, signature];
}
+ (NSString *)buildCanonicalString:(NSString *)method
resourcePath:(NSString *)resourcePath
request:(OSSAllRequestNeededMessage *)request
expires:(nullable NSString *)expires {
NSMutableString *canonicalString = [NSMutableString new];
[canonicalString appendString:method];
[canonicalString appendString:NewLine];
NSMutableDictionary<NSString *, NSString *> *headersToSign = @{}.mutableCopy;
if (request.contentType) {
headersToSign[OSSHttpHeaderContentType.lowercaseString] = request.contentType;
}
if (request.contentMd5) {
headersToSign[OSSHttpHeaderContentMD5.lowercaseString] = request.contentMd5;
}
[request.headerParams enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) {
NSString *lowerKey = [key lowercaseString];
if ([lowerKey isEqualToString:OSSHttpHeaderDate.lowercaseString] ||
[lowerKey hasPrefix:OSSPrefix.lowercaseString]) {
headersToSign[lowerKey] = [obj oss_trim];
}
}];
if (![[headersToSign allKeys] containsObject:OSSHttpHeaderContentType.lowercaseString]) {
headersToSign[OSSHttpHeaderContentType.lowercaseString] = @"";
}
if (![[headersToSign allKeys] containsObject:OSSHttpHeaderContentMD5.lowercaseString]) {
headersToSign[OSSHttpHeaderContentMD5.lowercaseString] = @"";
}
NSArray * sortedKey = [[headersToSign allKeys] sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
return [obj1 compare:obj2];
}];
for (NSString * key in sortedKey) {
if ([key hasPrefix:OSSPrefix]) {
[canonicalString appendString:key];
[canonicalString appendString:@":"];
[canonicalString appendString:headersToSign[key]];
} else {
[canonicalString appendString:headersToSign[key]];
}
[canonicalString appendString:NewLine];
}
[canonicalString appendString:[self buildCanonicalizedResource:resourcePath
parameters:request.params]];
return canonicalString;
}
+ (NSString *)buildCanonicalizedResource:(NSString *)resourcePath
parameters:(NSDictionary *)parameters {
NSAssert([resourcePath hasPrefix:@"/"], @"Resource path should start with slash character");
NSMutableArray * subresource = [NSMutableArray new];
NSArray *sortKeys = [parameters.allKeys sortedArrayUsingSelector:@selector(compare:)];
for (NSString *key in sortKeys) {
NSString * keyStr = [key oss_trim];
NSString * valueStr = [parameters[key] oss_trim];
if ([OSSUtil isSubresource:keyStr]) {
if ([valueStr length] == 0) {
[subresource addObject:keyStr];
} else {
[subresource addObject:[NSString stringWithFormat:@"%@=%@", keyStr, valueStr]];
}
}
}
if (subresource.count != 0) {
resourcePath = [[resourcePath stringByAppendingString:@"?"] stringByAppendingString:[subresource componentsJoinedByString:@"&"]];
}
return resourcePath;
}
+ (NSString *)buildSignature:(NSString *)secretAccessKey
httpMethod:(NSString *)httpMethod
resourcePath:(NSString *)resourcePath
request:(OSSAllRequestNeededMessage *)request {
NSString *canonicalString = [self buildCanonicalString:httpMethod
resourcePath:resourcePath
request:request
expires:nil];
return [[HmacSHA1Signature new] computeSignature:secretAccessKey
data:canonicalString];
}
@end

View File

@@ -0,0 +1,54 @@
//
// OSSSignerBase.h
// AliyunOSSSDK iOS
//
// Created by ws on 2023/12/26.
// Copyright © 2023 aliyun. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "OSSConstants.h"
@class OSSAllRequestNeededMessage;
@class OSSSignerParams;
@class OSSConstants;
@class OSSFederationToken;
@class OSSTask;
NS_ASSUME_NONNULL_BEGIN
@protocol OSSRequestSigner <NSObject>
- (OSSTask *)sign:(OSSAllRequestNeededMessage *)requestMessage;
@end
@protocol OSSRequestPresigner <NSObject>
- (OSSTask *)presign:(OSSAllRequestNeededMessage *)requestMessage;
@end
@interface OSSSignerBase : NSObject<OSSRequestSigner, OSSRequestPresigner>
@property (nonatomic, strong) OSSSignerParams *signerParams;
- (instancetype)initWithSignerParams:(OSSSignerParams *)signerParams;
- (void)addAuthorizationHeader:(OSSAllRequestNeededMessage *)request
federationToken:(OSSFederationToken *)federationToken;
- (void)addDateHeaderIfNeeded:(OSSAllRequestNeededMessage *)request;
- (void)addSecurityTokenHeaderIfNeeded:(OSSAllRequestNeededMessage *)request
federationToken:(OSSFederationToken *)federationToken;
+ (id<OSSRequestSigner>)createRequestSignerWithSignerVersion:(OSSSignVersion)signerVersion
signerParams:(OSSSignerParams *)signerParams;
+ (id<OSSRequestPresigner>)createRequestPresignerWithSignerVersion:(OSSSignVersion)signerVersion
signerParams:(OSSSignerParams *)signerParams;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,121 @@
//
// OSSSignerBase.m
// AliyunOSSSDK iOS
//
// Created by ws on 2023/12/26.
// Copyright © 2023 aliyun. All rights reserved.
//
#import "OSSSignerBase.h"
#import "NSDate+OSS.h"
#import "OSSDefine.h"
#import "OSSV1Signer.h"
#import "OSSV4Signer.h"
#import "OSSLog.h"
#import "OSSAllRequestNeededMessage.h"
#import "OSSSignerParams.h"
#import "OSSConstants.h"
#import "NSMutableDictionary+OSS.h"
@interface OSSSignerBase()
@end
@implementation OSSSignerBase
- (instancetype)initWithSignerParams:(OSSSignerParams *)signerParams {
self = [super init];
if (self) {
self.signerParams = signerParams;
}
return self;
}
- (void)addDateHeaderIfNeeded:(OSSAllRequestNeededMessage *)request {
NSDate *date = [NSDate oss_clockSkewFixedDate];
request.date = [date oss_asStringValue];
request.headerParams[OSSHttpHeaderDate] = [date oss_asStringValue];
}
- (void)addSecurityTokenHeaderIfNeeded:(OSSAllRequestNeededMessage *)request
federationToken:(OSSFederationToken *)federationToken {
if ([federationToken useSecurityToken] && !request.isUseUrlSignature) {
request.headerParams[OSSHttpHeaderSecurityToken] = federationToken.tToken;
}
}
- (void)addAuthorizationHeader:(OSSAllRequestNeededMessage *)request
federationToken:(OSSFederationToken *)federationToken {
}
- (NSString *)buildStringToSign:(OSSAllRequestNeededMessage *)request {
return nil;
}
- (OSSTask *)sign:(OSSAllRequestNeededMessage *)requestMessage {
id<OSSCredentialProvider> credentialProvider = self.signerParams.credentialProvider;
OSSFederationToken *federationToken;
NSError *error;
if ([credentialProvider isKindOfClass:[OSSFederationCredentialProvider class]]) {
federationToken = [(OSSFederationCredentialProvider *)credentialProvider getToken:&error];
} else if ([credentialProvider isKindOfClass:[OSSStsTokenCredentialProvider class]]) {
federationToken = [((OSSStsTokenCredentialProvider *)credentialProvider) getToken];
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
} else if ([credentialProvider isKindOfClass:[OSSPlainTextAKSKPairCredentialProvider class]]) {
federationToken = [[OSSFederationToken alloc] init];
federationToken.tAccessKey = ((OSSPlainTextAKSKPairCredentialProvider *)credentialProvider).accessKey;
federationToken.tSecretKey = ((OSSPlainTextAKSKPairCredentialProvider *)credentialProvider).secretKey;
}
#pragma clang diagnostic pop
if (error) {
[OSSTask taskWithError:error];
}
[self addDateHeaderIfNeeded:requestMessage];
if ([credentialProvider isKindOfClass:[OSSCustomSignerCredentialProvider class]]) {
OSSCustomSignerCredentialProvider *customSignerCredentialProvider = (OSSCustomSignerCredentialProvider *)credentialProvider;
NSString *stringToSign = [self buildStringToSign:requestMessage];
NSString *authorization = [customSignerCredentialProvider sign:stringToSign
error:&error];
[requestMessage.headerParams oss_setObject:authorization forKey:OSSHttpHeaderAuthorization];
} else {
if (federationToken == nil) {
OSSLogError(@"Can't get a federation token");
[OSSTask taskWithResult:[NSError errorWithDomain:OSSClientErrorDomain
code:OSSClientErrorCodeSignFailed
userInfo:@{OSSErrorMessageTOKEN: @"Can't get a federation token"}]];
}
[self addSecurityTokenHeaderIfNeeded:requestMessage federationToken:federationToken];
[self addAuthorizationHeader:requestMessage federationToken:federationToken];
}
if (error) {
[OSSTask taskWithError:error];
}
return [OSSTask taskWithResult:nil];
}
- (OSSTask *)presign:(OSSAllRequestNeededMessage *)requestMessage {
return [OSSTask taskWithResult:nil];
}
+ (id<OSSRequestSigner>)createRequestSignerWithSignerVersion:(OSSSignVersion)signerVersion
signerParams:(OSSSignerParams *)signerParams {
if (signerVersion == OSSSignVersionV4) {
return [[OSSV4Signer alloc] initWithSignerParams:signerParams];
} else {
return [[OSSV1Signer alloc] initWithSignerParams:signerParams];
}
}
+ (id<OSSRequestPresigner>)createRequestPresignerWithSignerVersion:(OSSSignVersion)signerVersion
signerParams:(OSSSignerParams *)signerParams {
if (signerVersion == OSSSignVersionV4) {
return [[OSSV4Signer alloc] initWithSignerParams:signerParams];
} else {
return [[OSSV1Signer alloc] initWithSignerParams:signerParams];
}
}
@end

View File

@@ -0,0 +1,32 @@
//
// OSSSignerParams.h
// AliyunOSSSDK iOS
//
// Created by ws on 2023/12/26.
// Copyright © 2023 aliyun. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "OSSModel.h"
NS_ASSUME_NONNULL_BEGIN
@interface OSSSignerParams : NSObject
@property (nonatomic, copy) NSString *resourcePath;
@property (nonatomic, strong) id<OSSCredentialProvider> credentialProvider;
@property (nonatomic, copy) NSString *product;
@property (nonatomic, copy) NSString *region;
@property (nonatomic, copy) NSString *cloudBoxId;
@property (nonatomic, assign) NSInteger expiration;
@property (nonatomic, strong) NSSet *additionalHeaderNames;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,13 @@
//
// OSSSignerParams.m
// AliyunOSSSDK iOS
//
// Created by ws on 2023/12/26.
// Copyright © 2023 aliyun. All rights reserved.
//
#import "OSSSignerParams.h"
@implementation OSSSignerParams
@end

View File

@@ -0,0 +1,17 @@
//
// OSSV1Signer.h
// AliyunOSSSDK
//
// Created by ws on 2023/12/26.
// Copyright © 2023 aliyun. All rights reserved.
//
#import "OSSSignerBase.h"
NS_ASSUME_NONNULL_BEGIN
@interface OSSV1Signer : OSSSignerBase
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,106 @@
//
// OSSV1Signer.m
// AliyunOSSSDK
//
// Created by ws on 2023/12/26.
// Copyright © 2023 aliyun. All rights reserved.
//
#import "OSSV1Signer.h"
#import "OSSModel.h"
#import "OSSAllRequestNeededMessage.h"
#import "OSSSignUtils.h"
#import "OSSSignerParams.h"
#import "OSSServiceSignature.h"
#import "OSSDefine.h"
#import "NSDate+OSS.h"
#import "NSMutableDictionary+OSS.h"
@implementation OSSV1Signer
- (void)addAuthorizationHeader:(OSSAllRequestNeededMessage *)request
federationToken:(OSSFederationToken *)federationToken {
NSString *canonicalString = [self buildStringToSign:request];
NSString *signature = [[HmacSHA1Signature new] computeSignature:federationToken.tSecretKey
data:canonicalString];
request.headerParams[OSSHttpHeaderAuthorization] = [OSSSignUtils composeRequestAuthorization:federationToken.tAccessKey
signature:signature];
}
- (OSSTask *)presign:(OSSAllRequestNeededMessage *)requestMessage {
NSMutableDictionary *params = requestMessage.params.mutableCopy;
id<OSSCredentialProvider> credentialProvider = self.signerParams.credentialProvider;
OSSFederationToken *federationToken;
NSError * error = nil;
if ([credentialProvider isKindOfClass:[OSSFederationCredentialProvider class]]) {
federationToken = [(OSSFederationCredentialProvider *)credentialProvider getToken:&error];
if (error) {
return [OSSTask taskWithError:error];
}
} else if ([credentialProvider isKindOfClass:[OSSStsTokenCredentialProvider class]]) {
federationToken = [(OSSStsTokenCredentialProvider *)credentialProvider getToken];
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
} else if ([credentialProvider isKindOfClass:[OSSPlainTextAKSKPairCredentialProvider class]]) {
federationToken = [[OSSFederationToken alloc] init];
federationToken.tAccessKey = ((OSSPlainTextAKSKPairCredentialProvider *)credentialProvider).accessKey;
federationToken.tSecretKey = ((OSSPlainTextAKSKPairCredentialProvider *)credentialProvider).secretKey;
}
#pragma clang diagnostic pop
NSString *canonicalResource = self.signerParams.resourcePath;
NSString * expires = [@((int64_t)[[NSDate oss_clockSkewFixedDate] timeIntervalSince1970] + self.signerParams.expiration) stringValue];
if (federationToken.useSecurityToken) {
[params oss_setObject:federationToken.tToken forKey:@"security-token"];
}
requestMessage.params = params;
requestMessage.headerParams[OSSHttpHeaderDate] = expires;
NSString *canonicalString = [OSSSignUtils buildCanonicalString:requestMessage.httpMethod
resourcePath:canonicalResource
request:requestMessage
expires:expires];
NSString *signature;
NSString *accessKey = federationToken.tAccessKey;
if ([credentialProvider isKindOfClass:[OSSCustomSignerCredentialProvider class]]) {
NSString *wholeSign = [(OSSCustomSignerCredentialProvider *)credentialProvider sign:canonicalString
error:&error];
NSArray * splitResult = [wholeSign componentsSeparatedByString:@":"];
if ([splitResult count] != 2
|| ![((NSString *)[splitResult objectAtIndex:0]) hasPrefix:@"OSS "]) {
return [OSSTask taskWithError:[NSError errorWithDomain:OSSClientErrorDomain
code:OSSClientErrorCodeSignFailed
userInfo:@{OSSErrorMessageTOKEN: @"the returned signature is invalid"}]];
}
accessKey = [(NSString *)[splitResult objectAtIndex:0] substringFromIndex:4];
signature = [splitResult objectAtIndex:1];
} else {
if (federationToken == nil) {
return [OSSTask taskWithError:[NSError errorWithDomain:OSSClientErrorDomain
code:OSSClientErrorCodeSignFailed
userInfo:@{OSSErrorMessageTOKEN: @"Can't get a federation token"}]];
}
signature = [[HmacSHA1Signature new] computeSignature:federationToken.tSecretKey
data:canonicalString];
}
if (error) {
return [OSSTask taskWithError:error];
}
[params oss_setObject:expires forKey:OSSRequestParameterExpires];
[params oss_setObject:accessKey forKey:OSSRequestParameterAccessKeyId];
[params oss_setObject:signature forKey:OSSRequestParameterSignature];
requestMessage.params = params;
return [OSSTask taskWithResult:nil];
}
- (NSString *)buildStringToSign:(OSSAllRequestNeededMessage *)request {
NSString *canonicalString = [OSSSignUtils buildCanonicalString:request.httpMethod
resourcePath:self.signerParams.resourcePath
request:request
expires:nil];
return canonicalString;
}
@end

View File

@@ -0,0 +1,19 @@
//
// OSSV4Signer.h
// AliyunOSSSDK
//
// Created by ws on 2023/12/26.
// Copyright © 2023 aliyun. All rights reserved.
//
#import "OSSSignerBase.h"
NS_ASSUME_NONNULL_BEGIN
@interface OSSV4Signer : OSSSignerBase
- (NSData *)buildSigningKey:(OSSFederationToken *)federationToken;
- (void)initRequestDateTime;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,361 @@
//
// OSSV4Signer.m
// AliyunOSSSDK
//
// Created by ws on 2023/12/26.
// Copyright © 2023 aliyun. All rights reserved.
//
#import "OSSV4Signer.h"
#import "NSDate+OSS.h"
#import "OSSDefine.h"
#import "OSSAllRequestNeededMessage.h"
#import "NSMutableDictionary+OSS.h"
#import "OSSSignerParams.h"
#import "OSSUtil.h"
#import "NSSet+OSS.h"
#import "NSData+OSS.h"
#import "OSSServiceSignature.h"
#import "OSSLog.h"
#define ISO8601DateTimeFormat @"yyyyMMdd'T'HHmmss'Z'"
#define ISO8601DateFormat @"yyyyMMdd"
#define NewLine @"\n"
#define SeparatorBackslash @"/"
#define Terminator @"aliyun_v4_request"
#define OSS4HMacSHA256 @"OSS4-HMAC-SHA256"
#define SecretKeyPrefix @"aliyun_v4"
@interface OSSV4Signer()
@property (nonatomic, copy) NSDate *requestDateTime;
@property (nonatomic, copy) NSArray<NSString *> *additionalSignedHeaders;
@end
@implementation OSSV4Signer
- (NSString *)getDateTime {
return [self.requestDateTime oss_asStringValueWithDateFormat:ISO8601DateTimeFormat];
}
- (NSString *)getDate {
return [self.requestDateTime oss_asStringValueWithDateFormat:ISO8601DateFormat];
}
- (BOOL)hasDefaultSignedHeaders:(NSString *)header {
if ([@[OSSHttpHeaderContentType.lowercaseString, OSSHttpHeaderContentMD5.lowercaseString] containsObject:header]) {
return YES;
}
return [header hasPrefix:OSSPrefix];
}
- (BOOL)hasSignedHeaders:(NSString *)header {
if ([self hasDefaultSignedHeaders:header]) {
return YES;
}
return [self.additionalSignedHeaders containsObject:header.lowercaseString];
}
- (BOOL)hasAdditionalSignedHeaders {
return self.additionalSignedHeaders != nil && self.additionalSignedHeaders.count != 0;
}
- (void)resolveAdditionalSignedHeaders:(OSSAllRequestNeededMessage *)request
headerNames:(NSSet<NSString *> *)headerNames {
NSMutableArray<NSString *> *signedHeaders = [NSMutableArray new];
if (headerNames) {
for (NSString *additionalHeader in headerNames) {
NSString *additionalHeaderKey = additionalHeader.lowercaseString;
[request.headerParams enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) {
if ([key isKindOfClass:[NSString class]] &&
[[key lowercaseString] isEqualToString:additionalHeaderKey] &&
![self hasDefaultSignedHeaders:additionalHeaderKey]) {
[signedHeaders addObject:additionalHeaderKey];
}
}];
}
}
self.additionalSignedHeaders = [signedHeaders sortedArrayUsingSelector:@selector(compare:)];
}
- (void)addSignedHeaderIfNeeded:(OSSAllRequestNeededMessage *)request {
if ([self.additionalSignedHeaders containsObject:OSSHttpHeaderHost.lowercaseString] &&
[request.headerParams.allKeys containsObject:OSSHttpHeaderHost.lowercaseString]) {
[request.headerParams oss_setObject:[[[NSURL alloc] initWithString:request.endpoint] host] forKey:OSSHttpHeaderHost];
}
}
- (void)addOSSContentSha256Header:(OSSAllRequestNeededMessage *)request {
request.headerParams[OSSHttpHeaderContentSha256] = @"UNSIGNED-PAYLOAD";
}
- (void)addDateHeaderIfNeeded:(OSSAllRequestNeededMessage *)request {
[self initRequestDateTime];
NSString *date = [self getDateTime];
request.date = date;
[request.headerParams oss_setObject:date forKey:OSSHttpHeaderDateEx];
[request.headerParams oss_setObject:date forKey:OSSHttpHeaderDate];
}
- (void)initRequestDateTime {
self.requestDateTime = [NSDate oss_clockSkewFixedDate];
}
- (NSString *)buildCanonicalRequest:(OSSAllRequestNeededMessage *)request {
NSString *method = request.httpMethod;
NSString *resourcePath = self.signerParams.resourcePath;
NSMutableString *canonicalString = [NSMutableString new];
//http method + "\n"
[canonicalString appendString:method];
[canonicalString appendString:NewLine];
//Canonical URI + "\n"
[canonicalString appendString:[OSSUtil encodeResourcePath:resourcePath]];
[canonicalString appendString:NewLine];
//Canonical Query String + "\n" +
NSMutableArray * params = [NSMutableArray new];
NSMutableDictionary *encodedParams = @{}.mutableCopy;
for (NSString *key in request.params.allKeys) {
NSString *encodedValue = [OSSUtil encodeQuery:[request.params[key] oss_trim]];
NSString *encodedKey = [OSSUtil encodeQuery:key];
[encodedParams oss_setObject:encodedValue forKey:encodedKey];
}
NSArray *allParamsKey = [encodedParams.allKeys sortedArrayUsingSelector:@selector(compare:)];
for (NSString *key in allParamsKey) {
NSString *value = encodedParams[key];
if ([value oss_isNotEmpty]) {
[params addObject:[NSString stringWithFormat:@"%@=%@", key, value]];
} else {
[params addObject:[NSString stringWithFormat:@"%@", key]];
}
}
[canonicalString appendString:[params componentsJoinedByString:@"&"]];
[canonicalString appendString:NewLine];
//Canonical Headers + "\n" +
NSMutableArray * headers = [NSMutableArray new];
NSMutableDictionary *headerParams = request.headerParams.mutableCopy;
if (request.contentType) {
headerParams[OSSHttpHeaderContentType.lowercaseString] = request.contentType;
}
if (request.contentMd5) {
headerParams[OSSHttpHeaderContentMD5.lowercaseString] = request.contentMd5;
}
NSMutableDictionary *lowercaseHeaders = @{}.mutableCopy;
for (NSString *key in headerParams.allKeys) {
[lowercaseHeaders oss_setObject:headerParams[key] forKey:key.lowercaseString];
}
NSArray *allHeaderKey = [lowercaseHeaders.allKeys sortedArrayUsingSelector:@selector(compare:)];
for (NSString *key in allHeaderKey) {
NSString *keyStr = [key oss_trim];
NSString *valueStr = [lowercaseHeaders[key] oss_trim];
if ([self hasSignedHeaders:keyStr] && [valueStr oss_isNotEmpty]) {
[headers addObject:[NSString stringWithFormat:@"%@:%@%@", keyStr, valueStr, NewLine]];
}
}
[canonicalString appendString:[headers componentsJoinedByString:@""]];
[canonicalString appendString:NewLine];
//Additional Headers + "\n" +
if (self.additionalSignedHeaders) {
NSString *canonicalPartStr = [self.additionalSignedHeaders componentsJoinedByString:@";"];
[canonicalString appendString:canonicalPartStr];
[canonicalString appendString:NewLine];
}
//Hashed PayLoad
NSString *hashedPayLoad = request.headerParams[OSSHttpHeaderContentSha256];
if (![hashedPayLoad oss_isNotEmpty]) {
hashedPayLoad = @"UNSIGNED-PAYLOAD";
}
[canonicalString appendString:hashedPayLoad];
return canonicalString;
}
- (NSString *)getSignRegion {
if ([self.signerParams.cloudBoxId oss_isNotEmpty]) {
return self.signerParams.cloudBoxId;
}
return self.signerParams.region;
}
- (NSString *)getSignProduct {
if ([self.signerParams.cloudBoxId oss_isNotEmpty]) {
return OSSProductCloudBox;
}
return OSSProductDefault;
}
- (NSString *)buildScope {
NSString *build = [[self getDate] stringByAppendingString:SeparatorBackslash];
build = [[build stringByAppendingString:[self getSignRegion]] stringByAppendingString:SeparatorBackslash];
build = [[build stringByAppendingString:[self getSignProduct]] stringByAppendingString:SeparatorBackslash];
build = [build stringByAppendingString:Terminator];
return build;
}
- (NSString *)buildStringToSign:(NSString *)canonicalString {
NSString *build = [OSS4HMacSHA256 stringByAppendingString:NewLine];
build = [[build stringByAppendingString:[self getDateTime]] stringByAppendingString:NewLine];
build = [[build stringByAppendingString:[self buildScope]] stringByAppendingString:NewLine];
build = [build stringByAppendingString:[[[canonicalString dataUsingEncoding:NSUTF8StringEncoding] calculateSha256] hexString]];
return build;
}
- (NSData *)buildSigningKey:(OSSFederationToken *)federationToken {
id<OSSServiceSignature> signature = [HmacSHA256Signature new];
NSData *signingSecret = [[SecretKeyPrefix stringByAppendingString:federationToken.tSecretKey] dataUsingEncoding:NSUTF8StringEncoding];
NSData *signingDate = [signature computeHash:signingSecret data:[[self getDate] dataUsingEncoding:NSUTF8StringEncoding]];
NSData *signingRegion = [signature computeHash:signingDate data:[[self getSignRegion] dataUsingEncoding:NSUTF8StringEncoding]];
NSData *signingService = [signature computeHash:signingRegion data:[[self getSignProduct] dataUsingEncoding:NSUTF8StringEncoding]];
return [signature computeHash:signingService data:[Terminator dataUsingEncoding:NSUTF8StringEncoding]];
}
- (NSString *)buildSignature:(NSData *)signingKey
stringToSign:(NSString *)stringToSign {
NSData *result = [[HmacSHA256Signature new] computeHash:signingKey
data:[stringToSign dataUsingEncoding:NSUTF8StringEncoding]];
return [result hexString];
}
- (NSString *)buildAuthorization:(NSString *)signature
federationToken:(OSSFederationToken *)federationToken {
NSString *credential = [@"Credential=" stringByAppendingFormat:@"%@%@%@", federationToken.tAccessKey, SeparatorBackslash, [self buildScope]];
NSString *signedHeaders = ![self hasAdditionalSignedHeaders] ? @"" : [@",AdditionalHeaders=" stringByAppendingString:[self.additionalSignedHeaders componentsJoinedByString:@";"]];
NSString *sign = [@",Signature=" stringByAppendingString:signature];
return [@"OSS4-HMAC-SHA256 " stringByAppendingFormat:@"%@%@%@", credential, signedHeaders, sign];
}
- (void)addAuthorizationHeader:(OSSAllRequestNeededMessage *)request
federationToken:(OSSFederationToken *)federationToken {
NSString *stringToSign = [self buildStringToSignWithRequest:request];
NSData *signingKey = [self buildSigningKey:federationToken];
NSString *signature = [self buildSignature:signingKey stringToSign:stringToSign];
NSString *authorization = [self buildAuthorization:signature
federationToken:federationToken];
[request.headerParams oss_setObject:authorization forKey:OSSHttpHeaderAuthorization];
}
- (NSString *)buildStringToSignWithRequest:(OSSAllRequestNeededMessage *)request {
NSString *canonicalRequest = [self buildCanonicalRequest:request];
OSSLogVerbose(@"canonicalRequest: %@", canonicalRequest);
NSString *stringToSign = [self buildStringToSign:canonicalRequest];
return stringToSign;
}
- (OSSTask *)sign:(OSSAllRequestNeededMessage *)requestMessage {
id<OSSCredentialProvider> credentialProvider = self.signerParams.credentialProvider;
if ([credentialProvider isKindOfClass:[OSSCustomSignerCredentialProvider class]]) {
return [OSSTask taskWithError:[NSError errorWithDomain:OSSClientErrorDomain
code:OSSClientErrorCodeSignFailed
userInfo:@{OSSErrorMessageTOKEN: @"V4 signature does not support OSSCustomSignerCredentialProvider"}]];
}
OSSFederationToken *federationToken;
NSError * error = nil;
if ([credentialProvider isKindOfClass:[OSSFederationCredentialProvider class]]) {
federationToken = [(OSSFederationCredentialProvider *)credentialProvider getToken:&error];
if (error) {
return [OSSTask taskWithError:error];
}
} else if ([credentialProvider isKindOfClass:[OSSStsTokenCredentialProvider class]]) {
federationToken = [(OSSStsTokenCredentialProvider *)credentialProvider getToken];
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
} else if ([credentialProvider isKindOfClass:[OSSPlainTextAKSKPairCredentialProvider class]]) {
federationToken = [[OSSFederationToken alloc] init];
federationToken.tAccessKey = ((OSSPlainTextAKSKPairCredentialProvider *)credentialProvider).accessKey;
federationToken.tSecretKey = ((OSSPlainTextAKSKPairCredentialProvider *)credentialProvider).secretKey;
}
#pragma clang diagnostic pop
[self addDateHeaderIfNeeded:requestMessage];
if (federationToken == nil) {
return [OSSTask taskWithError:[NSError errorWithDomain:OSSClientErrorDomain
code:OSSClientErrorCodeSignFailed
userInfo:@{OSSErrorMessageTOKEN: @"Can't get a federation token"}]];
}
[self resolveAdditionalSignedHeaders:requestMessage
headerNames:requestMessage.additionalHeaderNames];
[self addSignedHeaderIfNeeded:requestMessage];
[self addSecurityTokenHeaderIfNeeded:requestMessage
federationToken:federationToken];
[self addOSSContentSha256Header:requestMessage];
[self addAuthorizationHeader:requestMessage
federationToken:federationToken];
return [OSSTask taskWithResult:nil];
}
- (OSSTask *)presign:(OSSAllRequestNeededMessage *)requestMessage {
id<OSSCredentialProvider> credentialProvider = self.signerParams.credentialProvider;
if ([credentialProvider isKindOfClass:[OSSCustomSignerCredentialProvider class]]) {
return [OSSTask taskWithError:[NSError errorWithDomain:OSSClientErrorDomain
code:OSSClientErrorCodeSignFailed
userInfo:@{OSSErrorMessageTOKEN: @"V4 signature does not support OSSCustomSignerCredentialProvider"}]];
}
OSSFederationToken *federationToken;
NSError * error = nil;
if ([credentialProvider isKindOfClass:[OSSFederationCredentialProvider class]]) {
federationToken = [(OSSFederationCredentialProvider *)credentialProvider getToken:&error];
if (error) {
return [OSSTask taskWithError:error];
}
} else if ([credentialProvider isKindOfClass:[OSSStsTokenCredentialProvider class]]) {
federationToken = [(OSSStsTokenCredentialProvider *)credentialProvider getToken];
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
} else if ([credentialProvider isKindOfClass:[OSSPlainTextAKSKPairCredentialProvider class]]) {
federationToken = [[OSSFederationToken alloc] init];
federationToken.tAccessKey = ((OSSPlainTextAKSKPairCredentialProvider *)credentialProvider).accessKey;
federationToken.tSecretKey = ((OSSPlainTextAKSKPairCredentialProvider *)credentialProvider).secretKey;
}
#pragma clang diagnostic pop
NSMutableDictionary *params = requestMessage.params.mutableCopy;
// date
[self initRequestDateTime];
NSString *expires = [NSString stringWithFormat:@"%@", @(self.signerParams.expiration)];
params[@"x-oss-date"] = [self getDateTime];
params[@"x-oss-expires"] = expires;
// signed header
[self resolveAdditionalSignedHeaders:requestMessage
headerNames:self.signerParams.additionalHeaderNames];
[self addSignedHeaderIfNeeded:requestMessage];
if ([self hasAdditionalSignedHeaders]) {
params[@"x-oss-additional-headers"] = [self.additionalSignedHeaders componentsJoinedByString:@";"];
}
params[@"x-oss-signature-version"] = @"OSS4-HMAC-SHA256";
NSString *signature;
if ([federationToken useSecurityToken]) {
params[OSSHttpHeaderSecurityToken] = federationToken.tToken;
}
NSString *credential = [NSString stringWithFormat:@"%@%@%@", federationToken.tAccessKey, SeparatorBackslash, [self buildScope]];
params[@"x-oss-credential"] = credential;
requestMessage.params = params;
NSString *stringToSign = [self buildStringToSignWithRequest:requestMessage];
NSData *signingKey = [self buildSigningKey:federationToken];
signature = [self buildSignature:signingKey stringToSign:stringToSign];
params[@"x-oss-signature"] = signature;
requestMessage.params = params;
return [OSSTask taskWithResult:nil];
}
@end