diff options
64 files changed, 3671 insertions, 90 deletions
diff --git a/api/.gitignore b/api/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/api/.gitignore @@ -0,0 +1 @@ +/build
\ No newline at end of file diff --git a/api/build.gradle b/api/build.gradle new file mode 100644 index 0000000..b8ced30 --- /dev/null +++ b/api/build.gradle @@ -0,0 +1,90 @@ +apply plugin: 'com.android.library' +apply plugin: 'kotlin-android' +apply plugin: 'maven-publish' + +android { + compileSdkVersion buildConfig.compileSdk + + defaultConfig { + minSdkVersion buildConfig.minSdk + targetSdkVersion buildConfig.targetSdk + + consumerProguardFiles "consumer-rules.pro" + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } +} + +dependencies { + implementation( + Libs.Kotlin.stdlib, + Libs.AndroidX.coreKtxAPI29, + Libs.Coroutines.core + ) +} + +//url "https://gitlab.e.foundation/api/v4/groups/e/privacy-central/-/packages/maven" + +publishing { + publications { + maven(MavenPublication) { + groupId 'foundation.e' + //You can either define these here or get them from project conf elsewhere + artifactId 'privacymodule.api' + version buildConfig.version.name + artifact "$buildDir/outputs/aar/api-release.aar" + //aar artifact you want to publish + + //generate pom nodes for dependencies + pom.withXml { + def dependenciesNode = asNode().appendNode('dependencies') + configurations.implementation.allDependencies.each { dependency -> + if (dependency.name != 'unspecified') { + def dependencyNode = dependenciesNode.appendNode('dependency') + dependencyNode.appendNode('groupId', dependency.group) + dependencyNode.appendNode('artifactId', dependency.name) + dependencyNode.appendNode('version', dependency.version) + } + } + } + repositories { + def ciJobToken = System.getenv("CI_JOB_TOKEN") + def ciApiV4Url = System.getenv("CI_API_V4_URL") + if (ciJobToken != null) { + maven { + url "${ciApiV4Url}/projects/900/packages/maven" + credentials(HttpHeaderCredentials) { + name = 'Job-Token' + value = ciJobToken + } + authentication { + header(HttpHeaderAuthentication) + } + } + } else { + maven { + url "https://gitlab.e.foundation/api/v4/projects/900/packages/maven" + credentials(HttpHeaderCredentials) { + name = "Private-Token" + value = gitLabPrivateToken + // the variable resides in ~/.gradle/gradle.properties + } + authentication { + header(HttpHeaderAuthentication) + } + } + } + } + } + } +} diff --git a/api/consumer-rules.pro b/api/consumer-rules.pro new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/api/consumer-rules.pro diff --git a/api/proguard-rules.pro b/api/proguard-rules.pro new file mode 100644 index 0000000..481bb43 --- /dev/null +++ b/api/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile
\ No newline at end of file diff --git a/api/src/main/AndroidManifest.xml b/api/src/main/AndroidManifest.xml new file mode 100644 index 0000000..937e285 --- /dev/null +++ b/api/src/main/AndroidManifest.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2022 E FOUNDATION + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +--> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="foundation.e.privacymodules.api" + > +</manifest>
\ No newline at end of file diff --git a/api/src/main/java/foundation/e/privacymodules/DependencyInjector.kt b/api/src/main/java/foundation/e/privacymodules/DependencyInjector.kt new file mode 100644 index 0000000..bcf82d2 --- /dev/null +++ b/api/src/main/java/foundation/e/privacymodules/DependencyInjector.kt @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2022 E FOUNDATION + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +package foundation.e.privacymodules + +import foundation.e.privacymodules.trackers.IDNSBlocker + +object DependencyInjector { + fun initialize( + dnsBlocker: IDNSBlocker + ) { + this.dnsBlocker = dnsBlocker + } + + + lateinit var dnsBlocker: IDNSBlocker + private set +}
\ No newline at end of file diff --git a/api/src/main/java/foundation/e/privacymodules/location/IFakeLocationModule.kt b/api/src/main/java/foundation/e/privacymodules/location/IFakeLocationModule.kt new file mode 100644 index 0000000..ecad2a4 --- /dev/null +++ b/api/src/main/java/foundation/e/privacymodules/location/IFakeLocationModule.kt @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2022 E FOUNDATION + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +package foundation.e.privacymodules.location + +/** + * Manage a fake location on the device. + */ +interface IFakeLocationModule { + /** + * Start to fake the location module. Call [setFakeLocation] after to set the fake + * position. + */ + fun startFakeLocation() + + /** + * Set or update the faked position. + * @param latitude the latitude of the fake position in degrees. + * @param longitude the longitude of the fake position in degrees. + */ + fun setFakeLocation(latitude: Double, longitude: Double) + + /** + * Stop the fake location module, giving back hand to the true location modules. + */ + fun stopFakeLocation() +} diff --git a/api/src/main/java/foundation/e/privacymodules/permissions/APermissionsPrivacyModule.kt b/api/src/main/java/foundation/e/privacymodules/permissions/APermissionsPrivacyModule.kt new file mode 100644 index 0000000..68f7ee1 --- /dev/null +++ b/api/src/main/java/foundation/e/privacymodules/permissions/APermissionsPrivacyModule.kt @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2022 E FOUNDATION + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ +package foundation.e.privacymodules.permissions + +import android.app.AppOpsManager +import android.content.Context +import android.content.pm.ApplicationInfo +import android.content.pm.PackageManager +import android.content.pm.PermissionInfo +import android.content.pm.PermissionInfo.PROTECTION_DANGEROUS +import android.graphics.drawable.Drawable +import android.os.Build +import android.util.Log +import foundation.e.privacymodules.permissions.data.AppOpModes +import foundation.e.privacymodules.permissions.data.ApplicationDescription +import foundation.e.privacymodules.permissions.data.PermissionDescription + +/** + * Implementation of the commons functionality between privileged and standard + * versions of the module. + * @param context an Android context, to retrieve packageManager for example. + */ +abstract class APermissionsPrivacyModule(protected val context: Context): IPermissionsPrivacyModule { + + companion object { + private const val TAG = "PermissionsModule" + } + /** + * @see IPermissionsPrivacyModule.getAllApplications + */ + override fun getAllApplications(): List<ApplicationDescription> { + val appInfos = context.packageManager.getInstalledApplications(0) + return appInfos.map { buildApplicationDescription(it, false) } + } + + /** + * @see IPermissionsPrivacyModule.getInstalledApplications + */ + override fun getInstalledApplications(): List<ApplicationDescription> { + return context.packageManager.getInstalledApplications(0) + .filter { it.flags and ApplicationInfo.FLAG_SYSTEM == 0 } + .map { buildApplicationDescription(it, false) } + } + + /** + * @see IPermissionsPrivacyModule.getInstalledApplications + */ + override fun getApplicationDescription(packageName: String): ApplicationDescription { + val appDesc = buildApplicationDescription(context.packageManager.getApplicationInfo(packageName, 0), false) + appDesc.icon = getApplicationIcon(appDesc.packageName) + return appDesc + } + + /** + * * @see IPermissionsPrivacyModule.getPermissions + */ + override fun getPermissions(packageName: String): List<String> { + val packageInfo = context.packageManager.getPackageInfo(packageName, PackageManager.GET_PERMISSIONS) + return packageInfo.requestedPermissions?.asList() ?: emptyList() + } + + override fun getPermissionDescription(permissionName: String): PermissionDescription { + val info = context.packageManager.getPermissionInfo(permissionName, 0) + return PermissionDescription( + name = permissionName, + isDangerous = isPermissionsDangerous(info), + group = null, + label = info.loadLabel(context.packageManager), + description = info.loadDescription(context.packageManager) + ) + } + + /** + * @see IPermissionsPrivacyModule.isDangerousPermissionGranted + */ + override fun isDangerousPermissionGranted(packageName: String, permissionName: String): Boolean { + return context.packageManager + .checkPermission(permissionName, packageName) == PackageManager.PERMISSION_GRANTED + } + + // on google version, work only for the current package. + @Suppress("DEPRECATION") + override fun getAppOpMode( + appDesc: ApplicationDescription, + appOpPermissionName: String + ): AppOpModes { + + val appOps = context.getSystemService(Context.APP_OPS_SERVICE) as AppOpsManager + + val mode = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) { + appOps.checkOpNoThrow(appOpPermissionName, + + appDesc.uid, appDesc.packageName) + } else { + appOps.unsafeCheckOpNoThrow( + appOpPermissionName, + appDesc.uid, appDesc.packageName) + } + + return AppOpModes.getByModeValue(mode) + } + + override fun isPermissionsDangerous(permissionName: String): Boolean { + try { + val permissionInfo = context.packageManager.getPermissionInfo(permissionName, 0) + return isPermissionsDangerous(permissionInfo) + } catch (e: Exception) { + Log.w(TAG, "exception in isPermissionsDangerous(String)", e) + return false + } + } + + @Suppress("DEPRECATION") + private fun isPermissionsDangerous(permissionInfo: PermissionInfo): Boolean { + try { + return if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) { + permissionInfo.protectionLevel and PROTECTION_DANGEROUS == 1 + } else { + permissionInfo.protection == PROTECTION_DANGEROUS + } + } catch (e: Exception) { + Log.w(TAG, "exception in isPermissionsDangerous(PermissionInfo)", e) + return false + } + } + + override fun buildApplicationDescription(appInfo: ApplicationInfo, withIcon: Boolean) + : ApplicationDescription { + return ApplicationDescription( + packageName = appInfo.packageName, + uid = appInfo.uid, + label = getAppLabel(appInfo), + icon = if (withIcon) getApplicationIcon(appInfo.packageName) else null + ) + } + + private fun getAppLabel(appInfo: ApplicationInfo): CharSequence { + return context.packageManager.getApplicationLabel(appInfo) + } + + override fun getApplicationIcon(packageName: String): Drawable? { + return context.packageManager.getApplicationIcon(packageName) + } +} |