8000 Implement data access audit for Android app by clemente-xyz · Pull Request #1909 · LiskHQ/lisk-mobile · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Implement data access audit for Android app #1909

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jul 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 79 additions & 0 deletions android/app/src/main/java/com/lisk/AppOpsManagerModule.java
10000
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package io.lisk.mobile;

import android.app.AppOpsManager;
import android.app.AppOpsManager.OnOpNotedCallback;
import android.app.AsyncNotedAppOp;
import android.app.SyncNotedAppOp;
import android.content.Context;
import android.util.Log;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import java.util.Arrays;

public class AppOpsManagerModule extends ReactContextBaseJavaModule {

private static ReactApplicationContext reactContext;
private AppOpsManager.OnOpNotedCallback callback;

AppOpsManagerModule(ReactApplicationContext context) {
super(context);
reactContext = context;
}

@Override
public String getName() {
return "AppOpsManagerModule";
}

@ReactMethod
public void startWatching() {
AppOpsManager appOpsManager = (AppOpsManager) reactContext.getSystemService(
Context.APP_OPS_SERVICE
);

if (callback == null) {
callback =
new AppOpsManager.OnOpNotedCallback() {
private void logPrivateDataAccess(String opCode, String trace) {
Log.i(
"Lisk",
"Private data accessed. " + "Operation: " + opCode + "\nStack Trace:\n" + trace
);
}

@Override
public void onNoted(SyncNotedAppOp syncNotedAppOp) {
logPrivateDataAccess(
syncNotedAppOp.getOp(),
Arrays.toString(new Throwable().getStackTrace())
);
}

@Override
public void onSelfNoted(SyncNotedAppOp syncNotedAppOp) {
logPrivateDataAccess(
syncNotedAppOp.getOp(),
Arrays.toString(new Throwable().getStackTrace())
);
}

@Override
public void onAsyncNoted(AsyncNotedAppOp asyncNotedAppOp) {
logPrivateDataAccess(asyncNotedAppOp.getOp(), asyncNotedAppOp.getMessage());
}
};
}

if (appOpsManager != null && callback != null) {
try {
appOpsManager.setOnOpNotedCallback(reactContext.getMainExecutor(), callback);
} catch (IllegalStateException e) {
Log.w(
"AppOpsManagerModule",
"Attempted to register a callback when one was already registered"
);
}
}
}
}
26 changes: 26 additions & 0 deletions android/app/src/main/java/com/lisk/AppOpsManagerModulePackage.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package io.lisk.mobile;

import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class AppOpsManagerModulePackage implements ReactPackage {

@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Collections.emptyList();
}

@Override
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
List<NativeModule> modules = new ArrayList<>();

modules.add(new AppOpsManagerModule(reactContext));

return modules;
}
}
16 changes: 8 additions & 8 deletions android/app/src/main/java/com/lisk/MainActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,12 @@ protected String getMainComponentName() {
@Override
protected ReactActivityDelegate createReactActivityDelegate() {
return new DefaultReactActivityDelegate(
this,
getMainComponentName(),
// If you opted-in for the New Architecture, we enable the Fabric Renderer.
DefaultNewArchitectureEntryPoint.getFabricEnabled(), // fabricEnabled
// If you opted-in for the New Architecture, we enable Concurrent React (i.e. React 18).
DefaultNewArchitectureEntryPoint.getConcurrentReactEnabled() // concurrentRootEnabled
);
this,
getMainComponentName(),
// If you opted-in for the New Architecture, we enable the Fabric Renderer.
DefaultNewArchitectureEntryPoint.getFabricEnabled(), // fabricEnabled
// If you opted-in for the New Architecture, we enable Concurrent React (i.e. React 18).
DefaultNewArchitectureEntryPoint.getConcurrentReactEnabled() // concurrentRootEnabled
);
}
}
}
65 changes: 33 additions & 32 deletions android/app/src/main/java/com/lisk/MainApplication.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,42 +8,43 @@
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint;
import com.facebook.react.defaults.DefaultReactNativeHost;
import com.facebook.soloader.SoLoader;
import io.lisk.mobile.AppOpsManagerModulePackage;
import java.lang.reflect.InvocationTargetException;
import java.util.List;

public class MainApplication extends Application implements ReactApplication {

private final ReactNativeHost mReactNativeHost =
new DefaultReactNativeHost(this) {
@Override
public boolean getUseDeveloperSupport() {
return BuildConfig.DEBUG;
}

@Override
protected List<ReactPackage> getPackages() {
@SuppressWarnings("UnnecessaryLocalVariable")
List<ReactPackage> packages = new PackageList(this).getPackages();
// Packages that cannot be autolinked yet can be added manually here, for example:
// packages.add(new MyReactNativePackage());
return packages;
}

@Override
protected String getJSMainModuleName() {
return "index";
}

@Override
protected boolean isNewArchEnabled() {
return BuildConfig.IS_NEW_ARCHITECTURE_ENABLED;
}

@Override
protected Boolean isHermesEnabled() {
return BuildConfig.IS_HERMES_ENABLED;
}
};
private final ReactNativeHost mReactNativeHost = new DefaultReactNativeHost(this) {
@Override
public boolean getUseDeveloperSupport() {
return BuildConfig.DEBUG;
}

@Override
protected List<ReactPackage> getPackages() {
@SuppressWarnings("UnnecessaryLocalVariable")
List<ReactPackage> packages = new PackageList(this).getPackages();
// Packages that cannot be autolinked yet can be added manually here, for example:
// packages.add(new MyReactNativePackage());
packages.add(new AppOpsManagerModulePackage());
return packages;
}

@Override
protected String getJSMainModuleName() {
return "index";
}

@Override
protected boolean isNewArchEnabled() {
return BuildConfig.IS_NEW_ARCHITECTURE_ENABLED;
}

@Override
protected Boolean isHermesEnabled() {
return BuildConfig.IS_HERMES_ENABLED;
}
};

@Override
public ReactNativeHost getReactNativeHost() {
Expand All @@ -53,7 +54,7 @@ public ReactNativeHost getReactNativeHost() {
@Override
public void onCreate() {
super.onCreate();
SoLoader.init(this, /* native exopackage */ false);
SoLoader.init(this, /* native exopackage */false);
if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
// If you opted-in for the New Architecture, we load the native entry point for this app.
DefaultNewArchitectureEntryPoint.load();
Expand Down
2 changes: 1 addition & 1 deletion android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
buildscript {
ext {
buildToolsVersion = "33.0.0"
minSdkVersion = 21
minSdkVersion = 30
compileSdkVersion = 33
targetSdkVersion = 33

Expand Down
3 changes: 3 additions & 0 deletions src/App.js
A3DB
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,11 @@ import store, { persistedStore } from 'store/index';
import BootstrapApp from './BootstrapApp';
import i18n from '../locales';
import WalletConnectProvider from '../libs/wcm/context/connectionProvider';
import { useDataAudit } from './hooks/useDataAudit';

export default function App() {
useDataAudit();

return (
<GestureHandlerRootView style={{ flex: 1 }}>
<I18nextProvider i18n={i18n}>
Expand Down
15 changes: 15 additions & 0 deletions src/hooks/useDataAudit.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { useEffect } from 'react';
import { NativeModules, Platform } from 'react-native';

const { AppOpsManagerModule } = NativeModules;

/**
* Performs data auditing for monitoring user's private data access on the app.
*/
export function useDataAudit() {
useEffect(() => {
if (Platform.OS === 'android') {
AppOpsManagerModule.startWatching();
}
}, []);
}
0