Skip to content
This repository has been archived by the owner on Dec 18, 2022. It is now read-only.

Commit

Permalink
Got login working again
Browse files Browse the repository at this point in the history
  • Loading branch information
NSExceptional committed Oct 4, 2015
1 parent 3ce3871 commit 04084fa
Show file tree
Hide file tree
Showing 10 changed files with 120 additions and 59 deletions.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@
B4D11B9D1B90E3850012116A /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0640;
LastUpgradeCheck = 0700;
ORGANIZATIONNAME = "Tanner Bennett";
TargetAttributes = {
B4D11BA41B90E3850012116A = {
Expand Down Expand Up @@ -225,6 +225,7 @@
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
Expand Down
30 changes: 16 additions & 14 deletions Example/SnapchatKit-OSX/SnapchatKit-OSX/main.m
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,9 @@ int main(int argc, const char * argv[]) {
// Cannot seem to "solve" a captcha.
// registerAccount(@"[email protected]", @"12345678h", @"1995-08-01");

[SKClient sharedClient].casperAPIKey = kCasperAPIKey;
[SKClient sharedClient].casperAPISecret = kCasperAPISecret;

[[SKClient sharedClient] signInWithUsername:kUsername password:kPassword gmail:kGmail gpass:kGmailPassword completion:^(NSDictionary *dict, NSError *error) {
if (!error) {
SKSession *session = [SKClient sharedClient].currentSession;
Expand Down Expand Up @@ -245,19 +248,18 @@ int main(int argc, const char * argv[]) {
NSArray *unread = session.unread;
SKLog(@"%lu unread snaps: %@", unread.count, unread);

id foo = [dict[@"updates_response"] allKeys];

SKStoryCollection *friend = [[SKClient sharedClient].currentSession.stories
filteredOrderedSetUsingPredicate:[NSPredicate predicateWithFormat:@"%K BEGINSWITH %@", @"displayName", @""]].firstObject;
for (SKStory *s in friend.stories)
[s load:^(NSError *error1) {
if (!error1) {
NSLog(@"Saving %@: %@", SKStringFromMediaKind(s.mediaKind), s.suggestedFilename);
[s.blob writeToPath:[directory stringByAppendingString:@"/Test-download"] filename:s.suggestedFilename atomically:YES];
} else {
NSLog(@"Error loading %@: %@", SKStringFromMediaKind(s.mediaKind), error1.localizedDescription);
}
}];
//
// SKStoryCollection *friend = [[SKClient sharedClient].currentSession.stories
// filteredOrderedSetUsingPredicate:[NSPredicate predicateWithFormat:@"%K BEGINSWITH %@", @"displayName", @""]].firstObject;
// for (SKStory *s in friend.stories)
// [s load:^(NSError *error1) {
// if (!error1) {
// NSLog(@"Saving %@: %@", SKStringFromMediaKind(s.mediaKind), s.suggestedFilename);
// [s.blob writeToPath:[directory stringByAppendingString:@"/Test-download"] filename:s.suggestedFilename atomically:YES];
// } else {
// NSLog(@"Error loading %@: %@", SKStringFromMediaKind(s.mediaKind), error1.localizedDescription);
// }
// }];


// [[SKClient sharedClient] get:[NSString stringWithFormat:@"%@US", kepDiscoverChannels] callback:^(id object, NSError *error) {
Expand Down Expand Up @@ -297,7 +299,7 @@ int main(int argc, const char * argv[]) {
// testGetConversations();

// Download and save unread snaps
saveUnreadSnapsToDirectory(unread, directory);
// saveUnreadSnapsToDirectory(unread, directory);

// Mark snaps read
// markSnapsRead(unread);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0600"
LastUpgradeVersion = "0700"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
Expand All @@ -23,10 +23,10 @@
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
buildConfiguration = "Debug">
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO">
Expand All @@ -48,15 +48,18 @@
ReferencedContainer = "container:SnapchatKit.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
buildConfiguration = "Debug"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
Expand All @@ -72,10 +75,10 @@
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
buildConfiguration = "Release"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
Expand Down
3 changes: 2 additions & 1 deletion Pod/Classes/Categories/NSString+SnapchatKit.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@
+ (NSString *)hashSC:(NSData *)first and:(NSData *)second;
+ (NSString *)hashSCString:(NSString *)first and:(NSString *)second;

+ (NSString *)hashHMac:(NSString *)data key:(NSString *)key;
+ (NSData *)hashHMac:(NSString *)data key:(NSString *)key;
+ (NSString *)hashHMacToString:(NSString *)data key:(NSString *)key;

- (NSString *)MD5Hash;

Expand Down
10 changes: 6 additions & 4 deletions Pod/Classes/Categories/NSString+SnapchatKit.m
Original file line number Diff line number Diff line change
Expand Up @@ -71,15 +71,17 @@ + (NSString *)hashSC:(NSData *)a and:(NSData *)b {
return hash;
}

+ (NSString *)hashHMac:(NSString *)data key:(NSString *)key {
+ (NSString *)hashHMacToString:(NSString *)data key:(NSString *)key {
return [[self hashHMac:data key:key] base64EncodedStringWithOptions:0];
}

+ (NSData *)hashHMac:(NSString *)data key:(NSString *)key {
const char *cKey = [key cStringUsingEncoding:NSUTF8StringEncoding];
const char *cData = [data cStringUsingEncoding:NSUTF8StringEncoding];
unsigned char cHMAC[CC_SHA256_DIGEST_LENGTH];

CCHmac(kCCHmacAlgSHA256, cKey, strlen(cKey), cData, strlen(cData), cHMAC);
NSData *HMAC = [[NSData alloc] initWithBytes:cHMAC length:sizeof(cHMAC)];

return [HMAC base64EncodedStringWithOptions:0];
return [[NSData alloc] initWithBytes:cHMAC length:sizeof(cHMAC)];
}

- (NSString *)MD5Hash {
Expand Down
45 changes: 27 additions & 18 deletions Pod/Classes/Networking/SKClient.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@

#import "SKSession.h"

extern NSString *SKMakeCapserSignature(NSDictionary *params, NSString *secret);

/** Used to restructure JSON or modify an error returned from nearly any API call before being passed back to the application code. */
@protocol SKMiddleMan <NSObject>
/** @discussion This method is passed the JSON and any error generated by \c -[SKClient handleError:data:response:completion:].
Expand All @@ -36,6 +38,31 @@
/** The maxium sized to load videos in. */
@property (nonatomic) CGSize maxVideoSize;

/** The username of the currently signed in (or not yet singed in) user. @note Always lowercase. */
@property (nonatomic, readonly) NSString *username;
/** The \c SKSession object representing the current Snapchat session.
@discussion Many of the categories on \c SKClient will automatically update this property; rarely is it necessary to attempt to update it yourself. */
@property (nonatomic) SKSession *currentSession;

// Data used to sign in

/** Used internally to sign in. Passed in either of the \c -restoreSessionWithUsername:snapchatAuthToken: methods as the \c snapchatAuthToken: parameter. */
@property (nonatomic, readonly) NSString *authToken;
/** Used internally to sign in. Passed as the \c googleAuthToken: parameter to \c -restoreSessionWithUsername:snapchatAuthToken:googleAuthToken: method. */
@property (nonatomic, readonly) NSString *googleAuthToken;
/** Used internally. */
@property (nonatomic, readonly) NSString *deviceToken1i;
/** Used internally. */
@property (nonatomic, readonly) NSString *deviceToken1v;
/** Used internally to sign in and trick Snapchat into thinking we're using the first party client. */
@property (nonatomic, readonly) NSString *googleAttestation;

/** Required to sign in properly. See https://clients.casper.io to get your own. */
@property (nonatomic) NSString *casperAPIKey;
/** Required to sign in properly. See https://clients.casper.io to get your own. */
@property (nonatomic) NSString *casperAPISecret;


#pragma mark Signing in
/** Signs into Snapchat.
@discussion A valid GMail account is necessary to trick Snapchat into thinking we're using the first party client. Your data is only ever sent to Google, Scout's honor.
Expand Down Expand Up @@ -123,24 +150,6 @@ The first step in creating a new Snapchat account. Registers an email, password,
/** Completion is GUARANTEED to have one and only one non-nil parameter. */
- (void)handleError:(NSError *)error data:(NSData *)data response:(NSURLResponse *)response completion:(ResponseBlock)completion;

/** The username of the currently signed in (or not yet singed in) user. @note Always lowercase. */
@property (nonatomic, readonly) NSString *username;
/** The \c SKSession object representing the current Snapchat session.
@discussion Many of the categories on \c SKClient will automatically update this property; rarely is it necessary to attempt to update it yourself. */
@property (nonatomic) SKSession *currentSession;

// Data used to sign in
/** Used internally to sign in. Passed in either of the \c -restoreSessionWithUsername:snapchatAuthToken: methods as the \c snapchatAuthToken: parameter. */
@property (nonatomic, readonly) NSString *authToken;
/** Used internally to sign in. Passed as the \c googleAuthToken: parameter to \c -restoreSessionWithUsername:snapchatAuthToken:googleAuthToken: method. */
@property (nonatomic, readonly) NSString *googleAuthToken;
/** Used internally. */
@property (nonatomic, readonly) NSString *deviceToken1i;
/** Used internally. */
@property (nonatomic, readonly) NSString *deviceToken1v;
/** Used internally to sign in and trick Snapchat into thinking we're using the first party client. */
@property (nonatomic, readonly) NSString *googleAttestation;

@end

/** Used to assert that we are signed in before making certain requests. */
Expand Down
44 changes: 36 additions & 8 deletions Pod/Classes/Networking/SKClient.m
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,19 @@ BOOL SKHasActiveConnection() {
return @{@"googleAuthToken": gauth, @"attestation": attest, @"pushToken": ptoken?:@"e", @"clientAuthToken": clientAuthToken, @"dt": deviceTokens, @"ts": timestamp};
}

NSString * const kAttestationURLString = @"https://www.googleapis.com/androidcheck/v1/attestations/attest?alt=JSON&key=AIzaSyDqVnJBjE5ymo--oBJt3On7HQx9xNm1RHA";
NSString * const kAttestationBase64Request = @"ClMKABIUY29tLnNuYXBjaGF0LmFuZHJvaWQaIC8cqvyh7TDQtOOIY+76vqDoFXEfpM95uCJRmoJZ2VpYIgAojKq/AzIECgASADoECAEQAUD4kP+pBRIA";
NSString *SKMakeCapserSignature(NSDictionary *params, NSString *secret) {
assert(params.allKeys.count); assert(secret);
NSArray *sortedKeys = [params.allKeys sortedArrayUsingSelector:@selector(compare:options:)];
NSMutableString *signature = [NSMutableString string];

for (NSString *key in sortedKeys) {
[signature appendString:key];
[signature appendString:params[key]];
}

return [@"v1:" stringByAppendingString:[NSString hashHMac:signature key:secret].hexadecimalString];
}


@implementation SKClient

Expand Down Expand Up @@ -314,9 +325,12 @@ - (void)getGoogleCloudMessagingIdentifier:(StringBlock)callback {

/** Google attestation. */
- (void)getAttestation:(NSString *)username password:(NSString *)password ts:(NSString *)timestamp callback:(StringBlock)callback {
NSAssert(self.casperAPIKey, @"You must have a valid API key from https://clients.casper.io to sign in.");
NSAssert(self.casperAPISecret, @"You must have a valid API secret from https://clients.casper.io to sign in.");

NSString *hashString = [[NSString stringWithFormat:@"%@|%@|%@|%@", username, password, timestamp, SKEPAccount.login].sha256HashRaw base64EncodedStringWithOptions:0];
// Get binary data
NSData *binaryData = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"https://api.casper.io/droidguard/create/binary"]];
NSData *binaryData = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"https://api.casper.io/snapchat/attestation/create"]];
__block NSError *jsonError = nil;
__block NSDictionary *json = [NSJSONSerialization JSONObjectWithData:binaryData options:0 error:&jsonError];

Expand All @@ -334,11 +348,15 @@ - (void)getAttestation:(NSString *)username password:(NSString *)password ts:(NS

// Send it to Casper.io to build the protobuf
NSString *bytecodeProtobuf = [data base64EncodedStringWithOptions:0];
NSDictionary *query = @{@"bytecode_proto": bytecodeProtobuf,
NSDictionary *query = @{@"protobuf": bytecodeProtobuf,
@"nonce": hashString,
@"apk_digest": SKAttestation.digest9_14_2};
@"snapchat_version": SKConsts.snapchatVersion};
request.URL = [NSURL URLWithString:SKAttestation.protobufPOSTURL];
request.HTTPBody = [[NSString queryStringWithParams:query URLEscapeValues:YES] dataUsingEncoding:NSUTF8StringEncoding];

// Set headers
[request setValue:self.casperAPIKey forHTTPHeaderField:SKHeaders.casperAPIKey];
[request setValue:SKMakeCapserSignature(query, self.casperAPISecret) forHTTPHeaderField:SKHeaders.casperSignature];
[request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:SKHeaders.contentType];

[[session dataTaskWithRequest:request completionHandler:^(NSData *data2, NSURLResponse *response2, NSError *error2) {
Expand Down Expand Up @@ -387,11 +405,21 @@ - (void)getAttestation:(NSString *)username password:(NSString *)password ts:(NS

- (void)getClientAuthToken:(NSString *)username password:(NSString *)password timestamp:(NSString *)ts callback:(StringBlock)callback {
NSParameterAssert(username); NSParameterAssert(password); NSParameterAssert(ts);
NSAssert(self.casperAPIKey, @"You must have a valid API key from https://clients.casper.io to sign in.");
NSAssert(self.casperAPISecret, @"You must have a valid API secret from https://clients.casper.io to sign in.");

NSURL *url = [NSURL URLWithString:@"https://api.casper.io/security/login/signrequest/"];
// Params
NSDictionary *query = @{@"username": username, @"password": password, @"timestamp": ts, @"snapchat_version": SKConsts.snapchatVersion};

// Build request
NSURL *url = [NSURL URLWithString:@"https://api.casper.io/snapchat/clientauth/signrequest"];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
request.HTTPMethod = @"POST";
request.HTTPBody = [[NSString queryStringWithParams:@{@"username": username, @"password": password, @"timestamp": ts}] dataUsingEncoding:NSUTF8StringEncoding];
request.HTTPBody = [[NSString queryStringWithParams:query] dataUsingEncoding:NSUTF8StringEncoding];

// Set headers
[request setValue:self.casperAPIKey forHTTPHeaderField:SKHeaders.casperAPIKey];
[request setValue:SKMakeCapserSignature(query, self.casperAPISecret) forHTTPHeaderField:SKHeaders.casperSignature];

NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
[[session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
Expand Down Expand Up @@ -468,7 +496,7 @@ - (void)signInWithData:(NSDictionary *)loginData username:(NSString *)username p

NSString *req_token = [NSString hashSCString:SKConsts.staticToken and:timestamp];
NSString *string = [NSString stringWithFormat:@"%@|%@|%@|%@", username, password, timestamp, req_token];
NSString *deviceSig = [[NSString hashHMac:string key:self.deviceToken1v] substringWithRange:NSMakeRange(0, 20)];
NSString *deviceSig = [[[NSString hashHMac:string key:self.deviceToken1v] base64EncodedStringWithOptions:0] substringWithRange:NSMakeRange(0, 20)];

NSDictionary *post = @{@"username": username,
@"password": password,
Expand Down
3 changes: 3 additions & 0 deletions Pod/Classes/SnapchatKit-Constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ SK_NAMESPACE(SKConsts, {
NSNSString *boundary;
NSNSString *deviceToken1i;
NSNSString *deviceToken1v;
NSNSString *snapchatVersion;
});

#pragma mark Header fields / values
Expand All @@ -151,6 +152,8 @@ SK_NAMESPACE(SKHeaders, {
NSNSString *acceptLocale;
NSNSString *clientAuth;
NSNSString *clientAuthToken;
NSNSString *casperAPIKey;
NSNSString *casperSignature;
struct {
NSNSString *language;
NSNSString *locale;
Expand Down
Loading

0 comments on commit 04084fa

Please sign in to comment.