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" }, { "alter table " + TABLE_APK + " add sig string" },
// Version 7... // Version 7...
{ "alter table " + TABLE_REPO + " add pubkey string" } { "alter table " + TABLE_REPO + " add pubkey string" } };
};
private class DBHelper extends SQLiteOpenHelper { private class DBHelper extends SQLiteOpenHelper {
@ -339,9 +338,11 @@ public class DB {
include = false; include = false;
else if (af.equals("Tracking") && !pref_antiTracking) else if (af.equals("Tracking") && !pref_antiTracking)
include = false; include = false;
else if(af.equals("NonFreeNet") && !pref_antiNonFreeNet) else if (af.equals("NonFreeNet")
&& !pref_antiNonFreeNet)
include = false; include = false;
else if(af.equals("NonFreeAdd") && !pref_antiNonFreeAdd) else if (af.equals("NonFreeAdd")
&& !pref_antiNonFreeAdd)
include = false; include = false;
} }
} }
@ -656,6 +657,15 @@ public class DB {
new String[] { address }); 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) { public void addServer(String address, int priority, String pubkey) {
ContentValues values = new ContentValues(); ContentValues values = new ContentValues();
values.put("address", address); values.put("address", address);

View File

@ -24,9 +24,16 @@ import java.io.BufferedOutputStream;
import java.io.File; import java.io.File;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.FileReader; import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.URL; import java.net.URL;
import java.util.Vector; 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.SAXParser;
import javax.xml.parsers.SAXParserFactory; import javax.xml.parsers.SAXParserFactory;
@ -38,6 +45,8 @@ import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler; import org.xml.sax.helpers.DefaultHandler;
import android.content.Context; import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.util.Log; import android.util.Log;
public class RepoXMLHandler extends DefaultHandler { public class RepoXMLHandler extends DefaultHandler {
@ -50,9 +59,12 @@ public class RepoXMLHandler extends DefaultHandler {
private DB.Apk curapk = null; private DB.Apk curapk = null;
private String curchars = null; private String curchars = null;
public String pubkey;
public RepoXMLHandler(String srv, DB db) { public RepoXMLHandler(String srv, DB db) {
mserver = srv; mserver = srv;
this.db = db; this.db = db;
pubkey = null;
} }
@Override @Override
@ -77,12 +89,12 @@ public class RepoXMLHandler extends DefaultHandler {
String str = curchars; String str = curchars;
if (curel == "application" && curapp != null) { if (curel == "application" && curapp != null) {
Log.d("FDroid", "Repo: Updating application " + curapp.id); // Log.d("FDroid", "Repo: Updating application " + curapp.id);
db.updateApplication(curapp); db.updateApplication(curapp);
getIcon(curapp); getIcon(curapp);
curapp = null; curapp = null;
} else if (curel == "package" && curapk != null && 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); curapp.apks.add(curapk);
curapk = null; curapk = null;
} else if (curapk != null && str != null) { } else if (curapk != null && str != null) {
@ -111,7 +123,7 @@ public class RepoXMLHandler extends DefaultHandler {
} }
} else if (curapp != null && str != null) { } else if (curapp != null && str != null) {
if (curel == "id") { if (curel == "id") {
Log.d("FDroid", "App id is " + str); // Log.d("FDroid", "App id is " + str);
curapp.id = str; curapp.id = str;
} else if (curel == "name") { } else if (curel == "name") {
curapp.name = str; curapp.name = str;
@ -149,11 +161,15 @@ public class RepoXMLHandler extends DefaultHandler {
Attributes attributes) throws SAXException { Attributes attributes) throws SAXException {
super.startElement(uri, localName, qName, attributes); super.startElement(uri, localName, qName, attributes);
if (localName == "application" && curapp == null) { if (localName == "repo") {
Log.d("FDroid", "Repo: Found application at " + mserver); 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(); curapp = new DB.App();
} else if (localName == "package" && curapp != null && curapk == null) { } 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 = new DB.Apk();
curapk.id = curapp.id; curapk.id = curapp.id;
curapk.server = mserver; curapk.server = mserver;
@ -188,23 +204,13 @@ public class RepoXMLHandler extends DefaultHandler {
} }
} }
public static boolean doUpdates(Context ctx, DB db) { private static void getRemoteFile(Context ctx, String url, String dest)
db.beginUpdate(); throws MalformedURLException, IOException {
Vector<DB.Repo> repos = db.getRepos(); FileOutputStream f = ctx.openFileOutput(dest, Context.MODE_PRIVATE);
for (DB.Repo repo : repos) {
if (repo.inuse) {
try { BufferedInputStream getit = new BufferedInputStream(new URL(url)
.openStream());
FileOutputStream f = ctx.openFileOutput("tempindex.xml", BufferedOutputStream bout = new BufferedOutputStream(f, 1024);
Context.MODE_PRIVATE);
// Download the index file from the repo...
BufferedInputStream getit = new BufferedInputStream(
new URL(repo.address + "/index.xml").openStream());
BufferedOutputStream bout = new BufferedOutputStream(f,
1024);
byte data[] = new byte[1024]; byte data[] = new byte[1024];
int readed = getit.read(data, 0, 1024); int readed = getit.read(data, 0, 1024);
@ -216,6 +222,83 @@ public class RepoXMLHandler extends DefaultHandler {
getit.close(); getit.close();
f.close(); f.close();
}
public static boolean doUpdates(Context ctx, DB db) {
db.beginUpdate();
Vector<DB.Repo> repos = db.getRepos();
for (DB.Repo repo : repos) {
if (repo.inuse) {
try {
if (repo.pubkey != null) {
// 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;
}
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);
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");
}
// Process the index... // Process the index...
SAXParserFactory spf = SAXParserFactory.newInstance(); SAXParserFactory spf = SAXParserFactory.newInstance();
SAXParser sp = spf.newSAXParser(); SAXParser sp = spf.newSAXParser();
@ -230,12 +313,23 @@ public class RepoXMLHandler extends DefaultHandler {
InputSource is = new InputSource(isr); InputSource is = new InputSource(isr);
xr.parse(is); 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) { } catch (Exception e) {
Log.d("FDroid", "Exception updating from " + repo.address Log.d("FDroid", "Exception updating from " + repo.address
+ " - " + e.getMessage()); + " - " + e.toString());
return false; return false;
} finally { } finally {
ctx.deleteFile("tempindex.xml"); ctx.deleteFile("tempindex.xml");
ctx.deleteFile("tempindex.jar");
} }
} }