Search in sources :

Example 51 with Apk

use of org.fdroid.fdroid.data.Apk in project fdroidclient by f-droid.

the class ApkVerifierTest method testExtendedPerms.

@Test
public void testExtendedPerms() throws IOException, ApkVerifier.ApkPermissionUnequalException, ApkVerifier.ApkVerificationException {
    RepoDetails actualDetails = getFromFile(extendedPermsXml);
    HashSet<String> expectedSet = new HashSet<>(Arrays.asList("android.permission.ACCESS_NETWORK_STATE", "android.permission.ACCESS_WIFI_STATE", "android.permission.INTERNET", "android.permission.READ_SYNC_STATS", "android.permission.READ_SYNC_SETTINGS", "android.permission.WRITE_SYNC_SETTINGS", "android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS", "android.permission.READ_CONTACTS", "android.permission.WRITE_CONTACTS", "android.permission.READ_CALENDAR", "android.permission.WRITE_CALENDAR"));
    if (Build.VERSION.SDK_INT <= 18) {
        expectedSet.add("android.permission.READ_EXTERNAL_STORAGE");
        expectedSet.add("android.permission.WRITE_EXTERNAL_STORAGE");
    }
    if (Build.VERSION.SDK_INT <= 22) {
        expectedSet.add("android.permission.GET_ACCOUNTS");
        expectedSet.add("android.permission.AUTHENTICATE_ACCOUNTS");
        expectedSet.add("android.permission.MANAGE_ACCOUNTS");
    }
    if (Build.VERSION.SDK_INT >= 23) {
        expectedSet.add("android.permission.CAMERA");
        if (Build.VERSION.SDK_INT <= 23) {
            expectedSet.add("android.permission.CALL_PHONE");
        }
    }
    Apk apk = actualDetails.apks.get(0);
    HashSet<String> actualSet = new HashSet<>(Arrays.asList(apk.requestedPermissions));
    for (String permission : expectedSet) {
        if (!actualSet.contains(permission)) {
            Log.i(TAG, permission + " in expected but not actual! (android-" + Build.VERSION.SDK_INT + ")");
        }
    }
    for (String permission : actualSet) {
        if (!expectedSet.contains(permission)) {
            Log.i(TAG, permission + " in actual but not expected! (android-" + Build.VERSION.SDK_INT + ")");
        }
    }
    String[] expectedPermissions = expectedSet.toArray(new String[expectedSet.size()]);
    assertTrue(ApkVerifier.requestedPermissionsEqual(expectedPermissions, apk.requestedPermissions));
    String[] badPermissions = Arrays.copyOf(expectedPermissions, expectedPermissions.length + 1);
    assertFalse(ApkVerifier.requestedPermissionsEqual(badPermissions, apk.requestedPermissions));
    badPermissions[badPermissions.length - 1] = "notarealpermission";
    assertFalse(ApkVerifier.requestedPermissionsEqual(badPermissions, apk.requestedPermissions));
    Uri uri = Uri.fromFile(extendedPermissionsApk);
    ApkVerifier apkVerifier = new ApkVerifier(instrumentation.getContext(), uri, apk);
    apkVerifier.verifyApk();
}
Also used : Apk(org.fdroid.fdroid.data.Apk) Uri(android.net.Uri) RepoDetails(org.fdroid.fdroid.mock.RepoDetails) HashSet(java.util.HashSet) FileCompatTest(org.fdroid.fdroid.compat.FileCompatTest) Test(org.junit.Test)

Example 52 with Apk

use of org.fdroid.fdroid.data.Apk in project fdroidclient by f-droid.

the class ApkVerifierTest method testImpliedPerms.

