diff --git a/.circleci/config.yml b/.circleci/config.yml index f1c682510..438a84e19 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -3,8 +3,8 @@ parameters: flavor: type: enum default: "generic" - enum: ["generic", "lfe", "sakhi", "lfeTeachNagaland", "gramin"] - description: Flavor of the binary to generate. Must be one of "generic", "lfe", "lfeTeachNagaland" or "sakhi" + enum: ["generic", "lfe", "sakhi", "lfeTeachNagaland", "gramin", "lfeTeachNagalandSecurity"] + description: Flavor of the binary to generate. Must be one of "generic", "lfe", "lfeTeachNagaland", "gramin", "lfeTeachNagalandSecurity" or "sakhi" versionCode: type: string default: "1" diff --git a/Makefile b/Makefile index da559f30a..3285562b0 100644 --- a/Makefile +++ b/Makefile @@ -74,6 +74,7 @@ $(shell node -p "require('./packages/openchs-android/config/flavor_config.json') endef flavor_server_url:=$(call _get_from_config,$(flavor).server_url) +flavor_disable_app_run_on_rooted_devices:=$(call _get_from_config,$(flavor).disable_app_run_on_rooted_devices) bugsnag_env_var_name:=$(call _get_from_config,$(flavor).bugsnag.env_var_name) bugsnag_project_name:=$(call _get_from_config,$(flavor).bugsnag.project_name) app_android_package_name:=$(call _get_from_config,$(flavor).package_name) @@ -117,7 +118,7 @@ endif define _create_config @echo "Creating config for $1" @if [ $(1) = "prod" ]; then \ - echo "module.exports = Object.assign(require('../../config/env/$(1).json'), {COMMIT_ID: '$(sha)', SERVER_URL: '$(flavor_server_url)'});" > packages/openchs-android/src/framework/Config.js; \ + echo "module.exports = Object.assign(require('../../config/env/$(1).json'), {COMMIT_ID: '$(sha)', SERVER_URL: '$(flavor_server_url)', DISABLE_APP_RUN_ON_ROOTED_DEVICES: '$(flavor_disable_app_run_on_rooted_devices)'});" > packages/openchs-android/src/framework/Config.js; \ else \ echo "module.exports = Object.assign(require('../../config/env/$(1).json'), {COMMIT_ID: '$(sha)'});" > packages/openchs-android/src/framework/Config.js; \ fi diff --git a/packages/openchs-android/android/app/build.gradle b/packages/openchs-android/android/app/build.gradle index 9dbfc993a..33a9c7f76 100644 --- a/packages/openchs-android/android/app/build.gradle +++ b/packages/openchs-android/android/app/build.gradle @@ -5,9 +5,6 @@ apply plugin: 'com.google.gms.google-services' googleServices { disableVersionCheck = true } - -import com.android.build.OutputFile - /** * This is the configuration block to customize your React Native Android app. * By default you don't need to apply any configuration, just uncomment the lines you need. @@ -138,6 +135,14 @@ android { storePassword System.getenv("lfeTeachNagaland_KEYSTORE_PASSWORD") keyAlias "${System.getenv("KEY_STORE_PREFIX") ?: ""}${System.getenv("lfeTeachNagaland_KEY_ALIAS")}" keyPassword System.getenv("lfeTeachNagaland_KEY_PASSWORD") + enableV1Signing false + } + lfeTeachNagalandSecurity { + storeFile file("${System.getenv("KEY_STORE_PREFIX") ?: ""}lfeTeachNagaland-release-key.keystore") + storePassword System.getenv("lfeTeachNagaland_KEYSTORE_PASSWORD") + keyAlias "${System.getenv("KEY_STORE_PREFIX") ?: ""}${System.getenv("lfeTeachNagaland_KEY_ALIAS")}" + keyPassword System.getenv("lfeTeachNagaland_KEY_PASSWORD") + enableV1Signing false } sakhi { storeFile file("${System.getenv("KEY_STORE_PREFIX") ?: ""}sakhi-release-key.keystore") @@ -181,6 +186,16 @@ android { lfeTeachNagaland { applicationId "com.openchsclient.lfeteach.nagaland" resValue "string", "app_name", "TEACH Nagaland" + resValue "string", "sha256_app_google_signature", "80e6b34b2026ce180ca8d6f09a885031082d0acf64eb6bd0492f36121d064ebf" + resValue "string", "sha256_app_upload_key_signature", "ac19586277b021dcba5097f7e47d7473bab41bf0369fb771a2bff581734561fc" + signingConfig signingConfigs.lfeTeachNagaland + manifestPlaceholders = [bugsnagAPIKey: System.getenv("LFE_TEACH_NAGALAND_BUGSNAG_API_KEY") ?: "dummy"] + } + lfeTeachNagalandSecurity { + applicationId "com.openchsclient.lfeteach.nagaland" + resValue "string", "app_name", "TEACH Nagaland" + resValue "string", "sha256_app_google_signature", "80e6b34b2026ce180ca8d6f09a885031082d0acf64eb6bd0492f36121d064ebf" + resValue "string", "sha256_app_upload_key_signature", "ac19586277b021dcba5097f7e47d7473bab41bf0369fb771a2bff581734561fc" signingConfig signingConfigs.lfeTeachNagaland manifestPlaceholders = [bugsnagAPIKey: System.getenv("LFE_TEACH_NAGALAND_BUGSNAG_API_KEY") ?: "dummy"] } @@ -198,7 +213,10 @@ android { } } sourceSets { + // Required to enable TamperChecking, init this only for flavours which need Security Tamper Check enabled lfe.java.srcDir 'src/common/java' + lfeTeachNagaland.java.srcDir 'src/common/java' + lfeTeachNagalandSecurity.java.srcDir 'src/common/java' } } diff --git a/packages/openchs-android/android/app/lfeTeachNagalandSecurity-release-key.keystore b/packages/openchs-android/android/app/lfeTeachNagalandSecurity-release-key.keystore new file mode 100644 index 000000000..b5e331438 Binary files /dev/null and b/packages/openchs-android/android/app/lfeTeachNagalandSecurity-release-key.keystore differ diff --git a/packages/openchs-android/android/app/src/lfeTeachNagalandSecurity/assets/logo.png b/packages/openchs-android/android/app/src/lfeTeachNagalandSecurity/assets/logo.png new file mode 100644 index 000000000..db036e71c Binary files /dev/null and b/packages/openchs-android/android/app/src/lfeTeachNagalandSecurity/assets/logo.png differ diff --git a/packages/openchs-android/android/app/src/lfeTeachNagalandSecurity/google-services.json b/packages/openchs-android/android/app/src/lfeTeachNagalandSecurity/google-services.json new file mode 100644 index 000000000..bfe00adad --- /dev/null +++ b/packages/openchs-android/android/app/src/lfeTeachNagalandSecurity/google-services.json @@ -0,0 +1,68 @@ +{ + "project_info": { + "project_number": "26847192477", + "project_id": "lfe-teach", + "storage_bucket": "lfe-teach.appspot.com" + }, + "client": [ + { + "client_info": { + "mobilesdk_app_id": "1:26847192477:android:21d6539bf067d972f73b74", + "android_client_info": { + "package_name": "com.openchsclient.lfeteach.nagaland" + } + }, + "oauth_client": [ + { + "client_id": "26847192477-o32d9p3fto6cfsb98b5a3bs6d9f39j4l.apps.googleusercontent.com", + "client_type": 3 + } + ], + "api_key": [ + { + "current_key": "AIzaSyAcDPJkNYh2qyrdYxQ1SmgRhK_e8HbzV3Y" + } + ], + "services": { + "appinvite_service": { + "other_platform_oauth_client": [ + { + "client_id": "26847192477-o32d9p3fto6cfsb98b5a3bs6d9f39j4l.apps.googleusercontent.com", + "client_type": 3 + } + ] + } + } + }, + { + "client_info": { + "mobilesdk_app_id": "1:26847192477:android:cc8e0d3a01a383c2f73b74", + "android_client_info": { + "package_name": "org.lfeteach.openchsclient" + } + }, + "oauth_client": [ + { + "client_id": "26847192477-o32d9p3fto6cfsb98b5a3bs6d9f39j4l.apps.googleusercontent.com", + "client_type": 3 + } + ], + "api_key": [ + { + "current_key": "AIzaSyAcDPJkNYh2qyrdYxQ1SmgRhK_e8HbzV3Y" + } + ], + "services": { + "appinvite_service": { + "other_platform_oauth_client": [ + { + "client_id": "26847192477-o32d9p3fto6cfsb98b5a3bs6d9f39j4l.apps.googleusercontent.com", + "client_type": 3 + } + ] + } + } + } + ], + "configuration_version": "1" +} \ No newline at end of file diff --git a/packages/openchs-android/android/app/src/lfeTeachNagalandSecurity/res/mipmap-hdpi/openchs_launcher.png b/packages/openchs-android/android/app/src/lfeTeachNagalandSecurity/res/mipmap-hdpi/openchs_launcher.png new file mode 100644 index 000000000..1239f263b Binary files /dev/null and b/packages/openchs-android/android/app/src/lfeTeachNagalandSecurity/res/mipmap-hdpi/openchs_launcher.png differ diff --git a/packages/openchs-android/android/app/src/lfeTeachNagalandSecurity/res/mipmap-hdpi/openchs_launcher_round.png b/packages/openchs-android/android/app/src/lfeTeachNagalandSecurity/res/mipmap-hdpi/openchs_launcher_round.png new file mode 100644 index 000000000..ad5342c85 Binary files /dev/null and b/packages/openchs-android/android/app/src/lfeTeachNagalandSecurity/res/mipmap-hdpi/openchs_launcher_round.png differ diff --git a/packages/openchs-android/android/app/src/lfeTeachNagalandSecurity/res/mipmap-mdpi/openchs_launcher.png b/packages/openchs-android/android/app/src/lfeTeachNagalandSecurity/res/mipmap-mdpi/openchs_launcher.png new file mode 100644 index 000000000..95a780d32 Binary files /dev/null and b/packages/openchs-android/android/app/src/lfeTeachNagalandSecurity/res/mipmap-mdpi/openchs_launcher.png differ diff --git a/packages/openchs-android/android/app/src/lfeTeachNagalandSecurity/res/mipmap-mdpi/openchs_launcher_round.png b/packages/openchs-android/android/app/src/lfeTeachNagalandSecurity/res/mipmap-mdpi/openchs_launcher_round.png new file mode 100644 index 000000000..061c12819 Binary files /dev/null and b/packages/openchs-android/android/app/src/lfeTeachNagalandSecurity/res/mipmap-mdpi/openchs_launcher_round.png differ diff --git a/packages/openchs-android/android/app/src/lfeTeachNagalandSecurity/res/mipmap-xhdpi/openchs_launcher.png b/packages/openchs-android/android/app/src/lfeTeachNagalandSecurity/res/mipmap-xhdpi/openchs_launcher.png new file mode 100644 index 000000000..1cca93ac0 Binary files /dev/null and b/packages/openchs-android/android/app/src/lfeTeachNagalandSecurity/res/mipmap-xhdpi/openchs_launcher.png differ diff --git a/packages/openchs-android/android/app/src/lfeTeachNagalandSecurity/res/mipmap-xhdpi/openchs_launcher_round.png b/packages/openchs-android/android/app/src/lfeTeachNagalandSecurity/res/mipmap-xhdpi/openchs_launcher_round.png new file mode 100644 index 000000000..5a0211470 Binary files /dev/null and b/packages/openchs-android/android/app/src/lfeTeachNagalandSecurity/res/mipmap-xhdpi/openchs_launcher_round.png differ diff --git a/packages/openchs-android/android/app/src/lfeTeachNagalandSecurity/res/mipmap-xxhdpi/openchs_launcher.png b/packages/openchs-android/android/app/src/lfeTeachNagalandSecurity/res/mipmap-xxhdpi/openchs_launcher.png new file mode 100644 index 000000000..ccf34c294 Binary files /dev/null and b/packages/openchs-android/android/app/src/lfeTeachNagalandSecurity/res/mipmap-xxhdpi/openchs_launcher.png differ diff --git a/packages/openchs-android/android/app/src/lfeTeachNagalandSecurity/res/mipmap-xxhdpi/openchs_launcher_round.png b/packages/openchs-android/android/app/src/lfeTeachNagalandSecurity/res/mipmap-xxhdpi/openchs_launcher_round.png new file mode 100644 index 000000000..95cb1b528 Binary files /dev/null and b/packages/openchs-android/android/app/src/lfeTeachNagalandSecurity/res/mipmap-xxhdpi/openchs_launcher_round.png differ diff --git a/packages/openchs-android/android/app/src/lfeTeachNagalandSecurity/res/mipmap-xxxhdpi/openchs_launcher.png b/packages/openchs-android/android/app/src/lfeTeachNagalandSecurity/res/mipmap-xxxhdpi/openchs_launcher.png new file mode 100644 index 000000000..ad08f1212 Binary files /dev/null and b/packages/openchs-android/android/app/src/lfeTeachNagalandSecurity/res/mipmap-xxxhdpi/openchs_launcher.png differ diff --git a/packages/openchs-android/android/app/src/lfeTeachNagalandSecurity/res/mipmap-xxxhdpi/openchs_launcher_round.png b/packages/openchs-android/android/app/src/lfeTeachNagalandSecurity/res/mipmap-xxxhdpi/openchs_launcher_round.png new file mode 100644 index 000000000..5360dc09e Binary files /dev/null and b/packages/openchs-android/android/app/src/lfeTeachNagalandSecurity/res/mipmap-xxxhdpi/openchs_launcher_round.png differ diff --git a/packages/openchs-android/config/env/dev.json.template b/packages/openchs-android/config/env/dev.json.template index e0dcfb34e..794482460 100644 --- a/packages/openchs-android/config/env/dev.json.template +++ b/packages/openchs-android/config/env/dev.json.template @@ -4,5 +4,6 @@ "CLIENT_ID": "dummy", "goToLastPageOnNext": false, "debugFirebaseAnalyticsEvents": false, - "PLAYGROUND": false + "PLAYGROUND": false, + "DISABLE_APP_RUN_ON_ROOTED_DEVICES": false } diff --git a/packages/openchs-android/config/flavor_config.json b/packages/openchs-android/config/flavor_config.json index a6361fc2d..8bde9c4dd 100644 --- a/packages/openchs-android/config/flavor_config.json +++ b/packages/openchs-android/config/flavor_config.json @@ -21,6 +21,17 @@ "server_url": "https://app.lfe.avniproject.org", "package_name": "com.openchsclient.lfeteach.nagaland", "prod_admin_password_env_var_name": "LFE_PROD_ADMIN_PASSWORD", + "disable_app_run_on_rooted_devices": true, + "bugsnag": { + "project_name": "lfe-teach-nagaland", + "env_var_name": "LFE_TEACH_NAGALAND_BUGSNAG_API_KEY" + } + }, + "lfeTeachNagalandSecurity": { + "server_url": "https://app.security.lfe.avniproject.org", + "package_name": "com.openchsclient.lfeteach.nagaland", + "prod_admin_password_env_var_name": "LFE_PROD_ADMIN_PASSWORD", + "disable_app_run_on_rooted_devices": true, "bugsnag": { "project_name": "lfe-teach-nagaland", "env_var_name": "LFE_TEACH_NAGALAND_BUGSNAG_API_KEY" diff --git a/packages/openchs-android/package-lock.json b/packages/openchs-android/package-lock.json index 39ddaac38..32403e757 100644 --- a/packages/openchs-android/package-lock.json +++ b/packages/openchs-android/package-lock.json @@ -29,6 +29,7 @@ "i18n-js": "3.9.2", "immutable": "4.1.0", "invariant": "2.2.4", + "jail-monkey": "^2.8.0", "jwt-decode": "^3.1.2", "lodash": "4.17.21", "moment": "2.29.4", @@ -11111,6 +11112,11 @@ "node": ">=8" } }, + "node_modules/jail-monkey": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/jail-monkey/-/jail-monkey-2.8.0.tgz", + "integrity": "sha512-mz0sldKOEnt7qpqLLYM9Rwq9zGuGtj5nihz87KWBSy6PR9eu0cmyPkW3b+Exw4iVivcb2bFf6uVq0Q9aNgdIhw==" + }, "node_modules/javascript-obfuscator": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/javascript-obfuscator/-/javascript-obfuscator-4.0.2.tgz", @@ -31058,6 +31064,11 @@ "istanbul-lib-report": "^3.0.0" } }, + "jail-monkey": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/jail-monkey/-/jail-monkey-2.8.0.tgz", + "integrity": "sha512-mz0sldKOEnt7qpqLLYM9Rwq9zGuGtj5nihz87KWBSy6PR9eu0cmyPkW3b+Exw4iVivcb2bFf6uVq0Q9aNgdIhw==" + }, "javascript-obfuscator": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/javascript-obfuscator/-/javascript-obfuscator-4.0.2.tgz", diff --git a/packages/openchs-android/package.json b/packages/openchs-android/package.json index 0e454f835..1b9807335 100644 --- a/packages/openchs-android/package.json +++ b/packages/openchs-android/package.json @@ -53,6 +53,7 @@ "i18n-js": "3.9.2", "immutable": "4.1.0", "invariant": "2.2.4", + "jail-monkey": "^2.8.0", "jwt-decode": "^3.1.2", "lodash": "4.17.21", "moment": "2.29.4", diff --git a/packages/openchs-android/src/App.js b/packages/openchs-android/src/App.js index d691463b3..b97702669 100644 --- a/packages/openchs-android/src/App.js +++ b/packages/openchs-android/src/App.js @@ -1,4 +1,4 @@ -import {Alert, Clipboard, NativeModules, Text, View} from "react-native"; +import {Alert, Clipboard, NativeModules, Text, View, BackHandler} from "react-native"; import PropTypes from 'prop-types'; import React, {Component} from 'react'; import PathRegistry from './framework/routing/PathRegistry'; @@ -14,6 +14,7 @@ import RealmFactory from "./framework/db/RealmFactory"; import General from "./utility/General"; import EnvironmentConfig from "./framework/EnvironmentConfig"; import Config from './framework/Config'; +import JailMonkey from 'jail-monkey'; const {TamperCheckModule} = NativeModules; @@ -30,7 +31,7 @@ class App extends Component { this.getBean = this.getBean.bind(this); this.handleError = this.handleError.bind(this); ErrorHandler.set(this.handleError); - this.state = {error: '', isInitialisationDone: false}; + this.state = {error: '', isInitialisationDone: false, isDeviceRooted: false}; } handleError(error, stacktrace) { @@ -67,6 +68,23 @@ class App extends Component { return ; } + renderRootedDeviceErrorMessageAndExitApplication() { + const clipboardString = `This is a Rooted Device. Exiting Avni application due to security considerations.`; + General.logError("App", `renderError: ${clipboardString}`); + Alert.alert("App will exit now", clipboardString, + [ + { + text: "Ok", + onPress: () => { + BackHandler.exitApp(); + } + } + ], + {cancelable: false} + ); + return ; + } + getBean(name) { return GlobalContext.getInstance().beanRegistry.getService(name); } @@ -76,6 +94,11 @@ class App extends Component { try { if(!_.isNil(TamperCheckModule)) TamperCheckModule.validateAppSignature(); + const isThisProdLFEAppRunningOnRootedDevice = EnvironmentConfig.isProdAndDisallowedOnRootDevices() && JailMonkey.isJailBroken(); + if(isThisProdLFEAppRunningOnRootedDevice) { + this.setState(state => ({...state, isDeviceRooted: isThisProdLFEAppRunningOnRootedDevice})); + return; + } const globalContext = GlobalContext.getInstance(); if (!globalContext.isInitialised()) { @@ -95,6 +118,9 @@ class App extends Component { } render() { + if(this.state.isDeviceRooted) { + return this.renderRootedDeviceErrorMessageAndExitApplication(); + } if (this.state.error) { return this.renderError(); } diff --git a/packages/openchs-android/src/framework/EnvironmentConfig.js b/packages/openchs-android/src/framework/EnvironmentConfig.js index bf011e3bb..cd365d79a 100644 --- a/packages/openchs-android/src/framework/EnvironmentConfig.js +++ b/packages/openchs-android/src/framework/EnvironmentConfig.js @@ -30,6 +30,15 @@ class EnvironmentConfig { static logAnalytics() { return EnvironmentConfig.isProd() || Config.debugFirebaseAnalyticsEvents === true } + + static disallowedAppRunOnRootDevices() { + const isAppRunDisallowedOnRootDevices = Config.DISABLE_APP_RUN_ON_ROOTED_DEVICES; + return !_.isNil(isAppRunDisallowedOnRootDevices) && isAppRunDisallowedOnRootDevices; + } + + static isProdAndDisallowedOnRootDevices() { + return EnvironmentConfig.isProd() && EnvironmentConfig.disallowedAppRunOnRootDevices(); + } } export default EnvironmentConfig;