diff --git a/app/src/main/java/org/fdroid/fdroid/#RepoUpdater.java# b/app/src/main/java/org/fdroid/fdroid/#RepoUpdater.java#
deleted file mode 100644
index 4f34ea06a..000000000
--- a/app/src/main/java/org/fdroid/fdroid/#RepoUpdater.java#
+++ /dev/null
@@ -1,397 +0,0 @@
-
-
-package org.belmarket.shop;
-
-import android.content.ContentValues;
-import android.content.Context;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.text.TextUtils;
-import android.util.Log;
-
-import org.belmarket.shop.data.Apk;
-import org.belmarket.shop.data.App;
-import org.belmarket.shop.data.Repo;
-import org.belmarket.shop.data.RepoPersister;
-import org.belmarket.shop.data.RepoProvider;
-import org.belmarket.shop.data.Schema.RepoTable;
-import org.belmarket.shop.net.Downloader;
-import org.belmarket.shop.net.DownloaderFactory;
-import org.xml.sax.InputSource;
-import org.xml.sax.SAXException;
-import org.xml.sax.XMLReader;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.security.CodeSigner;
-import java.security.cert.Certificate;
-import java.security.cert.X509Certificate;
-import java.util.Date;
-import java.util.List;
-import java.util.jar.JarEntry;
-import java.util.jar.JarFile;
-
-import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.parsers.SAXParser;
-import javax.xml.parsers.SAXParserFactory;
-
-/**
- * Responsible for updating an individual repository. This will:
- * * Download the index.jar
- * * Verify that it is signed correctly and by the correct certificate
- * * Parse the index.xml from the .jar file
- * * Save the resulting repo, apps, and apks to the database.
- *
- * WARNING: this class is the central piece of the entire security model of
- * FDroid! Avoid modifying it when possible, if you absolutely must, be very,
- * very careful with the changes that you are making!
- */
-public class RepoUpdater {
-
- private static final String TAG = "RepoUpdater";
-
- private final String indexUrl;
-
- @NonNull
- private final Context context;
- @NonNull
- private final Repo repo;
- private boolean hasChanged;
-
- @Nullable
- private ProgressListener downloadProgressListener;
- private ProgressListener committingProgressListener;
- private ProgressListener processXmlProgressListener;
- private String cacheTag;
- private X509Certificate signingCertFromJar;
-
- @NonNull private final RepoPersister persister;
-
- /**
- * Updates an app repo as read out of the database into a {@link Repo} instance.
- *
- * @param repo A {@link Repo} read out of the local database
- */
- public RepoUpdater(@NonNull Context context, @NonNull Repo repo) {
- this.context = context;
- this.repo = repo;
- this.persister = new RepoPersister(context, repo);
-
- String url = repo.address + "/index.jar";
- String versionName = Utils.getVersionName(context);
- if (versionName != null) {
- url += "?client_version=" + versionName;
- }
- this.indexUrl = url;
- }
-
- public void setDownloadProgressListener(ProgressListener progressListener) {
- this.downloadProgressListener = progressListener;
- }
-
- public void setProcessXmlProgressListener(ProgressListener progressListener) {
- this.processXmlProgressListener = progressListener;
- }
-
- public void setCommittingProgressListener(ProgressListener progressListener) {
- this.committingProgressListener = progressListener;
- }
-
- public boolean hasChanged() {
- return hasChanged;
- }
-
- private Downloader downloadIndex() throws UpdateException {
- Downloader downloader = null;
- try {
- downloader = DownloaderFactory.create(context, indexUrl);
- downloader.setCacheTag(repo.lastetag);
- downloader.setListener(downloadProgressListener);
- downloader.download();
-
- if (downloader.isCached()) {
- // The index is unchanged since we last read it. We just mark
- // everything that came from this repo as being updated.
- Utils.debugLog(TAG, "Repo index for " + indexUrl + " is up to date (by etag)");
- }
-
- } catch (IOException e) {
- if (downloader != null && downloader.outputFile != null) {
- if (!downloader.outputFile.delete()) {
- Log.w(TAG, "Couldn't delete file: " + downloader.outputFile.getAbsolutePath());
- }
- }
-
- throw new UpdateException(repo, "Error getting index file", e);
- } catch (InterruptedException e) {
- // ignored if canceled, the local database just won't be updated
- e.printStackTrace();
- }
- return downloader;
- }
-
- /**
- * All repos are represented by a signed jar file, {@code index.jar}, which contains
- * a single file, {@code index.xml}. This takes the {@code index.jar}, verifies the
- * signature, then returns the unzipped {@code index.xml}.
- *
- * @throws UpdateException All error states will come from here.
- */
- public void update() throws UpdateException {
-
- final Downloader downloader = downloadIndex();
- hasChanged = downloader.hasChanged();
-
- if (hasChanged) {
- // Don't worry about checking the status code for 200. If it was a
- // successful download, then we will have a file ready to use:
- cacheTag = downloader.getCacheTag();
- processDownloadedFile(downloader.outputFile);
- }
- }
-
- private ContentValues repoDetailsToSave;
- private String signingCertFromIndexXml;
-
- private RepoXMLHandler.IndexReceiver createIndexReceiver() {
- return new RepoXMLHandler.IndexReceiver() {
- @Override
- public void receiveRepo(String name, String description, String signingCert, int maxAge, int version, long timestamp) {
- signingCertFromIndexXml = signingCert;
- repoDetailsToSave = prepareRepoDetailsForSaving(name, description, maxAge, version, timestamp);
- }
-
- @Override
- public void receiveApp(App app, List packages) {
- try {
- persister.saveToDb(app, packages);
- } catch (UpdateException e) {
- throw new RuntimeException("Error while saving repo details to database.", e);
- }
- }
- };
- }
-
- public void processDownloadedFile(File downloadedFile) throws UpdateException {
- InputStream indexInputStream = null;
- try {
- if (downloadedFile == null || !downloadedFile.exists()) {
- throw new UpdateException(repo, downloadedFile + " does not exist!");
- }
-
- // Due to a bug in Android 5.0 Lollipop, the inclusion of spongycastle causes
- // breakage when verifying the signature of the downloaded .jar. For more
- // details, check out https://gitlab.com/fdroid/fdroidclient/issues/111.
- FDroidApp.disableSpongyCastleOnLollipop();
-
- JarFile jarFile = new JarFile(downloadedFile, true);
- JarEntry indexEntry = (JarEntry) jarFile.getEntry("index.xml");
- indexInputStream = new ProgressBufferedInputStream(jarFile.getInputStream(indexEntry),
- processXmlProgressListener, new URL(repo.address), (int) indexEntry.getSize());
-
- // Process the index...
- SAXParserFactory factory = SAXParserFactory.newInstance();
- factory.setNamespaceAware(true);
- final SAXParser parser = factory.newSAXParser();
- final XMLReader reader = parser.getXMLReader();
- final RepoXMLHandler repoXMLHandler = new RepoXMLHandler(repo, createIndexReceiver());
- reader.setContentHandler(repoXMLHandler);
- reader.parse(new InputSource(indexInputStream));
-
- long timestamp = repoDetailsToSave.getAsLong(RepoTable.Cols.TIMESTAMP);
- if (timestamp < repo.timestamp) {
- throw new UpdateException(repo, "index.jar is older that current index! "
- + timestamp + " < " + repo.timestamp);
- }
-
- signingCertFromJar = getSigningCertFromJar(indexEntry);
-
- // JarEntry can only read certificates after the file represented by that JarEntry
- // has been read completely, so verification cannot run until now...
- assertSigningCertFromXmlCorrect();
- commitToDb();
- } catch (SAXException | ParserConfigurationException | IOException e) {
- throw new UpdateException(repo, "Error parsing index", e);
- } finally {
- FDroidApp.enableSpongyCastleOnLollipop();
- Utils.closeQuietly(indexInputStream);
- if (downloadedFile != null) {
- if (!downloadedFile.delete()) {
- Log.w(TAG, "Couldn't delete file: " + downloadedFile.getAbsolutePath());
- }
- }
- }
- }
-
- private void commitToDb() throws UpdateException {
- Log.i(TAG, "Repo signature verified, saving app metadata to database.");
- if (committingProgressListener != null) {
- try {
- //TODO this should be an event, not a progress listener
- committingProgressListener.onProgress(new URL(indexUrl), 0, -1);
- } catch (MalformedURLException e) {
- e.printStackTrace();
- }
- }
- persister.commit(repoDetailsToSave);
- }
-
- private void assertSigningCertFromXmlCorrect() throws SigningException {
-
- // no signing cert read from database, this is the first use
- if (repo.signingCertificate == null) {
- verifyAndStoreTOFUCerts(signingCertFromIndexXml, signingCertFromJar);
- }
- verifyCerts(signingCertFromIndexXml, signingCertFromJar);
-
- }
-
- /**
- * Update tracking data for the repo represented by this instance (index version, etag,
- * description, human-readable name, etc.
- */
- private ContentValues prepareRepoDetailsForSaving(String name, String description, int maxAge, int version, long timestamp) {
- ContentValues values = new ContentValues();
-
- values.put(RepoTable.Cols.LAST_UPDATED, Utils.formatTime(new Date(), ""));
-
- if (repo.lastetag == null || !repo.lastetag.equals(cacheTag)) {
- values.put(RepoTable.Cols.LAST_ETAG, cacheTag);
- }
-
- if (version != -1 && version != repo.version) {
- Utils.debugLog(TAG, "Repo specified a new version: from " + repo.version + " to " + version);
- values.put(RepoTable.Cols.VERSION, version);
- }
-
- if (maxAge != -1 && maxAge != repo.maxage) {
- Utils.debugLog(TAG, "Repo specified a new maximum age - updated");
- values.put(RepoTable.Cols.MAX_AGE, maxAge);
- }
-
- if (description != null && !description.equals(repo.description)) {
- values.put(RepoTable.Cols.DESCRIPTION, description);
- }
-
- if (name != null && !name.equals(repo.name)) {
- values.put(RepoTable.Cols.NAME, name);
- }
-
- if (timestamp != repo.timestamp) {
- values.put(RepoTable.Cols.TIMESTAMP, timestamp);
- }
-
- return values;
- }
-
- public static class UpdateException extends Exception {
-
- private static final long serialVersionUID = -4492452418826132803L;
- public final Repo repo;
-
- public UpdateException(Repo repo, String message) {
- super(message);
- this.repo = repo;
- }
-
- public UpdateException(Repo repo, String message, Exception cause) {
- super(message, cause);
- this.repo = repo;
- }
- }
-
- public static class SigningException extends UpdateException {
- public SigningException(Repo repo, String message) {
- super(repo, "Repository was not signed correctly: " + message);
- }
- }
-
- /**
- * FDroid's index.jar is signed using a particular format and does not allow lots of
- * signing setups that would be valid for a regular jar. This validates those
- * restrictions.
- */
- private X509Certificate getSigningCertFromJar(JarEntry jarEntry) throws SigningException {
- final CodeSigner[] codeSigners = jarEntry.getCodeSigners();
- if (codeSigners == null || codeSigners.length == 0) {
- throw new SigningException(repo, "No signature found in index");
- }
- /* we could in theory support more than 1, but as of now we do not */
- if (codeSigners.length > 1) {
- throw new SigningException(repo, "index.jar must be signed by a single code signer!");
- }
- List extends Certificate> certs = codeSigners[0].getSignerCertPath().getCertificates();
- if (certs.size() != 1) {
- throw new SigningException(repo, "index.jar code signers must only have a single certificate!");
- }
- return (X509Certificate) certs.get(0);
- }
-
- /**
- * A new repo can be added with or without the fingerprint of the signing
- * certificate. If no fingerprint is supplied, then do a pure TOFU and just
- * store the certificate as valid. If there is a fingerprint, then first
- * check that the signing certificate in the jar matches that fingerprint.
- */
- private void verifyAndStoreTOFUCerts(String certFromIndexXml, X509Certificate rawCertFromJar)
- throws SigningException {
- if (repo.signingCertificate != null) {
- return; // there is a repo.signingCertificate already, nothing to TOFU
- }
-
- /* The first time a repo is added, it can be added with the signing certificate's
- * fingerprint. In that case, check that fingerprint against what is
- * actually in the index.jar itself. If no fingerprint, just store the
- * signing certificate */
- if (repo.fingerprint != null) {
- String fingerprintFromIndexXml = Utils.calcFingerprint(certFromIndexXml);
- String fingerprintFromJar = Utils.calcFingerprint(rawCertFromJar);
- if (!repo.fingerprint.equalsIgnoreCase(fingerprintFromIndexXml)
- || !repo.fingerprint.equalsIgnoreCase(fingerprintFromJar)) {
- throw new SigningException(repo, "Supplied certificate fingerprint does not match!");
- }
- } // else - no info to check things are valid, so just Trust On First Use
-
- Utils.debugLog(TAG, "Saving new signing certificate in the database for " + repo.address);
- ContentValues values = new ContentValues(2);
- values.put(RepoTable.Cols.LAST_UPDATED, Utils.formatDate(new Date(), ""));
- values.put(RepoTable.Cols.SIGNING_CERT, Hasher.hex(rawCertFromJar));
- RepoProvider.Helper.update(context, repo, values);
- }
-
- /**
- * FDroid works with three copies of the signing certificate:
- * in the downloaded jar
- * in the index XML
- * stored in the local database
- * It would work better removing the copy from the index XML, but it needs to stay
- * there for backwards compatibility since the old TOFU process requires it. Therefore,
- * since all three have to be present, all three are compared.
- *
- * @param certFromIndexXml the cert written into the header of the index XML
- * @param rawCertFromJar the {@link X509Certificate} embedded in the downloaded jar
- */
- private void verifyCerts(String certFromIndexXml, X509Certificate rawCertFromJar) throws SigningException {
- // convert binary data to string version that is used in FDroid's database
- String certFromJar = Hasher.hex(rawCertFromJar);
-
- // repo and repo.signingCertificate must be pre-loaded from the database
- if (TextUtils.isEmpty(repo.signingCertificate)
- || TextUtils.isEmpty(certFromJar)
- || TextUtils.isEmpty(certFromIndexXml)) {
- throw new SigningException(repo, "A empty repo or signing certificate is invalid!");
- }
-
- // though its called repo.signingCertificate, its actually a X509 certificate
- if (repo.signingCertificate.equals(certFromJar)
- && repo.signingCertificate.equals(certFromIndexXml)
- && certFromIndexXml.equals(certFromJar)) {
- return; // we have a match!
- }
- throw new SigningException(repo, "Signing certificate does not match!");
- }
-
-}
diff --git a/app/src/main/java/org/fdroid/fdroid/#RepoXMLHandler.java# b/app/src/main/java/org/fdroid/fdroid/#RepoXMLHandler.java#
deleted file mode 100644
index 9aed07bcd..000000000
--- a/app/src/main/java/org/fdroid/fdroid/#RepoXMLHandler.java#
+++ /dev/null
@@ -1,307 +0,0 @@
-/*
- * Copyright (C) 2010-12 Ciaran Gultnieks, ciaran@ciarang.com
- * Copyright (C) 2009 Roberto Jacinto, roberto.jacinto@caixamagica.pt
- *
- * 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, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-package org.belmarket.shop;
-
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-
-import org.belmarket.shop.data.Apk;
-import org.belmarket.shop.data.App;
-import org.belmarket.shop.data.Repo;
-import org.xml.sax.Attributes;
-import org.xml.sax.SAXException;
-import org.xml.sax.helpers.DefaultHandler;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Parses the index.xml into Java data structures.
- */
-public class RepoXMLHandler extends DefaultHandler {
-
- // The repo we're processing.
- private final Repo repo;
-
- private List apksList = new ArrayList<>();
-
- private App curapp;
- private Apk curapk;
-
- private String currentApkHashType;
-
- // After processing the XML, these will be -1 if the index didn't specify
- // them - otherwise it will be the value specified.
- private int repoMaxAge = -1;
- private int repoVersion;
- private long repoTimestamp;
- private String repoDescription;
- private String repoName;
-
- // the X.509 signing certificate stored in the header of index.xml
- private String repoSigningCert;
-
- private final StringBuilder curchars = new StringBuilder();
-
- interface IndexReceiver {
- void receiveRepo(String name, String description, String signingCert, int maxage, int version, long timestamp);
-
- void receiveApp(App app, List packages);
- }
-
- private final IndexReceiver receiver;
-
- public RepoXMLHandler(Repo repo, @NonNull IndexReceiver receiver) {
- this.repo = repo;
- this.receiver = receiver;
- }
-
- @Override
- public void characters(char[] ch, int start, int length) {
- curchars.append(ch, start, length);
- }
-
- @Override
- public void endElement(String uri, String localName, String qName)
- throws SAXException {
-
- if ("application".equals(localName) && curapp != null) {
- onApplicationParsed();
- } else if ("package".equals(localName) && curapk != null && curapp != null) {
- apksList.add(curapk);
- curapk = null;
- } else if ("repo".equals(localName)) {
- onRepoParsed();
- } else if (curchars.length() == 0) {
- // All options below require non-empty content
- return;
- }
- final String str = curchars.toString().trim();
- if (curapk != null) {
- switch (localName) {
- case "version":
- curapk.versionName = str;
- break;
- case "versioncode":
- curapk.versionCode = Utils.parseInt(str, -1);
- break;
- case "size":
- curapk.size = Utils.parseInt(str, 0);
- break;
- case "hash":
- if (currentApkHashType == null || "md5".equals(currentApkHashType)) {
- if (curapk.hash == null) {
- curapk.hash = str;
- curapk.hashType = "SHA-256";
- }
- } else if ("sha256".equals(currentApkHashType)) {
- curapk.hash = str;
- curapk.hashType = "SHA-256";
- }
- break;
- case "sig":
- curapk.sig = str;
- break;
- case "srcname":
- curapk.srcname = str;
- break;
- case "apkname":
- curapk.apkName = str;
- break;
- case "sdkver":
- curapk.minSdkVersion = Utils.parseInt(str, Apk.SDK_VERSION_MIN_VALUE);
- break;
- case "targetSdkVersion":
- curapk.targetSdkVersion = Utils.parseInt(str, Apk.SDK_VERSION_MIN_VALUE);
- break;
- case "maxsdkver":
- curapk.maxSdkVersion = Utils.parseInt(str, Apk.SDK_VERSION_MAX_VALUE);
- if (curapk.maxSdkVersion == 0) {
- // before fc0df0dcf4dd0d5f13de82d7cd9254b2b48cb62d, this could be 0
- curapk.maxSdkVersion = Apk.SDK_VERSION_MAX_VALUE;
- }
- break;
- case "added":
- curapk.added = Utils.parseDate(str, null);
- break;
- case "permissions":
- curapk.permissions = Utils.parseCommaSeparatedString(str);
- break;
- case "features":
- curapk.features = Utils.parseCommaSeparatedString(str);
- break;
- case "nativecode":
- curapk.nativecode = Utils.parseCommaSeparatedString(str);
- break;
- }
- } else if (curapp != null) {
- switch (localName) {
- case "name":
- curapp.name = str;
- break;
- case "icon":
- curapp.icon = str;
- break;
- case "description":
- // This is the old-style description. We'll read it
- // if present, to support old repos, but in newer
- // repos it will get overwritten straight away!
- curapp.description = "" + str + "
";
- break;
- case "desc":
- // New-style description.
- curapp.description = str;
- break;
- case "summary":
- curapp.summary = str;
- break;
- case "license":
- curapp.license = str;
- break;
- case "author":
- curapp.author = str;
- break;
- case "email":
- curapp.email = str;
- break;
- case "source":
- curapp.sourceURL = str;
- break;
- case "changelog":
- curapp.changelogURL = str;
- break;
- case "donate":
- curapp.donateURL = str;
- break;
- case "bitcoin":
- curapp.bitcoinAddr = str;
- break;
- case "litecoin":
- curapp.litecoinAddr = str;
- break;
- case "flattr":
- curapp.flattrID = str;
- break;
- case "web":
- curapp.webURL = str;
- break;
- case "tracker":
- curapp.trackerURL = str;
- break;
- case "added":
- curapp.added = Utils.parseDate(str, null);
- break;
- case "lastupdated":
- curapp.lastUpdated = Utils.parseDate(str, null);
- break;
- case "marketversion":
- curapp.upstreamVersionName = str;
- break;
- case "marketvercode":
- curapp.upstreamVersionCode = Utils.parseInt(str, -1);
- break;
- case "categories":
- curapp.categories = Utils.parseCommaSeparatedString(str);
- break;
- case "antifeatures":
- curapp.antiFeatures = Utils.parseCommaSeparatedString(str);
- break;
- case "requirements":
- curapp.requirements = Utils.parseCommaSeparatedString(str);
- break;
- }
- } else if ("description".equals(localName)) {
- repoDescription = cleanWhiteSpace(str);
- }
- }
-
- private void onApplicationParsed() {
- receiver.receiveApp(curapp, apksList);
- curapp = null;
- apksList = new ArrayList<>();
- // If the app packageName is already present in this apps list, then it
- // means the same index file has a duplicate app, which should
- // not be allowed.
- // However, I'm thinking that it should be undefined behaviour,
- // because it is probably a bug in the fdroid server that made it
- // happen, and I don't *think* it will crash the client, because
- // the first app will insert, the second one will update the newly
- // inserted one.
-
- //////#TODO
-
- /*
-
- sample this as a xml handlers
- should add screen shot id the project as it be
- and also there is no way to contact developer
- another is to create a place to collect userr data and vote for a package
-
- */
- }
-
- private void onRepoParsed() {
- receiver.receiveRepo(repoName, repoDescription, repoSigningCert, repoMaxAge, repoVersion, repoTimestamp);
- }
-
- @Override
- public void startElement(String uri, String localName, String qName,
- Attributes attributes) throws SAXException {
- super.startElement(uri, localName, qName, attributes);
-
- if ("repo".equals(localName)) {
- repoSigningCert = attributes.getValue("", "pubkey");
- repoMaxAge = Utils.parseInt(attributes.getValue("", "maxage"), -1);
- repoVersion = Utils.parseInt(attributes.getValue("", "version"), -1);
- repoName = cleanWhiteSpace(attributes.getValue("", "name"));
- repoDescription = cleanWhiteSpace(attributes.getValue("", "description"));
- repoTimestamp = parseLong(attributes.getValue("", "timestamp"), 0);
- } else if ("application".equals(localName) && curapp == null) {
- curapp = new App();
- curapp.packageName = attributes.getValue("", "id");
- } else if ("package".equals(localName) && curapp != null && curapk == null) {
- curapk = new Apk();
- curapk.packageName = curapp.packageName;
- curapk.repo = repo.getId();
- currentApkHashType = null;
-
- } else if ("hash".equals(localName) && curapk != null) {
- currentApkHashType = attributes.getValue("", "type");
- }
- curchars.setLength(0);
- }
-
- private static String cleanWhiteSpace(@Nullable String str) {
- return str == null ? null : str.replaceAll("\\s", " ");
- }
-
- private static long parseLong(String str, long fallback) {
- if (str == null || str.length() == 0) {
- return fallback;
- }
- long result;
- try {
- result = Long.parseLong(str);
- } catch (NumberFormatException e) {
- result = fallback;
- }
- return result;
- }
-}
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index 2d6cb5fac..8045bbac2 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -6,7 +6,7 @@
#ffdd2c00
#ffdd2c00
- #ff0d47a1
+ #9e1010
#ff042570
#ff8ab000
#ff222222
diff --git a/app/src/main/res/values/default_repos.xml b/app/src/main/res/values/default_repos.xml
index 3a895f579..6547c7ef0 100644
--- a/app/src/main/res/values/default_repos.xml
+++ b/app/src/main/res/values/default_repos.xml
@@ -4,13 +4,12 @@
- - F-Droid
+ - BelMarket
- - https://f-droid.org/repo
+ - https://shop.belmarket.ir/
- - The official F-Droid repository. Applications in this repository are mostly built
- directory from the source code. Some are official binaries built by the original
- application developers - these will be replaced by source-built versions over time.
+
-
+ مخزن رسمی بِلمارکت ساخته شده از آخرین نسخهٔ سورسکد نرمافزارها
- 13
@@ -22,71 +21,28 @@
- ignore
-
- 3082035e30820246a00302010202044c49cd00300d06092a864886f70d01010505003071310b300906035504061302554b3110300e06035504081307556e6b6e6f776e3111300f0603550407130857657468657262793110300e060355040a1307556e6b6e6f776e3110300e060355040b1307556e6b6e6f776e311930170603550403131043696172616e2047756c746e69656b73301e170d3130303732333137313032345a170d3337313230383137313032345a3071310b300906035504061302554b3110300e06035504081307556e6b6e6f776e3111300f0603550407130857657468657262793110300e060355040a1307556e6b6e6f776e3110300e060355040b1307556e6b6e6f776e311930170603550403131043696172616e2047756c746e69656b7330820122300d06092a864886f70d01010105000382010f003082010a028201010096d075e47c014e7822c89fd67f795d23203e2a8843f53ba4e6b1bf5f2fd0e225938267cfcae7fbf4fe596346afbaf4070fdb91f66fbcdf2348a3d92430502824f80517b156fab00809bdc8e631bfa9afd42d9045ab5fd6d28d9e140afc1300917b19b7c6c4df4a494cf1f7cb4a63c80d734265d735af9e4f09455f427aa65a53563f87b336ca2c19d244fcbba617ba0b19e56ed34afe0b253ab91e2fdb1271f1b9e3c3232027ed8862a112f0706e234cf236914b939bcf959821ecb2a6c18057e070de3428046d94b175e1d89bd795e535499a091f5bc65a79d539a8d43891ec504058acb28c08393b5718b57600a211e803f4a634e5c57f25b9b8c4422c6fd90203010001300d06092a864886f70d0101050500038201010008e4ef699e9807677ff56753da73efb2390d5ae2c17e4db691d5df7a7b60fc071ae509c5414be7d5da74df2811e83d3668c4a0b1abc84b9fa7d96b4cdf30bba68517ad2a93e233b042972ac0553a4801c9ebe07bf57ebe9a3b3d6d663965260e50f3b8f46db0531761e60340a2bddc3426098397fda54044a17e5244549f9869b460ca5e6e216b6f6a2db0580b480ca2afe6ec6b46eedacfa4aa45038809ece0c5978653d6c85f678e7f5a2156d1bedd8117751e64a4b0dcd140f3040b021821a8d93aed8d01ba36db6c82372211fed714d9a32607038cdfd565bd529ffc637212aaa2c224ef22b603eccefb5bf1e085c191d4b24fe742b17ab3f55d4e6f05ef
+ 308204f1308202d9a003020102020430b0c5af300d06092a864886f70d01010b050030293110300e060355040b1307462d44726f6964311530130603550403130c4275696c642d536572766572301e170d3136303832323035313132355a170d3434303130383035313132355a30293110300e060355040b1307462d44726f6964311530130603550403130c4275696c642d53657276657230820222300d06092a864886f70d01010105000382020f003082020a028202010099c822a51e759fbcc83561cd415b99b679de2521c679b5929ba9ed5fd85ebf8c7b22567b1c9b44a8c863ad066f1df2b78ef99bb0e3fbc6f904a5cc146d3fd1a06fe696c04aab97dac037956743b9e26f32a4fa4280e23cadd1042f17caad7837af946307c369cf3bbef4cf9ae5ff4fff06979fc7229464d030ea7f6f0bd720c8b84c8f398cf3cb750a788a6b0a0a6954f2b47a325ee30be3062645f41dedc67ce95614626d625b0072fd8560e856f83da5cb3d65efe048b86ddbd9c828e316bc554ec7cb9d2608f1d71aa1ebc18d08525675627b53ec2966e8eae4e79a659b196bce20721b5652b7ce1c0e2130d5ddb1a52718652721fc67ebfbfa6b54dfaca64bb7d5c02fcdbdcd5cc912f4b751db2573545b5d3b67f6338d2513b6b1f12054591d6b3fb4f22c6aadfe50a4077ed9c92ac99dbca9c4380a86cb534ce6a315a30f6b65b6b8dd0aa2df6b416b868323c05929c24324024933160ca620931099de010a308196811106d958cbae02554af2a2b2883e56753a975e2ac2ae351923a80871d445495f9e86f40d308eb1000bf173264ca9ed774caf0d7c6ab48512b7cffe8c20982d196cd04c285c06a6dccb1b7d26c79bbb4603f297c3fc128776751cfa97de6af4ef90266e81c667ede0a8a8feb9ba1645e517c7f98695a85ef773d618d35c07ec597c64c1c461510db7da8172ed2769ce92dc2658aa00f6e02a28f30203010001a321301f301d0603551d0e041604145e653e4723c8cbbb83b615a95728266944a0a396300d06092a864886f70d01010b050003820201006589602a0ffa7131f21d57a5354b3e22f988852508332cd05dec3673c9ce955834829aec6ae1f58304e8cef7d5707e8340c5d370f640b1b6b5c2c46d3aace0f1568d1951148b76205cd72c66870449c3e75d2ce748463d459b568f3cf8d4c1719c11a3e0d039105f2c6750821954be5c40887af6ca800a39b77a4db1f2038c9f98cc1c5a5382ff136e9a708c17333d43400fc0f14f2ebc56442565aa95e84e224dcb665faedc92be8c9449c594668cef78018bae5c86f57ed00926afeada8e0a42bbc02ee4dc069b92f43b4679288a755401e1d733d1146abcc0574d39cd4c057f1edb23d17411d6495712b604f9e88073ffab6bb05c73e685b5d47eab1bcbb433719cc36b3bb024c993a3da85334774bac4ba18963f237dcf5d2ecd663700b76352b5347206bcf1635135c9694cf9ce8d75b37642792b08be56e3b13dde797a6642368a2203e0dd013f533edd73816c8bc61aea1f121c3bb210571cac50005b4b234d6d30d5e48b6292b0e5774d23da036639ef1bc4070fb33461f07892bcf3fbb5d8ba5b8e23a945774da3d618d1b6ba59e262bf1f5b71dbce11da59cf05e979a1bf4d62805c9c2a88cb7155075d14c9264b29ec122b76cff78e88ab9035b5a4540c0f3cc2339fc2ec5928f5ffa3a17f6bc6fdcc92ac89b55d29525206c74a9281ab91da24f3db5c46882476caa8dc6eed9a22624c25907990b48953b730bf
- - F-Droid Archive
+ - Belmarket Binary repo
- - https://f-droid.org/archive
+ - https://bin.belmarket.ir/
- - The archive repository of the F-Droid client. This contains older versions of
- applications from the main repository.
+
-
+ مخزن دودویی بِل مارکت، ساخته شده توسط فایلهای نصبی سیستمعامل
- - 13
+ - 12
- - 0
+ - 1
- 2
- ignore
-
- 3082035e30820246a00302010202044c49cd00300d06092a864886f70d01010505003071310b300906035504061302554b3110300e06035504081307556e6b6e6f776e3111300f0603550407130857657468657262793110300e060355040a1307556e6b6e6f776e3110300e060355040b1307556e6b6e6f776e311930170603550403131043696172616e2047756c746e69656b73301e170d3130303732333137313032345a170d3337313230383137313032345a3071310b300906035504061302554b3110300e06035504081307556e6b6e6f776e3111300f0603550407130857657468657262793110300e060355040a1307556e6b6e6f776e3110300e060355040b1307556e6b6e6f776e311930170603550403131043696172616e2047756c746e69656b7330820122300d06092a864886f70d01010105000382010f003082010a028201010096d075e47c014e7822c89fd67f795d23203e2a8843f53ba4e6b1bf5f2fd0e225938267cfcae7fbf4fe596346afbaf4070fdb91f66fbcdf2348a3d92430502824f80517b156fab00809bdc8e631bfa9afd42d9045ab5fd6d28d9e140afc1300917b19b7c6c4df4a494cf1f7cb4a63c80d734265d735af9e4f09455f427aa65a53563f87b336ca2c19d244fcbba617ba0b19e56ed34afe0b253ab91e2fdb1271f1b9e3c3232027ed8862a112f0706e234cf236914b939bcf959821ecb2a6c18057e070de3428046d94b175e1d89bd795e535499a091f5bc65a79d539a8d43891ec504058acb28c08393b5718b57600a211e803f4a634e5c57f25b9b8c4422c6fd90203010001300d06092a864886f70d0101050500038201010008e4ef699e9807677ff56753da73efb2390d5ae2c17e4db691d5df7a7b60fc071ae509c5414be7d5da74df2811e83d3668c4a0b1abc84b9fa7d96b4cdf30bba68517ad2a93e233b042972ac0553a4801c9ebe07bf57ebe9a3b3d6d663965260e50f3b8f46db0531761e60340a2bddc3426098397fda54044a17e5244549f9869b460ca5e6e216b6f6a2db0580b480ca2afe6ec6b46eedacfa4aa45038809ece0c5978653d6c85f678e7f5a2156d1bedd8117751e64a4b0dcd140f3040b021821a8d93aed8d01ba36db6c82372211fed714d9a32607038cdfd565bd529ffc637212aaa2c224ef22b603eccefb5bf1e085c191d4b24fe742b17ab3f55d4e6f05ef
-
-
-
- - Guardian Project
-
- - https://guardianproject.info/fdroid/repo
-
- - The official app repository of The Guardian Project. Applications in this repository
- are official binaries build by the original application developers and signed by the
- same key as the APKs that are released in the Google Play store.
-
-
- - 13
-
- - 0
-
- - 3
-
- - ignore
-
- -
- 308205d8308203c0020900a397b4da7ecda034300d06092a864886f70d01010505003081ad310b30090603550406130255533111300f06035504080c084e657720596f726b3111300f06035504070c084e657720596f726b31143012060355040b0c0b4644726f6964205265706f31193017060355040a0c10477561726469616e2050726f6a656374311d301b06035504030c14677561726469616e70726f6a6563742e696e666f3128302606092a864886f70d0109011619726f6f7440677561726469616e70726f6a6563742e696e666f301e170d3134303632363139333931385a170d3431313131303139333931385a3081ad310b30090603550406130255533111300f06035504080c084e657720596f726b3111300f06035504070c084e657720596f726b31143012060355040b0c0b4644726f6964205265706f31193017060355040a0c10477561726469616e2050726f6a656374311d301b06035504030c14677561726469616e70726f6a6563742e696e666f3128302606092a864886f70d0109011619726f6f7440677561726469616e70726f6a6563742e696e666f30820222300d06092a864886f70d01010105000382020f003082020a0282020100b3cd79121b9b883843be3c4482e320809106b0a23755f1dd3c7f46f7d315d7bb2e943486d61fc7c811b9294dcc6b5baac4340f8db2b0d5e14749e7f35e1fc211fdbc1071b38b4753db201c314811bef885bd8921ad86facd6cc3b8f74d30a0b6e2e6e576f906e9581ef23d9c03e926e06d1f033f28bd1e21cfa6a0e3ff5c9d8246cf108d82b488b9fdd55d7de7ebb6a7f64b19e0d6b2ab1380a6f9d42361770d1956701a7f80e2de568acd0bb4527324b1e0973e89595d91c8cc102d9248525ae092e2c9b69f7414f724195b81427f28b1d3d09a51acfe354387915fd9521e8c890c125fc41a12bf34d2a1b304067ab7251e0e9ef41833ce109e76963b0b256395b16b886bca21b831f1408f836146019e7908829e716e72b81006610a2af08301de5d067c9e114a1e5759db8a6be6a3cc2806bcfe6fafd41b5bc9ddddb3dc33d6f605b1ca7d8a9e0ecdd6390d38906649e68a90a717bea80fa220170eea0c86fc78a7e10dac7b74b8e62045a3ecca54e035281fdc9fe5920a855fde3c0be522e3aef0c087524f13d973dff3768158b01a5800a060c06b451ec98d627dd052eda804d0556f60dbc490d94e6e9dea62ffcafb5beffbd9fc38fb2f0d7050004fe56b4dda0a27bc47554e1e0a7d764e17622e71f83a475db286bc7862deee1327e2028955d978272ea76bf0b88e70a18621aba59ff0c5993ef5f0e5d6b6b98e68b70203010001300d06092a864886f70d0101050500038202010079c79c8ef408a20d243d8bd8249fb9a48350dc19663b5e0fce67a8dbcb7de296c5ae7bbf72e98a2020fb78f2db29b54b0e24b181aa1c1d333cc0303685d6120b03216a913f96b96eb838f9bff125306ae3120af838c9fc07ebb5100125436bd24ec6d994d0bff5d065221871f8410daf536766757239bf594e61c5432c9817281b985263bada8381292e543a49814061ae11c92a316e7dc100327b59e3da90302c5ada68c6a50201bda1fcce800b53f381059665dbabeeb0b50eb22b2d7d2d9b0aa7488ca70e67ac6c518adb8e78454a466501e89d81a45bf1ebc350896f2c3ae4b6679ecfbf9d32960d4f5b493125c7876ef36158562371193f600bc511000a67bdb7c664d018f99d9e589868d103d7e0994f166b2ba18ff7e67d8c4da749e44dfae1d930ae5397083a51675c409049dfb626a96246c0015ca696e94ebb767a20147834bf78b07fece3f0872b057c1c519ff882501995237d8206b0b3832f78753ebd8dcbd1d3d9f5ba733538113af6b407d960ec4353c50eb38ab29888238da843cd404ed8f4952f59e4bbc0035fc77a54846a9d419179c46af1b4a3b7fc98e4d312aaa29b9b7d79e739703dc0fa41c7280d5587709277ffa11c3620f5fba985b82c238ba19b17ebd027af9424be0941719919f620dd3bb3c3f11638363708aa11f858e153cf3a69bce69978b90e4a273836100aa1e617ba455cd00426847f
-
-
-
- - Guardian Project Archive
-
- - https://guardianproject.info/fdroid/archive
-
- - The official repository of The Guardian Project apps for use with F-Droid client. This
- contains older versions of applications from the main repository.
-
-
- - 13
-
- - 0
-
- - 4
-
- - ignore
-
- -
- 308205d8308203c0020900a397b4da7ecda034300d06092a864886f70d01010505003081ad310b30090603550406130255533111300f06035504080c084e657720596f726b3111300f06035504070c084e657720596f726b31143012060355040b0c0b4644726f6964205265706f31193017060355040a0c10477561726469616e2050726f6a656374311d301b06035504030c14677561726469616e70726f6a6563742e696e666f3128302606092a864886f70d0109011619726f6f7440677561726469616e70726f6a6563742e696e666f301e170d3134303632363139333931385a170d3431313131303139333931385a3081ad310b30090603550406130255533111300f06035504080c084e657720596f726b3111300f06035504070c084e657720596f726b31143012060355040b0c0b4644726f6964205265706f31193017060355040a0c10477561726469616e2050726f6a656374311d301b06035504030c14677561726469616e70726f6a6563742e696e666f3128302606092a864886f70d0109011619726f6f7440677561726469616e70726f6a6563742e696e666f30820222300d06092a864886f70d01010105000382020f003082020a0282020100b3cd79121b9b883843be3c4482e320809106b0a23755f1dd3c7f46f7d315d7bb2e943486d61fc7c811b9294dcc6b5baac4340f8db2b0d5e14749e7f35e1fc211fdbc1071b38b4753db201c314811bef885bd8921ad86facd6cc3b8f74d30a0b6e2e6e576f906e9581ef23d9c03e926e06d1f033f28bd1e21cfa6a0e3ff5c9d8246cf108d82b488b9fdd55d7de7ebb6a7f64b19e0d6b2ab1380a6f9d42361770d1956701a7f80e2de568acd0bb4527324b1e0973e89595d91c8cc102d9248525ae092e2c9b69f7414f724195b81427f28b1d3d09a51acfe354387915fd9521e8c890c125fc41a12bf34d2a1b304067ab7251e0e9ef41833ce109e76963b0b256395b16b886bca21b831f1408f836146019e7908829e716e72b81006610a2af08301de5d067c9e114a1e5759db8a6be6a3cc2806bcfe6fafd41b5bc9ddddb3dc33d6f605b1ca7d8a9e0ecdd6390d38906649e68a90a717bea80fa220170eea0c86fc78a7e10dac7b74b8e62045a3ecca54e035281fdc9fe5920a855fde3c0be522e3aef0c087524f13d973dff3768158b01a5800a060c06b451ec98d627dd052eda804d0556f60dbc490d94e6e9dea62ffcafb5beffbd9fc38fb2f0d7050004fe56b4dda0a27bc47554e1e0a7d764e17622e71f83a475db286bc7862deee1327e2028955d978272ea76bf0b88e70a18621aba59ff0c5993ef5f0e5d6b6b98e68b70203010001300d06092a864886f70d0101050500038202010079c79c8ef408a20d243d8bd8249fb9a48350dc19663b5e0fce67a8dbcb7de296c5ae7bbf72e98a2020fb78f2db29b54b0e24b181aa1c1d333cc0303685d6120b03216a913f96b96eb838f9bff125306ae3120af838c9fc07ebb5100125436bd24ec6d994d0bff5d065221871f8410daf536766757239bf594e61c5432c9817281b985263bada8381292e543a49814061ae11c92a316e7dc100327b59e3da90302c5ada68c6a50201bda1fcce800b53f381059665dbabeeb0b50eb22b2d7d2d9b0aa7488ca70e67ac6c518adb8e78454a466501e89d81a45bf1ebc350896f2c3ae4b6679ecfbf9d32960d4f5b493125c7876ef36158562371193f600bc511000a67bdb7c664d018f99d9e589868d103d7e0994f166b2ba18ff7e67d8c4da749e44dfae1d930ae5397083a51675c409049dfb626a96246c0015ca696e94ebb767a20147834bf78b07fece3f0872b057c1c519ff882501995237d8206b0b3832f78753ebd8dcbd1d3d9f5ba733538113af6b407d960ec4353c50eb38ab29888238da843cd404ed8f4952f59e4bbc0035fc77a54846a9d419179c46af1b4a3b7fc98e4d312aaa29b9b7d79e739703dc0fa41c7280d5587709277ffa11c3620f5fba985b82c238ba19b17ebd027af9424be0941719919f620dd3bb3c3f11638363708aa11f858e153cf3a69bce69978b90e4a273836100aa1e617ba455cd00426847f
+ 308204f1308202d9a0030201020204297435a4300d06092a864886f70d01010b050030293110300e060355040b1307462d44726f6964311530130603550403130c4275696c642d536572766572301e170d3136313031373131303834355a170d3434303330343131303834355a30293110300e060355040b1307462d44726f6964311530130603550403130c4275696c642d53657276657230820222300d06092a864886f70d01010105000382020f003082020a02820201009441ca19cbb4a9d6021bc5c91bee5da803807d12aaeb7e8ce3b6ae701e681702c1a96b9e9c4c7c8988d681f30fab152dea265d00bc9dd45b187c3eee1755091d8ed37a4a19ee4687d6dc3c675f2132c8e116a3b9e2c7b60f38ded458496702c19963bd0673dc710c63f952f17fd43bee9ff9cb4e1f84585e8abdd379ce2564044a049abd31108bb7b06ce3e136a222be42aa85ace041c12c92b3737d4767d7e313a559127165e3b49fed77fcdbe29485e82ff9cd71b3b36735bf747969406574e8f93343d0e388230b8aeba945e524b5158b3582ed4d336f2d42f1b079c34a40b9c35e125b7fc95585b74072add11c41663b966bb1eeac025cd31e911f8eb955c7c6bd2e5eee701bc8b91843037372dcd3c2509c9431d28b9d76924556d2cda7383a37b3d54d7db2db634a8e5fde89fdcba1ddcc57ba25050ed7a5591fb1031e02457147203c546765555684d2b1f1a865b1fa874e8e2aeaa16c83db389cf85a2fe1bebfde0f50fd309d69f52514b6ef63c26918a14f9d993eb01ea133228103bdab3a66b31e55754f8cdb753ed620074fcfdf1e9fcac279faad671425e3afdd2c8a27a15d65c1f7bc2fc708e9643ae06898b165c1a1881c649ac2894e79653c5a33a6d8276847010caa747fe1995b35c791b3540b4ce713f99a515aa30c813066d4ae60ce9e473855429f3f0973ef26b4047ee7df70696ed9cbd0bd4f196f7f0203010001a321301f301d0603551d0e0416041445a91de5179148e2c0e3a8e89b7a48de1d872e3d300d06092a864886f70d01010b050003820201001f76cdd43617b464b7dab3e3eb942ad2d01c0ade31853c26893d553d8c3028f385e8e68c9da508389c15892ff5d492b203c1637660d59ac55149fa43c19bcef24ea8111661c63b444f414ccba6ad6d114b2ef489087d715aa91ce57d512d89be392af4d0ba7006ee5c8497bf676d3d3e85cc097c24bcbeabcf32fdd225d2df10f3f53432a60aa51b974fb978eefaaee9ea8f0d5b08ef539531c07f7284df1e6f6fef2b60fb415c4292ceb2ac0ed71fa36a4c075f8b86021660e8194c0ecd00ca65195312c9d76da6232d137c350a912977e4ba5fef8e5212108ea76084b1b02b1e686d9839e3c35745c24bbe19ce1b886bf8b70aa82556cf977ac16d7bc3b2eec5ca2d63f07600a534274a45a156639228b43d46b3547983ea76c6e912c9be85dea68b4cb5227814c50dcc38e289d08ad5d96c997591a949ac9f21883a57ad2f22bcf9ac39b88de831f301827a12db0f051a6cafa97b88aca0abcf86002296a593f27eb5b30f25afacfa4ccf7e53095f70929fadbe84330bb15e491974b8163e34b14c2c0e1ff9afa27466a0f17e74d53108e7fe7c3a2a6122f470df69e68da1fcd6bfd9ef7bd7e5b4511c22786c49ab7c638ec246a41a54f646815bfc29a0a9e6e32f90960ffa0c52b1fee2c8ff0429bb18d7f148a49c34f9d118e9761c9b1a09d3b5debb5b2e2e1cb3c772c2687035fc9c4aef796b0eb45c5d4fa62c787f12