├── android ├── .settings │ └── org.eclipse.buildship.core.prefs ├── src │ └── main │ │ ├── libs │ │ └── CloudPayments.aar │ │ ├── AndroidManifest.xml │ │ └── java │ │ └── com │ │ └── rncloudpayments │ │ ├── RCTCloudPaymentsPackage.java │ │ └── CloudPayments.java ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── .classpath ├── settings.gradle ├── .project ├── build.gradle ├── gradlew.bat └── gradlew ├── ios ├── RNCloudPayments.h ├── SDK │ ├── Card.h │ ├── NSDataENBase64.h │ ├── NSDataENBase64.m │ └── Card.m ├── RNCloudPayments.m └── RNCloudPayments.xcodeproj │ └── project.pbxproj ├── .gitignore ├── package.json ├── index.js └── README.md /android/.settings/org.eclipse.buildship.core.prefs: -------------------------------------------------------------------------------- 1 | #Tue May 15 08:57:32 SAMT 2018 2 | connection.project.dir= 3 | -------------------------------------------------------------------------------- /ios/RNCloudPayments.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface RNCloudPayments : NSObject 4 | @end 5 | -------------------------------------------------------------------------------- /android/src/main/libs/CloudPayments.aar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gazaret/react-native-cloudpayments/HEAD/android/src/main/libs/CloudPayments.aar -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gazaret/react-native-cloudpayments/HEAD/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Mon May 14 14:00:12 SAMT 2018 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.7-all.zip 7 | -------------------------------------------------------------------------------- /android/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /android/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * This file was generated by the Gradle 'init' task. 3 | * 4 | * The settings file is used to specify which projects to include in your build. 5 | * 6 | * Detailed information about configuring a multi-project build in Gradle can be found 7 | * in the user guide at https://docs.gradle.org/4.7/userguide/multi_project_builds.html 8 | */ 9 | 10 | // include ':app', ':CloudPayments_AndroidSDK' 11 | rootProject.name = 'rncloudpayments' 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # OSX 2 | # 3 | .DS_Store 4 | 5 | # IDE 6 | # 7 | .idea 8 | .vscode 9 | 10 | # node.js 11 | # 12 | node_modules 13 | npm-debug.log* 14 | yarn-debug.log* 15 | yarn-error.log* 16 | 17 | # Xcode 18 | # 19 | build/ 20 | *.pbxuser 21 | !default.pbxuser 22 | *.mode1v3 23 | !default.mode1v3 24 | *.mode2v3 25 | !default.mode2v3 26 | *.perspectivev3 27 | !default.perspectivev3 28 | xcuserdata 29 | *.xccheckout 30 | *.moved-aside 31 | DerivedData 32 | *.hmap 33 | *.ipa 34 | *.xcuserstate 35 | project.xcworkspace 36 | 37 | # Android/IntelliJ 38 | # 39 | local.properties 40 | .gradle 41 | build/ 42 | *.iml 43 | 44 | # BUCK 45 | buck-out/ 46 | \.buckd/ 47 | *.keystore 48 | -------------------------------------------------------------------------------- /android/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | rncloudpayments 4 | Project rncloudpayments created by Buildship. 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | org.eclipse.buildship.core.gradleprojectbuilder 15 | 16 | 17 | 18 | 19 | 20 | org.eclipse.jdt.core.javanature 21 | org.eclipse.buildship.core.gradleprojectnature 22 | 23 | 24 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | jcenter() 4 | google() 5 | } 6 | 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:3.0.1' 9 | } 10 | } 11 | 12 | apply plugin: 'com.android.library' 13 | 14 | android { 15 | compileSdkVersion 27 16 | buildToolsVersion "27.0.3" 17 | 18 | defaultConfig { 19 | minSdkVersion 19 20 | targetSdkVersion 27 21 | versionCode 1 22 | versionName "1.0" 23 | } 24 | lintOptions { 25 | abortOnError false 26 | } 27 | } 28 | 29 | repositories { 30 | mavenCentral() 31 | } 32 | 33 | dependencies { 34 | implementation "com.facebook.react:react-native:+" 35 | implementation files('src/main/libs/CloudPayments.aar') 36 | } 37 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-native-cloudpayments", 3 | "version": "1.0.0", 4 | "description": "CloudPayments SDK for react-native", 5 | "main": "index.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "git+https://github.com/gazaret/react-native-cloudpayments.git" 9 | }, 10 | "bugs": { 11 | "url": "https://github.com/gazaret/react-native-cloudpayments/issues" 12 | }, 13 | "homepage": "https://github.com/gazaret/react-native-cloudpayments", 14 | "keywords": [ 15 | "react-native", 16 | "native", 17 | "cloudpayments" 18 | ], 19 | "author": { 20 | "name": "gazaret", 21 | "email": "polu-hin@mail.ru", 22 | "url": "https://github.com/gazaret" 23 | }, 24 | "license": "MIT", 25 | "peerDependencies": { 26 | "react-native": "*" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /android/src/main/java/com/rncloudpayments/RCTCloudPaymentsPackage.java: -------------------------------------------------------------------------------- 1 | package com.rncloudpayments; 2 | 3 | import com.facebook.react.ReactPackage; 4 | import com.facebook.react.bridge.NativeModule; 5 | import com.facebook.react.bridge.ReactApplicationContext; 6 | import com.facebook.react.uimanager.ViewManager; 7 | 8 | import java.util.ArrayList; 9 | import java.util.Collections; 10 | import java.util.List; 11 | 12 | public class RCTCloudPaymentsPackage implements ReactPackage { 13 | @Override 14 | public List createNativeModules(ReactApplicationContext reactContext) { 15 | List modules = new ArrayList<>(); 16 | 17 | modules.add(new CloudPayments(reactContext)); 18 | 19 | return modules; 20 | } 21 | 22 | @Override 23 | public List createViewManagers(ReactApplicationContext reactContext) { 24 | return Collections.emptyList(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /ios/SDK/Card.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | typedef enum { 4 | Unknown, 5 | Visa, 6 | MasterCard, 7 | Maestro, 8 | Mir, 9 | JCB 10 | } CardType; 11 | 12 | @interface Card : NSObject { 13 | NSMutableArray *keyRefs; 14 | } 15 | 16 | +(BOOL) isCardNumberValid: (NSString *) cardNumberString; 17 | 18 | /** 19 | * Create cryptogram 20 | * cardNumberString valid card number stirng 21 | * expDateString string in format YYMM 22 | * CVVString 3-digit number 23 | * storePublicID public_id of store 24 | */ 25 | -(NSString *) makeCardCryptogramPacket: (NSString *) cardNumberString andExpDate: (NSString *) expDateString andCVV: (NSString *) CVVString andMerchantPublicID: (NSString *) merchantPublicIDString; 26 | 27 | +(CardType) cardTypeFromCardNumber:(NSString *)cardNumberString; 28 | +(NSString *) cardTypeToString:(CardType)cardType; 29 | @end 30 | 31 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | import { NativeModules } from 'react-native'; 2 | 3 | const RNCloudPaymentsModule = NativeModules.RNCloudPayments; 4 | 5 | export default class RNCloudPayments { 6 | static async isValidCard(cardNumber, cardExp, cardCvv) { 7 | try { 8 | return await RNCloudPaymentsModule.isValidNumber(cardNumber, cardExp, cardCvv); 9 | } catch(error) { 10 | return createError(error); 11 | } 12 | } 13 | 14 | static async getType(cardNumber, cardExp, cardCvv) { 15 | try { 16 | return await RNCloudPaymentsModule.getType(cardNumber, cardExp, cardCvv); 17 | } catch(error) { 18 | return createError(error); 19 | } 20 | } 21 | 22 | static async createCryptogram(cardNumber, cardExp, cardCvv, publicId) { 23 | try { 24 | return await RNCloudPaymentsModule.createCryptogram(cardNumber, cardExp, cardCvv, publicId); 25 | } catch(error) { 26 | return createError(error); 27 | } 28 | } 29 | } 30 | 31 | class RNCloudPaymentsError extends Error { 32 | constructor(details) { 33 | super(); 34 | 35 | this.name = 'RNCloudPaymentsError'; 36 | this.message = typeof details === 'string' ? details : details.message; 37 | } 38 | } 39 | 40 | function createError(error) { 41 | return new RNCloudPaymentsError(error); 42 | } 43 | -------------------------------------------------------------------------------- /ios/RNCloudPayments.m: -------------------------------------------------------------------------------- 1 | #import "RNCloudPayments.h" 2 | #import "SDK/Card.m" 3 | 4 | @implementation RNCloudPayments 5 | 6 | RCT_EXPORT_MODULE(); 7 | 8 | RCT_EXPORT_METHOD(isValidNumber: (NSString *)cardNumber 9 | cardExp: (NSString *)cardExp 10 | cardCvv: (NSString *)cardCvv 11 | resolve: (RCTPromiseResolveBlock)resolve 12 | reject: (RCTPromiseRejectBlock)reject) 13 | { 14 | if([Card isCardNumberValid: cardNumber]) { 15 | resolve(@YES); 16 | } else { 17 | resolve(@NO); 18 | } 19 | }; 20 | 21 | RCT_EXPORT_METHOD(getType: (NSString *)cardNumber 22 | cardExp: (NSString *)cardExp 23 | cardCvv: (NSString *)cardCvv 24 | resolve: (RCTPromiseResolveBlock)resolve 25 | reject: (RCTPromiseRejectBlock)reject) 26 | { 27 | CardType cardType = [Card cardTypeFromCardNumber: cardNumber]; 28 | NSString *cardTypeString = [Card cardTypeToString: cardType]; 29 | 30 | resolve(cardTypeString); 31 | } 32 | 33 | RCT_EXPORT_METHOD(createCryptogram: (NSString *)cardNumber 34 | cardExp: (NSString *)cardExp 35 | cardCvv: (NSString *)cardCvv 36 | publicId: (NSString *)publicId 37 | resolve: (RCTPromiseResolveBlock)resolve 38 | reject: (RCTPromiseRejectBlock)reject) 39 | { 40 | Card *_card = [[Card alloc] init]; 41 | 42 | NSString *cryptogram = [_card makeCardCryptogramPacket: cardNumber andExpDate:cardExp andCVV:cardCvv andMerchantPublicID:publicId]; 43 | 44 | resolve(cryptogram); 45 | } 46 | @end 47 | -------------------------------------------------------------------------------- /ios/SDK/NSDataENBase64.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSData+ENBase64.h 3 | // base64 4 | // 5 | // Created by Matt Gallagher on 2009/06/03. 6 | // Copyright 2009 Matt Gallagher. All rights reserved. 7 | // 8 | // This software is provided 'as-is', without any express or implied 9 | // warranty. In no event will the authors be held liable for any damages 10 | // arising from the use of this software. Permission is granted to anyone to 11 | // use this software for any purpose, including commercial applications, and to 12 | // alter it and redistribute it freely, subject to the following restrictions: 13 | // 14 | // 1. The origin of this software must not be misrepresented; you must not 15 | // claim that you wrote the original software. If you use this software 16 | // in a product, an acknowledgment in the product documentation would be 17 | // appreciated but is not required. 18 | // 2. Altered source versions must be plainly marked as such, and must not be 19 | // misrepresented as being the original software. 20 | // 3. This notice may not be removed or altered from any source 21 | // distribution. 22 | // 23 | 24 | #import 25 | 26 | void *NewBase64Decode( 27 | const char *inputBuffer, 28 | size_t length, 29 | size_t *outputLength); 30 | 31 | char *NewBase64Encode( 32 | const void *inputBuffer, 33 | size_t length, 34 | bool separateLines, 35 | size_t *outputLength); 36 | 37 | @interface NSDataENBase64: NSData 38 | 39 | + (NSData *)dataFromBase64String:(NSString *)aString; 40 | + (NSString *)base64StringFromData: (NSData *)aData; 41 | 42 | - (NSString *)base64EncodedString; 43 | 44 | @end 45 | 46 | -------------------------------------------------------------------------------- /android/src/main/java/com/rncloudpayments/CloudPayments.java: -------------------------------------------------------------------------------- 1 | package com.rncloudpayments; 2 | 3 | import com.facebook.react.bridge.Promise; 4 | import com.facebook.react.bridge.ReactApplicationContext; 5 | import com.facebook.react.bridge.ReactContextBaseJavaModule; 6 | import com.facebook.react.bridge.ReactMethod; 7 | 8 | import ru.cloudpayments.cpcard.CPCard; 9 | import ru.cloudpayments.cpcard.CPCardFactory; 10 | 11 | public class CloudPayments extends ReactContextBaseJavaModule { 12 | public CloudPayments(ReactApplicationContext reactContext) { 13 | super(reactContext); 14 | } 15 | 16 | @Override 17 | public String getName() { 18 | return "RNCloudPayments"; 19 | } 20 | 21 | @ReactMethod 22 | public void isValidNumber(String cardNumber, String cardExp, String cardCvv, Promise promise) { 23 | try { 24 | CPCard card = CPCardFactory.create(cardNumber, cardExp, cardCvv); 25 | 26 | boolean numberStatus = card.isValidNumber(); 27 | 28 | promise.resolve(numberStatus); 29 | } catch (Exception e) { 30 | promise.reject(e.getMessage()); 31 | } 32 | } 33 | 34 | @ReactMethod 35 | public void getType(String cardNumber, String cardExp, String cardCvv, Promise promise) { 36 | try { 37 | CPCard card = CPCardFactory.create(cardNumber, cardExp, cardCvv); 38 | 39 | String cardType = card.getType(); 40 | 41 | promise.resolve(cardType); 42 | } catch (Exception e) { 43 | promise.reject(e.getMessage()); 44 | } 45 | } 46 | 47 | @ReactMethod 48 | public void createCryptogram(String cardNumber, String cardExp, String cardCvv, String publicId, Promise promise) { 49 | try { 50 | CPCard card = CPCardFactory.create(cardNumber, cardExp, cardCvv); 51 | 52 | String cryptoprogram = card.cardCryptogram(publicId); 53 | 54 | promise.resolve(cryptoprogram); 55 | } catch (Exception e) { 56 | e.printStackTrace(); 57 | promise.reject(e.getMessage()); 58 | } 59 | } 60 | } -------------------------------------------------------------------------------- /android/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # React Native CloudPayments 2 | 3 | [React Native](http://facebook.github.io/react-native/) library for accepting payments with [CloudPayments](https://cloudpayments.ru) SDK 4 | 5 | # Install 6 | Download package: 7 | ```shell 8 | npm install --save react-native-cloudpayments 9 | ``` 10 | 11 | or 12 | 13 | ```shell 14 | yarn add react-native-cloudpayments 15 | ``` 16 | 17 | Link dependencies: 18 | ```shell 19 | react-native link react-native-cloudpayments 20 | ``` 21 | 22 | # Methods 23 | ### isValidCard() 24 | Validate card. 25 | Returns a `Promise` that resolve card status (`Boolean`). 26 | 27 | __Arguments__ 28 | - `cardNumber` - `String` Number of payment card. 29 | - `cardExp` - `String` Expire date of payment card. 30 | - `cardCvv` - `String` CVV code of payment card. 31 | 32 | __Examples__ 33 | ```js 34 | import RNCloudPayment from 'react-native-cloudpayments'; 35 | 36 | const demoCard = { 37 | number: '5105105105105100', 38 | extDate: '10/18', 39 | cvvCode: '123', 40 | }; 41 | 42 | RNCloudPayment.isValidCard(demoCard.number, demoCard.extDate, demoCard.cvvCode) 43 | .then(cardStatus => { 44 | console.log(cardStatus); // true 45 | }); 46 | ``` 47 | 48 | ### getType() 49 | Retrive card type. 50 | Returns a `Promise` that resolve card type (`String`). 51 | 52 | Card types: 53 | - Unknown 54 | - Visa 55 | - MasterCard 56 | - Maestro 57 | - Mir 58 | - JCB 59 | 60 | __Arguments__ 61 | - `cardNumber` - `String` Number of payment card. 62 | - `cardExp` - `String` Expire date of payment card. 63 | - `cardCvv` - `String` CVV code of payment card. 64 | 65 | __Examples__ 66 | ```js 67 | import RNCloudPayment from 'react-native-cloudpayments'; 68 | 69 | const demoCard = { 70 | number: '5105105105105100', 71 | extDate: '10/18', 72 | cvvCode: '123', 73 | }; 74 | 75 | RNCloudPayment.getType(demoCard.number, demoCard.extDate, demoCard.cvvCode) 76 | .then(cardType => { 77 | console.log(getType); // MasterCard 78 | }); 79 | ``` 80 | 81 | ### createCryptogram() 82 | Create cryptogram. Used in CloudPayment [API](https://cloudpayments.ru/Docs/Api#payWithCrypto). 83 | Returns a `Promise` that resolve cryptogram (`String`). 84 | 85 | __Arguments__ 86 | - `cardNumber` - `String` Number of payment card. 87 | - `cardExp` - `String` Expire date of payment card. 88 | - `cardCvv` - `String` CVV code of payment card. 89 | - `publicId` - `String` Your Public ID, you need to get it in your [personal account](https://merchant.cloudpayments.ru/). 90 | 91 | __Examples__ 92 | ```js 93 | import RNCloudPayment from 'react-native-cloudpayments'; 94 | 95 | const demoCard = { 96 | number: '5105105105105100', 97 | extDate: '10/18', 98 | cvvCode: '123', 99 | }; 100 | 101 | const publicId = 'pk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxx'; 102 | 103 | RNCloudPayment.createCryptogram(demoCard.number, demoCard.extDate, demoCard.cvvCode, publicId) 104 | .then(cryptogram => { 105 | console.log(cryptogram); // 025105105100/11004bpp9ltxt6c0jpdk8ErH+N33N9jZBm9Gr0jO7SVslLg/RdWYyjG5wiLrzmrUserhfblFVydij4wpjDvHH4kRnOskjnbn1XrPI8X9LMkvlR5Pkc63U5puXtnS0rkswS6JYaSErcKMq4TazimKY4rGobvhhYfg45LWdLlX0602t7ZybbaBTMff6wtta870/244s65GTbCI1zt6odDMckpEuiczwM68m6j0Rn2IuKpK8kR58x7tFFc7fWrrW0RHvLNxQIW9P+SpsySoiA4xaZfC7lXL57O80Ye6JDi6PWAim5dENNxIc81T1kmXnKn94x8h2+XS83yMHHfTUOeDb7J1fLg== 106 | }); 107 | ``` 108 | 109 | # License 110 | Licensed under the MIT License. 111 | -------------------------------------------------------------------------------- /android/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /ios/SDK/NSDataENBase64.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSData+ENBase64.m 3 | // base64 4 | // 5 | // Created by Matt Gallagher on 2009/06/03. 6 | // Copyright 2009 Matt Gallagher. All rights reserved. 7 | // 8 | // This software is provided 'as-is', without any express or implied 9 | // warranty. In no event will the authors be held liable for any damages 10 | // arising from the use of this software. Permission is granted to anyone to 11 | // use this software for any purpose, including commercial applications, and to 12 | // alter it and redistribute it freely, subject to the following restrictions: 13 | // 14 | // 1. The origin of this software must not be misrepresented; you must not 15 | // claim that you wrote the original software. If you use this software 16 | // in a product, an acknowledgment in the product documentation would be 17 | // appreciated but is not required. 18 | // 2. Altered source versions must be plainly marked as such, and must not be 19 | // misrepresented as being the original software. 20 | // 3. This notice may not be removed or altered from any source 21 | // distribution. 22 | // 23 | 24 | #import "NSDataENBase64.h" 25 | 26 | // 27 | // Mapping from 6 bit pattern to ASCII character. 28 | // 29 | static unsigned char base64EncodeLookup[65] = 30 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 31 | 32 | // 33 | // Definition for "masked-out" areas of the base64DecodeLookup mapping 34 | // 35 | #define xx 65 36 | 37 | // 38 | // Mapping from ASCII character to 6 bit pattern. 39 | // 40 | static unsigned char base64DecodeLookup[256] = 41 | { 42 | xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, 43 | xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, 44 | xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, 62, xx, xx, xx, 63, 45 | 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, xx, xx, xx, xx, xx, xx, 46 | xx, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 47 | 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, xx, xx, xx, xx, xx, 48 | xx, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 49 | 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, xx, xx, xx, xx, xx, 50 | xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, 51 | xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, 52 | xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, 53 | xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, 54 | xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, 55 | xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, 56 | xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, 57 | xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, 58 | }; 59 | 60 | // 61 | // Fundamental sizes of the binary and base64 encode/decode units in bytes 62 | // 63 | #define BINARY_UNIT_SIZE 3 64 | #define BASE64_UNIT_SIZE 4 65 | 66 | // 67 | // NewBase64Decode 68 | // 69 | // Decodes the base64 ASCII string in the inputBuffer to a newly malloced 70 | // output buffer. 71 | // 72 | // inputBuffer - the source ASCII string for the decode 73 | // length - the length of the string or -1 (to specify strlen should be used) 74 | // outputLength - if not-NULL, on output will contain the decoded length 75 | // 76 | // returns the decoded buffer. Must be free'd by caller. Length is given by 77 | // outputLength. 78 | // 79 | void *NewBase64Decode( 80 | const char *inputBuffer, 81 | size_t length, 82 | size_t *outputLength) 83 | { 84 | size_t invalLength = -1; 85 | if (length == invalLength) 86 | { 87 | length = strlen(inputBuffer); 88 | } 89 | 90 | size_t outputBufferSize = 91 | ((length+BASE64_UNIT_SIZE-1) / BASE64_UNIT_SIZE) * BINARY_UNIT_SIZE; 92 | unsigned char *outputBuffer = (unsigned char *)malloc(outputBufferSize); 93 | 94 | size_t i = 0; 95 | size_t j = 0; 96 | while (i < length) 97 | { 98 | // 99 | // Accumulate 4 valid characters (ignore everything else) 100 | // 101 | unsigned char accumulated[BASE64_UNIT_SIZE]; 102 | size_t accumulateIndex = 0; 103 | while (i < length) 104 | { 105 | unsigned char decode = base64DecodeLookup[inputBuffer[i++]]; 106 | if (decode != xx) 107 | { 108 | accumulated[accumulateIndex] = decode; 109 | accumulateIndex++; 110 | 111 | if (accumulateIndex == BASE64_UNIT_SIZE) 112 | { 113 | break; 114 | } 115 | } 116 | } 117 | 118 | // 119 | // Store the 6 bits from each of the 4 characters as 3 bytes 120 | // 121 | // (Uses improved bounds checking suggested by Alexandre Colucci) 122 | // 123 | if(accumulateIndex >= 2) 124 | outputBuffer[j] = (accumulated[0] << 2) | (accumulated[1] >> 4); 125 | if(accumulateIndex >= 3) 126 | outputBuffer[j + 1] = (accumulated[1] << 4) | (accumulated[2] >> 2); 127 | if(accumulateIndex >= 4) 128 | outputBuffer[j + 2] = (accumulated[2] << 6) | accumulated[3]; 129 | j += accumulateIndex - 1; 130 | } 131 | 132 | if (outputLength) 133 | { 134 | *outputLength = j; 135 | } 136 | return outputBuffer; 137 | } 138 | 139 | // 140 | // NewBase64Encode 141 | // 142 | // Encodes the arbitrary data in the inputBuffer as base64 into a newly malloced 143 | // output buffer. 144 | // 145 | // inputBuffer - the source data for the encode 146 | // length - the length of the input in bytes 147 | // separateLines - if zero, no CR/LF characters will be added. Otherwise 148 | // a CR/LF pair will be added every 64 encoded chars. 149 | // outputLength - if not-NULL, on output will contain the encoded length 150 | // (not including terminating 0 char) 151 | // 152 | // returns the encoded buffer. Must be free'd by caller. Length is given by 153 | // outputLength. 154 | // 155 | char *NewBase64Encode( 156 | const void *buffer, 157 | size_t length, 158 | bool separateLines, 159 | size_t *outputLength) 160 | { 161 | const unsigned char *inputBuffer = (const unsigned char *)buffer; 162 | 163 | #define MAX_NUM_PADDING_CHARS 2 164 | #define OUTPUT_LINE_LENGTH 64 165 | #define INPUT_LINE_LENGTH ((OUTPUT_LINE_LENGTH / BASE64_UNIT_SIZE) * BINARY_UNIT_SIZE) 166 | #define CR_LF_SIZE 2 167 | 168 | // 169 | // Byte accurate calculation of final buffer size 170 | // 171 | size_t outputBufferSize = 172 | ((length / BINARY_UNIT_SIZE) 173 | + ((length % BINARY_UNIT_SIZE) ? 1 : 0)) 174 | * BASE64_UNIT_SIZE; 175 | if (separateLines) 176 | { 177 | outputBufferSize += 178 | (outputBufferSize / OUTPUT_LINE_LENGTH) * CR_LF_SIZE; 179 | } 180 | 181 | // 182 | // Include space for a terminating zero 183 | // 184 | outputBufferSize += 1; 185 | 186 | // 187 | // Allocate the output buffer 188 | // 189 | char *outputBuffer = (char *)malloc(outputBufferSize); 190 | if (!outputBuffer) 191 | { 192 | return NULL; 193 | } 194 | 195 | size_t i = 0; 196 | size_t j = 0; 197 | const size_t lineLength = separateLines ? INPUT_LINE_LENGTH : length; 198 | size_t lineEnd = lineLength; 199 | 200 | while (true) 201 | { 202 | if (lineEnd > length) 203 | { 204 | lineEnd = length; 205 | } 206 | 207 | for (; i + BINARY_UNIT_SIZE - 1 < lineEnd; i += BINARY_UNIT_SIZE) 208 | { 209 | // 210 | // Inner loop: turn 48 bytes into 64 base64 characters 211 | // 212 | outputBuffer[j++] = base64EncodeLookup[(inputBuffer[i] & 0xFC) >> 2]; 213 | outputBuffer[j++] = base64EncodeLookup[((inputBuffer[i] & 0x03) << 4) 214 | | ((inputBuffer[i + 1] & 0xF0) >> 4)]; 215 | outputBuffer[j++] = base64EncodeLookup[((inputBuffer[i + 1] & 0x0F) << 2) 216 | | ((inputBuffer[i + 2] & 0xC0) >> 6)]; 217 | outputBuffer[j++] = base64EncodeLookup[inputBuffer[i + 2] & 0x3F]; 218 | } 219 | 220 | if (lineEnd == length) 221 | { 222 | break; 223 | } 224 | 225 | // 226 | // Add the newline 227 | // 228 | outputBuffer[j++] = '\r'; 229 | outputBuffer[j++] = '\n'; 230 | lineEnd += lineLength; 231 | } 232 | 233 | if (i + 1 < length) 234 | { 235 | // 236 | // Handle the single '=' case 237 | // 238 | outputBuffer[j++] = base64EncodeLookup[(inputBuffer[i] & 0xFC) >> 2]; 239 | outputBuffer[j++] = base64EncodeLookup[((inputBuffer[i] & 0x03) << 4) 240 | | ((inputBuffer[i + 1] & 0xF0) >> 4)]; 241 | outputBuffer[j++] = base64EncodeLookup[(inputBuffer[i + 1] & 0x0F) << 2]; 242 | outputBuffer[j++] = '='; 243 | } 244 | else if (i < length) 245 | { 246 | // 247 | // Handle the double '=' case 248 | // 249 | outputBuffer[j++] = base64EncodeLookup[(inputBuffer[i] & 0xFC) >> 2]; 250 | outputBuffer[j++] = base64EncodeLookup[(inputBuffer[i] & 0x03) << 4]; 251 | outputBuffer[j++] = '='; 252 | outputBuffer[j++] = '='; 253 | } 254 | outputBuffer[j] = 0; 255 | 256 | // 257 | // Set the output length and return the buffer 258 | // 259 | if (outputLength) 260 | { 261 | *outputLength = j; 262 | } 263 | return outputBuffer; 264 | } 265 | 266 | @implementation NSDataENBase64 : NSData 267 | 268 | // 269 | // dataFromBase64String: 270 | // 271 | // Creates an NSData object containing the base64 decoded representation of 272 | // the base64 string 'aString' 273 | // 274 | // Parameters: 275 | // aString - the base64 string to decode 276 | // 277 | // returns the autoreleased NSData representation of the base64 string 278 | // 279 | + (NSData *)dataFromBase64String:(NSString *)aString 280 | { 281 | NSData *data = [aString dataUsingEncoding:NSASCIIStringEncoding]; 282 | size_t outputLength; 283 | void *outputBuffer = NewBase64Decode([data bytes], [data length], &outputLength); 284 | NSData *result = [NSData dataWithBytes:outputBuffer length:outputLength]; 285 | free(outputBuffer); 286 | return result; 287 | } 288 | 289 | + (NSString *)base64StringFromData: (NSData *)aData { 290 | size_t outputLength = 0; 291 | char *outputBuffer = 292 | NewBase64Encode([aData bytes], [aData length], true, &outputLength); 293 | 294 | NSString *result = 295 | [[NSString alloc] 296 | initWithBytes:outputBuffer 297 | length:outputLength 298 | encoding:NSASCIIStringEncoding]; 299 | free(outputBuffer); 300 | return result; 301 | } 302 | 303 | // 304 | // base64EncodedString 305 | // 306 | // Creates an NSString object that contains the base 64 encoding of the 307 | // receiver's data. Lines are broken at 64 characters long. 308 | // 309 | // returns an autoreleased NSString being the base 64 representation of the 310 | // receiver. 311 | // 312 | - (NSString *)base64EncodedString 313 | { 314 | size_t outputLength = 0; 315 | char *outputBuffer = 316 | NewBase64Encode([self bytes], [self length], true, &outputLength); 317 | 318 | NSString *result = 319 | [[NSString alloc] 320 | initWithBytes:outputBuffer 321 | length:outputLength 322 | encoding:NSASCIIStringEncoding]; 323 | free(outputBuffer); 324 | return result; 325 | } 326 | 327 | @end 328 | 329 | -------------------------------------------------------------------------------- /ios/RNCloudPayments.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 954FC90C20AADA700017B273 /* RNCloudPayments.m in Sources */ = {isa = PBXBuildFile; fileRef = 954FC90B20AADA700017B273 /* RNCloudPayments.m */; }; 11 | 954FC9F920AC08E60017B273 /* Card.m in Sources */ = {isa = PBXBuildFile; fileRef = 954FC9F620AC08E60017B273 /* Card.m */; }; 12 | 954FC9FA20AC08E60017B273 /* NSDataENBase64.m in Sources */ = {isa = PBXBuildFile; fileRef = 954FC9F720AC08E60017B273 /* NSDataENBase64.m */; }; 13 | /* End PBXBuildFile section */ 14 | 15 | /* Begin PBXCopyFilesBuildPhase section */ 16 | 95E3C63020ADAE9D0098BA8E /* CopyFiles */ = { 17 | isa = PBXCopyFilesBuildPhase; 18 | buildActionMask = 2147483647; 19 | dstPath = "include/$(PRODUCT_NAME)"; 20 | dstSubfolderSpec = 16; 21 | files = ( 22 | ); 23 | runOnlyForDeploymentPostprocessing = 0; 24 | }; 25 | /* End PBXCopyFilesBuildPhase section */ 26 | 27 | /* Begin PBXFileReference section */ 28 | 954FC90720AADA700017B273 /* libRNCloudPayments.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRNCloudPayments.a; sourceTree = BUILT_PRODUCTS_DIR; }; 29 | 954FC90A20AADA700017B273 /* RNCloudPayments.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNCloudPayments.h; sourceTree = ""; }; 30 | 954FC90B20AADA700017B273 /* RNCloudPayments.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNCloudPayments.m; sourceTree = ""; }; 31 | 954FC9F520AC08E60017B273 /* NSDataENBase64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NSDataENBase64.h; sourceTree = ""; }; 32 | 954FC9F620AC08E60017B273 /* Card.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Card.m; sourceTree = ""; }; 33 | 954FC9F720AC08E60017B273 /* NSDataENBase64.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NSDataENBase64.m; sourceTree = ""; }; 34 | 954FC9F820AC08E60017B273 /* Card.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Card.h; sourceTree = ""; }; 35 | /* End PBXFileReference section */ 36 | 37 | /* Begin PBXFrameworksBuildPhase section */ 38 | 954FC90420AADA700017B273 /* Frameworks */ = { 39 | isa = PBXFrameworksBuildPhase; 40 | buildActionMask = 2147483647; 41 | files = ( 42 | ); 43 | runOnlyForDeploymentPostprocessing = 0; 44 | }; 45 | /* End PBXFrameworksBuildPhase section */ 46 | 47 | /* Begin PBXGroup section */ 48 | 954FC8FE20AADA700017B273 = { 49 | isa = PBXGroup; 50 | children = ( 51 | 954FC9F420AC08D70017B273 /* SDK */, 52 | 954FC90B20AADA700017B273 /* RNCloudPayments.m */, 53 | 954FC90A20AADA700017B273 /* RNCloudPayments.h */, 54 | 954FC90820AADA700017B273 /* Products */, 55 | ); 56 | sourceTree = ""; 57 | }; 58 | 954FC90820AADA700017B273 /* Products */ = { 59 | isa = PBXGroup; 60 | children = ( 61 | 954FC90720AADA700017B273 /* libRNCloudPayments.a */, 62 | ); 63 | name = Products; 64 | sourceTree = ""; 65 | }; 66 | 954FC9F420AC08D70017B273 /* SDK */ = { 67 | isa = PBXGroup; 68 | children = ( 69 | 954FC9F820AC08E60017B273 /* Card.h */, 70 | 954FC9F620AC08E60017B273 /* Card.m */, 71 | 954FC9F520AC08E60017B273 /* NSDataENBase64.h */, 72 | 954FC9F720AC08E60017B273 /* NSDataENBase64.m */, 73 | ); 74 | path = SDK; 75 | sourceTree = ""; 76 | }; 77 | /* End PBXGroup section */ 78 | 79 | /* Begin PBXNativeTarget section */ 80 | 954FC90620AADA700017B273 /* RNCloudPayments */ = { 81 | isa = PBXNativeTarget; 82 | buildConfigurationList = 954FC91020AADA700017B273 /* Build configuration list for PBXNativeTarget "RNCloudPayments" */; 83 | buildPhases = ( 84 | 954FC90320AADA700017B273 /* Sources */, 85 | 954FC90420AADA700017B273 /* Frameworks */, 86 | 95E3C63020ADAE9D0098BA8E /* CopyFiles */, 87 | ); 88 | buildRules = ( 89 | ); 90 | dependencies = ( 91 | ); 92 | name = RNCloudPayments; 93 | productName = RNCloudPayments; 94 | productReference = 954FC90720AADA700017B273 /* libRNCloudPayments.a */; 95 | productType = "com.apple.product-type.library.static"; 96 | }; 97 | /* End PBXNativeTarget section */ 98 | 99 | /* Begin PBXProject section */ 100 | 954FC8FF20AADA700017B273 /* Project object */ = { 101 | isa = PBXProject; 102 | attributes = { 103 | LastUpgradeCheck = 0930; 104 | TargetAttributes = { 105 | 954FC90620AADA700017B273 = { 106 | CreatedOnToolsVersion = 9.3; 107 | }; 108 | }; 109 | }; 110 | buildConfigurationList = 954FC90220AADA700017B273 /* Build configuration list for PBXProject "RNCloudPayments" */; 111 | compatibilityVersion = "Xcode 9.3"; 112 | developmentRegion = en; 113 | hasScannedForEncodings = 0; 114 | knownRegions = ( 115 | en, 116 | ); 117 | mainGroup = 954FC8FE20AADA700017B273; 118 | productRefGroup = 954FC90820AADA700017B273 /* Products */; 119 | projectDirPath = ""; 120 | projectRoot = ""; 121 | targets = ( 122 | 954FC90620AADA700017B273 /* RNCloudPayments */, 123 | ); 124 | }; 125 | /* End PBXProject section */ 126 | 127 | /* Begin PBXSourcesBuildPhase section */ 128 | 954FC90320AADA700017B273 /* Sources */ = { 129 | isa = PBXSourcesBuildPhase; 130 | buildActionMask = 2147483647; 131 | files = ( 132 | 954FC90C20AADA700017B273 /* RNCloudPayments.m in Sources */, 133 | 954FC9F920AC08E60017B273 /* Card.m in Sources */, 134 | 954FC9FA20AC08E60017B273 /* NSDataENBase64.m in Sources */, 135 | ); 136 | runOnlyForDeploymentPostprocessing = 0; 137 | }; 138 | /* End PBXSourcesBuildPhase section */ 139 | 140 | /* Begin XCBuildConfiguration section */ 141 | 954FC90E20AADA700017B273 /* Debug */ = { 142 | isa = XCBuildConfiguration; 143 | buildSettings = { 144 | ALWAYS_SEARCH_USER_PATHS = NO; 145 | CLANG_ANALYZER_NONNULL = YES; 146 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 147 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 148 | CLANG_CXX_LIBRARY = "libc++"; 149 | CLANG_ENABLE_MODULES = YES; 150 | CLANG_ENABLE_OBJC_ARC = YES; 151 | CLANG_ENABLE_OBJC_WEAK = YES; 152 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 153 | CLANG_WARN_BOOL_CONVERSION = YES; 154 | CLANG_WARN_COMMA = YES; 155 | CLANG_WARN_CONSTANT_CONVERSION = YES; 156 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 157 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 158 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 159 | CLANG_WARN_EMPTY_BODY = YES; 160 | CLANG_WARN_ENUM_CONVERSION = YES; 161 | CLANG_WARN_INFINITE_RECURSION = YES; 162 | CLANG_WARN_INT_CONVERSION = YES; 163 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 164 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 165 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 166 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 167 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 168 | CLANG_WARN_STRICT_PROTOTYPES = YES; 169 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 170 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 171 | CLANG_WARN_UNREACHABLE_CODE = YES; 172 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 173 | CODE_SIGN_IDENTITY = "iPhone Developer"; 174 | COPY_PHASE_STRIP = NO; 175 | DEBUG_INFORMATION_FORMAT = dwarf; 176 | ENABLE_STRICT_OBJC_MSGSEND = YES; 177 | ENABLE_TESTABILITY = YES; 178 | GCC_C_LANGUAGE_STANDARD = gnu11; 179 | GCC_DYNAMIC_NO_PIC = NO; 180 | GCC_NO_COMMON_BLOCKS = YES; 181 | GCC_OPTIMIZATION_LEVEL = 0; 182 | GCC_PREPROCESSOR_DEFINITIONS = ( 183 | "DEBUG=1", 184 | "$(inherited)", 185 | ); 186 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 187 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 188 | GCC_WARN_UNDECLARED_SELECTOR = YES; 189 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 190 | GCC_WARN_UNUSED_FUNCTION = YES; 191 | GCC_WARN_UNUSED_VARIABLE = YES; 192 | IPHONEOS_DEPLOYMENT_TARGET = 11.3; 193 | MTL_ENABLE_DEBUG_INFO = YES; 194 | ONLY_ACTIVE_ARCH = YES; 195 | SDKROOT = iphoneos; 196 | }; 197 | name = Debug; 198 | }; 199 | 954FC90F20AADA700017B273 /* Release */ = { 200 | isa = XCBuildConfiguration; 201 | buildSettings = { 202 | ALWAYS_SEARCH_USER_PATHS = NO; 203 | CLANG_ANALYZER_NONNULL = YES; 204 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 205 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 206 | CLANG_CXX_LIBRARY = "libc++"; 207 | CLANG_ENABLE_MODULES = YES; 208 | CLANG_ENABLE_OBJC_ARC = YES; 209 | CLANG_ENABLE_OBJC_WEAK = YES; 210 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 211 | CLANG_WARN_BOOL_CONVERSION = YES; 212 | CLANG_WARN_COMMA = YES; 213 | CLANG_WARN_CONSTANT_CONVERSION = YES; 214 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 215 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 216 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 217 | CLANG_WARN_EMPTY_BODY = YES; 218 | CLANG_WARN_ENUM_CONVERSION = YES; 219 | CLANG_WARN_INFINITE_RECURSION = YES; 220 | CLANG_WARN_INT_CONVERSION = YES; 221 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 222 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 223 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 224 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 225 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 226 | CLANG_WARN_STRICT_PROTOTYPES = YES; 227 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 228 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 229 | CLANG_WARN_UNREACHABLE_CODE = YES; 230 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 231 | CODE_SIGN_IDENTITY = "iPhone Developer"; 232 | COPY_PHASE_STRIP = NO; 233 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 234 | ENABLE_NS_ASSERTIONS = NO; 235 | ENABLE_STRICT_OBJC_MSGSEND = YES; 236 | GCC_C_LANGUAGE_STANDARD = gnu11; 237 | GCC_NO_COMMON_BLOCKS = YES; 238 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 239 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 240 | GCC_WARN_UNDECLARED_SELECTOR = YES; 241 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 242 | GCC_WARN_UNUSED_FUNCTION = YES; 243 | GCC_WARN_UNUSED_VARIABLE = YES; 244 | IPHONEOS_DEPLOYMENT_TARGET = 11.3; 245 | MTL_ENABLE_DEBUG_INFO = NO; 246 | SDKROOT = iphoneos; 247 | VALIDATE_PRODUCT = YES; 248 | }; 249 | name = Release; 250 | }; 251 | 954FC91120AADA700017B273 /* Debug */ = { 252 | isa = XCBuildConfiguration; 253 | buildSettings = { 254 | CODE_SIGN_STYLE = Automatic; 255 | OTHER_LDFLAGS = "-ObjC"; 256 | PRODUCT_NAME = "$(TARGET_NAME)"; 257 | SKIP_INSTALL = YES; 258 | TARGETED_DEVICE_FAMILY = "1,2"; 259 | }; 260 | name = Debug; 261 | }; 262 | 954FC91220AADA700017B273 /* Release */ = { 263 | isa = XCBuildConfiguration; 264 | buildSettings = { 265 | CODE_SIGN_STYLE = Automatic; 266 | OTHER_LDFLAGS = "-ObjC"; 267 | PRODUCT_NAME = "$(TARGET_NAME)"; 268 | SKIP_INSTALL = YES; 269 | TARGETED_DEVICE_FAMILY = "1,2"; 270 | }; 271 | name = Release; 272 | }; 273 | /* End XCBuildConfiguration section */ 274 | 275 | /* Begin XCConfigurationList section */ 276 | 954FC90220AADA700017B273 /* Build configuration list for PBXProject "RNCloudPayments" */ = { 277 | isa = XCConfigurationList; 278 | buildConfigurations = ( 279 | 954FC90E20AADA700017B273 /* Debug */, 280 | 954FC90F20AADA700017B273 /* Release */, 281 | ); 282 | defaultConfigurationIsVisible = 0; 283 | defaultConfigurationName = Release; 284 | }; 285 | 954FC91020AADA700017B273 /* Build configuration list for PBXNativeTarget "RNCloudPayments" */ = { 286 | isa = XCConfigurationList; 287 | buildConfigurations = ( 288 | 954FC91120AADA700017B273 /* Debug */, 289 | 954FC91220AADA700017B273 /* Release */, 290 | ); 291 | defaultConfigurationIsVisible = 0; 292 | defaultConfigurationName = Release; 293 | }; 294 | /* End XCConfigurationList section */ 295 | }; 296 | rootObject = 954FC8FF20AADA700017B273 /* Project object */; 297 | } 298 | -------------------------------------------------------------------------------- /ios/SDK/Card.m: -------------------------------------------------------------------------------- 1 | #import "Card.h" 2 | #import "NSDataENBase64.h" 3 | 4 | #define kPublicKey @"-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArBZ1NNjvszen6BNWsgyD\nUJvDUZDtvR4jKNQtEwW1iW7hqJr0TdD8hgTxw3DfH+Hi/7ZjSNdH5EfChvgVW9wt\nTxrvUXCOyJndReq7qNMo94lHpoSIVW82dp4rcDB4kU+q+ekh5rj9Oj6EReCTuXr3\nfoLLBVpH0/z1vtgcCfQzsLlGkSTwgLqASTUsuzfI8viVUbxE1a+600hN0uBh/CYK\noMnCp/EhxV8g7eUmNsWjZyiUrV8AA/5DgZUCB+jqGQT/Dhc8e21tAkQ3qan/jQ5i\n/QYocA/4jW3WQAldMLj0PA36kINEbuDKq8qRh25v+k4qyjb7Xp4W2DywmNtG3Q20\nMQIDAQAB\n-----END PUBLIC KEY-----" 5 | #define kPublicKeyVersion @"04" 6 | 7 | @interface Card (Private) 8 | + (NSString *)cleanCreditCardNo:(NSString *)aCreditCardNo; 9 | @end 10 | 11 | @implementation Card 12 | 13 | -(id)init 14 | { 15 | self = [super init]; 16 | if(self) { 17 | keyRefs = [NSMutableArray array]; 18 | [self addPublicKey:kPublicKey withTag:@"public_key"]; 19 | } 20 | return self; 21 | } 22 | 23 | #pragma mark - Private messages 24 | + (NSString *)cleanCreditCardNo:(NSString *)aCreditCardNo { 25 | return [[aCreditCardNo componentsSeparatedByCharactersInSet: 26 | [[NSCharacterSet decimalDigitCharacterSet] invertedSet]] 27 | componentsJoinedByString:@""]; 28 | } 29 | 30 | 31 | // gets public key from const in .pch file 32 | + (NSData *) getPublicKey { 33 | NSString *s_key = [NSString string]; 34 | NSArray *a_key = [kPublicKey componentsSeparatedByString:@"\n"]; 35 | BOOL f_key = FALSE; 36 | 37 | for (NSString *a_line in a_key) { 38 | if ([a_line isEqualToString:@"-----BEGIN PUBLIC KEY-----"]) { 39 | f_key = TRUE; 40 | } 41 | else if ([a_line isEqualToString:@"-----END PUBLIC KEY-----"]) { 42 | f_key = FALSE; 43 | } 44 | else if (f_key) { 45 | s_key = [s_key stringByAppendingString:a_line]; 46 | } 47 | } 48 | if (s_key.length == 0) { 49 | return(FALSE); 50 | } else { 51 | 52 | // s_key = [s_key stringByAppendingString:@"\n"]; 53 | NSData *returnData = [[NSData alloc] initWithBase64EncodedString:s_key options:NSDataBase64DecodingIgnoreUnknownCharacters]; 54 | 55 | returnData = [Card stripPublicKeyHeader:returnData]; 56 | 57 | 58 | return returnData; 59 | } 60 | } 61 | 62 | + (NSData *)stripPublicKeyHeader:(NSData *)d_key 63 | { 64 | // Skip ASN.1 public key header 65 | if (d_key == nil) return(nil); 66 | 67 | unsigned long len = [d_key length]; 68 | if (!len) return(nil); 69 | 70 | unsigned char *c_key = (unsigned char *)[d_key bytes]; 71 | unsigned int idx = 0; 72 | 73 | if (c_key[idx++] != 0x30) return(nil); 74 | 75 | if (c_key[idx] > 0x80) idx += c_key[idx] - 0x80 + 1; 76 | else idx++; 77 | 78 | // PKCS #1 rsaEncryption szOID_RSA_RSA 79 | static unsigned char seqiod[] = 80 | { 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 81 | 0x01, 0x05, 0x00 }; 82 | if (memcmp(&c_key[idx], seqiod, 15)) return(nil); 83 | 84 | idx += 15; 85 | 86 | if (c_key[idx++] != 0x03) return(nil); 87 | 88 | if (c_key[idx] > 0x80) idx += c_key[idx] - 0x80 + 1; 89 | else idx++; 90 | 91 | if (c_key[idx++] != '\0') return(nil); 92 | 93 | // Now make a new NSData from this buffer 94 | return([NSData dataWithBytes:&c_key[idx] length:len - idx]); 95 | } 96 | 97 | #pragma mark - Public messages 98 | +(BOOL) isCardNumberValid: (NSString *) cardNumberString { 99 | NSString *cleanCardNumber = [Card cleanCreditCardNo:cardNumberString]; 100 | 101 | if (cleanCardNumber.length == 0) { 102 | return NO; 103 | } 104 | 105 | NSMutableArray *cardNumberCharactersArray = [[NSMutableArray alloc] initWithCapacity:[cleanCardNumber length]]; 106 | for (int i=0; i < [cleanCardNumber length]; i++) { 107 | NSString *ichar = [NSString stringWithFormat:@"%c", [cleanCardNumber characterAtIndex:i]]; 108 | [cardNumberCharactersArray addObject:ichar]; 109 | } 110 | 111 | // INFO: one of Luhn algorithm implementation 112 | BOOL isOdd = YES; 113 | int oddSum = 0; 114 | int evenSum = 0; 115 | 116 | for (int i = (int)[cleanCardNumber length] - 1; i >= 0; i--) { 117 | int digit = [(NSString *)[cardNumberCharactersArray objectAtIndex:i] intValue]; 118 | if (isOdd) { 119 | oddSum += digit; 120 | } else { 121 | evenSum += digit/5 + (2*digit) % 10; 122 | } 123 | 124 | isOdd = !isOdd; 125 | } 126 | 127 | return ((oddSum + evenSum) % 10 == 0); 128 | } 129 | 130 | -(NSString *) makeCardCryptogramPacket: (NSString *) cardNumberString andExpDate: (NSString *) expDateString andCVV: (NSString *) CVVString andMerchantPublicID: (NSString *) merchantPublicIDString { 131 | 132 | // ExpDate must be in YYMM format 133 | NSArray *cardDateComponents = [expDateString componentsSeparatedByString:@"/"]; 134 | NSString *cardExpirationDateString = [NSString stringWithFormat:@"%@%@",cardDateComponents[1],cardDateComponents[0]]; 135 | 136 | NSMutableString *packetString = [NSMutableString string]; 137 | NSString *cryptogramString = nil; 138 | NSString *decryptedCryptogram = nil; 139 | 140 | // create cryptogram 141 | NSString *cleanCardNumber = [Card cleanCreditCardNo:cardNumberString]; 142 | decryptedCryptogram = [NSString stringWithFormat:@"%@@%@@%@@%@", 143 | cleanCardNumber, 144 | cardExpirationDateString, 145 | CVVString, 146 | merchantPublicIDString]; 147 | 148 | SecKeyRef key = [self publicKey]; 149 | cryptogramString = [Card encryptRSA:decryptedCryptogram key:key]; 150 | cryptogramString = [cryptogramString stringByReplacingOccurrencesOfString:@"\n" withString:@""]; 151 | cryptogramString = [cryptogramString stringByReplacingOccurrencesOfString:@"\r" withString:@""]; 152 | 153 | [packetString appendString:@"02"]; 154 | [packetString appendString:[cleanCardNumber substringWithRange:NSMakeRange(0, 6)]]; 155 | [packetString appendString:[cleanCardNumber substringWithRange:NSMakeRange(cleanCardNumber.length-4, 4)]]; 156 | [packetString appendString:cardExpirationDateString]; 157 | [packetString appendString:kPublicKeyVersion]; 158 | [packetString appendString:cryptogramString]; 159 | 160 | return (NSString *) packetString; 161 | } 162 | 163 | 164 | +(CardType) cardTypeFromCardNumber:(NSString *)cardNumberString { 165 | NSString *cleanCardNumber = [Card cleanCreditCardNo:cardNumberString]; 166 | 167 | if (cleanCardNumber.length < 1) { 168 | return Unknown; 169 | } 170 | 171 | int first = [[cleanCardNumber substringWithRange:NSMakeRange(0, 1)] intValue]; 172 | 173 | if (first == 4) { 174 | return Visa; 175 | } 176 | 177 | if (first == 6) { 178 | return Maestro; 179 | } 180 | 181 | if (cleanCardNumber.length < 2) { 182 | return Unknown; 183 | } 184 | 185 | int firstTwo = [[cleanCardNumber substringWithRange:NSMakeRange(0, 2)] intValue]; 186 | 187 | if (firstTwo == 35) { 188 | return JCB; 189 | } 190 | 191 | if (firstTwo == 50 || (firstTwo >= 56 && firstTwo <= 58)) { 192 | return Maestro; 193 | } 194 | 195 | if (firstTwo >= 51 && firstTwo <= 55) { 196 | return MasterCard; 197 | } 198 | 199 | if (cleanCardNumber.length < 4) { 200 | return Unknown; 201 | } 202 | 203 | int firstFour = [[cleanCardNumber substringWithRange:NSMakeRange(0, 4)] intValue]; 204 | 205 | if (firstFour >= 2200 && firstFour <= 2204) { 206 | return Mir; 207 | } 208 | 209 | if (firstFour >= 2221 && firstFour <= 2720) { 210 | return MasterCard; 211 | } 212 | 213 | return Unknown; 214 | } 215 | 216 | 217 | +(NSString *) cardTypeToString:(CardType)cardType { 218 | 219 | switch(cardType) { 220 | case Visa: 221 | return @"Visa"; 222 | break; 223 | case MasterCard: 224 | return @"MasterCard"; 225 | break; 226 | case Maestro: 227 | return @"Maestro"; 228 | break; 229 | case Mir: 230 | return @"MIR"; 231 | break; 232 | case JCB: 233 | return @"JCB"; 234 | break; 235 | default: 236 | return @"Unknown"; 237 | } 238 | } 239 | 240 | #pragma mark - Security 241 | +(NSString *)encryptRSA:(NSString *)plainTextString key:(SecKeyRef)publicKey 242 | { 243 | size_t cipherBufferSize = SecKeyGetBlockSize(publicKey); 244 | uint8_t *cipherBuffer = malloc(cipherBufferSize); 245 | uint8_t *nonce = (uint8_t *)[plainTextString cStringUsingEncoding:NSASCIIStringEncoding]; 246 | SecKeyEncrypt(publicKey, 247 | kSecPaddingOAEP, 248 | nonce, 249 | strlen( (char*)nonce ), 250 | &cipherBuffer[0], 251 | &cipherBufferSize); 252 | NSData *encryptedData = [NSData dataWithBytes:cipherBuffer length:cipherBufferSize]; 253 | return [NSDataENBase64 base64StringFromData:encryptedData]; 254 | } 255 | 256 | +(NSString *)decryptRSA:(NSString *)cipherString key:(SecKeyRef) privateKey { 257 | size_t plainBufferSize = SecKeyGetBlockSize(privateKey); 258 | uint8_t *plainBuffer = malloc(plainBufferSize); 259 | NSData *incomingData = [NSDataENBase64 dataFromBase64String:cipherString]; 260 | uint8_t *cipherBuffer = (uint8_t*)[incomingData bytes]; 261 | size_t cipherBufferSize = SecKeyGetBlockSize(privateKey); 262 | SecKeyDecrypt(privateKey, 263 | kSecPaddingOAEP, 264 | cipherBuffer, 265 | cipherBufferSize, 266 | plainBuffer, 267 | &plainBufferSize); 268 | NSData *decryptedData = [NSData dataWithBytes:plainBuffer length:plainBufferSize]; 269 | NSString *decryptedString = [[NSString alloc] initWithData:decryptedData encoding:NSASCIIStringEncoding]; 270 | return decryptedString; 271 | } 272 | 273 | -(SecKeyRef)publicKey 274 | { 275 | SecKeyRef p_key = NULL; 276 | for (NSValue *refVal in keyRefs) { 277 | [refVal getValue:&p_key]; 278 | if (p_key == NULL) continue; 279 | } 280 | return p_key; 281 | } 282 | 283 | - (NSData *)stripPublicKeyHeader:(NSData *)d_key 284 | { 285 | // Skip ASN.1 public key header 286 | if (d_key == nil) return(nil); 287 | 288 | unsigned long len = [d_key length]; 289 | if (!len) return(nil); 290 | 291 | unsigned char *c_key = (unsigned char *)[d_key bytes]; 292 | unsigned int idx = 0; 293 | 294 | if (c_key[idx++] != 0x30) return(nil); 295 | 296 | if (c_key[idx] > 0x80) idx += c_key[idx] - 0x80 + 1; 297 | else idx++; 298 | 299 | // PKCS #1 rsaEncryption szOID_RSA_RSA 300 | static unsigned char seqiod[] = 301 | { 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 302 | 0x01, 0x05, 0x00 }; 303 | if (memcmp(&c_key[idx], seqiod, 15)) return(nil); 304 | 305 | idx += 15; 306 | 307 | if (c_key[idx++] != 0x03) return(nil); 308 | 309 | if (c_key[idx] > 0x80) idx += c_key[idx] - 0x80 + 1; 310 | else idx++; 311 | 312 | if (c_key[idx++] != '\0') return(nil); 313 | 314 | // Now make a new NSData from this buffer 315 | return([NSData dataWithBytes:&c_key[idx] length:len - idx]); 316 | } 317 | 318 | - (BOOL)addPublicKey:(NSString *)key withTag:(NSString *)tag 319 | { 320 | NSString *s_key = [NSString string]; 321 | NSArray *a_key = [key componentsSeparatedByString:@"\n"]; 322 | BOOL f_key = FALSE; 323 | 324 | for (NSString *a_line in a_key) { 325 | if ([a_line isEqualToString:@"-----BEGIN PUBLIC KEY-----"]) { 326 | f_key = TRUE; 327 | } 328 | else if ([a_line isEqualToString:@"-----END PUBLIC KEY-----"]) { 329 | f_key = FALSE; 330 | } 331 | else if (f_key) { 332 | s_key = [s_key stringByAppendingString:a_line]; 333 | } 334 | } 335 | if (s_key.length == 0) return(FALSE); 336 | 337 | // This will be base64 encoded, decode it. 338 | NSData *d_key = [NSDataENBase64 dataFromBase64String:s_key]; 339 | d_key = [self stripPublicKeyHeader:d_key]; 340 | if (d_key == nil) return(FALSE); 341 | 342 | NSData *d_tag = [NSData dataWithBytes:[tag UTF8String] length:[tag length]]; 343 | 344 | // Delete any old lingering key with the same tag 345 | NSMutableDictionary *publicKey = [[NSMutableDictionary alloc] init]; 346 | [publicKey setObject:(__bridge id) kSecClassKey forKey:(__bridge id)kSecClass]; 347 | [publicKey setObject:(__bridge id) kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType]; 348 | [publicKey setObject:d_tag forKey:(__bridge id)kSecAttrApplicationTag]; 349 | SecItemDelete((__bridge CFDictionaryRef)publicKey); 350 | 351 | CFTypeRef persistKey = nil; 352 | 353 | // Add persistent version of the key to system keychain 354 | [publicKey setObject:d_key forKey:(__bridge id)kSecValueData]; 355 | [publicKey setObject:(__bridge id) kSecAttrKeyClassPublic forKey:(__bridge id) 356 | kSecAttrKeyClass]; 357 | [publicKey setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id) 358 | kSecReturnPersistentRef]; 359 | 360 | OSStatus secStatus = SecItemAdd((__bridge CFDictionaryRef)publicKey, &persistKey); 361 | if (persistKey != nil) CFRelease(persistKey); 362 | 363 | if ((secStatus != noErr) && (secStatus != errSecDuplicateItem)) { 364 | return(FALSE); 365 | } 366 | 367 | // Now fetch the SecKeyRef version of the key 368 | SecKeyRef keyRef = nil; 369 | 370 | [publicKey removeObjectForKey:(__bridge id)kSecValueData]; 371 | [publicKey removeObjectForKey:(__bridge id)kSecReturnPersistentRef]; 372 | [publicKey setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id)kSecReturnRef 373 | ]; 374 | [publicKey setObject:(__bridge id) kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType]; 375 | secStatus = SecItemCopyMatching((__bridge CFDictionaryRef)publicKey, 376 | (CFTypeRef *)&keyRef); 377 | 378 | if (keyRef == nil) return(FALSE); 379 | 380 | // Add to our pseudo keychain 381 | [keyRefs addObject:[NSValue valueWithBytes:&keyRef objCType:@encode( 382 | SecKeyRef)]]; 383 | 384 | return(TRUE); 385 | } 386 | 387 | @end 388 | --------------------------------------------------------------------------------