// Do an update from the given repo. All applications found, and their
  // APKs, are added to 'apps'. (If 'apps' already contains an app, its
  // APKs are merged into the existing one).
  // Returns null if successful, otherwise an error message to be displayed
  // to the user (if there is an interactive user!)
  // 'newetag' should be passed empty. On success, it may contain an etag
  // value for the index that was successfully processed, or it may contain
  // null if none was available.
  public static String doUpdate(
      Context ctx,
      DB.Repo repo,
      List<DB.App> apps,
      StringBuilder newetag,
      List<Integer> keeprepos,
      ProgressListener progressListener) {
    try {

      int code = 0;
      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
                + " at "
                + logDateFormat.format(new Date(System.currentTimeMillis())));
        String address = repo.address + "/index.jar";
        PackageManager pm = ctx.getPackageManager();
        try {
          PackageInfo pi = pm.getPackageInfo(ctx.getPackageName(), 0);
          address += "?" + pi.versionName;
        } catch (Exception e) {
        }
        Bundle progressData = createProgressData(repo.address);
        ProgressListener.Event event =
            new ProgressListener.Event(RepoXMLHandler.PROGRESS_TYPE_DOWNLOAD, progressData);
        code =
            getRemoteFile(
                ctx, address, "tempindex.jar", repo.lastetag, newetag, progressListener, event);
        if (code == 200) {
          String jarpath = ctx.getFilesDir() + "/tempindex.jar";
          JarFile jar = null;
          JarEntry je;
          Certificate[] certs;
          try {
            jar = new JarFile(jarpath, true);
            je = (JarEntry) jar.getEntry("index.xml");
            File efile = new File(ctx.getFilesDir(), "/tempindex.xml");
            InputStream input = null;
            OutputStream output = null;
            try {
              input = jar.getInputStream(je);
              output = new FileOutputStream(efile);
              Utils.copy(input, output);
            } finally {
              Utils.closeQuietly(output);
              Utils.closeQuietly(input);
            }
            certs = je.getCertificates();
          } catch (SecurityException e) {
            Log.e("FDroid", "Invalid hash for index file");
            return "Invalid hash for index file";
          } finally {
            if (jar != null) {
              jar.close();
            }
          }
          if (certs == null) {
            Log.d("FDroid", "No signature found in index");
            return "No signature found in index";
          }
          Log.d(
              "FDroid",
              "Index has " + certs.length + " signature" + (certs.length > 1 ? "s." : "."));

          boolean match = false;
          for (Certificate cert : certs) {
            String certdata = Hasher.hex(cert.getEncoded());
            if (repo.pubkey.equals(certdata)) {
              match = true;
              break;
            }
          }
          if (!match) {
            Log.d("FDroid", "Index signature mismatch");
            return "Index signature mismatch";
          }
        }

      } else {

        // It's an old-fashioned unsigned repo...
        Log.d("FDroid", "Getting unsigned index from " + repo.address);
        Bundle eventData = createProgressData(repo.address);
        ProgressListener.Event event =
            new ProgressListener.Event(RepoXMLHandler.PROGRESS_TYPE_DOWNLOAD, eventData);
        code =
            getRemoteFile(
                ctx,
                repo.address + "/index.xml",
                "tempindex.xml",
                repo.lastetag,
                newetag,
                progressListener,
                event);
      }

      if (code == 200) {
        // Process the index...
        SAXParserFactory spf = SAXParserFactory.newInstance();
        SAXParser sp = spf.newSAXParser();
        XMLReader xr = sp.getXMLReader();
        RepoXMLHandler handler = new RepoXMLHandler(repo, apps, progressListener);
        xr.setContentHandler(handler);

        File tempIndex = new File(ctx.getFilesDir() + "/tempindex.xml");
        BufferedReader r = new BufferedReader(new FileReader(tempIndex));

        // A bit of a hack, this might return false positives if an apps description
        // or some other part of the XML file contains this, but it is a pretty good
        // estimate and makes the progress counter more informative.
        // As with asking the server about the size of the index before downloading,
        // this also has a time tradeoff. It takes about three seconds to iterate
        // through the file and count 600 apps on a slow emulator (v17), but if it is
        // taking two minutes to update, the three second wait may be worth it.
        final String APPLICATION = "<application";
        handler.setTotalAppCount(Utils.countSubstringOccurrence(tempIndex, APPLICATION));

        InputSource is = new InputSource(r);
        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;
          try {
            DB db = DB.getDB();
            db.updateRepoByAddress(repo);
          } finally {
            DB.releaseDB();
          }
        }

      } else if (code == 304) {
        // The index is unchanged since we last read it. We just mark
        // everything that came from this repo as being updated.
        Log.d("FDroid", "Repo index for " + repo.address + " is up to date (by etag)");
        keeprepos.add(repo.id);
        // Make sure we give back the same etag. (The 200 route will
        // have supplied a new one.
        newetag.append(repo.lastetag);

      } else {
        return "Failed to read index - HTTP response " + Integer.toString(code);
      }

    } catch (SSLHandshakeException sslex) {
      Log.e(
          "FDroid",
          "SSLHandShakeException updating from "
              + repo.address
              + ":\n"
              + Log.getStackTraceString(sslex));
      return "A problem occurred while establishing an SSL connection. If this problem persists, AND you have a very old device, you could try using http instead of https for the repo URL.";
    } catch (Exception e) {
      Log.e(
          "FDroid", "Exception updating from " + repo.address + ":\n" + Log.getStackTraceString(e));
      return "Failed to update - " + e.getMessage();
    } finally {
      ctx.deleteFile("tempindex.xml");
      ctx.deleteFile("tempindex.jar");
    }

    return null;
  }
Ejemplo n.º 2
0
 public static LessonServiceInterface getModelService() {
   return DB.getDB();
 }