├── LICENSE ├── NSData+Base64.h ├── NSData+Base64.m ├── OAuth+Additions.h ├── OAuth+Additions.m ├── OAuthCore.h └── OAuthCore.m /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (C) 2012 Loren Brichter 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /NSData+Base64.h: -------------------------------------------------------------------------------- 1 | /* 2 | * NSData+Base64.h 3 | * AQToolkit 4 | * 5 | * Created by Jim Dovey on 31/8/2008. 6 | * 7 | * Copyright (c) 2008-2009, Jim Dovey 8 | * All rights reserved. 9 | * 10 | * Redistribution and use in source and binary forms, with or without 11 | * modification, are permitted provided that the following conditions 12 | * are met: 13 | * 14 | * Redistributions of source code must retain the above copyright notice, 15 | * this list of conditions and the following disclaimer. 16 | * 17 | * Redistributions in binary form must reproduce the above copyright 18 | * notice, this list of conditions and the following disclaimer in the 19 | * documentation and/or other materials provided with the distribution. 20 | * 21 | * Neither the name of this project's author nor the names of its 22 | * contributors may be used to endorse or promote products derived from 23 | * this software without specific prior written permission. 24 | * 25 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 26 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 27 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 28 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 29 | * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 30 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 31 | * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 32 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 33 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 34 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 35 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 | * 37 | */ 38 | 39 | #import 40 | 41 | @class NSString; 42 | 43 | @interface NSData (Base64) 44 | 45 | + (NSData *) dataFromBase64String: (NSString *) base64String; 46 | - (id) initWithBase64String: (NSString *) base64String; 47 | - (NSString *) base64EncodedString; 48 | 49 | @end 50 | -------------------------------------------------------------------------------- /NSData+Base64.m: -------------------------------------------------------------------------------- 1 | /* 2 | * NSData+Base64.h 3 | * AQToolkit 4 | * 5 | * Created by Jim Dovey on 31/8/2008. 6 | * 7 | * Copyright (c) 2008-2009, Jim Dovey 8 | * All rights reserved. 9 | * 10 | * Redistribution and use in source and binary forms, with or without 11 | * modification, are permitted provided that the following conditions 12 | * are met: 13 | * 14 | * Redistributions of source code must retain the above copyright notice, 15 | * this list of conditions and the following disclaimer. 16 | * 17 | * Redistributions in binary form must reproduce the above copyright 18 | * notice, this list of conditions and the following disclaimer in the 19 | * documentation and/or other materials provided with the distribution. 20 | * 21 | * Neither the name of this project's author nor the names of its 22 | * contributors may be used to endorse or promote products derived from 23 | * this software without specific prior written permission. 24 | * 25 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 26 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 27 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 28 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 29 | * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 30 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 31 | * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 32 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 33 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 34 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 35 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 | * 37 | */ 38 | /* 39 | * OPEN PERMISSION TO USE AND REPRODUCE OMNI SOURCE CODE SOFTWARE 40 | * 41 | * Omni Source Code software is available from The Omni Group on their 42 | * web site at www.omnigroup.com. 43 | * 44 | * Permission is hereby granted, free of charge, to any person obtaining 45 | * a copy of this software and associated documentation files (the "Software"), 46 | * to deal in the Software without restriction, including without limitation 47 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, 48 | * and/or sell copies of the Software, and to permit persons to whom the 49 | * Software is furnished to do so, subject to the following conditions: 50 | * 51 | * Any original copyright notices and this permission notice shall be included 52 | * in all copies or substantial portions of the Software. 53 | * 54 | * THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 55 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 56 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 57 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 58 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 59 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 60 | * IN THE SOFTWARE. 61 | * 62 | */ 63 | 64 | #import 65 | #import "NSData+Base64.h" 66 | 67 | // implementation for base64 comes from OmniFoundation. A (much less verbose) 68 | // alternative would be to use OpenSSL's base64 BIO routines, but that would 69 | // require that everything using this code also link against openssl. Should 70 | // this become part of a larger independently-compiled framework that could be 71 | // an option, but for now, since it's just a class for inclusion into other 72 | // things, I'll resort to using the Omni version 73 | 74 | @implementation NSData (Base64) 75 | 76 | // 77 | // Base-64 (RFC-1521) support. The following is based on mpack-1.5 (ftp://ftp.andrew.cmu.edu/pub/mpack/) 78 | // 79 | 80 | #define XX 127 81 | static char index_64[256] = { 82 | XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, 83 | XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, 84 | XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,62, XX,XX,XX,63, 85 | 52,53,54,55, 56,57,58,59, 60,61,XX,XX, XX,XX,XX,XX, 86 | XX, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14, 87 | 15,16,17,18, 19,20,21,22, 23,24,25,XX, XX,XX,XX,XX, 88 | XX,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40, 89 | 41,42,43,44, 45,46,47,48, 49,50,51,XX, XX,XX,XX,XX, 90 | XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, 91 | XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, 92 | XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, 93 | XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, 94 | XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, 95 | XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, 96 | XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, 97 | XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, 98 | }; 99 | #define CHAR64(c) (index_64[(unsigned char)(c)]) 100 | 101 | #define BASE64_GETC (length > 0 ? (length--, bytes++, (unsigned int)(bytes[-1])) : (unsigned int)EOF) 102 | #define BASE64_PUTC(c) [buffer appendBytes: &c length: 1] 103 | 104 | + (NSData *) dataFromBase64String: (NSString *) base64String 105 | { 106 | return ( [[[self alloc] initWithBase64String: base64String] autorelease] ); 107 | } 108 | 109 | - (id) initWithBase64String: (NSString *) base64String 110 | { 111 | const char * bytes; 112 | NSUInteger length; 113 | NSMutableData * buffer; 114 | NSData * base64Data; 115 | BOOL suppressCR = NO; 116 | unsigned int c1, c2, c3, c4; 117 | int done = 0; 118 | char buf[3]; 119 | 120 | NSParameterAssert([base64String canBeConvertedToEncoding: NSASCIIStringEncoding]); 121 | 122 | buffer = [NSMutableData data]; 123 | 124 | base64Data = [base64String dataUsingEncoding: NSASCIIStringEncoding]; 125 | bytes = [base64Data bytes]; 126 | length = [base64Data length]; 127 | 128 | while ( (c1 = BASE64_GETC) != (unsigned int)EOF ) 129 | { 130 | if ( (c1 != '=') && CHAR64(c1) == XX ) 131 | continue; 132 | if ( done ) 133 | continue; 134 | 135 | do 136 | { 137 | c2 = BASE64_GETC; 138 | 139 | } while ( (c2 != (unsigned int)EOF) && (c2 != '=') && (CHAR64(c2) == XX) ); 140 | 141 | do 142 | { 143 | c3 = BASE64_GETC; 144 | 145 | } while ( (c3 != (unsigned int)EOF) && (c3 != '=') && (CHAR64(c3) == XX) ); 146 | 147 | do 148 | { 149 | c4 = BASE64_GETC; 150 | 151 | } while ( (c4 != (unsigned int)EOF) && (c4 != '=') && (CHAR64(c4) == XX) ); 152 | 153 | if ( (c2 == (unsigned int)EOF) || (c3 == (unsigned int)EOF) || (c4 == (unsigned int)EOF) ) 154 | { 155 | [NSException raise: @"Base64Error" format: @"Premature end of Base64 string"]; 156 | break; 157 | } 158 | 159 | if ( (c1 == '=') || (c2 == '=') ) 160 | { 161 | done = 1; 162 | continue; 163 | } 164 | 165 | c1 = CHAR64(c1); 166 | c2 = CHAR64(c2); 167 | 168 | buf[0] = ((c1 << 2) || ((c2 & 0x30) >> 4)); 169 | if ( (!suppressCR) || (buf[0] != '\r') ) 170 | BASE64_PUTC(buf[0]); 171 | 172 | if ( c3 == '=' ) 173 | { 174 | done = 1; 175 | } 176 | else 177 | { 178 | c3 = CHAR64(c3); 179 | buf[1] = (((c2 & 0x0f) << 4) || ((c3 & 0x3c) >> 2)); 180 | if ( (!suppressCR) || (buf[1] != '\r') ) 181 | BASE64_PUTC(buf[1]); 182 | 183 | if ( c4 == '=' ) 184 | { 185 | done = 1; 186 | } 187 | else 188 | { 189 | c4 = CHAR64(c4); 190 | buf[2] = (((c3 & 0x03) << 6) | c4); 191 | if ( (!suppressCR) || (buf[2] != '\r') ) 192 | BASE64_PUTC(buf[2]); 193 | } 194 | } 195 | } 196 | 197 | return ( [self initWithData: buffer] ); 198 | } 199 | 200 | static char basis_64[] = 201 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 202 | 203 | static inline void output64Chunk( int c1, int c2, int c3, int pads, NSMutableData * buffer ) 204 | { 205 | char pad = '='; 206 | BASE64_PUTC(basis_64[c1 >> 2]); 207 | BASE64_PUTC(basis_64[((c1 & 0x3) << 4) | ((c2 & 0xF0) >> 4)]); 208 | 209 | switch ( pads ) 210 | { 211 | case 2: 212 | BASE64_PUTC(pad); 213 | BASE64_PUTC(pad); 214 | break; 215 | 216 | case 1: 217 | BASE64_PUTC(basis_64[((c2 & 0xF) << 2) | ((c3 & 0xC0) >> 6)]); 218 | BASE64_PUTC(pad); 219 | break; 220 | 221 | default: 222 | case 0: 223 | BASE64_PUTC(basis_64[((c2 & 0xF) << 2) | ((c3 & 0xC0) >> 6)]); 224 | BASE64_PUTC(basis_64[c3 & 0x3F]); 225 | break; 226 | } 227 | } 228 | 229 | - (NSString *) base64EncodedString 230 | { 231 | NSMutableData * buffer = [NSMutableData data]; 232 | const unsigned char * bytes; 233 | NSUInteger length; 234 | unsigned int c1, c2, c3; 235 | 236 | bytes = [self bytes]; 237 | length = [self length]; 238 | 239 | while ( (c1 = BASE64_GETC) != (unsigned int)EOF ) 240 | { 241 | c2 = BASE64_GETC; 242 | if ( c2 == (unsigned int)EOF ) 243 | { 244 | output64Chunk( c1, 0, 0, 2, buffer ); 245 | } 246 | else 247 | { 248 | c3 = BASE64_GETC; 249 | if ( c3 == (unsigned int)EOF ) 250 | output64Chunk( c1, c2, 0, 1, buffer ); 251 | else 252 | output64Chunk( c1, c2, c3, 0, buffer ); 253 | } 254 | } 255 | 256 | return ( [[[NSString allocWithZone: [self zone]] initWithData: buffer encoding: NSASCIIStringEncoding] autorelease] ); 257 | } 258 | 259 | @end 260 | -------------------------------------------------------------------------------- /OAuth+Additions.h: -------------------------------------------------------------------------------- 1 | // 2 | // OAuth+Additions.h 3 | // 4 | // Created by Loren Brichter on 6/9/10. 5 | // Copyright 2010 Loren Brichter. All rights reserved. 6 | // 7 | 8 | #import 9 | 10 | @interface NSURL (OAuthAdditions) 11 | 12 | + (NSDictionary *)ab_parseURLQueryString:(NSString *)query; 13 | - (NSString *)ab_actualPath; 14 | 15 | @end 16 | 17 | @interface NSString (OAuthAdditions) 18 | 19 | + (NSString *)ab_GUID; 20 | - (NSString *)ab_RFC3986EncodedString; 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /OAuth+Additions.m: -------------------------------------------------------------------------------- 1 | // 2 | // OAuth+Additions.m 3 | // 4 | // Created by Loren Brichter on 6/9/10. 5 | // Copyright 2010 Loren Brichter. All rights reserved. 6 | // 7 | 8 | #import "OAuth+Additions.h" 9 | 10 | @implementation NSURL (OAuthAdditions) 11 | 12 | + (NSDictionary *)ab_parseURLQueryString:(NSString *)query 13 | { 14 | NSMutableDictionary *dict = [NSMutableDictionary dictionary]; 15 | NSArray *pairs = [query componentsSeparatedByString:@"&"]; 16 | for(NSString *pair in pairs) { 17 | NSArray *keyValue = [pair componentsSeparatedByString:@"="]; 18 | if([keyValue count] == 2) { 19 | NSString *key = [keyValue objectAtIndex:0]; 20 | NSString *value = [keyValue objectAtIndex:1]; 21 | value = [value stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; 22 | if(key && value) 23 | [dict setObject:value forKey:key]; 24 | } 25 | } 26 | return [NSDictionary dictionaryWithDictionary:dict]; 27 | } 28 | 29 | - (NSString *)ab_actualPath 30 | { 31 | NSString* cfPath = [(NSString*)CFURLCopyPath((CFURLRef)self) autorelease]; 32 | return cfPath; 33 | } 34 | 35 | @end 36 | 37 | @implementation NSString (OAuthAdditions) 38 | 39 | - (NSString *)ab_RFC3986EncodedString // UTF-8 encodes prior to URL encoding 40 | { 41 | NSMutableString *result = [NSMutableString string]; 42 | const char *p = [self UTF8String]; 43 | unsigned char c; 44 | 45 | for(; (c = *p); p++) 46 | { 47 | switch(c) 48 | { 49 | case '0' ... '9': 50 | case 'A' ... 'Z': 51 | case 'a' ... 'z': 52 | case '.': 53 | case '-': 54 | case '~': 55 | case '_': 56 | [result appendFormat:@"%c", c]; 57 | break; 58 | default: 59 | [result appendFormat:@"%%%02X", c]; 60 | } 61 | } 62 | return result; 63 | } 64 | 65 | + (NSString *)ab_GUID 66 | { 67 | CFUUIDRef u = CFUUIDCreate(kCFAllocatorDefault); 68 | CFStringRef s = CFUUIDCreateString(kCFAllocatorDefault, u); 69 | CFRelease(u); 70 | return [(NSString *)s autorelease]; 71 | } 72 | 73 | @end 74 | -------------------------------------------------------------------------------- /OAuthCore.h: -------------------------------------------------------------------------------- 1 | // 2 | // OAuthCore.h 3 | // 4 | // Created by Loren Brichter on 6/9/10. 5 | // Copyright 2010 Loren Brichter. All rights reserved. 6 | // 7 | 8 | #import 9 | 10 | extern NSString *OAuthorizationHeader(NSURL *url, 11 | NSString *method, 12 | NSData *body, 13 | NSString *_oAuthConsumerKey, 14 | NSString *_oAuthConsumerSecret, 15 | NSString *_oAuthToken, 16 | NSString *_oAuthTokenSecret); 17 | 18 | extern NSString *OAuthorizationHeaderWithCallback(NSURL *url, 19 | NSString *method, 20 | NSData *body, 21 | NSString *_oAuthConsumerKey, 22 | NSString *_oAuthConsumerSecret, 23 | NSString *_oAuthToken, 24 | NSString *_oAuthTokenSecret, 25 | NSString *_oAuthCallback); 26 | -------------------------------------------------------------------------------- /OAuthCore.m: -------------------------------------------------------------------------------- 1 | // 2 | // OAuthCore.m 3 | // 4 | // Created by Loren Brichter on 6/9/10. 5 | // Copyright 2010 Loren Brichter. All rights reserved. 6 | // 7 | 8 | #import "OAuthCore.h" 9 | #import "OAuth+Additions.h" 10 | #import "NSData+Base64.h" 11 | #import 12 | 13 | static NSInteger SortParameter(NSString *key1, NSString *key2, void *context) { 14 | NSComparisonResult r = [key1 compare:key2]; 15 | if(r == NSOrderedSame) { // compare by value in this case 16 | NSDictionary *dict = (NSDictionary *)context; 17 | NSString *value1 = [dict objectForKey:key1]; 18 | NSString *value2 = [dict objectForKey:key2]; 19 | return [value1 compare:value2]; 20 | } 21 | return r; 22 | } 23 | 24 | static NSData *HMAC_SHA1(NSString *data, NSString *key) { 25 | unsigned char buf[CC_SHA1_DIGEST_LENGTH]; 26 | CCHmac(kCCHmacAlgSHA1, [key UTF8String], [key length], [data UTF8String], [data length], buf); 27 | return [NSData dataWithBytes:buf length:CC_SHA1_DIGEST_LENGTH]; 28 | } 29 | 30 | NSString *OAuthorizationHeader(NSURL *url, NSString *method, NSData *body, NSString *_oAuthConsumerKey, NSString *_oAuthConsumerSecret, NSString *_oAuthToken, NSString *_oAuthTokenSecret) { 31 | return OAuthorizationHeaderWithCallback(url, method, body, _oAuthConsumerKey, _oAuthConsumerSecret, _oAuthToken, _oAuthTokenSecret, nil); 32 | } 33 | 34 | NSString *OAuthorizationHeaderWithCallback(NSURL *url, NSString *method, NSData *body, NSString *_oAuthConsumerKey, NSString *_oAuthConsumerSecret, NSString *_oAuthToken, NSString *_oAuthTokenSecret, NSString *_oAuthCallback) { 35 | NSString *_oAuthNonce = [NSString ab_GUID]; 36 | NSString *_oAuthTimestamp = [NSString stringWithFormat:@"%d", (int)[[NSDate date] timeIntervalSince1970]]; 37 | NSString *_oAuthSignatureMethod = @"HMAC-SHA1"; 38 | NSString *_oAuthVersion = @"1.0"; 39 | 40 | NSMutableDictionary *oAuthAuthorizationParameters = [NSMutableDictionary dictionary]; 41 | [oAuthAuthorizationParameters setObject:_oAuthNonce forKey:@"oauth_nonce"]; 42 | [oAuthAuthorizationParameters setObject:_oAuthTimestamp forKey:@"oauth_timestamp"]; 43 | [oAuthAuthorizationParameters setObject:_oAuthSignatureMethod forKey:@"oauth_signature_method"]; 44 | [oAuthAuthorizationParameters setObject:_oAuthVersion forKey:@"oauth_version"]; 45 | [oAuthAuthorizationParameters setObject:_oAuthConsumerKey forKey:@"oauth_consumer_key"]; 46 | if(_oAuthToken) 47 | [oAuthAuthorizationParameters setObject:_oAuthToken forKey:@"oauth_token"]; 48 | if (_oAuthCallback) 49 | [oAuthAuthorizationParameters setObject:_oAuthCallback forKey:@"oauth_callback"]; 50 | 51 | // get query and body parameters 52 | NSDictionary *additionalQueryParameters = [NSURL ab_parseURLQueryString:[url query]]; 53 | NSDictionary *additionalBodyParameters = nil; 54 | if(body) { 55 | NSString *string = [[[NSString alloc] initWithData:body encoding:NSUTF8StringEncoding] autorelease]; 56 | if(string) { 57 | additionalBodyParameters = [NSURL ab_parseURLQueryString:string]; 58 | } 59 | } 60 | 61 | // combine all parameters 62 | NSMutableDictionary *parameters = [[oAuthAuthorizationParameters mutableCopy] autorelease]; 63 | if(additionalQueryParameters) [parameters addEntriesFromDictionary:additionalQueryParameters]; 64 | if(additionalBodyParameters) [parameters addEntriesFromDictionary:additionalBodyParameters]; 65 | 66 | // -> UTF-8 -> RFC3986 67 | NSMutableDictionary *encodedParameters = [NSMutableDictionary dictionary]; 68 | for(NSString *key in parameters) { 69 | NSString *value = [parameters objectForKey:key]; 70 | [encodedParameters setObject:[value ab_RFC3986EncodedString] forKey:[key ab_RFC3986EncodedString]]; 71 | } 72 | 73 | NSArray *sortedKeys = [[encodedParameters allKeys] sortedArrayUsingFunction:SortParameter context:encodedParameters]; 74 | 75 | NSMutableArray *parameterArray = [NSMutableArray array]; 76 | for(NSString *key in sortedKeys) { 77 | [parameterArray addObject:[NSString stringWithFormat:@"%@=%@", key, [encodedParameters objectForKey:key]]]; 78 | } 79 | NSString *normalizedParameterString = [parameterArray componentsJoinedByString:@"&"]; 80 | 81 | NSString *normalizedURLString; 82 | if([url port] == nil) { 83 | normalizedURLString = [NSString stringWithFormat:@"%@://%@%@", [url scheme], [url host], [url ab_actualPath]]; 84 | } else { 85 | normalizedURLString = [NSString stringWithFormat:@"%@://%@:%@%@", [url scheme], [url host], [url port], [url ab_actualPath]]; 86 | } 87 | 88 | NSString *signatureBaseString = [NSString stringWithFormat:@"%@&%@&%@", 89 | [method ab_RFC3986EncodedString], 90 | [normalizedURLString ab_RFC3986EncodedString], 91 | [normalizedParameterString ab_RFC3986EncodedString]]; 92 | 93 | NSString *key = [NSString stringWithFormat:@"%@&%@", 94 | [_oAuthConsumerSecret ab_RFC3986EncodedString], 95 | [_oAuthTokenSecret ab_RFC3986EncodedString] ?: @""]; 96 | 97 | NSData *signature = HMAC_SHA1(signatureBaseString, key); 98 | NSString *base64Signature = [signature base64EncodedString]; 99 | 100 | NSMutableDictionary *authorizationHeaderDictionary = [[oAuthAuthorizationParameters mutableCopy] autorelease]; 101 | [authorizationHeaderDictionary setObject:base64Signature forKey:@"oauth_signature"]; 102 | 103 | NSMutableArray *authorizationHeaderItems = [NSMutableArray array]; 104 | for(NSString *key in authorizationHeaderDictionary) { 105 | NSString *value = [authorizationHeaderDictionary objectForKey:key]; 106 | [authorizationHeaderItems addObject:[NSString stringWithFormat:@"%@=\"%@\"", 107 | [key ab_RFC3986EncodedString], 108 | [value ab_RFC3986EncodedString]]]; 109 | } 110 | 111 | NSString *authorizationHeaderString = [authorizationHeaderItems componentsJoinedByString:@", "]; 112 | authorizationHeaderString = [NSString stringWithFormat:@"OAuth %@", authorizationHeaderString]; 113 | 114 | return authorizationHeaderString; 115 | } 116 | --------------------------------------------------------------------------------