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 rsrcs.addAll(app.getDigestOnly());
85 for (Application.AuxGroup ag : app.getAuxGroups()) {
86 rsrcs.addAll(ag.codes);
87 rsrcs.addAll(ag.rsrcs);
90 // now generate the digest file
91 Digest.createDigest(version, rsrcs, target);
95 * Creates a digest file in the specified application directory.
97 public static void signDigest (int version, File appdir,
98 File storePath, String storePass, String storeAlias)
99 throws IOException, GeneralSecurityException
101 String filename = Digest.digestFile(version);
102 File inputFile = new File(appdir, filename);
103 File signatureFile = new File(appdir, filename + Application.SIGNATURE_SUFFIX);
105 try (FileInputStream storeInput = new FileInputStream(storePath);
106 FileInputStream dataInput = new FileInputStream(inputFile);
107 FileOutputStream signatureOutput = new FileOutputStream(signatureFile)) {
109 // initialize the keystore
110 KeyStore store = KeyStore.getInstance("JKS");
111 store.load(storeInput, storePass.toCharArray());
112 PrivateKey key = (PrivateKey)store.getKey(storeAlias, storePass.toCharArray());
114 // sign the digest file
115 String algo = Digest.sigAlgorithm(version);
116 Signature sig = Signature.getInstance(algo);
117 byte[] buffer = new byte[8192];
121 while ((length = dataInput.read(buffer)) != -1) {
122 sig.update(buffer, 0, length);
125 // Write out the signature
126 String signed = Base64.encodeToString(sig.sign(), Base64.DEFAULT);
127 signatureOutput.write(signed.getBytes(UTF_8));