Merge branch 'installed-sig' into 'master'
Cache installed signature This will later be useful for #122 and others. Also a few more fixes related to signatures and package information. CC @pserwylo See merge request !158
This commit is contained in:
commit
3df93940c8
@ -30,7 +30,6 @@ import android.content.Context;
|
|||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.IntentFilter;
|
import android.content.IntentFilter;
|
||||||
import android.content.pm.PackageInfo;
|
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.database.ContentObserver;
|
import android.database.ContentObserver;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
@ -96,7 +95,6 @@ import org.fdroid.fdroid.net.AsyncDownloaderFromAndroid;
|
|||||||
import org.fdroid.fdroid.net.Downloader;
|
import org.fdroid.fdroid.net.Downloader;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.security.NoSuchAlgorithmException;
|
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@ -104,8 +102,6 @@ interface AppDetailsData {
|
|||||||
App getApp();
|
App getApp();
|
||||||
|
|
||||||
AppDetails.ApkListAdapter getApks();
|
AppDetails.ApkListAdapter getApks();
|
||||||
|
|
||||||
String getInstalledSigHash();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -188,8 +184,8 @@ public class AppDetails extends AppCompatActivity implements ProgressListener, A
|
|||||||
return getString(R.string.app_not_installed);
|
return getString(R.string.app_not_installed);
|
||||||
}
|
}
|
||||||
// Definitely installed this version.
|
// Definitely installed this version.
|
||||||
if (mInstalledSigID != null && apk.sig != null
|
if (app.installedSig != null && apk.sig != null
|
||||||
&& apk.sig.equals(mInstalledSigID)) {
|
&& apk.sig.equals(app.installedSig)) {
|
||||||
return getString(R.string.app_installed);
|
return getString(R.string.app_installed);
|
||||||
}
|
}
|
||||||
// Installed the same version, but from someplace else.
|
// Installed the same version, but from someplace else.
|
||||||
@ -447,9 +443,6 @@ public class AppDetails extends AppCompatActivity implements ProgressListener, A
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// The signature of the installed version.
|
|
||||||
private String mInstalledSigID;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onStart() {
|
protected void onStart() {
|
||||||
super.onStart();
|
super.onStart();
|
||||||
@ -601,7 +594,6 @@ public class AppDetails extends AppCompatActivity implements ProgressListener, A
|
|||||||
* like that) and then finish the activity.
|
* like that) and then finish the activity.
|
||||||
*/
|
*/
|
||||||
private void setApp(App newApp) {
|
private void setApp(App newApp) {
|
||||||
|
|
||||||
if (newApp == null) {
|
if (newApp == null) {
|
||||||
Toast.makeText(this, R.string.no_such_app, Toast.LENGTH_LONG).show();
|
Toast.makeText(this, R.string.no_such_app, Toast.LENGTH_LONG).show();
|
||||||
finish();
|
finish();
|
||||||
@ -612,21 +604,6 @@ public class AppDetails extends AppCompatActivity implements ProgressListener, A
|
|||||||
|
|
||||||
startingIgnoreAll = app.ignoreAllUpdates;
|
startingIgnoreAll = app.ignoreAllUpdates;
|
||||||
startingIgnoreThis = app.ignoreThisUpdate;
|
startingIgnoreThis = app.ignoreThisUpdate;
|
||||||
|
|
||||||
// Get the signature of the installed package...
|
|
||||||
mInstalledSigID = null;
|
|
||||||
|
|
||||||
if (app.isInstalled()) {
|
|
||||||
try {
|
|
||||||
PackageInfo pi = mPm.getPackageInfo(app.id, PackageManager.GET_SIGNATURES);
|
|
||||||
Hasher hash = new Hasher("MD5", pi.signatures[0].toCharsString().getBytes());
|
|
||||||
mInstalledSigID = hash.getHash();
|
|
||||||
} catch (PackageManager.NameNotFoundException e) {
|
|
||||||
Log.w(TAG, "Failed to get installed signature");
|
|
||||||
} catch (NoSuchAlgorithmException e) {
|
|
||||||
Log.w(TAG, "Failed to calculate signature MD5 sum");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void refreshApkList() {
|
private void refreshApkList() {
|
||||||
@ -853,8 +830,8 @@ public class AppDetails extends AppCompatActivity implements ProgressListener, A
|
|||||||
alert.show();
|
alert.show();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (mInstalledSigID != null && apk.sig != null
|
if (app.installedSig != null && apk.sig != null
|
||||||
&& !apk.sig.equals(mInstalledSigID)) {
|
&& !apk.sig.equals(app.installedSig)) {
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||||
builder.setMessage(R.string.SignatureMismatch).setPositiveButton(
|
builder.setMessage(R.string.SignatureMismatch).setPositiveButton(
|
||||||
R.string.ok,
|
R.string.ok,
|
||||||
@ -1044,11 +1021,6 @@ public class AppDetails extends AppCompatActivity implements ProgressListener, A
|
|||||||
return adapter;
|
return adapter;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getInstalledSigHash() {
|
|
||||||
return mInstalledSigID;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class AppDetailsSummaryFragment extends Fragment {
|
public static class AppDetailsSummaryFragment extends Fragment {
|
||||||
|
|
||||||
protected final Preferences prefs;
|
protected final Preferences prefs;
|
||||||
@ -1092,10 +1064,6 @@ public class AppDetails extends AppCompatActivity implements ProgressListener, A
|
|||||||
return data.getApks();
|
return data.getApks();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String getInstalledSigHash() {
|
|
||||||
return data.getInstalledSigHash();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||||
super.onCreateView(inflater, container, savedInstanceState);
|
super.onCreateView(inflater, container, savedInstanceState);
|
||||||
@ -1408,11 +1376,11 @@ public class AppDetails extends AppCompatActivity implements ProgressListener, A
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
App app = getApp();
|
||||||
TextView signatureView = (TextView) view.findViewById(R.id.signature);
|
TextView signatureView = (TextView) view.findViewById(R.id.signature);
|
||||||
String sig = getInstalledSigHash();
|
if (prefs.expertMode() && !TextUtils.isEmpty(app.installedSig)) {
|
||||||
if (prefs.expertMode() && !TextUtils.isEmpty(sig)) {
|
|
||||||
signatureView.setVisibility(View.VISIBLE);
|
signatureView.setVisibility(View.VISIBLE);
|
||||||
signatureView.setText("Signed: " + sig);
|
signatureView.setText("Signed: " + app.installedSig);
|
||||||
} else {
|
} else {
|
||||||
signatureView.setVisibility(View.GONE);
|
signatureView.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
|
@ -100,6 +100,8 @@ public class App extends ValueObject implements Comparable<App> {
|
|||||||
|
|
||||||
public Apk installedApk; // might be null if not installed
|
public Apk installedApk; // might be null if not installed
|
||||||
|
|
||||||
|
public String installedSig;
|
||||||
|
|
||||||
public boolean system;
|
public boolean system;
|
||||||
public boolean updatedSystemApp;
|
public boolean updatedSystemApp;
|
||||||
|
|
||||||
@ -209,6 +211,9 @@ public class App extends ValueObject implements Comparable<App> {
|
|||||||
case AppProvider.DataColumns.InstalledApp.VERSION_NAME:
|
case AppProvider.DataColumns.InstalledApp.VERSION_NAME:
|
||||||
installedVersionName = cursor.getString(i);
|
installedVersionName = cursor.getString(i);
|
||||||
break;
|
break;
|
||||||
|
case AppProvider.DataColumns.InstalledApp.SIGNATURE:
|
||||||
|
installedSig = cursor.getString(i);
|
||||||
|
break;
|
||||||
case "_id":
|
case "_id":
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -209,6 +209,7 @@ public class AppProvider extends FDroidProvider {
|
|||||||
interface InstalledApp {
|
interface InstalledApp {
|
||||||
String VERSION_CODE = "installedVersionCode";
|
String VERSION_CODE = "installedVersionCode";
|
||||||
String VERSION_NAME = "installedVersionName";
|
String VERSION_NAME = "installedVersionName";
|
||||||
|
String SIGNATURE = "installedSig";
|
||||||
}
|
}
|
||||||
|
|
||||||
String[] ALL = {
|
String[] ALL = {
|
||||||
@ -220,6 +221,7 @@ public class AppProvider extends FDroidProvider {
|
|||||||
IGNORE_THISUPDATE, ICON_URL, ICON_URL_LARGE,
|
IGNORE_THISUPDATE, ICON_URL, ICON_URL_LARGE,
|
||||||
SUGGESTED_VERSION_CODE, SuggestedApk.VERSION,
|
SUGGESTED_VERSION_CODE, SuggestedApk.VERSION,
|
||||||
InstalledApp.VERSION_CODE, InstalledApp.VERSION_NAME,
|
InstalledApp.VERSION_CODE, InstalledApp.VERSION_NAME,
|
||||||
|
InstalledApp.SIGNATURE,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -354,6 +356,9 @@ public class AppProvider extends FDroidProvider {
|
|||||||
case DataColumns.InstalledApp.VERSION_CODE:
|
case DataColumns.InstalledApp.VERSION_CODE:
|
||||||
addInstalledAppVersionCode();
|
addInstalledAppVersionCode();
|
||||||
break;
|
break;
|
||||||
|
case DataColumns.InstalledApp.SIGNATURE:
|
||||||
|
addInstalledSig();
|
||||||
|
break;
|
||||||
case DataColumns._COUNT:
|
case DataColumns._COUNT:
|
||||||
appendCountField();
|
appendCountField();
|
||||||
break;
|
break;
|
||||||
@ -402,6 +407,13 @@ public class AppProvider extends FDroidProvider {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void addInstalledSig() {
|
||||||
|
addInstalledAppField(
|
||||||
|
InstalledAppProvider.DataColumns.SIGNATURE,
|
||||||
|
DataColumns.InstalledApp.SIGNATURE
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
private void addInstalledAppField(String fieldName, String alias) {
|
private void addInstalledAppField(String fieldName, String alias) {
|
||||||
leftJoinToInstalledTable();
|
leftJoinToInstalledTable();
|
||||||
appendField(fieldName, "installed", alias);
|
appendField(fieldName, "installed", alias);
|
||||||
|
@ -97,10 +97,12 @@ public class DBHelper extends SQLiteOpenHelper {
|
|||||||
+ InstalledAppProvider.DataColumns.APP_ID + " TEXT NOT NULL PRIMARY KEY, "
|
+ InstalledAppProvider.DataColumns.APP_ID + " TEXT NOT NULL PRIMARY KEY, "
|
||||||
+ InstalledAppProvider.DataColumns.VERSION_CODE + " INT NOT NULL, "
|
+ InstalledAppProvider.DataColumns.VERSION_CODE + " INT NOT NULL, "
|
||||||
+ InstalledAppProvider.DataColumns.VERSION_NAME + " TEXT NOT NULL, "
|
+ InstalledAppProvider.DataColumns.VERSION_NAME + " TEXT NOT NULL, "
|
||||||
+ InstalledAppProvider.DataColumns.APPLICATION_LABEL + " TEXT NOT NULL "
|
+ InstalledAppProvider.DataColumns.APPLICATION_LABEL + " TEXT NOT NULL, "
|
||||||
|
+ InstalledAppProvider.DataColumns.SIGNATURE + " TEXT NOT NULL "
|
||||||
+ " );";
|
+ " );";
|
||||||
|
private static final String DROP_TABLE_INSTALLED_APP = "DROP TABLE " + TABLE_INSTALLED_APP + ";";
|
||||||
|
|
||||||
private static final int DB_VERSION = 50;
|
private static final int DB_VERSION = 51;
|
||||||
|
|
||||||
private final Context context;
|
private final Context context;
|
||||||
|
|
||||||
@ -278,11 +280,11 @@ public class DBHelper extends SQLiteOpenHelper {
|
|||||||
renameRepoId(db, oldVersion);
|
renameRepoId(db, oldVersion);
|
||||||
populateRepoNames(db, oldVersion);
|
populateRepoNames(db, oldVersion);
|
||||||
if (oldVersion < 43) createInstalledApp(db);
|
if (oldVersion < 43) createInstalledApp(db);
|
||||||
addAppLabelToInstalledCache(db, oldVersion);
|
|
||||||
addIsSwapToRepo(db, oldVersion);
|
addIsSwapToRepo(db, oldVersion);
|
||||||
addChangelogToApp(db, oldVersion);
|
addChangelogToApp(db, oldVersion);
|
||||||
addIconUrlLargeToApp(db, oldVersion);
|
addIconUrlLargeToApp(db, oldVersion);
|
||||||
updateIconUrlLarge(db, oldVersion);
|
updateIconUrlLarge(db, oldVersion);
|
||||||
|
recreateInstalledCache(db, oldVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -478,13 +480,11 @@ public class DBHelper extends SQLiteOpenHelper {
|
|||||||
db.execSQL(CREATE_TABLE_INSTALLED_APP);
|
db.execSQL(CREATE_TABLE_INSTALLED_APP);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addAppLabelToInstalledCache(SQLiteDatabase db, int oldVersion) {
|
// If any column was added or removed, just drop the table, create it
|
||||||
if (oldVersion < 45) {
|
// again and let the cache be filled from scratch again.
|
||||||
Utils.debugLog(TAG, "Adding applicationLabel to installed app table. " +
|
private void recreateInstalledCache(SQLiteDatabase db, int oldVersion) {
|
||||||
"Turns out we will need to repopulate the cache after doing this, " +
|
if (oldVersion < 51) {
|
||||||
"so just dropping and recreating the table (instead of altering and adding a column). " +
|
db.execSQL(DROP_TABLE_INSTALLED_APP);
|
||||||
"This will force the entire cache to be rebuilt, including app names.");
|
|
||||||
db.execSQL("DROP TABLE fdroid_installedApp;");
|
|
||||||
createInstalledApp(db);
|
createInstalledApp(db);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ import android.content.ContentProviderOperation;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.OperationApplicationException;
|
import android.content.OperationApplicationException;
|
||||||
import android.content.pm.PackageInfo;
|
import android.content.pm.PackageInfo;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
@ -110,7 +111,8 @@ public class InstalledAppCacheUpdater {
|
|||||||
|
|
||||||
Map<String, Integer> cachedInfo = InstalledAppProvider.Helper.all(context);
|
Map<String, Integer> cachedInfo = InstalledAppProvider.Helper.all(context);
|
||||||
|
|
||||||
List<PackageInfo> installedPackages = context.getPackageManager().getInstalledPackages(0);
|
List<PackageInfo> installedPackages = context.getPackageManager()
|
||||||
|
.getInstalledPackages(PackageManager.GET_SIGNATURES);
|
||||||
for (PackageInfo appInfo : installedPackages) {
|
for (PackageInfo appInfo : installedPackages) {
|
||||||
toInsert.add(appInfo);
|
toInsert.add(appInfo);
|
||||||
if (cachedInfo.containsKey(appInfo.packageName)) {
|
if (cachedInfo.containsKey(appInfo.packageName)) {
|
||||||
@ -137,6 +139,8 @@ public class InstalledAppCacheUpdater {
|
|||||||
.withValue(InstalledAppProvider.DataColumns.VERSION_NAME, info.versionName)
|
.withValue(InstalledAppProvider.DataColumns.VERSION_NAME, info.versionName)
|
||||||
.withValue(InstalledAppProvider.DataColumns.APPLICATION_LABEL,
|
.withValue(InstalledAppProvider.DataColumns.APPLICATION_LABEL,
|
||||||
InstalledAppProvider.getApplicationLabel(context, info.packageName))
|
InstalledAppProvider.getApplicationLabel(context, info.packageName))
|
||||||
|
.withValue(InstalledAppProvider.DataColumns.SIGNATURE,
|
||||||
|
InstalledAppProvider.getPackageSig(info))
|
||||||
.build();
|
.build();
|
||||||
ops.add(op);
|
ops.add(op);
|
||||||
}
|
}
|
||||||
|
@ -4,15 +4,19 @@ import android.content.ContentValues;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.UriMatcher;
|
import android.content.UriMatcher;
|
||||||
import android.content.pm.ApplicationInfo;
|
import android.content.pm.ApplicationInfo;
|
||||||
|
import android.content.pm.PackageInfo;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
|
import android.content.pm.Signature;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import org.fdroid.fdroid.R;
|
import org.fdroid.fdroid.R;
|
||||||
|
import org.fdroid.fdroid.Hasher;
|
||||||
import org.fdroid.fdroid.Utils;
|
import org.fdroid.fdroid.Utils;
|
||||||
|
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@ -59,9 +63,11 @@ public class InstalledAppProvider extends FDroidProvider {
|
|||||||
String VERSION_CODE = "versionCode";
|
String VERSION_CODE = "versionCode";
|
||||||
String VERSION_NAME = "versionName";
|
String VERSION_NAME = "versionName";
|
||||||
String APPLICATION_LABEL = "applicationLabel";
|
String APPLICATION_LABEL = "applicationLabel";
|
||||||
|
String SIGNATURE = "sig";
|
||||||
|
|
||||||
String[] ALL = {
|
String[] ALL = {
|
||||||
_ID, APP_ID, VERSION_CODE, VERSION_NAME, APPLICATION_LABEL,
|
_ID, APP_ID, VERSION_CODE, VERSION_NAME, APPLICATION_LABEL,
|
||||||
|
SIGNATURE,
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -106,6 +112,18 @@ public class InstalledAppProvider extends FDroidProvider {
|
|||||||
return packageName; // all else fails, return id
|
return packageName; // all else fails, return id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String getPackageSig(PackageInfo info) {
|
||||||
|
Signature sig = info.signatures[0];
|
||||||
|
String sigHash = "";
|
||||||
|
try {
|
||||||
|
Hasher hash = new Hasher("MD5", sig.toCharsString().getBytes());
|
||||||
|
sigHash = hash.getHash();
|
||||||
|
} catch (NoSuchAlgorithmException e) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
return sigHash;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String getTableName() {
|
protected String getTableName() {
|
||||||
return DBHelper.TABLE_INSTALLED_APP;
|
return DBHelper.TABLE_INSTALLED_APP;
|
||||||
|
@ -57,6 +57,8 @@ public class PackageAddedReceiver extends PackageReceiver {
|
|||||||
values.put(InstalledAppProvider.DataColumns.VERSION_NAME, info.versionName);
|
values.put(InstalledAppProvider.DataColumns.VERSION_NAME, info.versionName);
|
||||||
values.put(InstalledAppProvider.DataColumns.APPLICATION_LABEL,
|
values.put(InstalledAppProvider.DataColumns.APPLICATION_LABEL,
|
||||||
InstalledAppProvider.getApplicationLabel(context, appId));
|
InstalledAppProvider.getApplicationLabel(context, appId));
|
||||||
|
values.put(InstalledAppProvider.DataColumns.SIGNATURE,
|
||||||
|
InstalledAppProvider.getPackageSig(info));
|
||||||
context.getContentResolver().insert(uri, values);
|
context.getContentResolver().insert(uri, values);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@ abstract class PackageReceiver extends BroadcastReceiver {
|
|||||||
protected PackageInfo getPackageInfo(Context context, String appId) {
|
protected PackageInfo getPackageInfo(Context context, String appId) {
|
||||||
PackageInfo info = null;
|
PackageInfo info = null;
|
||||||
try {
|
try {
|
||||||
info = context.getPackageManager().getPackageInfo(appId, 0);
|
info = context.getPackageManager().getPackageInfo(appId, PackageManager.GET_SIGNATURES);
|
||||||
} catch (PackageManager.NameNotFoundException e) {
|
} catch (PackageManager.NameNotFoundException e) {
|
||||||
// ignore
|
// ignore
|
||||||
}
|
}
|
||||||
|
@ -59,6 +59,8 @@ public class PackageUpgradedReceiver extends PackageReceiver {
|
|||||||
values.put(InstalledAppProvider.DataColumns.VERSION_NAME, info.versionName);
|
values.put(InstalledAppProvider.DataColumns.VERSION_NAME, info.versionName);
|
||||||
values.put(InstalledAppProvider.DataColumns.APPLICATION_LABEL,
|
values.put(InstalledAppProvider.DataColumns.APPLICATION_LABEL,
|
||||||
InstalledAppProvider.getApplicationLabel(context, appId));
|
InstalledAppProvider.getApplicationLabel(context, appId));
|
||||||
|
values.put(InstalledAppProvider.DataColumns.SIGNATURE,
|
||||||
|
InstalledAppProvider.getPackageSig(info));
|
||||||
context.getContentResolver().insert(uri, values);
|
context.getContentResolver().insert(uri, values);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user