Ability to read signed indexes (and switch from unsigned to signed if a signed one is detected

This commit is contained in:
Ciaran Gultnieks 2011-01-30 15:16:10 +00:00
parent 8c30e0cfdb
commit 497722c634
2 changed files with 149 additions and 45 deletions

View File

@ -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,21 +330,23 @@ 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;
}
}
if (include) {
app.id = c.getString(c.getColumnIndex("id"));
app.name = c.getString(c.getColumnIndex("name"));
@ -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);

View File

@ -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");
}
}