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" },
|
{ "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 {
|
||||||
|
|
||||||
@ -331,18 +330,20 @@ public class DB {
|
|||||||
App app = new App();
|
App app = new App();
|
||||||
app.antiFeatures = c
|
app.antiFeatures = c
|
||||||
.getString(c.getColumnIndex("antiFeatures"));
|
.getString(c.getColumnIndex("antiFeatures"));
|
||||||
boolean include=true;
|
boolean include = true;
|
||||||
if(app.antiFeatures!=null && app.antiFeatures.length()>0) {
|
if (app.antiFeatures != null && app.antiFeatures.length() > 0) {
|
||||||
String[] afs=app.antiFeatures.split(",");
|
String[] afs = app.antiFeatures.split(",");
|
||||||
for(String af : afs) {
|
for (String af : afs) {
|
||||||
if (af.equals("Ads") && !pref_antiAds)
|
if (af.equals("Ads") && !pref_antiAds)
|
||||||
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")
|
||||||
include=false;
|
&& !pref_antiNonFreeNet)
|
||||||
else if(af.equals("NonFreeAdd") && !pref_antiNonFreeAdd)
|
include = false;
|
||||||
include=false;
|
else if (af.equals("NonFreeAdd")
|
||||||
|
&& !pref_antiNonFreeAdd)
|
||||||
|
include = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -517,8 +518,8 @@ public class DB {
|
|||||||
boolean found = false;
|
boolean found = false;
|
||||||
for (App app : updateApps) {
|
for (App app : updateApps) {
|
||||||
if (app.id.equals(upapp.id)) {
|
if (app.id.equals(upapp.id)) {
|
||||||
// Log.d("FDroid", "AppUpdate: " + app.id
|
// Log.d("FDroid", "AppUpdate: " + app.id
|
||||||
// + " is already in the database.");
|
// + " is already in the database.");
|
||||||
updateAppIfDifferent(app, upapp);
|
updateAppIfDifferent(app, upapp);
|
||||||
app.updated = true;
|
app.updated = true;
|
||||||
found = true;
|
found = true;
|
||||||
@ -526,8 +527,8 @@ public class DB {
|
|||||||
boolean afound = false;
|
boolean afound = false;
|
||||||
for (Apk apk : app.apks) {
|
for (Apk apk : app.apks) {
|
||||||
if (apk.version.equals(upapk.version)) {
|
if (apk.version.equals(upapk.version)) {
|
||||||
// Log.d("FDroid", "AppUpdate: " + apk.version
|
// Log.d("FDroid", "AppUpdate: " + apk.version
|
||||||
// + " is a known version.");
|
// + " is a known version.");
|
||||||
updateApkIfDifferent(apk, upapk);
|
updateApkIfDifferent(apk, upapk);
|
||||||
apk.updated = true;
|
apk.updated = true;
|
||||||
afound = true;
|
afound = true;
|
||||||
@ -536,8 +537,8 @@ public class DB {
|
|||||||
}
|
}
|
||||||
if (!afound) {
|
if (!afound) {
|
||||||
// A new version of this application.
|
// A new version of this application.
|
||||||
// Log.d("FDroid", "AppUpdate: " + upapk.version
|
// Log.d("FDroid", "AppUpdate: " + upapk.version
|
||||||
// + " is a new version.");
|
// + " is a new version.");
|
||||||
updateApkIfDifferent(null, upapk);
|
updateApkIfDifferent(null, upapk);
|
||||||
upapk.updated = true;
|
upapk.updated = true;
|
||||||
app.apks.add(upapk);
|
app.apks.add(upapk);
|
||||||
@ -548,9 +549,9 @@ public class DB {
|
|||||||
}
|
}
|
||||||
if (!found) {
|
if (!found) {
|
||||||
// It's a brand new application...
|
// It's a brand new application...
|
||||||
// Log
|
// Log
|
||||||
// .d("FDroid", "AppUpdate: " + upapp.id
|
// .d("FDroid", "AppUpdate: " + upapp.id
|
||||||
// + " is a new application.");
|
// + " is a new application.");
|
||||||
updateAppIfDifferent(null, upapp);
|
updateAppIfDifferent(null, upapp);
|
||||||
for (Apk upapk : upapp.apks) {
|
for (Apk upapk : upapp.apks) {
|
||||||
updateApkIfDifferent(null, upapk);
|
updateApkIfDifferent(null, upapk);
|
||||||
@ -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);
|
||||||
|
@ -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,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) {
|
public static boolean doUpdates(Context ctx, DB db) {
|
||||||
db.beginUpdate();
|
db.beginUpdate();
|
||||||
Vector<DB.Repo> repos = db.getRepos();
|
Vector<DB.Repo> repos = db.getRepos();
|
||||||
@ -196,25 +232,72 @@ public class RepoXMLHandler extends DefaultHandler {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
FileOutputStream f = ctx.openFileOutput("tempindex.xml",
|
if (repo.pubkey != null) {
|
||||||
Context.MODE_PRIVATE);
|
|
||||||
|
|
||||||
// Download the index file from the repo...
|
// This is a signed repo - we download the jar file,
|
||||||
BufferedInputStream getit = new BufferedInputStream(
|
// check the signature, and extract the index...
|
||||||
new URL(repo.address + "/index.xml").openStream());
|
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,
|
byte[] sig = certs[0].getEncoded();
|
||||||
1024);
|
byte[] csig = new byte[sig.length * 2];
|
||||||
byte data[] = new byte[1024];
|
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);
|
if (!ssig.equals(repo.pubkey)) {
|
||||||
while (readed != -1) {
|
Log.d("FDroid", "Index signature mismatch");
|
||||||
bout.write(data, 0, readed);
|
return false;
|
||||||
readed = getit.read(data, 0, 1024);
|
}
|
||||||
|
|
||||||
|
} 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...
|
// Process the index...
|
||||||
SAXParserFactory spf = SAXParserFactory.newInstance();
|
SAXParserFactory spf = SAXParserFactory.newInstance();
|
||||||
@ -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");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user