From 34644dfdf1cf8fdb3f15cb5088af1b6d6c23824b Mon Sep 17 00:00:00 2001 From: Abhishek Pandey <64667840+1abhishekpandey@users.noreply.github.com> Date: Fri, 1 Sep 2023 16:01:25 +0530 Subject: [PATCH] feat: add encrypt database api support (#236) * feat(rudder-sdk-react-native): add db encryption support * feat(rudder-sdk-react-native): add db encyption support in ios module * fix(rudder-sdk-react-native): improve db encryption null value handling * chore(rudder-sdk-react-native): increase the sdk version in constant to 1.9.0 * feat(rudder-sdk-react-native): add db encyption support in android module * chore(example): update sample app with db encryption feature * chore(example): update sample app * chore(rudder-sdk-react-native-monorepo): update package-lock.json * chore(example): remove GoogleService-Info.plist file * chore(rudder-sdk-react-native): implement sql cipher dependency in android * chore(example): fix appsflyer architecture x86_64 issue * chore(example): update sample app * fix(rudder-sdk-react-native): filter out empty key in android module * fix(rudder-sdk-react-native): remove null as a default argument for encyrption parameter instead use undefined * refactor(rudder-sdk-react-native): add dbEncryption key conditionally to config object * refactor(rudder-sdk-react-native): rndbencryption file to dbencryption * chore(example): update sample app * fix(rudder-sdk-react-native): filter out empty key in ios module * chore(rudder-sdk-react-native): update the minimum rudder ios dependency to 1.19.2 * chore(example): update podfile.lock * fix(rudder-sdk-react-native): move sql-cipher implementation in android sample app * chore(rudder-sdk-react-native-monorepo): remove sql-cipher compileOnly dependency from android module --- README.md | 33 +++++++++++++++++++ apps/example/android/app/build.gradle | 3 ++ .../ios/Example.xcodeproj/project.pbxproj | 4 --- apps/example/ios/Podfile | 1 + apps/example/ios/Podfile.lock | 20 +++++------ apps/example/src/app/App.tsx | 5 ++- libs/sdk/RNRudderSdk.podspec | 2 +- libs/sdk/android/build.gradle | 2 +- .../react/android/RNParamsConfigurator.java | 11 +++++++ .../rudderstack/react/android/Utility.java | 16 +++++++++ libs/sdk/ios/RNParamsConfigurator.m | 8 +++++ libs/sdk/src/Constants.ts | 2 +- libs/sdk/src/DBEncryption.ts | 10 ++++++ libs/sdk/src/NativeBridge.ts | 2 ++ libs/sdk/src/RudderConfiguration.ts | 7 +++- libs/sdk/src/index.ts | 3 +- package-lock.json | 2 +- 17 files changed, 110 insertions(+), 21 deletions(-) create mode 100644 libs/sdk/src/DBEncryption.ts diff --git a/README.md b/README.md index ba369da6..45ab42f7 100644 --- a/README.md +++ b/README.md @@ -111,6 +111,39 @@ Example Usage: rudderClient.setAnonymousId(ANONYMOUS_ID); ``` +## Database Encryption + +To encrypt the database first add the below line to `import` the rudderClient and DBEncryption. + +``` +import rudderClient, { RUDDER_LOG_LEVEL, DBEncryption } from '@rudderstack/rudder-sdk-react-native'; +``` + +Then open your `app/build.gradle` and add the dependency under `dependencies` as shown below: + +``` +//sql-cipher +implementation "net.zetetic:android-database-sqlcipher:4.5.4" +implementation "androidx.sqlite:sqlite:2.3.1" +``` + +Add the following code in your application: + +``` +const dbEncryption = new DBEncryption('versys', true); + +const config = { + dataPlaneUrl: , + trackAppLifecycleEvents: true, + logLevel: RUDDER_LOG_LEVEL.DEBUG, + dbEncryption: dbEncryption, +}; + +await rudderClient.setup(, config); +``` + +This feature is supported starting from version `1.9.0` of the SDK. + For more details, check out our [documentation](https://www.rudderstack.com/docs/sources/event-streams/sdks/rudderstack-react-native-sdk). ## Contact Us diff --git a/apps/example/android/app/build.gradle b/apps/example/android/app/build.gradle index 44654612..57edd53b 100644 --- a/apps/example/android/app/build.gradle +++ b/apps/example/android/app/build.gradle @@ -302,6 +302,9 @@ dependencies { implementation 'com.google.code.gson:gson:2.8.6' implementation 'com.google.firebase:firebase-messaging:21.0.0' + //sql-cipher + implementation "net.zetetic:android-database-sqlcipher:4.5.4" + implementation "androidx.sqlite:sqlite:2.3.1" androidTestImplementation(project(path: ":detox")) diff --git a/apps/example/ios/Example.xcodeproj/project.pbxproj b/apps/example/ios/Example.xcodeproj/project.pbxproj index ff4696ca..e0273511 100644 --- a/apps/example/ios/Example.xcodeproj/project.pbxproj +++ b/apps/example/ios/Example.xcodeproj/project.pbxproj @@ -13,7 +13,6 @@ 13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; }; 572899A5661046CED23B3DC6 /* libPods-Example.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 2846C63330CECB73DE262FD5 /* libPods-Example.a */; }; 81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */; }; - 8C690C862A69005300E631F0 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 8C690C852A69005300E631F0 /* GoogleService-Info.plist */; }; FECB4DA94BF95A215192377D /* libPods-Example-ExampleTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = CB256E5F615F81481C8756EE /* libPods-Example-ExampleTests.a */; }; /* End PBXBuildFile section */ @@ -41,7 +40,6 @@ 2846C63330CECB73DE262FD5 /* libPods-Example.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Example.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 57C1791C2982A27EC162ADDA /* Pods-Example.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Example.release.xcconfig"; path = "Target Support Files/Pods-Example/Pods-Example.release.xcconfig"; sourceTree = ""; }; 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = LaunchScreen.storyboard; path = Example/LaunchScreen.storyboard; sourceTree = ""; }; - 8C690C852A69005300E631F0 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; BFB8B5DECB5F049E1E8B8C65 /* Pods-Example.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Example.debug.xcconfig"; path = "Target Support Files/Pods-Example/Pods-Example.debug.xcconfig"; sourceTree = ""; }; CB256E5F615F81481C8756EE /* libPods-Example-ExampleTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Example-ExampleTests.a"; sourceTree = BUILT_PRODUCTS_DIR; }; ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; }; @@ -88,7 +86,6 @@ 13B07FAE1A68108700A75B9A /* Example */ = { isa = PBXGroup; children = ( - 8C690C852A69005300E631F0 /* GoogleService-Info.plist */, 13B07FAF1A68108700A75B9A /* AppDelegate.h */, 13B07FB01A68108700A75B9A /* AppDelegate.mm */, 13B07FB51A68108700A75B9A /* Images.xcassets */, @@ -247,7 +244,6 @@ files = ( 81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */, 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */, - 8C690C862A69005300E631F0 /* GoogleService-Info.plist in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/apps/example/ios/Podfile b/apps/example/ios/Podfile index 46d9ad0d..41321161 100644 --- a/apps/example/ios/Podfile +++ b/apps/example/ios/Podfile @@ -78,6 +78,7 @@ target 'Example' do installer.pods_project.targets.each do |target| target.build_configurations.each do |config| config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '12.4' + config.build_settings['EXCLUDED_ARCHS[sdk=iphonesimulator*]'] = "arm64" end end react_native_post_install( diff --git a/apps/example/ios/Podfile.lock b/apps/example/ios/Podfile.lock index 6afb09bb..72f7d476 100644 --- a/apps/example/ios/Podfile.lock +++ b/apps/example/ios/Podfile.lock @@ -27,9 +27,9 @@ PODS: - AppCenter/Core (5.0.3) - AppCenter/Crashes (5.0.3): - AppCenter/Core - - AppsFlyerFramework (6.12.1): - - AppsFlyerFramework/Main (= 6.12.1) - - AppsFlyerFramework/Main (6.12.1) + - AppsFlyerFramework (6.12.2): + - AppsFlyerFramework/Main (= 6.12.2) + - AppsFlyerFramework/Main (6.12.2) - boost (1.76.0) - CleverTap-iOS-SDK (4.2.2): - SDWebImage (~> 5.11) @@ -510,15 +510,15 @@ PODS: - React-perflogger (= 0.71.4) - RNCAsyncStorage (1.18.0): - React-Core - - RNRudderSdk (1.8.0): + - RNRudderSdk (1.8.1): - React - - Rudder (~> 1.13) + - Rudder (< 2.0, >= 1.19.2) - RNScreens (3.20.0): - React-Core - React-RCTImage - RNSVG (13.8.0): - React-Core - - Rudder (1.19.1): + - Rudder (1.19.2): - MetricsReporter (= 1.0.0) - Rudder-Amplitude (1.1.1): - Amplitude (= 8.16.0) @@ -803,7 +803,7 @@ SPEC CHECKSUMS: AnalyticsConnector: eccd7e1cd3dd18e6bd09ac2506e37d4ed43ba3f4 Appboy-iOS-SDK: 2fc5b290fe1caa85718b811a19b303d45caea975 AppCenter: a4070ec3d4418b5539067a51f57155012e486ebd - AppsFlyerFramework: e29b63fc5441400a38a31c5501c1da500b9d53d0 + AppsFlyerFramework: 6eb4d89d2eb9a6632317f1055b359d9fd85fd5ff boost: 57d2868c099736d80fcd648bf211b4431e51a558 CleverTap-iOS-SDK: 36c21b8a671d87a0f9c7b389b339d02528bbe4d7 CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99 @@ -863,10 +863,10 @@ SPEC CHECKSUMS: React-runtimeexecutor: 8fa50b38df6b992c76537993a2b0553d3b088004 ReactCommon: 1fed1243105330aa50ad7051207b61656f5e570b RNCAsyncStorage: a46ee6bf15cf1ba863d0a47287236f9c95d5b213 - RNRudderSdk: b8cbccae069ea1a16ae1fd93e1b1072c1f1b7af7 + RNRudderSdk: 7efd553fa0ef684d61ba27548d8e6d7af54db9a6 RNScreens: 218801c16a2782546d30bd2026bb625c0302d70f RNSVG: c1e76b81c76cdcd34b4e1188852892dc280eb902 - Rudder: 187a8fc060057605b6e78fb8077b4d989943d804 + Rudder: 26a9b6756628cb953f3151d835104ac9f5635861 Rudder-Amplitude: a353ca07ba381d23ae587f2f74ea79a6c1563145 Rudder-AppCenter: 9eca9241e3707a0e9610714dd91dc8da4bae7e1f Rudder-Appsflyer: 8108ad9e323a5c0e9aeecdbfc4fa2dfe68497146 @@ -890,6 +890,6 @@ SPEC CHECKSUMS: Yoga: 79dd7410de6f8ad73a77c868d3d368843f0c93e0 YogaKit: f782866e155069a2cca2517aafea43200b01fd5a -PODFILE CHECKSUM: 1f734483bc51f36f263f2253ff0038e4adf6734a +PODFILE CHECKSUM: 977a4cd75cd9d6f6ff277b285d4c9cf0b64ae999 COCOAPODS: 1.11.3 diff --git a/apps/example/src/app/App.tsx b/apps/example/src/app/App.tsx index f5eeed09..5cbb26da 100644 --- a/apps/example/src/app/App.tsx +++ b/apps/example/src/app/App.tsx @@ -3,7 +3,7 @@ import { useEffect } from 'react'; import { Button, Text } from 'react-native'; import { NavigationContainer } from '@react-navigation/native'; import { createNativeStackNavigator } from '@react-navigation/native-stack'; -import rc, { RUDDER_LOG_LEVEL } from '@rudderstack/rudder-sdk-react-native'; +import rc, { RUDDER_LOG_LEVEL, DBEncryption } from '@rudderstack/rudder-sdk-react-native'; import amplitude from '@rudderstack/rudder-integration-amplitude-react-native'; import appcenter from '@rudderstack/rudder-integration-appcenter-react-native'; import braze from '@rudderstack/rudder-integration-braze-react-native'; @@ -69,6 +69,8 @@ const initRNAppsFlyerSDK = async () => { }; const initRudderReactNativeSDK = async () => { + const dbEncryption = new DBEncryption('versys', false); + const config = { dataPlaneUrl: TEST_DATAPLANE_URL, autoCollectAdvertId: true, @@ -78,6 +80,7 @@ const initRudderReactNativeSDK = async () => { enableBackgroundMode: true, trackAppLifecycleEvents: true, autoSessionTracking: true, + dbEncryption: dbEncryption, withFactories: [ appsflyer, amplitude, diff --git a/libs/sdk/RNRudderSdk.podspec b/libs/sdk/RNRudderSdk.podspec index fe895360..8c8c036a 100644 --- a/libs/sdk/RNRudderSdk.podspec +++ b/libs/sdk/RNRudderSdk.podspec @@ -19,7 +19,7 @@ Pod::Spec.new do |s| s.requires_arc = true s.dependency "React" - s.dependency "Rudder", "~> 1.13" + s.dependency "Rudder", ">= 1.19.2", "< 2.0" end diff --git a/libs/sdk/android/build.gradle b/libs/sdk/android/build.gradle index 86f886c1..e866f556 100644 --- a/libs/sdk/android/build.gradle +++ b/libs/sdk/android/build.gradle @@ -57,5 +57,5 @@ repositories { dependencies { compileOnly 'com.facebook.react:react-native:+' implementation 'com.google.code.gson:gson:2.8.9' - implementation 'com.rudderstack.android.sdk:core:[1.13.0, 2.0.0)' + implementation 'com.rudderstack.android.sdk:core:[1.18.0, 2.0.0)' } diff --git a/libs/sdk/android/src/main/java/com/rudderstack/react/android/RNParamsConfigurator.java b/libs/sdk/android/src/main/java/com/rudderstack/react/android/RNParamsConfigurator.java index 409790e2..321416d6 100644 --- a/libs/sdk/android/src/main/java/com/rudderstack/react/android/RNParamsConfigurator.java +++ b/libs/sdk/android/src/main/java/com/rudderstack/react/android/RNParamsConfigurator.java @@ -2,6 +2,9 @@ import com.facebook.react.bridge.ReadableMap; import com.rudderstack.android.sdk.core.RudderConfig; +import com.rudderstack.android.sdk.core.util.Utils; + +import java.util.Map; class RNParamsConfigurator { private final ReadableMap config; @@ -72,6 +75,14 @@ private RudderConfig.Builder buildConfig() { if (config.hasKey("logLevel")) { configBuilder.withLogLevel(config.getInt("logLevel")); } + if (config.hasKey("dbEncryption")) { + Map dbEncryption = Utility.convertReadableMapToMap(config.getMap("dbEncryption")); + String key = (String) (Utility.getValueFromMap(dbEncryption, "key", "")); + Boolean enable = (Boolean) (Utility.getValueFromMap(dbEncryption, "enable", false)); + if (!Utility.isEmpty(key)) { + configBuilder.withDbEncryption(new RudderConfig.DBEncryption(enable, key)); + } + } return configBuilder; } diff --git a/libs/sdk/android/src/main/java/com/rudderstack/react/android/Utility.java b/libs/sdk/android/src/main/java/com/rudderstack/react/android/Utility.java index bb09ed26..e15c4d61 100644 --- a/libs/sdk/android/src/main/java/com/rudderstack/react/android/Utility.java +++ b/libs/sdk/android/src/main/java/com/rudderstack/react/android/Utility.java @@ -20,6 +20,8 @@ import java.util.List; import java.util.Map; +import javax.annotation.Nonnull; + public class Utility { public static Map convertReadableMapToMap(ReadableMap readableMap) { @@ -164,4 +166,18 @@ public static WritableArray convertJsonToWriteAbleArray(JSONArray jsonArray) thr } return array; } + + @Nonnull + public static Object getValueFromMap(Map map, String key, Object defaultValue) { + if (map == null || key == null) return defaultValue; + if (map.containsKey(key)) { + return map.get(key); + } + return defaultValue; + } + + @Nonnull + public static boolean isEmpty(String str) { + return str == null || str.length() == 0; + } } diff --git a/libs/sdk/ios/RNParamsConfigurator.m b/libs/sdk/ios/RNParamsConfigurator.m index d8a87ec1..59b9f33c 100644 --- a/libs/sdk/ios/RNParamsConfigurator.m +++ b/libs/sdk/ios/RNParamsConfigurator.m @@ -78,6 +78,14 @@ -(RSConfigBuilder*)buildConfig { if ([config objectForKey:@"logLevel"]) { [configBuilder withLoglevel:[config[@"logLevel"] intValue]]; } + if ([config objectForKey:@"dbEncryption"]) { + NSDictionary *dbEncryption = config[@"dbEncryption"]; + NSString *key = dbEncryption[@"key"]; + BOOL enable = [dbEncryption[@"enable"] boolValue]; + if (key != nil && [key length] > 0) { + [configBuilder withDBEncryption:[[RSDBEncryption alloc] initWithKey:key enable:enable]]; + } + } return configBuilder; } diff --git a/libs/sdk/src/Constants.ts b/libs/sdk/src/Constants.ts index 4bfbbff4..23d8b361 100644 --- a/libs/sdk/src/Constants.ts +++ b/libs/sdk/src/Constants.ts @@ -10,7 +10,7 @@ export const AUTO_COLLECT_ADVERT_ID = false; export const TRACK_LIFECYCLE_EVENTS = true; export const RECORD_SCREEN_VIEWS = false; export const LOG_LEVEL = RUDDER_LOG_LEVEL.ERROR; -export const SDK_VERSION = '1.8.0'; +export const SDK_VERSION = '1.9.0'; export const AUTO_SESSION_TRACKING = true; export const SESSION_TIMEOUT = 300000; export const ENABLE_BACKGROUND_MODE = false; diff --git a/libs/sdk/src/DBEncryption.ts b/libs/sdk/src/DBEncryption.ts new file mode 100644 index 00000000..32686660 --- /dev/null +++ b/libs/sdk/src/DBEncryption.ts @@ -0,0 +1,10 @@ +class DBEncryption { + key: string; + enable: boolean; + constructor(key: string, enable: boolean) { + this.key = key; + this.enable = enable; + } +} + +export default DBEncryption; diff --git a/libs/sdk/src/NativeBridge.ts b/libs/sdk/src/NativeBridge.ts index 1c551bef..70bac865 100644 --- a/libs/sdk/src/NativeBridge.ts +++ b/libs/sdk/src/NativeBridge.ts @@ -1,4 +1,5 @@ import { NativeModules } from 'react-native'; +import DBEncryption from './DBEncryption'; export interface Configuration { dataPlaneUrl?: string; @@ -14,6 +15,7 @@ export interface Configuration { autoSessionTracking?: boolean; sessionTimeout?: number; enableBackgroundMode?: boolean; + dbEncryption?: DBEncryption; // eslint-disable-next-line @typescript-eslint/ban-types withFactories?: Array | Function>; } diff --git a/libs/sdk/src/RudderConfiguration.ts b/libs/sdk/src/RudderConfiguration.ts index 5e6d8636..3db42cec 100644 --- a/libs/sdk/src/RudderConfiguration.ts +++ b/libs/sdk/src/RudderConfiguration.ts @@ -31,6 +31,7 @@ export const configure = async ( autoCollectAdvertId = AUTO_COLLECT_ADVERT_ID, trackAppLifecycleEvents = TRACK_LIFECYCLE_EVENTS, recordScreenViews = RECORD_SCREEN_VIEWS, + dbEncryption, withFactories = [], }: Configuration, ): Promise => { @@ -62,5 +63,9 @@ export const configure = async ( recordScreenViews, }; - return { ...config }; + if (dbEncryption !== undefined) { + return { ...config, dbEncryption }; + } + + return config; }; diff --git a/libs/sdk/src/index.ts b/libs/sdk/src/index.ts index 1c315e23..453f420f 100644 --- a/libs/sdk/src/index.ts +++ b/libs/sdk/src/index.ts @@ -1,5 +1,6 @@ import rudderClient from './RudderClient'; import { RUDDER_LOG_LEVEL } from './Logger'; +import DBEncryption from './DBEncryption'; -export { RUDDER_LOG_LEVEL }; +export { RUDDER_LOG_LEVEL, DBEncryption }; export default rudderClient; diff --git a/package-lock.json b/package-lock.json index 08c99839..dccac526 100644 --- a/package-lock.json +++ b/package-lock.json @@ -173,7 +173,7 @@ }, "libs/sdk": { "name": "@rudderstack/rudder-sdk-react-native", - "version": "1.8.0", + "version": "1.8.1", "license": "MIT", "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0",