Last active
March 13, 2019 07:10
-
-
Save antons/3bb151c1659ef47cf1ad17e07ea28c71 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#import <Foundation/Foundation.h> | |
#import <CommonCrypto/CommonHMAC.h> | |
#import <CoreFoundation/CoreFoundation.h> | |
static NSString *Base64URLEncodedStringWithData(NSData *data) { | |
NSMutableString *string = [[data base64EncodedStringWithOptions:0] mutableCopy]; | |
[string replaceOccurrencesOfString:@"+" withString:@"-" options:0 range:NSMakeRange(0, string.length)]; | |
[string replaceOccurrencesOfString:@"/" withString:@"_" options:0 range:NSMakeRange(0, string.length)]; | |
[string replaceOccurrencesOfString:@"=" withString:@"" options:0 range:NSMakeRange(0, string.length)]; | |
return string.copy; | |
} | |
static NSData *DataWithHexString(NSString *hex) { | |
if (hex.length % 2 == 0) { | |
char buf[3]; | |
buf[2] = '\0'; | |
unsigned char *bytes = calloc(hex.length / 2, sizeof(unsigned char)); | |
unsigned char *bp = bytes; | |
CFStringInlineBuffer inlineBuffer; | |
CFStringInitInlineBuffer((__bridge CFStringRef)hex, &inlineBuffer, CFRangeMake(0, hex.length)); | |
for (CFIndex i = 0; i < hex.length; i += 2) { | |
buf[0] = CFStringGetCharacterFromInlineBuffer(&inlineBuffer, i); | |
buf[1] = CFStringGetCharacterFromInlineBuffer(&inlineBuffer, i + 1); | |
char *b2 = NULL; | |
*bp++ = strtol(buf, &b2, 16); | |
} | |
return [NSData dataWithBytesNoCopy:bytes length:hex.length / 2 freeWhenDone:YES]; | |
} | |
return nil; | |
} | |
@implementation NSMutableURLRequest (Ghost) | |
+ (NSMutableURLRequest *)requestWithGhostAPIKey:(NSString *)APIKey APIURL:(NSURL *)APIURL endpoint:(NSString *)endpoint { | |
NSArray<NSString *> *APIKeyComponents = [APIKey componentsSeparatedByString:@":"]; | |
NSString *kid = APIKeyComponents.count != 2 ? @"unknown" : APIKeyComponents[0]; | |
NSString *secret = APIKeyComponents.count != 2 ? @"unknown" : APIKeyComponents[1]; | |
NSDate *date = [NSDate date]; | |
NSDateComponents *expirationDateComponents = [[NSDateComponents alloc] init]; | |
expirationDateComponents.minute = 5; | |
NSDate *expirationDate = [[NSCalendar currentCalendar] dateByAddingComponents:expirationDateComponents toDate:date options:0]; | |
NSError *JSONError; | |
NSData *headerData = [NSJSONSerialization dataWithJSONObject:@{@"alg": @"HS256", @"kid": kid, @"typ": @"JWT"} options:0 error:&JSONError]; | |
NSData *payloadData = [NSJSONSerialization dataWithJSONObject:@{@"exp": @(lround(expirationDate.timeIntervalSince1970)), @"iat": @(lround(date.timeIntervalSince1970)), @"aud": @"/v2/admin/"} options:0 error:&JSONError]; | |
NSMutableArray<NSString *> *tokenComponents = [[NSMutableArray alloc] init]; | |
[tokenComponents addObject:Base64URLEncodedStringWithData(headerData)]; | |
[tokenComponents addObject:Base64URLEncodedStringWithData(payloadData)]; | |
NSData *data = [[tokenComponents componentsJoinedByString:@"."] dataUsingEncoding:NSUTF8StringEncoding]; | |
NSData *secretData = DataWithHexString(secret); | |
NSMutableData *hmacData = [[NSMutableData alloc] initWithLength:CC_SHA256_DIGEST_LENGTH]; | |
CCHmac(kCCHmacAlgSHA256, secretData.bytes, secretData.length, data.bytes, data.length, hmacData.mutableBytes); | |
[tokenComponents addObject:Base64URLEncodedStringWithData(hmacData)]; | |
NSString *token = [tokenComponents componentsJoinedByString:@"."]; | |
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init]; | |
request.URL = [NSURL URLWithString:[NSString pathWithComponents:@[@"/ghost/api/v2/admin/", endpoint]] relativeToURL:APIURL]; | |
[request setValue:[NSString stringWithFormat:@"Ghost %@", token] forHTTPHeaderField:@"Authorization"]; | |
return request; | |
} | |
@end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment