Merge branch 'java8' into 'master'
update to Java8 and compileSdkVersion 29 See merge request fdroid/fdroidclient!974
This commit is contained in:
commit
b21dbb8646
@ -27,6 +27,7 @@ stages:
|
||||
artifacts:
|
||||
name: "${CI_PROJECT_PATH}_${CI_JOB_STAGE}_${CI_COMMIT_REF_NAME}_${CI_COMMIT_SHA}"
|
||||
paths:
|
||||
- kernel.log
|
||||
- logcat.txt
|
||||
- app/core*
|
||||
- app/*.log
|
||||
@ -70,6 +71,10 @@ errorprone:
|
||||
- cat config/errorprone.gradle >> app/build.gradle
|
||||
- ./gradlew -Dorg.gradle.dependency.verification=lenient assembleDebug
|
||||
|
||||
# Run the tests in the emulator. Each step is broken out to run on
|
||||
# its own since the CI runner can have limited RAM, and the emulator
|
||||
# can take a while to start.
|
||||
#
|
||||
# once these prove stable, the task should be switched to
|
||||
# connectedCheck to test all the build flavors
|
||||
.connected-template: &connected-template
|
||||
@ -90,16 +95,14 @@ errorprone:
|
||||
- wait-for-emulator
|
||||
- adb devices
|
||||
- adb shell input keyevent 82 &
|
||||
- ./gradlew installFullDebug
|
||||
- adb shell am start -n org.fdroid.fdroid.debug/org.fdroid.fdroid.views.main.MainActivity
|
||||
- if [ $AVD_SDK -lt 25 ] || ! emulator -accel-check; then
|
||||
export FLAG=-Pandroid.testInstrumentationRunnerArguments.notAnnotation=androidx.test.filters.LargeTest;
|
||||
fi
|
||||
- ./gradlew connectedFullDebugAndroidTest $FLAG
|
||||
|| ./gradlew connectedFullDebugAndroidTest $FLAG
|
||||
|| ./gradlew connectedFullDebugAndroidTest $FLAG
|
||||
|| (adb -e logcat -d > logcat.txt; exit 1)
|
||||
|
||||
connected 22 default armeabi-v7a:
|
||||
retry: 1
|
||||
no-accel 22 default x86:
|
||||
<<: *test-template
|
||||
<<: *connected-template
|
||||
|
||||
@ -107,15 +110,14 @@ connected 22 default armeabi-v7a:
|
||||
tags:
|
||||
- fdroid
|
||||
- kvm
|
||||
allow_failure: true
|
||||
only:
|
||||
variables:
|
||||
- $RUN_KVM_JOBS
|
||||
<<: *test-template
|
||||
<<: *connected-template
|
||||
|
||||
connected 26 google_apis x86:
|
||||
kvm 29 microg x86_64:
|
||||
<<: *kvm-template
|
||||
only:
|
||||
- branches@fdroid/fdroidclient
|
||||
- branches@eighthave/fdroidclient
|
||||
|
||||
deploy_nightly:
|
||||
extends: .base
|
||||
|
@ -21,7 +21,7 @@ def basicApplicationId = "org.fdroid.basic"
|
||||
def privilegedExtensionApplicationId = '"org.fdroid.fdroid.privileged"'
|
||||
|
||||
android {
|
||||
compileSdkVersion 28
|
||||
compileSdkVersion 29
|
||||
|
||||
defaultConfig {
|
||||
versionCode 1012000
|
||||
@ -75,6 +75,8 @@ android {
|
||||
|
||||
compileOptions {
|
||||
compileOptions.encoding = "UTF-8"
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
|
||||
aaptOptions {
|
||||
|
7
app/proguard-rules.pro
vendored
7
app/proguard-rules.pro
vendored
@ -4,13 +4,11 @@
|
||||
-keep class org.fdroid.fdroid.** {*;}
|
||||
-dontskipnonpubliclibraryclassmembers
|
||||
-dontwarn android.test.**
|
||||
-dontwarn com.android.support.test.**
|
||||
|
||||
-dontwarn javax.naming.**
|
||||
-dontwarn org.slf4j.**
|
||||
-dontnote org.apache.http.**
|
||||
-dontnote android.net.http.**
|
||||
-dontnote android.support.**
|
||||
-dontnote **ILicensingService
|
||||
|
||||
# Needed for espresso https://stackoverflow.com/a/21706087
|
||||
@ -48,4 +46,9 @@
|
||||
public static final org.codehaus.jackson.annotate.JsonAutoDetect$Visibility *; }
|
||||
-keep public class your.class.** {
|
||||
*;
|
||||
}
|
||||
|
||||
# This is necessary so that RemoteWorkManager can be initialized (also marked with @Keep)
|
||||
-keep class androidx.work.multiprocess.RemoteWorkManagerClient {
|
||||
public <init>(...);
|
||||
}
|
@ -177,6 +177,7 @@ public class MainActivityEspressoTest {
|
||||
}
|
||||
|
||||
@LargeTest
|
||||
@Test
|
||||
public void showSettings() {
|
||||
ViewInteraction settingsBottonNavButton = onView(
|
||||
allOf(withText(R.string.menu_settings), isDisplayed()));
|
||||
@ -211,6 +212,7 @@ public class MainActivityEspressoTest {
|
||||
}
|
||||
|
||||
@LargeTest
|
||||
@Test
|
||||
public void showUpdates() {
|
||||
ViewInteraction updatesBottonNavButton = onView(allOf(withText(R.string.main_menu__updates), isDisplayed()));
|
||||
updatesBottonNavButton.perform(click());
|
||||
@ -218,6 +220,7 @@ public class MainActivityEspressoTest {
|
||||
}
|
||||
|
||||
@LargeTest
|
||||
@Test
|
||||
public void startSwap() {
|
||||
if (!BuildConfig.FLAVOR.startsWith("full")) {
|
||||
return;
|
||||
@ -233,6 +236,7 @@ public class MainActivityEspressoTest {
|
||||
}
|
||||
|
||||
@LargeTest
|
||||
@Test
|
||||
public void showCategories() {
|
||||
if (!BuildConfig.FLAVOR.startsWith("full")) {
|
||||
return;
|
||||
@ -258,6 +262,7 @@ public class MainActivityEspressoTest {
|
||||
}
|
||||
|
||||
@LargeTest
|
||||
@Test
|
||||
public void showLatest() {
|
||||
if (!BuildConfig.FLAVOR.startsWith("full")) {
|
||||
return;
|
||||
@ -280,6 +285,7 @@ public class MainActivityEspressoTest {
|
||||
}
|
||||
|
||||
@LargeTest
|
||||
@Test
|
||||
public void showSearch() {
|
||||
onView(allOf(withText(R.string.menu_settings), isDisplayed())).perform(click());
|
||||
onView(withId(R.id.fab_search)).check(doesNotExist());
|
||||
|
@ -17,14 +17,13 @@ import android.os.AsyncTask;
|
||||
import android.os.IBinder;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.app.NotificationCompat;
|
||||
import androidx.core.app.ServiceCompat;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
||||
|
||||
import cc.mvdan.accesspoint.WifiApControl;
|
||||
import org.fdroid.fdroid.FDroidApp;
|
||||
import org.fdroid.fdroid.NotificationHelper;
|
||||
import org.fdroid.fdroid.Preferences;
|
||||
@ -48,8 +47,6 @@ import java.util.Set;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
import cc.mvdan.accesspoint.WifiApControl;
|
||||
|
||||
/**
|
||||
* Central service which manages all of the different moving parts of swap which are required
|
||||
* to enable p2p swapping of apps.
|
||||
@ -429,7 +426,9 @@ public class SwapService extends Service {
|
||||
localBroadcastManager.unregisterReceiver(bonjourPeerFound);
|
||||
localBroadcastManager.unregisterReceiver(bonjourPeerRemoved);
|
||||
|
||||
unregisterReceiver(bluetoothScanModeChanged);
|
||||
if (bluetoothAdapter != null) {
|
||||
unregisterReceiver(bluetoothScanModeChanged);
|
||||
}
|
||||
|
||||
BluetoothManager.stop(this);
|
||||
|
||||
|
@ -18,7 +18,7 @@
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/both_parties_need_fdroid_text"
|
||||
android:layout_marginTop="36dp"
|
||||
android:tint="?attr/mainTabSwapSplashTint"
|
||||
app:tint="?attr/mainTabSwapSplashTint"
|
||||
android:scaleType="fitXY"
|
||||
tools:targetApi="jelly_bean"/>
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/listPreferredItemHeight"
|
||||
@ -20,7 +21,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:src="@drawable/circle"
|
||||
android:tint="@color/swap_light_grey_icon"/>
|
||||
app:tint="@color/swap_light_grey_icon"/>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/icon"
|
||||
|
@ -266,8 +266,11 @@
|
||||
android:name=".AddRepoIntentService"
|
||||
android:exported="false"/>
|
||||
|
||||
|
||||
<!-- Warning: Please add all new services to HidingManager -->
|
||||
<provider
|
||||
android:name="androidx.work.impl.WorkManagerInitializer"
|
||||
android:authorities="${applicationId}.workmanager-init"
|
||||
android:exported="false"
|
||||
tools:node="remove" />
|
||||
|
||||
<activity
|
||||
android:name=".views.main.MainActivity"
|
||||
|
@ -46,11 +46,10 @@ import android.util.Log;
|
||||
import android.view.Display;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.collection.LongSparseArray;
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
import com.nostra13.universalimageloader.cache.disc.DiskCache;
|
||||
import com.nostra13.universalimageloader.cache.disc.impl.UnlimitedDiskCache;
|
||||
import com.nostra13.universalimageloader.cache.disc.impl.ext.LruDiskCache;
|
||||
@ -58,7 +57,8 @@ import com.nostra13.universalimageloader.core.DefaultConfigurationFactory;
|
||||
import com.nostra13.universalimageloader.core.ImageLoader;
|
||||
import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;
|
||||
import com.nostra13.universalimageloader.core.process.BitmapProcessor;
|
||||
|
||||
import info.guardianproject.netcipher.NetCipher;
|
||||
import info.guardianproject.netcipher.proxy.OrbotHelper;
|
||||
import org.acra.ACRA;
|
||||
import org.acra.ReportField;
|
||||
import org.acra.ReportingInteractionMode;
|
||||
@ -82,17 +82,13 @@ import org.fdroid.fdroid.net.ImageLoaderForUIL;
|
||||
import org.fdroid.fdroid.panic.HidingManager;
|
||||
import org.fdroid.fdroid.work.CleanCacheWorker;
|
||||
|
||||
import javax.microedition.khronos.opengles.GL10;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.security.Security;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import javax.microedition.khronos.opengles.GL10;
|
||||
|
||||
import info.guardianproject.netcipher.NetCipher;
|
||||
import info.guardianproject.netcipher.proxy.OrbotHelper;
|
||||
|
||||
@ReportsCrashes(mailTo = BuildConfig.ACRA_REPORT_EMAIL,
|
||||
mode = ReportingInteractionMode.DIALOG,
|
||||
reportDialogClass = org.fdroid.fdroid.acra.CrashReportActivity.class,
|
||||
@ -113,7 +109,7 @@ import info.guardianproject.netcipher.proxy.OrbotHelper;
|
||||
ReportField.STACK_TRACE,
|
||||
}
|
||||
)
|
||||
public class FDroidApp extends Application {
|
||||
public class FDroidApp extends Application implements androidx.work.Configuration.Provider {
|
||||
|
||||
private static final String TAG = "FDroidApp";
|
||||
private static final String ACRA_ID = BuildConfig.APPLICATION_ID + ":acra";
|
||||
@ -654,7 +650,7 @@ public class FDroidApp extends Application {
|
||||
|
||||
/**
|
||||
* Put proxy settings (or Tor settings) globally into effect based on whats configured in Preferences.
|
||||
*
|
||||
* <p>
|
||||
* Must be called on App startup and after every proxy configuration change.
|
||||
*/
|
||||
public static void configureProxy(Preferences preferences) {
|
||||
@ -676,4 +672,26 @@ public class FDroidApp extends Application {
|
||||
public static Context getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up WorkManager on demand to avoid slowing down starts.
|
||||
*
|
||||
* @see CleanCacheWorker
|
||||
* @see org.fdroid.fdroid.work.PopularityContestWorker
|
||||
* @see org.fdroid.fdroid.work.UpdateWorker
|
||||
* @see <a href="https://developer.android.com/codelabs/android-adv-workmanager#3">example</a>
|
||||
*/
|
||||
@NonNull
|
||||
@Override
|
||||
public androidx.work.Configuration getWorkManagerConfiguration() {
|
||||
if (BuildConfig.DEBUG) {
|
||||
return new androidx.work.Configuration.Builder()
|
||||
.setMinimumLoggingLevel(Log.DEBUG)
|
||||
.build();
|
||||
} else {
|
||||
return new androidx.work.Configuration.Builder()
|
||||
.setMinimumLoggingLevel(Log.ERROR)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -33,10 +33,6 @@ import android.os.Build;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.StatFs;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.RequiresApi;
|
||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
|
||||
import android.text.Editable;
|
||||
import android.text.Html;
|
||||
import android.text.SpannableStringBuilder;
|
||||
@ -52,6 +48,10 @@ import android.view.View;
|
||||
import android.view.ViewTreeObserver;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.Toast;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.RequiresApi;
|
||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
|
||||
import com.nostra13.universalimageloader.core.DisplayImageOptions;
|
||||
import com.nostra13.universalimageloader.core.ImageLoader;
|
||||
import com.nostra13.universalimageloader.core.assist.ImageScaleType;
|
||||
@ -406,10 +406,26 @@ public final class Utils {
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the fingerprint used to represent an APK signing key in F-Droid.
|
||||
* This is a custom fingerprint algorithm that was kind of accidentally
|
||||
* created, but is still in use.
|
||||
*
|
||||
* @see #getPackageSig(PackageInfo)
|
||||
* @see org.fdroid.fdroid.data.Apk#sig
|
||||
*/
|
||||
public static String getsig(byte[] rawCertBytes) {
|
||||
return Utils.hashBytes(toHexString(rawCertBytes).getBytes(), "md5");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the fingerprint used to represent an APK signing key in F-Droid.
|
||||
* This is a custom fingerprint algorithm that was kind of accidentally
|
||||
* created, but is still in use.
|
||||
*
|
||||
* @see #getsig(byte[])
|
||||
* @see org.fdroid.fdroid.data.Apk#sig
|
||||
*/
|
||||
public static String getPackageSig(PackageInfo info) {
|
||||
if (info == null || info.signatures == null || info.signatures.length < 1) {
|
||||
@ -556,7 +572,7 @@ public final class Utils {
|
||||
}
|
||||
|
||||
byte[] mdbytes = md.digest();
|
||||
return toHexString(mdbytes).toLowerCase(Locale.ENGLISH);
|
||||
return toHexString(mdbytes);
|
||||
} catch (IOException e) {
|
||||
String message = e.getMessage();
|
||||
if (message.contains("read failed: EIO (I/O error)")) {
|
||||
@ -576,7 +592,7 @@ public final class Utils {
|
||||
* Computes the base 16 representation of the byte array argument.
|
||||
*
|
||||
* @param bytes an array of bytes.
|
||||
* @return the bytes represented as a string of hexadecimal digits.
|
||||
* @return the bytes represented as a string of lowercase hexadecimal digits.
|
||||
* @see <a href="https://stackoverflow.com/a/9855338">source</a>
|
||||
*/
|
||||
public static String toHexString(byte[] bytes) {
|
||||
@ -589,7 +605,7 @@ public final class Utils {
|
||||
return new String(hexChars);
|
||||
}
|
||||
|
||||
private static final char[] HEX_LOOKUP_ARRAY = "0123456789ABCDEF".toCharArray();
|
||||
private static final char[] HEX_LOOKUP_ARRAY = "0123456789abcdef".toCharArray();
|
||||
|
||||
public static int parseInt(String str, int fallback) {
|
||||
if (str == null || str.length() == 0) {
|
||||
|
@ -949,24 +949,7 @@ public class App extends ValueObject implements Comparable<App>, Parcelable {
|
||||
}
|
||||
apkJar.close();
|
||||
|
||||
/*
|
||||
* I don't fully understand the loop used here. I've copied it verbatim
|
||||
* from getsig.java bundled with FDroidServer. I *believe* it is taking
|
||||
* the raw byte encoding of the certificate & converting it to a byte
|
||||
* array of the hex representation of the original certificate byte
|
||||
* array. This is then MD5 sum'd. It's a really bad way to be doing this
|
||||
* if I'm right... If I'm not right, I really don't know! see lines
|
||||
* 67->75 in getsig.java bundled with Fdroidserver
|
||||
*/
|
||||
final byte[] fdroidSig = new byte[rawCertBytes.length * 2];
|
||||
for (int j = 0; j < rawCertBytes.length; j++) {
|
||||
byte v = rawCertBytes[j];
|
||||
int d = (v >> 4) & 0xF;
|
||||
fdroidSig[j * 2] = (byte) (d >= 10 ? ('a' + d - 10) : ('0' + d));
|
||||
d = v & 0xF;
|
||||
fdroidSig[j * 2 + 1] = (byte) (d >= 10 ? ('a' + d - 10) : ('0' + d));
|
||||
}
|
||||
apk.sig = Utils.hashBytes(fdroidSig, "md5");
|
||||
apk.sig = Utils.getsig(rawCertBytes);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -37,7 +37,6 @@ import android.view.ViewGroup;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
@ -45,11 +44,9 @@ import androidx.core.content.ContextCompat;
|
||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.ashokvarma.bottomnavigation.BottomNavigationBar;
|
||||
import com.ashokvarma.bottomnavigation.BottomNavigationItem;
|
||||
import com.ashokvarma.bottomnavigation.TextBadgeItem;
|
||||
|
||||
import org.fdroid.fdroid.AppUpdateStatusManager;
|
||||
import org.fdroid.fdroid.AppUpdateStatusManager.AppUpdateStatus;
|
||||
import org.fdroid.fdroid.BuildConfig;
|
||||
@ -305,6 +302,11 @@ public class MainActivity extends AppCompatActivity implements BottomNavigationB
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Since any app could send this {@link Intent}, and the search terms are
|
||||
* fed into a SQL query, the data must be strictly sanitized to avoid
|
||||
* SQL injection attacks.
|
||||
*/
|
||||
private void handleSearchOrAppViewIntent(Intent intent) {
|
||||
if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
|
||||
String query = intent.getStringExtra(SearchManager.QUERY);
|
||||
@ -391,6 +393,8 @@ public class MainActivity extends AppCompatActivity implements BottomNavigationB
|
||||
}
|
||||
|
||||
if (!TextUtils.isEmpty(packageName)) {
|
||||
// sanitize packageName to be a valid Java packageName and prevent exploits
|
||||
packageName = packageName.replaceAll("[^A-Za-z\\d_.]", "");
|
||||
Utils.debugLog(TAG, "FDroid launched via app link for '" + packageName + "'");
|
||||
Intent intentToInvoke = new Intent(this, AppDetailsActivity.class);
|
||||
intentToInvoke.putExtra(AppDetailsActivity.EXTRA_APPID, packageName);
|
||||
@ -402,12 +406,19 @@ public class MainActivity extends AppCompatActivity implements BottomNavigationB
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* These strings might end up in a SQL query, so strip all non-alpha-num
|
||||
*/
|
||||
static String sanitizeSearchTerms(String query) {
|
||||
return query.replaceAll("[^\\p{L}\\d_ -]", " ");
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiates the {@link AppListActivity} with the relevant search terms passed in via the query arg.
|
||||
*/
|
||||
private void performSearch(String query) {
|
||||
Intent searchIntent = new Intent(this, AppListActivity.class);
|
||||
searchIntent.putExtra(AppListActivity.EXTRA_SEARCH_TERMS, query);
|
||||
searchIntent.putExtra(AppListActivity.EXTRA_SEARCH_TERMS, sanitizeSearchTerms(query));
|
||||
startActivity(searchIntent);
|
||||
}
|
||||
|
||||
|
@ -20,6 +20,7 @@
|
||||
|
||||
<view class="org.fdroid.fdroid.privileged.views.AppSecurityPermissions$PermissionItemView"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
@ -34,7 +35,7 @@
|
||||
android:layout_marginRight="8dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:scaleType="fitCenter"
|
||||
android:tint="@android:color/black" />
|
||||
app:tint="@android:color/black" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
|
@ -20,6 +20,7 @@
|
||||
|
||||
<view class="org.fdroid.fdroid.privileged.views.AppSecurityPermissions$PermissionItemView"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
@ -58,7 +59,7 @@
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_alignBottom="@+id/perm_money_label"
|
||||
android:scaleType="fitCenter"
|
||||
android:tint="@color/perms_costs_money"
|
||||
app:tint="@color/perms_costs_money"
|
||||
android:tintMode="src_in"
|
||||
android:src="@drawable/ic_coins_s" />
|
||||
<TextView
|
||||
|
@ -55,7 +55,7 @@
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/empty_state"
|
||||
android:tint="?attr/mainTabSwapSplashTint"
|
||||
app:tint="?attr/mainTabSwapSplashTint"
|
||||
android:scaleType="fitCenter"
|
||||
android:visibility="gone" />
|
||||
|
||||
|
@ -2,9 +2,9 @@
|
||||
package org.fdroid.fdroid;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.Signature;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
|
||||
import org.fdroid.fdroid.views.AppDetailsRecyclerViewAdapter;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
@ -12,6 +12,7 @@ import org.robolectric.RobolectricTestRunner;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Date;
|
||||
import java.util.Random;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
@ -215,4 +216,40 @@ public class UtilsTest {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the replacement for the ancient fingerprint algorithm.
|
||||
*
|
||||
* @see org.fdroid.fdroid.data.Apk#sig
|
||||
*/
|
||||
@Test
|
||||
public void testGetsig() {
|
||||
/*
|
||||
* I don't fully understand the loop used here. I've copied it verbatim
|
||||
* from getsig.java bundled with FDroidServer. I *believe* it is taking
|
||||
* the raw byte encoding of the certificate & converting it to a byte
|
||||
* array of the hex representation of the original certificate byte
|
||||
* array. This is then MD5 sum'd. It's a really bad way to be doing this
|
||||
* if I'm right... If I'm not right, I really don't know! see lines
|
||||
* 67->75 in getsig.java bundled with Fdroidserver
|
||||
*/
|
||||
for (int length : new int[]{256, 345, 1233, 4032, 12092}) {
|
||||
byte[] rawCertBytes = new byte[length];
|
||||
new Random().nextBytes(rawCertBytes);
|
||||
final byte[] fdroidSig = new byte[rawCertBytes.length * 2];
|
||||
for (int j = 0; j < rawCertBytes.length; j++) {
|
||||
byte v = rawCertBytes[j];
|
||||
int d = (v >> 4) & 0xF;
|
||||
fdroidSig[j * 2] = (byte) (d >= 10 ? ('a' + d - 10) : ('0' + d));
|
||||
d = v & 0xF;
|
||||
fdroidSig[j * 2 + 1] = (byte) (d >= 10 ? ('a' + d - 10) : ('0' + d));
|
||||
}
|
||||
String sig = Utils.hashBytes(fdroidSig, "md5");
|
||||
assertEquals(sig, Utils.getsig(rawCertBytes));
|
||||
|
||||
PackageInfo packageInfo = new PackageInfo();
|
||||
packageInfo.signatures = new Signature[]{new Signature(rawCertBytes)};
|
||||
assertEquals(sig, Utils.getPackageSig(packageInfo));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import org.junit.Test;
|
||||
import java.io.File;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
import static org.junit.Assume.assumeTrue;
|
||||
|
||||
public class SanitizedFileTest {
|
||||
@ -45,4 +46,13 @@ public class SanitizedFileTest {
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSanitizeFileName() {
|
||||
for (String valid : new String[]{"An.stop", "a.0", "packageName", "com.this-and-that", "A_.o"}) {
|
||||
assertEquals(valid, SanitizedFile.sanitizeFileName(valid));
|
||||
}
|
||||
for (String invalid : new String[]{"'--;DROP", "a.0)", "packageName\n"}) {
|
||||
assertNotEquals(invalid, SanitizedFile.sanitizeFileName(invalid));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,25 @@
|
||||
package org.fdroid.fdroid.views.main;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
|
||||
public class MainActivityTest {
|
||||
|
||||
@Test
|
||||
public void testSanitizeSearchTerms() {
|
||||
for (String valid : new String[]{"private browser", "πÇÇ", "现代 通用字", "български", "عربي"}) {
|
||||
assertEquals(valid, MainActivity.sanitizeSearchTerms(valid));
|
||||
}
|
||||
for (String invalid : new String[]{
|
||||
"Robert'); DROP TABLE Students; --",
|
||||
"xxx') OR 1 = 1 -- ]",
|
||||
"105 OR 1=1;",
|
||||
"\" OR \"=\"",
|
||||
}) {
|
||||
assertNotEquals(invalid, MainActivity.sanitizeSearchTerms(invalid));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -115,7 +115,6 @@
|
||||
<module name="FinalClass" />
|
||||
|
||||
<module name="ArrayTypeStyle" />
|
||||
<module name="ArrayTrailingComma" />
|
||||
<module name="UpperEll" />
|
||||
|
||||
<module name="StringLiteralEquality" />
|
||||
|
Loading…
x
Reference in New Issue
Block a user