ios-unity/Classes_cocos/UIViewController+Wallet.mm
2023-08-17 16:01:15 +08:00

347 lines
13 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// UIViewController+Wallet.m
// Unity-iPhone
//
// Created by zhl on 2022/9/1.
//
#import "UIViewController+Wallet.h"
#import "WebPageViewController.h"
#import <TikTokOpenSDK/TikTokOpenSDKAuth.h>
#include <string>
#include "WalletEvent.h"
#include "JcWallet.h"
#import <GoogleSignIn/GoogleSignIn.h>
#include "KeyChain/DataManager.h"
#import "NSString+Customer.h"
#import "NSData+Base64.h"
#import "AppleSignIn.h"
#include "cocos/scripting/js-bindings/manual/jsb_global.h"
#import <LocalAuthentication/LocalAuthentication.h>
@import FBSDKLoginKit;
@import GoogleSignIn;
static NSString * const kClientID =
@"53206975661-0d6q9pqljn84n9l63gm0to1ulap9cbk4.apps.googleusercontent.com";
static WebPageViewController *webpageVC = nil;
@implementation UIViewController (Wallet)
+(void)toWallet:(NSString *)url{
UIApplication *app = [UIApplication sharedApplication];
[app openURL:[NSURL URLWithString:url]];
}
// save key to key chain
-(void)saveKey:(NSString *) account key:(NSString *) key {
// NSLog(@"saveKey::account:%@, key:%@", account, key);
[[DataManager sharedInstanceWith: SynLock] saveKey: account key: key];
}
// load key from key chain
-(NSString *)loadKey:(NSString *) account {
// NSLog(@"loadKey::account:%@", account);
return [[DataManager sharedInstanceWith: SynLock] loadKey: account];
}
-(void)signToGoogle:(NSString *) funid {
GIDConfiguration *_configuration = [[GIDConfiguration alloc] initWithClientID:kClientID];
[GIDSignIn.sharedInstance signInWithConfiguration:_configuration
presentingViewController:self
completion:^(GIDGoogleUser *user, NSError *error) {
if (error) {
NSLog(@"Status: Authentication error: %@", error);
[self nativeCb:funid hasErr:YES dataStr: error.localizedDescription];
return;
}
[self refreshTokenID: user funid:funid];
}];
}
-(void)clientLogin:(NSString *) funid {
NSString *clientKey = @"game_client_id";
NSString *clientID = [self loadKey:clientKey];
// if clientID is empty, then generate a new one with uuid
if ([NSString isStringEmpty:clientID]) {
NSString *pre_id = [[NSUUID UUID] UUIDString];
// cast pre_id to lower case
std::string uuid = [[pre_id lowercaseString] UTF8String];
std::string clientIdStr = generate_clientid(uuid);
clientID = [NSString stringWithUTF8String:clientIdStr.c_str()];
NSLog(@"new clientID: %@", clientID);
[self saveKey:clientKey key:clientID];
}
NSLog(@"clientID: %@", clientID);
[self nativeCb:funid hasErr:NO dataStr: clientID];
}
-(void) refreshTokenID:(GIDGoogleUser *)user funid:(NSString*) funid{
[user.authentication doWithFreshTokens:^(GIDAuthentication * _Nullable authentication,
NSError * _Nullable error) {
if (error) {
[self nativeCb:funid hasErr:YES dataStr: error.localizedDescription];
return;
}
if (authentication == nil) {
[self nativeCb:funid hasErr:YES dataStr: @"empty authenication"];
return;
}
NSString *idToken = authentication.idToken;
// Send ID token to backend (example below).
NSLog(@"idToken: %@", idToken);
[self nativeCb:funid hasErr:NO dataStr:idToken];
}];
}
-(void)signWithGoogle:(NSString *)funid {
[GIDSignIn.sharedInstance restorePreviousSignInWithCompletion:^(GIDGoogleUser * _Nullable user,
NSError * _Nullable error) {
if (error) {
// Show the app's signed-out state.
[self signToGoogle: funid];
} else {
// Show the app's signed-in state.
[self refreshTokenID: user funid:funid];
}
}];
}
-(void)signOutGoogle:(NSString *)funid {
[GIDSignIn.sharedInstance signOut];
}
#pragma mark- - Sign In With Apple
- (void) signWithApple:(NSString *)funid{
if (@available(iOS 13.0, *)) {
[[AppleSignIn sharedInstance] signIn:funid presentingViewController:self completion:^(NSString *idToken, NSError *error){
if (error != nil) {
[self nativeCb:funid hasErr:YES dataStr: error.localizedDescription];
} else {
NSLog(@"signWithApple: %@", idToken);
[self nativeCb:funid hasErr:NO dataStr:idToken];
}
}];
} else {
NSLog(@"system is lower");
[self nativeCb:funid hasErr:YES dataStr: @"system is lower"];
}
}
#pragma mark -- Sign In with TikTok
- (void) signWithTikTok:(NSString *) funid {
/* STEP 1: Create the request and set permissions */
NSArray *scopes = [NSArray arrayWithObjects: @"user.info.basic", @"video.list", nil]; // list your scopes;
NSOrderedSet *scopesSet = [NSOrderedSet orderedSetWithArray:scopes];
TikTokOpenSDKAuthRequest *request = [[TikTokOpenSDKAuthRequest alloc] init];
request.permissions = scopesSet;
/* STEP 2: Send the request */
// __weak typeof(self) ws = self;
[request sendAuthRequestViewController:self
completion:^(TikTokOpenSDKAuthResponse *_Nonnull resp) {
// __strong typeof(ws) sf = ws;
/* STEP 3: Parse and handle the response */
if (resp.errCode == 0) {
NSString *responseCode = resp.code;
// Upload response code to your server and obtain user access token
[self nativeCb:funid hasErr:NO dataStr:responseCode];
NSLog(@"tiktok resp: %@", responseCode);
} else {
// User authorization failed. Handle errors
NSLog(@"tiktok resp error: %@", resp.description);
[self nativeCb:funid hasErr:YES dataStr: resp.description];
}
}];
}
#pragma mark -- Sign In with Facebook
- (void) signWithFacebook:(NSString *) funid {
FBSDKLoginManager *loginManager = [[FBSDKLoginManager alloc] init];
if ([FBSDKAccessToken currentAccessToken]) {
NSLog(@"Token is available, no need login again : %@",[[FBSDKAccessToken currentAccessToken]tokenString]);
[self nativeCb:funid hasErr:NO dataStr: [[FBSDKAccessToken currentAccessToken]tokenString]];
} else {
[loginManager logInWithPermissions:@[@"public_profile", @"email"] fromViewController:self handler:^(FBSDKLoginManagerLoginResult *result, NSError *error) {
if (error) {
[self nativeCb:funid hasErr:YES dataStr: error.description];
} else if (result.isCancelled) {
[self nativeCb:funid hasErr:YES dataStr: @"user cancel"];
} else {
if ([FBSDKAccessToken currentAccessToken]) {
NSString *token = [[FBSDKAccessToken currentAccessToken]tokenString];
NSLog(@"Token is available : %@", token);
[self nativeCb:funid hasErr:NO dataStr: token];
}
else {
[self nativeCb:funid hasErr:YES dataStr: @"no token"];
}
}
}];
}
}
#pragma mark -- Sign In with Twitter
- (void) signWithTwitter:(NSString *) funid {
}
-(void)nativeCb:(NSString *)funid hasErr: (BOOL) hasErr dataStr:(NSString *) dataStr {
if ([NSString isStringEmpty:funid]) {
NSLog(@"nativeCallBack with empty funid: %@", funid);
return;
}
std::string methodName = "nativeCallBack";
NSMutableDictionary *json = [[NSMutableDictionary alloc] init];
if (hasErr) {
json[@"errcode"] = @1;
json[@"errmessage"] = dataStr;
} else {
json[@"errcode"] = @0;
json[@"data"] = dataStr;
}
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:json options:NSJSONWritingPrettyPrinted error:&error];
NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
std::string sfunid = std::string([funid UTF8String], [funid lengthOfBytesUsingEncoding:NSUTF8StringEncoding]);
if (error) {
NSLog(@"Got an error: %@", error);
NSString *errorStr = [NSString stringWithFormat:@"{\"errcode\": 1, \"errmessage\": \"%@\"}", error];
std::string sparam = std::string([errorStr UTF8String], [errorStr lengthOfBytesUsingEncoding:NSUTF8StringEncoding]);
cocos2d::nativeCallBack(sfunid.c_str(), methodName.c_str(), sparam.c_str());
return;
}
std::string sparam = std::string([jsonString UTF8String], [jsonString lengthOfBytesUsingEncoding:NSUTF8StringEncoding]);
cocos2d::nativeCallBack(sfunid.c_str(), methodName.c_str(), sparam.c_str());
}
#pragma mark -- show webpage
-(void)showPage:(NSString *)url{
if (webpageVC == nil) {
webpageVC = [WebPageViewController new];
}
webpageVC.url = url;
self.definesPresentationContext = YES;
webpageVC.modalPresentationStyle = UIModalPresentationOverCurrentContext;
[self presentViewController:webpageVC animated:YES completion:nil];
}
#pragma mark -- biometrics
-(BOOL)checkTouchIDFaceID{
LAContext *LAContent = [[LAContext alloc] init];
NSError *authError = nil;
BOOL isCanEvaluatePolicy = [LAContent canEvaluatePolicy:LAPolicyDeviceOwnerAuthentication error:&authError];
NSLog(@"isCanEvaluatePolicy: %d", isCanEvaluatePolicy);
if (authError) {
NSLog(@"check TouchID or FaceID fail\n error : %@",authError.localizedDescription);
return NO;
} else {
if (isCanEvaluatePolicy) {
if (@available(iOS 11.0, *)) {
switch (LAContent.biometryType) {
case LABiometryTypeNone:
{
NSLog(@"The device does not support biometry.");
return NO;
}
case LABiometryTypeTouchID:
{
NSLog(@"The device supports Touch ID.");
return YES;
}
case LABiometryTypeFaceID:
{
NSLog(@"The device supports Face ID.");
return YES;
}
default:
return NO;
}
} else {
// Fallback on earlier versions
NSLog(@"The device supports Face ID.");
return YES;
}
} else {
return NO;
}
}
}
- (NSString *) generateAccountKey:(NSString *) account {
NSString *key = [NSString stringWithFormat:@"%@%@", account, @"_pass"];
return key;
}
- (void)storagePass:(NSString *)funid account:(NSString *)account pass:(NSString *)pass {
// NSLog(@"storagePass: %@, %@", account, pass);
std::string passStr = std::string([pass UTF8String], [pass lengthOfBytesUsingEncoding:NSUTF8StringEncoding]);
std::string keyStr = std::string([account UTF8String], [account lengthOfBytesUsingEncoding:NSUTF8StringEncoding]);
keyStr = keyStr + "0x741482aE1480E552735E44Ff3A733448AcBbeD8d";
std::string passEncrypt = encrypt_aes(passStr, keyStr);
NSString *passEncryptStr = [NSString stringWithCString:passEncrypt.c_str() encoding:NSUTF8StringEncoding];
NSString *accountKey = [self generateAccountKey:account];
[self saveKey:accountKey key:passEncryptStr];
[self nativeCb:funid hasErr:NO dataStr: @"success"];
}
-(void)passStorageState: (NSString *) funid account:(NSString *) account {
BOOL hasTouchID = [self checkTouchIDFaceID];
NSString *accountKey = [self generateAccountKey:account];
NSString *val = [self loadKey: accountKey];
NSMutableDictionary *json = [[NSMutableDictionary alloc] init];
json[@"biometrics"] = hasTouchID ? @1 : @0;
json[@"haspass"] = [NSString isStringEmpty:val] ? @0 : @1;
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:json options:NSJSONWritingPrettyPrinted error:&error];
if (error) {
[self nativeCb:funid hasErr:YES dataStr: @"serialization json error"];
} else {
NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
[self nativeCb:funid hasErr:NO dataStr: jsonString];
}
}
-(void)authGetStoragePass: (NSString *) funid account: (NSString *) account{
LAContext *context = [LAContext new];
NSError *error = nil;
BOOL isUseTouchID = [context canEvaluatePolicy:LAPolicyDeviceOwnerAuthentication error:&error];
if (error) {
[self nativeCb:funid hasErr:YES dataStr:error.localizedDescription];
} else {
if (isUseTouchID) {
NSLog(@"had biometrics");
[context evaluatePolicy:LAPolicyDeviceOwnerAuthentication localizedReason:@"Access keychain password" reply:^(BOOL success, NSError * _Nullable error) {
if (success) {
NSString *accountKey = [self generateAccountKey:account];
NSString *val = [self loadKey: accountKey];
if ([NSString isStringEmpty:val]) {
[self nativeCb:funid hasErr:YES dataStr:@"no pass"];
} else {
std::string keyStr = std::string([account UTF8String], [account lengthOfBytesUsingEncoding:NSUTF8StringEncoding]);
keyStr = keyStr + "0x741482aE1480E552735E44Ff3A733448AcBbeD8d";
std::string passEncrypt = std::string([val UTF8String], [val lengthOfBytesUsingEncoding:NSUTF8StringEncoding]);
std::string passDecrypt = decrypt_aes(passEncrypt, keyStr);
NSString *passDecryptStr = [NSString stringWithCString:passDecrypt.c_str() encoding:NSUTF8StringEncoding];
[self nativeCb:funid hasErr:NO dataStr: passDecryptStr];
}
}else{
NSLog(@"%ld||%@",error.code, error.localizedDescription);
[self nativeCb:funid hasErr:YES dataStr:error.localizedDescription];
}
}];
}else{
NSLog(@"no biometrics");
NSLog(@"%ld||%@",error.code, error.localizedDescription);
[self nativeCb:funid hasErr:YES dataStr:error.localizedDescription];
}
}
}
@end