@Test
public void testImpliedPerms() throws IOException {
    RepoDetails actualDetails = getFromFile(extendedPermsXml);
    TreeSet<String> expectedSet = new TreeSet<>(Arrays.asList("android.permission.ACCESS_NETWORK_STATE", "android.permission.ACCESS_WIFI_STATE", "android.permission.INTERNET", "android.permission.READ_CALENDAR", "android.permission.READ_CONTACTS", "android.permission.READ_EXTERNAL_STORAGE", "android.permission.READ_SYNC_SETTINGS", "android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS", "android.permission.WRITE_CALENDAR", "android.permission.WRITE_CONTACTS", "android.permission.WRITE_EXTERNAL_STORAGE", "android.permission.WRITE_SYNC_SETTINGS", "org.dmfs.permission.READ_TASKS", "org.dmfs.permission.WRITE_TASKS"));
    if (Build.VERSION.SDK_INT <= 22) {
        // maxSdkVersion="22"
        expectedSet.addAll(Arrays.asList("android.permission.AUTHENTICATE_ACCOUNTS", "android.permission.GET_ACCOUNTS", "android.permission.MANAGE_ACCOUNTS"));
    }
    if (Build.VERSION.SDK_INT >= 29) {
        expectedSet.add("android.permission.ACCESS_MEDIA_LOCATION");
    }
    Apk apk = actualDetails.apks.get(1);
    Log.i(TAG, "APK: " + apk.apkName);
    HashSet<String> actualSet = new HashSet<>(Arrays.asList(apk.requestedPermissions));
    for (String permission : expectedSet) {
        if (!actualSet.contains(permission)) {
            Log.i(TAG, permission + " in expected but not actual! (android-" + Build.VERSION.SDK_INT + ")");
        }
    }
    for (String permission : actualSet) {
        if (!expectedSet.contains(permission)) {
            Log.i(TAG, permission + " in actual but not expected! (android-" + Build.VERSION.SDK_INT + ")");
        }
    }
    String[] expectedPermissions = expectedSet.toArray(new String[expectedSet.size()]);
    assertTrue(ApkVerifier.requestedPermissionsEqual(expectedPermissions, apk.requestedPermissions));
    expectedSet = new TreeSet<>(Arrays.asList("android.permission.ACCESS_NETWORK_STATE", "android.permission.ACCESS_WIFI_STATE", "android.permission.AUTHENTICATE_ACCOUNTS", "android.permission.GET_ACCOUNTS", "android.permission.INTERNET", "android.permission.MANAGE_ACCOUNTS", "android.permission.READ_CALENDAR", "android.permission.READ_CONTACTS", "android.permission.READ_EXTERNAL_STORAGE", "android.permission.READ_SYNC_SETTINGS", "android.permission.WRITE_CALENDAR", "android.permission.WRITE_CONTACTS", "android.permission.WRITE_EXTERNAL_STORAGE", "android.permission.WRITE_SYNC_SETTINGS", "org.dmfs.permission.READ_TASKS", "org.dmfs.permission.WRITE_TASKS"));
    if (Build.VERSION.SDK_INT >= 29) {
        expectedSet.add("android.permission.ACCESS_MEDIA_LOCATION");
    }
    expectedPermissions = expectedSet.toArray(new String[expectedSet.size()]);
    apk = actualDetails.apks.get(2);
    Log.i(TAG, "APK: " + apk.apkName);
    actualSet = new HashSet<>(Arrays.asList(apk.requestedPermissions));
    for (String permission : expectedSet) {
        if (!actualSet.contains(permission)) {
            Log.i(TAG, permission + " in expected but not actual! (android-" + Build.VERSION.SDK_INT + ")");
        }
    }
    for (String permission : actualSet) {
        if (!expectedSet.contains(permission)) {
            Log.i(TAG, permission + " in actual but not expected! (android-" + Build.VERSION.SDK_INT + ")");
        }
    }
    assertTrue(ApkVerifier.requestedPermissionsEqual(expectedPermissions, apk.requestedPermissions));
}
Also used : TreeSet(java.util.TreeSet) Apk(org.fdroid.fdroid.data.Apk) RepoDetails(org.fdroid.fdroid.mock.RepoDetails) HashSet(java.util.HashSet) FileCompatTest(org.fdroid.fdroid.compat.FileCompatTest) Test(org.junit.Test)

Example 53 with Apk

use of org.fdroid.fdroid.data.Apk in project fdroidclient by f-droid.

the class FileInstallerTest method testInstallOtaZip.

@Test
public void testInstallOtaZip() {
    Apk apk = new Apk();
    apk.apkName = "org.fdroid.fdroid.privileged.ota_2010.zip";
    apk.packageName = "org.fdroid.fdroid.privileged.ota";
    apk.versionCode = 2010;
    assertFalse(apk.isApk());
    Installer installer = InstallerFactory.create(context, apk);
    assertEquals("should be a FileInstaller", FileInstaller.class, installer.getClass());
}
Also used : Apk(org.fdroid.fdroid.data.Apk) Test(org.junit.Test)

Example 54 with Apk

use of org.fdroid.fdroid.data.Apk in project fdroidclient by f-droid.

the class AntiFeaturesTest method antiFeaturesSaveCorrectly.

