2 // Getdown - application installer, patcher and launcher
3 // Copyright (C) 2004-2018 Getdown authors
4 // https://github.com/threerings/getdown/blob/master/LICENSE
6 package com.threerings.getdown.tools;
9 import java.io.FileInputStream;
10 import java.io.FileOutputStream;
11 import java.io.IOException;
13 import java.security.GeneralSecurityException;
14 import java.security.KeyStore;
15 import java.security.PrivateKey;
16 import java.security.Signature;
18 import java.util.ArrayList;
19 import java.util.List;
21 import com.threerings.getdown.data.Application;
22 import com.threerings.getdown.data.Digest;
23 import com.threerings.getdown.data.EnvConfig;
24 import com.threerings.getdown.data.Resource;
25 import com.threerings.getdown.util.Base64;
27 import static java.nio.charset.StandardCharsets.UTF_8;
30 * Handles the generation of the digest.txt file.
35 * A command line entry point for the digester.
37 public static void main (String[] args)
38 throws IOException, GeneralSecurityException
40 switch (args.length) {
42 createDigests(new File(args[0]), null, null, null);
45 createDigests(new File(args[0]), new File(args[1]), args[2], args[3]);
48 System.err.println("Usage: Digester app_dir [keystore_path password alias]");
54 * Creates digest file(s) and optionally signs them if {@code keystore} is not null.
56 public static void createDigests (File appdir, File keystore, String password, String alias)
57 throws IOException, GeneralSecurityException
59 for (int version = 1; version <= Digest.VERSION; version++) {
60 createDigest(version, appdir);
61 if (keystore != null) {
62 signDigest(version, appdir, keystore, password, alias);
68 * Creates a digest file in the specified application directory.
70 public static void createDigest (int version, File appdir)
73 File target = new File(appdir, Digest.digestFile(version));
74 System.out.println("Generating digest file '" + target + "'...");
76 // create our application and instruct it to parse its business
77 Application app = new Application(new EnvConfig(appdir));
80 List<Resource> rsrcs = new ArrayList<>();
81 rsrcs.add(app.getConfigResource());
82 rsrcs.addAll(app.getCodeResources());
83 rsrcs.addAll(app.getResources());
84 for (Application.AuxGroup ag : app.getAuxGroups()) {
85 rsrcs.addAll(ag.codes);
86 rsrcs.addAll(ag.rsrcs);
89 // now generate the digest file
90 Digest.createDigest(version, rsrcs, target);
94 * Creates a digest file in the specified application directory.
96 public static void signDigest (int version, File appdir,
97 File storePath, String storePass, String storeAlias)
98 throws IOException, GeneralSecurityException
100 String filename = Digest.digestFile(version);
101 File inputFile = new File(appdir, filename);
102 File signatureFile = new File(appdir, filename + Application.SIGNATURE_SUFFIX);
104 try (FileInputStream storeInput = new FileInputStream(storePath);
105 FileInputStream dataInput = new FileInputStream(inputFile);
106 FileOutputStream signatureOutput = new FileOutputStream(signatureFile)) {
108 // initialize the keystore
109 KeyStore store = KeyStore.getInstance("JKS");
110 store.load(storeInput, storePass.toCharArray());
111 PrivateKey key = (PrivateKey)store.getKey(storeAlias, storePass.toCharArray());
113 // sign the digest file
114 String algo = Digest.sigAlgorithm(version);
115 Signature sig = Signature.getInstance(algo);
116 byte[] buffer = new byte[8192];
120 while ((length = dataInput.read(buffer)) != -1) {
121 sig.update(buffer, 0, length);
124 // Write out the signature
125 String signed = Base64.encodeToString(sig.sign(), Base64.DEFAULT);
126 signatureOutput.write(signed.getBytes(UTF_8));