From 91788740a610aeecfa041b5c01533205e805384b Mon Sep 17 00:00:00 2001 From: Infi Date: Sat, 16 Sep 2023 15:29:09 +0200 Subject: [PATCH] feat: move beta access control into c++ Signed-off-by: Infi --- app/build.gradle | 11 +++++ app/src/main/cpp/CMakeLists.txt | 41 +++++++++++++++++++ app/src/main/cpp/libpipebomb/pipebomb.cpp | 25 +++++++++++ .../chat/revolt/activities/MainActivity.kt | 7 ++++ .../java/chat/revolt/ndk/NativeLibraries.kt | 13 ++++++ app/src/main/java/chat/revolt/ndk/Pipebomb.kt | 12 ++++++ .../revolt/screens/chat/ChatRouterScreen.kt | 10 ++--- 7 files changed, 113 insertions(+), 6 deletions(-) create mode 100644 app/src/main/cpp/CMakeLists.txt create mode 100644 app/src/main/cpp/libpipebomb/pipebomb.cpp create mode 100644 app/src/main/java/chat/revolt/ndk/NativeLibraries.kt create mode 100644 app/src/main/java/chat/revolt/ndk/Pipebomb.kt diff --git a/app/build.gradle b/app/build.gradle index 06af6c60..d4f4bdfa 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -65,6 +65,11 @@ android { } resourceConfigurations += ["en", "de", "fr", "id", "b+es+419", "bn", "ca", "es", "gl", "in", "pt-rBR", "pt", "ru", "tr", "uk", "zh-rCN"] + externalNativeBuild { + cmake { + cppFlags '' + } + } } buildTypes { @@ -114,6 +119,12 @@ android { disable 'MissingTranslation' } namespace 'chat.revolt' + externalNativeBuild { + cmake { + path file('src/main/cpp/CMakeLists.txt') + version '3.22.1' + } + } } sentry { diff --git a/app/src/main/cpp/CMakeLists.txt b/app/src/main/cpp/CMakeLists.txt new file mode 100644 index 00000000..74394700 --- /dev/null +++ b/app/src/main/cpp/CMakeLists.txt @@ -0,0 +1,41 @@ + +# For more information about using CMake with Android Studio, read the +# documentation: https://d.android.com/studio/projects/add-native-code.html. +# For more examples on how to use CMake, see https://github.com/android/ndk-samples. + +# Sets the minimum CMake version required for this project. +cmake_minimum_required(VERSION 3.22.1) + +# Declares the project name. The project name can be accessed via ${ PROJECT_NAME}, +# Since this is the top level CMakeLists.txt, the project name is also accessible +# with ${CMAKE_PROJECT_NAME} (both CMake variables are in-sync within the top level +# build script scope). +project("revolt") + +set(LIB_NAME_ACCESS_CONTROL "pipebomb") + +# Creates and names a library, sets it as either STATIC +# or SHARED, and provides the relative paths to its source code. +# You can define multiple libraries, and CMake builds them for you. +# Gradle automatically packages shared libraries with your APK. +# +# In this top level CMakeLists.txt, ${CMAKE_PROJECT_NAME} is used to define +# the target library name; in the sub-module's CMakeLists.txt, ${PROJECT_NAME} +# is preferred for the same purpose. +# +# In order to load a library into your app from Java/Kotlin, you must call +# System.loadLibrary() and pass the name of the library defined here; +# for GameActivity/NativeActivity derived applications, the same library name must be +# used in the AndroidManifest.xml file. +add_library(${LIB_NAME_ACCESS_CONTROL} SHARED + # List C/C++ source files with relative paths to this CMakeLists.txt. + lib${LIB_NAME_ACCESS_CONTROL}/${LIB_NAME_ACCESS_CONTROL}.cpp +) + +# Specifies libraries CMake should link to your target library. You +# can link libraries from various origins, such as libraries defined in this +# build script, prebuilt third-party libraries, or Android system libraries. +target_link_libraries(${LIB_NAME_ACCESS_CONTROL} + # List libraries link to the target library + android + log) diff --git a/app/src/main/cpp/libpipebomb/pipebomb.cpp b/app/src/main/cpp/libpipebomb/pipebomb.cpp new file mode 100644 index 00000000..3d35c4c1 --- /dev/null +++ b/app/src/main/cpp/libpipebomb/pipebomb.cpp @@ -0,0 +1,25 @@ +#include +#include +#include + +int hardCrashCounter = 0; + +extern "C" +JNIEXPORT void JNICALL +Java_chat_revolt_ndk_Pipebomb_incrementHardCrashCounter(JNIEnv *env, jobject thiz) { + hardCrashCounter++; +} + +extern "C" +JNIEXPORT void JNICALL +Java_chat_revolt_ndk_Pipebomb_doHardCrash(JNIEnv *env, + jobject thiz) { + int *p = nullptr; + *p = 0; +} + +extern "C" +JNIEXPORT jboolean JNICALL +Java_chat_revolt_ndk_Pipebomb_checkHardCrash(JNIEnv *env, jobject thiz) { + return hardCrashCounter > 3; +} \ No newline at end of file diff --git a/app/src/main/java/chat/revolt/activities/MainActivity.kt b/app/src/main/java/chat/revolt/activities/MainActivity.kt index 00d0a880..739e1486 100644 --- a/app/src/main/java/chat/revolt/activities/MainActivity.kt +++ b/app/src/main/java/chat/revolt/activities/MainActivity.kt @@ -26,6 +26,7 @@ import androidx.navigation.compose.dialog import androidx.navigation.compose.rememberNavController import chat.revolt.BuildConfig import chat.revolt.api.settings.GlobalState +import chat.revolt.ndk.NativeLibraries import chat.revolt.screens.SplashScreen import chat.revolt.screens.about.AboutScreen import chat.revolt.screens.about.AttributionScreen @@ -65,6 +66,12 @@ class MainActivity : FragmentActivity() { AppEntrypoint(windowSizeClass) } } + + companion object { + init { + NativeLibraries.init() + } + } } val RevoltTweenInt: FiniteAnimationSpec = tween(400, easing = EaseInOutExpo) diff --git a/app/src/main/java/chat/revolt/ndk/NativeLibraries.kt b/app/src/main/java/chat/revolt/ndk/NativeLibraries.kt new file mode 100644 index 00000000..18675104 --- /dev/null +++ b/app/src/main/java/chat/revolt/ndk/NativeLibraries.kt @@ -0,0 +1,13 @@ +package chat.revolt.ndk + +annotation class NativeLibrary(val name: String) { + companion object { + const val LIB_NAME_ACCESS_CONTROL = "pipebomb" + } +} + +object NativeLibraries { + fun init() { + System.loadLibrary(NativeLibrary.LIB_NAME_ACCESS_CONTROL) + } +} \ No newline at end of file diff --git a/app/src/main/java/chat/revolt/ndk/Pipebomb.kt b/app/src/main/java/chat/revolt/ndk/Pipebomb.kt new file mode 100644 index 00000000..9e8320e6 --- /dev/null +++ b/app/src/main/java/chat/revolt/ndk/Pipebomb.kt @@ -0,0 +1,12 @@ +package chat.revolt.ndk + +@NativeLibrary(NativeLibrary.LIB_NAME_ACCESS_CONTROL) +object Pipebomb { + init { + System.loadLibrary(NativeLibrary.LIB_NAME_ACCESS_CONTROL) + } + + external fun incrementHardCrashCounter() + external fun checkHardCrash(): Boolean + external fun doHardCrash() +} \ No newline at end of file diff --git a/app/src/main/java/chat/revolt/screens/chat/ChatRouterScreen.kt b/app/src/main/java/chat/revolt/screens/chat/ChatRouterScreen.kt index 180cb354..c4a4b8f0 100644 --- a/app/src/main/java/chat/revolt/screens/chat/ChatRouterScreen.kt +++ b/app/src/main/java/chat/revolt/screens/chat/ChatRouterScreen.kt @@ -81,6 +81,7 @@ import chat.revolt.components.screens.chat.drawer.server.DrawerServer import chat.revolt.components.screens.chat.drawer.server.DrawerServerlikeIcon import chat.revolt.components.screens.chat.drawer.server.ServerDrawerSeparator import chat.revolt.internals.Changelogs +import chat.revolt.ndk.Pipebomb import chat.revolt.persistence.KVStorage import chat.revolt.screens.chat.dialogs.safety.ReportMessageDialog import chat.revolt.screens.chat.views.HomeScreen @@ -188,16 +189,13 @@ class ChatRouterViewModel @Inject constructor( } } - @FeatureFlag("ClosedBetaAccessControl") - private var hardCrashCounter = 0 - fun navigateToChannel(channelId: String, navController: NavController, pure: Boolean = false) { if (!pure) setSaveCurrentChannel(channelId) // Only allow access to closed beta users, currently "has access to #beta-chat in Jenvolt" @FeatureFlag("ClosedBetaAccessControl") if (RevoltAPI.channelCache.size > 0 && !RevoltAPI.channelCache.containsKey("01H7X2KRB0CA4QDSMB4N7WGERF")) { - hardCrashCounter++ + Pipebomb.incrementHardCrashCounter() navController.navigate("no_current_channel") { navController.graph.startDestinationRoute?.let { route -> @@ -205,7 +203,7 @@ class ChatRouterViewModel @Inject constructor( } } - if (hardCrashCounter > 2) { + if (Pipebomb.checkHardCrash()) { Toast.makeText( context, "You do not have access to the closed beta.", @@ -220,7 +218,7 @@ class ChatRouterViewModel @Inject constructor( ) context.startActivity(intent) // i'm just messing with the user at this point, they know what they did - throw IllegalStateException() + Pipebomb.doHardCrash() } } else { // Navigate as normal