@Test
public void antiFeaturesSaveCorrectly() {
    List<Apk> notVulnApks = ApkProvider.Helper.findByPackageName(context, notVuln.packageName);
    assertEquals(3, notVulnApks.size());
    List<Apk> allVulnApks = ApkProvider.Helper.findByPackageName(context, allVuln.packageName);
    assertEquals(3, allVulnApks.size());
    for (Apk apk : allVulnApks) {
        assertArrayEquals(new String[] { "KnownVuln", "ContainsGreenButtons" }, apk.antiFeatures);
    }
    List<Apk> vulnAtV2Apks = ApkProvider.Helper.findByPackageName(context, vulnAtV2.packageName);
    assertEquals(3, vulnAtV2Apks.size());
    for (Apk apk : vulnAtV2Apks) {
        if (apk.versionCode == 2) {
            assertArrayEquals(new String[] { "KnownVuln", "ContainsGreenButtons" }, apk.antiFeatures);
        } else {
            assertNull(apk.antiFeatures);
        }
    }
}
Also used : Apk(org.fdroid.fdroid.data.Apk) Test(org.junit.Test) FDroidProviderTest(org.fdroid.fdroid.data.FDroidProviderTest)

Example 55 with Apk

use of org.fdroid.fdroid.data.Apk in project fdroidclient by f-droid.

the class IndexV1Updater method processIndexV1.

/**
 * Parses the index and feeds it to the database via {@link Repo}, {@link App},
 * and {@link Apk} instances.  This uses {@link RepoPersister}  to add the apps
 * and packages to the database in {@link RepoPersister#saveToDb(App, List)}
 * to write the {@link Repo}, and commit the whole thing in
 * {@link RepoPersister#commit(ContentValues, long)}.  One confusing thing about this
 * whole process is that {@link RepoPersister} needs to first create and entry
 * in the database, then fetch the ID from the database to populate
 * {@link Repo#id}.  That has to happen first, then the rest of the {@code Repo}
 * data must be added later.
 *
 * @param indexInputStream {@link InputStream} to {@code index-v1.json}
 * @param etag             the {@code etag} value from HTTP headers
 * @throws IOException
 * @throws UpdateException
 */
