Skip to content

Commit

Permalink
Working in in-memory pass generation (#48)
Browse files Browse the repository at this point in the history
  • Loading branch information
drallgood committed Oct 31, 2015
1 parent cfadff2 commit ec43f7f
Show file tree
Hide file tree
Showing 9 changed files with 425 additions and 62 deletions.
Expand Up @@ -17,17 +17,20 @@

import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Map;

public interface IPKPassTemplate {

/**
* Prepare pass at directory with files included in this template
*
* @param tempPassDir
* path to directory where temporary pass will be created
* path to directory where temporary pass will be created
* @throws IOException
* if anything goes wrong while copying the files
* if anything goes wrong while copying the files
*/
void provisionPassAtDirectory(File tempPassDir) throws IOException;

Map<String, ByteBuffer> getAllFiles() throws IOException;
}
Expand Up @@ -15,6 +15,8 @@
*/
package de.brendamour.jpasskit.signing;

import java.io.File;
import java.nio.charset.Charset;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Date;
Expand All @@ -38,6 +40,18 @@
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;

import com.fasterxml.jackson.annotation.JsonFilter;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectWriter;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter;
import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider;
import com.fasterxml.jackson.databind.util.ISO8601DateFormat;

import de.brendamour.jpasskit.PKBarcode;
import de.brendamour.jpasskit.PKPass;

public abstract class PKAbstractSIgningUtil implements IPKSigningUtil {

/*
Expand Down Expand Up @@ -92,4 +106,50 @@ protected byte[] signManifestUsingContent(PKSigningInformation signingInformatio
throw new PKSigningException("Error when signing manifest", e);
}
}

protected ObjectWriter configureObjectMapper(final ObjectMapper jsonObjectMapper) {
jsonObjectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
jsonObjectMapper.setDateFormat(new ISO8601DateFormat());

SimpleFilterProvider filters = new SimpleFilterProvider();

// haven't found out, how to stack filters. Copying the validation one for now.
filters.addFilter("validateFilter", SimpleBeanPropertyFilter.serializeAllExcept("valid", "validationErrors"));
filters.addFilter("pkPassFilter", SimpleBeanPropertyFilter.serializeAllExcept("valid", "validationErrors", "foregroundColorAsObject",
"backgroundColorAsObject", "labelColorAsObject", "passThatWasSet"));
filters.addFilter("barcodeFilter", SimpleBeanPropertyFilter.serializeAllExcept("valid", "validationErrors", "messageEncodingAsString"));
filters.addFilter("charsetFilter", SimpleBeanPropertyFilter.filterOutAllExcept("name"));
jsonObjectMapper.setSerializationInclusion(Include.NON_NULL);
jsonObjectMapper.addMixIn(Object.class, ValidateFilterMixIn.class);
jsonObjectMapper.addMixIn(PKPass.class, PkPassFilterMixIn.class);
jsonObjectMapper.addMixIn(PKBarcode.class, BarcodeFilterMixIn.class);
jsonObjectMapper.addMixIn(Charset.class, CharsetFilterMixIn.class);
return jsonObjectMapper.writer(filters);
}

protected String getRelativePathOfZipEntry(final String fileToZip, final String base) {
String relativePathOfFile = fileToZip.substring(base.length()).replaceAll("^/+", "");
if (File.separatorChar != '/') {
relativePathOfFile = relativePathOfFile.replace(File.separatorChar, '/');
}

return relativePathOfFile;
}

protected @JsonFilter("pkPassFilter") class PkPassFilterMixIn {
// just a dummy
}

protected @JsonFilter("validateFilter") class ValidateFilterMixIn {
// just a dummy
}

protected @JsonFilter("barcodeFilter") class BarcodeFilterMixIn {
// just a dummy
}

protected @JsonFilter("charsetFilter") class CharsetFilterMixIn {
// just a dummy
}

}
Expand Up @@ -21,7 +21,6 @@
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URL;
import java.nio.charset.Charset;
import java.security.Security;
import java.util.HashMap;
import java.util.Map;
Expand All @@ -38,36 +37,27 @@
import org.bouncycastle.jce.provider.BouncyCastleProvider;

import com.fasterxml.jackson.annotation.JsonFilter;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectWriter;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter;
import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider;
import com.fasterxml.jackson.databind.util.ISO8601DateFormat;
import com.google.common.hash.HashCode;
import com.google.common.hash.HashFunction;
import com.google.common.hash.Hashing;
import com.google.common.io.Files;

import de.brendamour.jpasskit.PKBarcode;
import de.brendamour.jpasskit.PKPass;

public final class PKFileBasedSigningUtil extends PKAbstractSIgningUtil {

private static final int ZIP_BUFFER_SIZE = 8192;
private static final String FILE_SEPARATOR_UNIX = "/";
private static final String MANIFEST_JSON_FILE_NAME = "manifest.json";
private static final String PASS_JSON_FILE_NAME = "pass.json";

private ObjectMapper jsonObjectMapper;
private ObjectWriter objectWriter;

@Inject
public PKFileBasedSigningUtil(ObjectMapper objectMapper) {
addBCProvider();
jsonObjectMapper = objectMapper;
jsonObjectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
jsonObjectMapper.setDateFormat(new ISO8601DateFormat());
objectWriter = configureObjectMapper(objectMapper);
}

/*
Expand All @@ -87,9 +77,9 @@ public byte[] createSignedAndZippedPkPassArchive(PKPass pass, IPKPassTemplate pa
throw new PKSigningException("Error when provisioning template", e);
}

createPassJSONFile(pass, tempPassDir, jsonObjectMapper);
createPassJSONFile(pass, tempPassDir);

File manifestJSONFile = createManifestJSONFile(tempPassDir, jsonObjectMapper);
File manifestJSONFile = createManifestJSONFile(tempPassDir);

signManifestFileAndWriteToDirectory(tempPassDir, manifestJSONFile, signingInformation);

Expand Down Expand Up @@ -135,25 +125,24 @@ public void signManifestFileAndWriteToDirectory(final File temporaryPassDirector
}
}

private void createPassJSONFile(final PKPass pass, final File tempPassDir, final ObjectMapper jsonObjectMapper) throws PKSigningException {
private void createPassJSONFile(final PKPass pass, final File tempPassDir) throws PKSigningException {
File passJSONFile = new File(tempPassDir.getAbsolutePath() + File.separator + PASS_JSON_FILE_NAME);

ObjectWriter objectWriter = getObjectWriterWithFilters(jsonObjectMapper);
try {
objectWriter.writeValue(passJSONFile, pass);
} catch (IOException e) {
throw new PKSigningException("Error when writing pass.json", e);
}
}

private File createManifestJSONFile(final File tempPassDir, final ObjectMapper jsonObjectMapper) throws PKSigningException {
private File createManifestJSONFile(final File tempPassDir) throws PKSigningException {
Map<String, String> fileWithHashMap = new HashMap<String, String>();

HashFunction hashFunction = Hashing.sha1();
File[] filesInTempDir = tempPassDir.listFiles();
hashFilesInDirectory(filesInTempDir, fileWithHashMap, hashFunction, null);
File manifestJSONFile = new File(tempPassDir.getAbsolutePath() + File.separator + MANIFEST_JSON_FILE_NAME);
ObjectWriter objectWriter = getObjectWriterWithFilters(jsonObjectMapper);

try {
objectWriter.writeValue(manifestJSONFile, fileWithHashMap);
} catch (IOException e) {
Expand All @@ -162,25 +151,6 @@ private File createManifestJSONFile(final File tempPassDir, final ObjectMapper j
return manifestJSONFile;
}

private ObjectWriter getObjectWriterWithFilters(final ObjectMapper jsonObjectMapper) {
SimpleFilterProvider filters = new SimpleFilterProvider();

// haven't found out, how to stack filters. Copying the validation one for now.
filters.addFilter("validateFilter", SimpleBeanPropertyFilter.serializeAllExcept("valid", "validationErrors"));
filters.addFilter("pkPassFilter", SimpleBeanPropertyFilter.serializeAllExcept("valid", "validationErrors", "foregroundColorAsObject",
"backgroundColorAsObject", "labelColorAsObject", "passThatWasSet"));
filters.addFilter("barcodeFilter", SimpleBeanPropertyFilter.serializeAllExcept("valid", "validationErrors", "messageEncodingAsString"));
filters.addFilter("charsetFilter", SimpleBeanPropertyFilter.filterOutAllExcept("name"));
jsonObjectMapper.setSerializationInclusion(Include.NON_NULL);
jsonObjectMapper.addMixIn(Object.class, ValidateFilterMixIn.class);
jsonObjectMapper.addMixIn(PKPass.class, PkPassFilterMixIn.class);
jsonObjectMapper.addMixIn(PKBarcode.class, BarcodeFilterMixIn.class);
jsonObjectMapper.addMixIn(Charset.class, CharsetFilterMixIn.class);

ObjectWriter objectWriter = jsonObjectMapper.writer(filters);
return objectWriter;
}

/* Windows OS separators did not work */
private void hashFilesInDirectory(final File[] files, final Map<String, String> fileWithHashMap, final HashFunction hashFunction,
final String parentName) throws PKSigningException {
Expand Down Expand Up @@ -229,21 +199,18 @@ private byte[] createZippedPassAndReturnAsByteArray(final File tempPassDir) thro

private final void zip(final File directory, final File base, final ZipOutputStream zipOutputStream) throws PKSigningException {
File[] files = directory.listFiles();
byte[] buffer = new byte[ZIP_BUFFER_SIZE];
int read = 0;
for (int i = 0, n = files.length; i < n; i++) {
if (files[i].isDirectory()) {
zip(files[i], base, zipOutputStream);
} else {
FileInputStream fileInputStream = null;
try {
fileInputStream = new FileInputStream(files[i]);
ZipEntry entry = new ZipEntry(getRelativePathOfZipEntry(files[i], base));
ZipEntry entry = new ZipEntry(getRelativePathOfZipEntry(files[i].getPath(), base.getPath()));
zipOutputStream.putNextEntry(entry);
while (-1 != (read = fileInputStream.read(buffer))) {
zipOutputStream.write(buffer, 0, read);
}
IOUtils.copy(fileInputStream, zipOutputStream);
} catch (IOException e) {
IOUtils.closeQuietly(zipOutputStream);
throw new PKSigningException("Error when zipping file", e);
} finally {
IOUtils.closeQuietly(fileInputStream);
Expand All @@ -252,15 +219,6 @@ private final void zip(final File directory, final File base, final ZipOutputStr
}
}

private String getRelativePathOfZipEntry(final File fileToZip, final File base) {
String relativePathOfFile = fileToZip.getPath().substring(base.getPath().length() + 1);
if (File.separatorChar != '/') {
relativePathOfFile = relativePathOfFile.replace(File.separatorChar, '/');
}

return relativePathOfFile;
}

@JsonFilter("pkPassFilter")
private class PkPassFilterMixIn {
// just a dummy
Expand Down

0 comments on commit ec43f7f

Please sign in to comment.