Ability to read signed indexes (and switch from unsigned to signed if a signed one is detected
This commit is contained in:
parent
8c30e0cfdb
commit
497722c634
@ -219,8 +219,7 @@ public class DB {
|
||||
{ "alter table " + TABLE_APK + " add sig string" },
|
||||
|
||||
// Version 7...
|
||||
{ "alter table " + TABLE_REPO + " add pubkey string" }
|
||||
};
|
||||
{ "alter table " + TABLE_REPO + " add pubkey string" } };
|
||||
|
||||
private class DBHelper extends SQLiteOpenHelper {
|
||||
|
||||
@ -331,18 +330,20 @@ public class DB {
|
||||
App app = new App();
|
||||
app.antiFeatures = c
|
||||
.getString(c.getColumnIndex("antiFeatures"));
|
||||
boolean include=true;
|
||||
if(app.antiFeatures!=null && app.antiFeatures.length()>0) {
|
||||
String[] afs=app.antiFeatures.split(",");
|
||||
for(String af : afs) {
|
||||
boolean include = true;
|
||||
if (app.antiFeatures != null && app.antiFeatures.length() > 0) {
|
||||
String[] afs = app.antiFeatures.split(",");
|
||||
for (String af : afs) {
|
||||
if (af.equals("Ads") && !pref_antiAds)
|
||||
include=false;
|
||||
else if(af.equals("Tracking") && !pref_antiTracking)
|
||||
include=false;
|
||||
else if(af.equals("NonFreeNet") && !pref_antiNonFreeNet)
|
||||
include=false;
|
||||
else if(af.equals("NonFreeAdd") && !pref_antiNonFreeAdd)
|
||||
include=false;
|
||||
include = false;
|
||||
else if (af.equals("Tracking") && !pref_antiTracking)
|
||||
include = false;
|
||||
else if (af.equals("NonFreeNet")
|
||||
&& !pref_antiNonFreeNet)
|
||||
include = false;
|
||||
else if (af.equals("NonFreeAdd")
|
||||
&& !pref_antiNonFreeAdd)
|
||||
include = false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -517,8 +518,8 @@ public class DB {
|
||||
boolean found = false;
|
||||
for (App app : updateApps) {
|
||||
if (app.id.equals(upapp.id)) {
|
||||
// Log.d("FDroid", "AppUpdate: " + app.id
|
||||
// + " is already in the database.");
|
||||
// Log.d("FDroid", "AppUpdate: " + app.id
|
||||
// + " is already in the database.");
|
||||
updateAppIfDifferent(app, upapp);
|
||||
app.updated = true;
|
||||
found = true;
|
||||
@ -526,8 +527,8 @@ public class DB {
|
||||
boolean afound = false;
|
||||
for (Apk apk : app.apks) {
|
||||
if (apk.version.equals(upapk.version)) {
|
||||
// Log.d("FDroid", "AppUpdate: " + apk.version
|
||||
// + " is a known version.");
|
||||
// Log.d("FDroid", "AppUpdate: " + apk.version
|
||||
// + " is a known version.");
|
||||
updateApkIfDifferent(apk, upapk);
|
||||
apk.updated = true;
|
||||
afound = true;
|
||||
@ -536,8 +537,8 @@ public class DB {
|
||||
}
|
||||
if (!afound) {
|
||||
// A new version of this application.
|
||||
// Log.d("FDroid", "AppUpdate: " + upapk.version
|
||||
// + " is a new version.");
|
||||
// Log.d("FDroid", "AppUpdate: " + upapk.version
|
||||
// + " is a new version.");
|
||||
updateApkIfDifferent(null, upapk);
|
||||
upapk.updated = true;
|
||||
app.apks.add(upapk);
|
||||
@ -548,9 +549,9 @@ public class DB {
|
||||
}
|
||||
if (!found) {
|
||||
// It's a brand new application...
|
||||
// Log
|
||||
// .d("FDroid", "AppUpdate: " + upapp.id
|
||||
// + " is a new application.");
|
||||
// Log
|
||||
// .d("FDroid", "AppUpdate: " + upapp.id
|
||||
// + " is a new application.");
|
||||
updateAppIfDifferent(null, upapp);
|
||||
for (Apk upapk : upapp.apks) {
|
||||
updateApkIfDifferent(null, upapk);
|
||||
@ -656,6 +657,15 @@ public class DB {
|
||||
new String[] { address });
|
||||
}
|
||||
|
||||
public void updateRepoByAddress(Repo repo) {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put("inuse", repo.inuse);
|
||||
values.put("priority", repo.priority);
|
||||
values.put("pubkey", repo.pubkey);
|
||||
db.update(TABLE_REPO, values, "address = ?",
|
||||
new String[] { repo.address });
|
||||
}
|
||||
|
||||
public void addServer(String address, int priority, String pubkey) {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put("address", address);
|
||||
|
@ -24,9 +24,16 @@ import java.io.BufferedOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.Vector;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.zip.ZipEntry;
|
||||
|
||||
import javax.xml.parsers.SAXParser;
|
||||
import javax.xml.parsers.SAXParserFactory;
|
||||
@ -38,6 +45,8 @@ import org.xml.sax.XMLReader;
|
||||
import org.xml.sax.helpers.DefaultHandler;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.util.Log;
|
||||
|
||||
public class RepoXMLHandler extends DefaultHandler {
|
||||
@ -50,9 +59,12 @@ public class RepoXMLHandler extends DefaultHandler {
|
||||
private DB.Apk curapk = null;
|
||||
private String curchars = null;
|
||||
|
||||
public String pubkey;
|
||||
|
||||
public RepoXMLHandler(String srv, DB db) {
|
||||
mserver = srv;
|
||||
this.db = db;
|
||||
pubkey = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -77,12 +89,12 @@ public class RepoXMLHandler extends DefaultHandler {
|
||||
String str = curchars;
|
||||
|
||||
if (curel == "application" && curapp != null) {
|
||||
Log.d("FDroid", "Repo: Updating application " + curapp.id);
|
||||
// Log.d("FDroid", "Repo: Updating application " + curapp.id);
|
||||
db.updateApplication(curapp);
|
||||
getIcon(curapp);
|
||||
curapp = null;
|
||||
} else if (curel == "package" && curapk != null && curapp != null) {
|
||||
Log.d("FDroid", "Repo: Package added (" + curapk.version + ")");
|
||||
// Log.d("FDroid", "Repo: Package added (" + curapk.version + ")");
|
||||
curapp.apks.add(curapk);
|
||||
curapk = null;
|
||||
} else if (curapk != null && str != null) {
|
||||
@ -111,7 +123,7 @@ public class RepoXMLHandler extends DefaultHandler {
|
||||
}
|
||||
} else if (curapp != null && str != null) {
|
||||
if (curel == "id") {
|
||||
Log.d("FDroid", "App id is " + str);
|
||||
// Log.d("FDroid", "App id is " + str);
|
||||
curapp.id = str;
|
||||
} else if (curel == "name") {
|
||||
curapp.name = str;
|
||||
@ -149,11 +161,15 @@ public class RepoXMLHandler extends DefaultHandler {
|
||||
Attributes attributes) throws SAXException {
|
||||
|
||||
super.startElement(uri, localName, qName, attributes);
|
||||
if (localName == "application" && curapp == null) {
|
||||
Log.d("FDroid", "Repo: Found application at " + mserver);
|
||||
if (localName == "repo") {
|
||||
String pk = attributes.getValue("", "pubkey");
|
||||
if (pk != null)
|
||||
pubkey = pk;
|
||||
} else if (localName == "application" && curapp == null) {
|
||||
// Log.d("FDroid", "Repo: Found application at " + mserver);
|
||||
curapp = new DB.App();
|
||||
} else if (localName == "package" && curapp != null && curapk == null) {
|
||||
Log.d("FDroid", "Repo: Found package for " + curapp.id);
|
||||
// Log.d("FDroid", "Repo: Found package for " + curapp.id);
|
||||
curapk = new DB.Apk();
|
||||
curapk.id = curapp.id;
|
||||
curapk.server = mserver;
|
||||
@ -188,6 +204,26 @@ public class RepoXMLHandler extends DefaultHandler {
|
||||
}
|
||||
}
|
||||
|
||||
private static void getRemoteFile(Context ctx, String url, String dest)
|
||||
throws MalformedURLException, IOException {
|
||||
FileOutputStream f = ctx.openFileOutput(dest, Context.MODE_PRIVATE);
|
||||
|
||||
BufferedInputStream getit = new BufferedInputStream(new URL(url)
|
||||
.openStream());
|
||||
BufferedOutputStream bout = new BufferedOutputStream(f, 1024);
|
||||
byte data[] = new byte[1024];
|
||||
|
||||
int readed = getit.read(data, 0, 1024);
|
||||
while (readed != -1) {
|
||||
bout.write(data, 0, readed);
|
||||
readed = getit.read(data, 0, 1024);
|
||||
}
|
||||
bout.close();
|
||||
getit.close();
|
||||
f.close();
|
||||
|
||||
}
|
||||
|
||||
public static boolean doUpdates(Context ctx, DB db) {
|
||||
db.beginUpdate();
|
||||
Vector<DB.Repo> repos = db.getRepos();
|
||||
@ -196,25 +232,72 @@ public class RepoXMLHandler extends DefaultHandler {
|
||||
|
||||
try {
|
||||
|
||||
FileOutputStream f = ctx.openFileOutput("tempindex.xml",
|
||||
Context.MODE_PRIVATE);
|
||||
if (repo.pubkey != null) {
|
||||
|
||||
// Download the index file from the repo...
|
||||
BufferedInputStream getit = new BufferedInputStream(
|
||||
new URL(repo.address + "/index.xml").openStream());
|
||||
// This is a signed repo - we download the jar file,
|
||||
// check the signature, and extract the index...
|
||||
Log.d("FDroid", "Getting signed index from "
|
||||
+ repo.address);
|
||||
getRemoteFile(ctx, repo.address + "/index.jar",
|
||||
"tempindex.jar");
|
||||
String jarpath = ctx.getFilesDir() + "/tempindex.jar";
|
||||
JarFile jar = new JarFile(jarpath);
|
||||
JarEntry je = (JarEntry) jar.getEntry("index.xml");
|
||||
File efile = new File(ctx.getFilesDir(),
|
||||
"/tempindex.xml");
|
||||
InputStream in = new BufferedInputStream(jar
|
||||
.getInputStream(je), 8192);
|
||||
OutputStream out = new BufferedOutputStream(
|
||||
new FileOutputStream(efile), 8192);
|
||||
byte[] buffer = new byte[8192];
|
||||
while (true) {
|
||||
int nBytes = in.read(buffer);
|
||||
if (nBytes <= 0)
|
||||
break;
|
||||
out.write(buffer, 0, nBytes);
|
||||
}
|
||||
out.flush();
|
||||
out.close();
|
||||
in.close();
|
||||
java.security.cert.Certificate[] certs = je
|
||||
.getCertificates();
|
||||
jar.close();
|
||||
if (certs == null) {
|
||||
Log.d("FDroid", "No signature found in index");
|
||||
return false;
|
||||
}
|
||||
if (certs.length != 1) {
|
||||
Log.d("FDroid", "Expected one signature - found "
|
||||
+ certs.length);
|
||||
return false;
|
||||
}
|
||||
|
||||
BufferedOutputStream bout = new BufferedOutputStream(f,
|
||||
1024);
|
||||
byte data[] = new byte[1024];
|
||||
byte[] sig = certs[0].getEncoded();
|
||||
byte[] csig = new byte[sig.length * 2];
|
||||
for (int j = 0; j < sig.length; j++) {
|
||||
byte v = sig[j];
|
||||
int d = (v >> 4) & 0xf;
|
||||
csig[j * 2] = (byte) (d >= 10 ? ('a' + d - 10)
|
||||
: ('0' + d));
|
||||
d = v & 0xf;
|
||||
csig[j * 2 + 1] = (byte) (d >= 10 ? ('a' + d - 10)
|
||||
: ('0' + d));
|
||||
}
|
||||
String ssig = new String(csig);
|
||||
|
||||
int readed = getit.read(data, 0, 1024);
|
||||
while (readed != -1) {
|
||||
bout.write(data, 0, readed);
|
||||
readed = getit.read(data, 0, 1024);
|
||||
if (!ssig.equals(repo.pubkey)) {
|
||||
Log.d("FDroid", "Index signature mismatch");
|
||||
return false;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// It's an old-fashioned unsigned repo...
|
||||
Log.d("FDroid", "Getting unsigned index from "
|
||||
+ repo.address);
|
||||
getRemoteFile(ctx, repo.address + "/index.xml",
|
||||
"tempindex.xml");
|
||||
}
|
||||
bout.close();
|
||||
getit.close();
|
||||
f.close();
|
||||
|
||||
// Process the index...
|
||||
SAXParserFactory spf = SAXParserFactory.newInstance();
|
||||
@ -230,12 +313,23 @@ public class RepoXMLHandler extends DefaultHandler {
|
||||
InputSource is = new InputSource(isr);
|
||||
xr.parse(is);
|
||||
|
||||
if (handler.pubkey != null && repo.pubkey == null) {
|
||||
// We read an unsigned index, but that indicates that
|
||||
// a signed version is now available...
|
||||
Log
|
||||
.d("FDroid",
|
||||
"Public key found - switching to signed repo for future updates");
|
||||
repo.pubkey = handler.pubkey;
|
||||
db.updateRepoByAddress(repo);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
Log.d("FDroid", "Exception updating from " + repo.address
|
||||
+ " - " + e.getMessage());
|
||||
+ " - " + e.toString());
|
||||
return false;
|
||||
} finally {
|
||||
ctx.deleteFile("tempindex.xml");
|
||||
ctx.deleteFile("tempindex.jar");
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user