public void processIndexV1(InputStream indexInputStream, JarEntry indexEntry, String etag) throws IOException, UpdateException {
    Utils.Profiler profiler = new Utils.Profiler(TAG);
    profiler.log("Starting to process index-v1.json");
    ObjectMapper mapper = getObjectMapperInstance(repo.getId());
    JsonFactory f = mapper.getFactory();
    JsonParser parser = f.createParser(indexInputStream);
    HashMap<String, Object> repoMap = null;
    App[] apps = null;
    Map<String, String[]> requests = null;
    Map<String, List<Apk>> packages = null;
    // go into the main object block
    parser.nextToken();
    while (true) {
        String fieldName = parser.nextFieldName();
        if (fieldName == null) {
            break;
        }
        switch(fieldName) {
            case "repo":
                repoMap = parseRepo(mapper, parser);
                break;
            case "requests":
                requests = parseRequests(mapper, parser);
                break;
            case "apps":
                apps = parseApps(mapper, parser);
                break;
            case "packages":
                packages = parsePackages(mapper, parser);
                break;
        }
    }
    // ensure resources get cleaned up timely and properly
    parser.close();
    profiler.log("Finished processing index-v1.json. Now verifying certificate...");
    if (repoMap == null) {
        return;
    }
    long timestamp = (Long) repoMap.get("timestamp") / 1000;
    if (repo.timestamp > timestamp) {
        throw new IndexUpdater.UpdateException(repo, "index.jar is older that current index! " + timestamp + " < " + repo.timestamp);
    }
    X509Certificate certificate = getSigningCertFromJar(indexEntry);
    verifySigningCertificate(certificate);
    profiler.log("Certificate verified. Now saving to database...");
    // timestamp is absolutely required
    repo.timestamp = timestamp;
    // below are optional, can be null
    repo.lastetag = etag;
    repo.name = getStringRepoValue(repoMap, "name");
    repo.icon = getStringRepoValue(repoMap, "icon");
    repo.description = getStringRepoValue(repoMap, "description");
    // ensure the canonical URL is included in the "mirrors" list as the first entry
    LinkedHashSet<String> mirrors = new LinkedHashSet<>();
    mirrors.add(repo.address);
    mirrors.addAll(getStringListRepoValue(repoMap, "mirrors"));
    repo.mirrors = mirrors.toArray(new String[mirrors.size()]);
    // below are optional, can be default value
    repo.maxage = getIntRepoValue(repoMap, "maxage");
    repo.version = getIntRepoValue(repoMap, "version");
    if (TextUtils.isEmpty(platformSigCache)) {
        PackageInfo androidPackageInfo = Utils.getPackageInfoWithSignatures(context, "android");
        platformSigCache = Utils.getPackageSig(androidPackageInfo);
    }
    RepoPersister repoPersister = new RepoPersister(context, repo);
    if (apps != null && apps.length > 0) {
        int appCount = 0;
        for (App app : apps) {
            appCount++;
            List<Apk> apks = null;
            if (packages != null) {
                apks = packages.get(app.packageName);
            }
            if (apks == null) {
                Log.i(TAG, "processIndexV1 empty packages");
                apks = new ArrayList<>(0);
            }
            if (apks.size() > 0) {
                app.preferredSigner = apks.get(0).sig;
                app.isApk = true;
                for (Apk apk : apks) {
                    if (!apk.isApk()) {
                        app.isApk = false;
                    } else if (apk.sig.equals(platformSigCache)) {
                        app.preferredSigner = platformSigCache;
                    }
                }
            }
            if (appCount % 50 == 0) {
                notifyProcessingApps(appCount, apps.length);
            }
            repoPersister.saveToDb(app, apks);
        }
    }
    profiler.log("Saved to database, but only a temporary table. Now persisting to database...");
    notifyCommittingToDb();
    ContentValues contentValues = new ContentValues();
    contentValues.put(Schema.RepoTable.Cols.LAST_UPDATED, Utils.formatTime(new Date(), ""));
    contentValues.put(Schema.RepoTable.Cols.TIMESTAMP, repo.timestamp);
    contentValues.put(Schema.RepoTable.Cols.LAST_ETAG, repo.lastetag);
    if (repo.version != Repo.INT_UNSET_VALUE) {
        contentValues.put(Schema.RepoTable.Cols.VERSION, repo.version);
    }
    if (repo.maxage != Repo.INT_UNSET_VALUE) {
        contentValues.put(Schema.RepoTable.Cols.MAX_AGE, repo.maxage);
    }
    if (repo.description != null) {
        contentValues.put(Schema.RepoTable.Cols.DESCRIPTION, repo.description);
    }
    if (repo.name != null) {
        contentValues.put(Schema.RepoTable.Cols.NAME, repo.name);
    }
    if (repo.icon != null) {
        contentValues.put(Schema.RepoTable.Cols.ICON, repo.icon);
    }
    if (repo.mirrors != null && repo.mirrors.length > 0) {
        contentValues.put(Schema.RepoTable.Cols.MIRRORS, Utils.serializeCommaSeparatedString(repo.mirrors));
    }
    repoPersister.commit(contentValues, repo.getId());
    profiler.log("Persisted to database.");
    if (repo.pushRequests == Repo.PUSH_REQUEST_ACCEPT_ALWAYS) {
        processRepoPushRequests(requests);
        Utils.debugLog(TAG, "Completed Repo Push Requests: " + requests);
    }
}
Also used : App(org.fdroid.fdroid.data.App) LinkedHashSet(java.util.LinkedHashSet) JsonFactory(com.fasterxml.jackson.core.JsonFactory) ArrayList(java.util.ArrayList) List(java.util.List) ObjectMapper(com.fasterxml.jackson.databind.ObjectMapper) JsonParser(com.fasterxml.jackson.core.JsonParser) RepoPersister(org.fdroid.fdroid.data.RepoPersister) ContentValues(android.content.ContentValues) PackageInfo(android.content.pm.PackageInfo) X509Certificate(java.security.cert.X509Certificate) Date(java.util.Date) TextUtils(android.text.TextUtils) FileUtils(org.apache.commons.io.FileUtils) Apk(org.fdroid.fdroid.data.Apk)

Aggregations

Apk (org.fdroid.fdroid.data.Apk)63 Test (org.junit.Test)17 Uri (android.net.Uri)16 File (java.io.File)12 Intent (android.content.Intent)11 App (org.fdroid.fdroid.data.App)10 Repo (org.fdroid.fdroid.data.Repo)10 ArrayList (java.util.ArrayList)8 PendingIntent (android.app.PendingIntent)7 Context (android.content.Context)7 PackageInfo (android.content.pm.PackageInfo)7 FileCompatTest (org.fdroid.fdroid.compat.FileCompatTest)7 BroadcastReceiver (android.content.BroadcastReceiver)6 PackageManager (android.content.pm.PackageManager)5 IOException (java.io.IOException)4 HashSet (java.util.HashSet)4 FDroidProviderTest (org.fdroid.fdroid.data.FDroidProviderTest)4 LocalBroadcastManager (androidx.localbroadcastmanager.content.LocalBroadcastManager)3 RepoDetails (org.fdroid.fdroid.mock.RepoDetails)3 SuppressLint (android.annotation.SuppressLint)2