Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,13 @@
import de.brendamour.jpasskit.PKPass;
import de.brendamour.jpasskit.personalization.PKPersonalization;

import java.io.OutputStream;

public interface IPKSigningUtil {

/**
* Creates a signed and zipped pass using a template
*
*
* @param pass
* The pass to sign
* @param passTemplate
Expand All @@ -36,9 +38,26 @@ public interface IPKSigningUtil {
byte[] createSignedAndZippedPkPassArchive(PKPass pass, IPKPassTemplate passTemplate, PKSigningInformation signingInformation)
throws PKSigningException;

/**
* Creates a signed and zipped pass using a template and writes it to the provided output stream
*
* @param pass
* The pass to sign
* @param passTemplate
* A {@link IPKPassTemplate} object
* @param signingInformation
* A {@link PKSigningInformation} object containing the signing info
* @param outputStream
* The output stream to write the signed and zipped .pkpass file to
* @throws PKSigningException
* will throw any underlying exception in case something goes wrong (i.e. template not found)
*/
void createSignedAndZippedPkPassArchiveStream(PKPass pass, IPKPassTemplate passTemplate, PKSigningInformation signingInformation, OutputStream outputStream)
throws PKSigningException;

/**
* Creates a signed and zipped personalized pass using a template
*
*
* @param pass
* The pass to sign
* @param personalization
Expand All @@ -54,9 +73,28 @@ byte[] createSignedAndZippedPkPassArchive(PKPass pass, IPKPassTemplate passTempl
byte[] createSignedAndZippedPersonalizedPkPassArchive(PKPass pass, PKPersonalization personalization, IPKPassTemplate passTemplate,
PKSigningInformation signingInformation) throws PKSigningException;

/**
* Creates a signed and zipped personalized pass using a template and writes it to the provided output stream
*
* @param pass
* The pass to sign
* @param personalization
* Personalization info
* @param passTemplate
* A {@link IPKPassTemplate} object
* @param signingInformation
* A {@link PKSigningInformation} object containing the signing info
* @param outputStream
* The output stream to write the signed and zipped .pkpass file to
* @throws PKSigningException
* will throw any underlying exception in case something goes wrong (i.e. template not found)
*/
void createSignedAndZippedPersonalizedPkPassArchiveStream(PKPass pass, PKPersonalization personalization, IPKPassTemplate passTemplate,
PKSigningInformation signingInformation, OutputStream outputStream) throws PKSigningException;

/**
* Sign the manifest file
*
*
* @param manifestJSON
* JSON file as byte array
* @param signingInformation
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,21 @@ public byte[] createSignedAndZippedPkPassArchive(PKPass pass, IPKPassTemplate pa
return this.createSignedAndZippedPersonalizedPkPassArchive(pass, null, passTemplate, signingInformation);
}

@Override
public void createSignedAndZippedPkPassArchiveStream(PKPass pass, IPKPassTemplate passTemplate, PKSigningInformation signingInformation, OutputStream outputStream) throws PKSigningException {
this.createSignedAndZippedPersonalizedPkPassArchiveStream(pass, null, passTemplate, signingInformation, outputStream);
}

@Override
public byte[] createSignedAndZippedPersonalizedPkPassArchive(PKPass pass, PKPersonalization personalization, IPKPassTemplate passTemplate,
PKSigningInformation signingInformation) throws PKSigningException {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
createSignedAndZippedPersonalizedPkPassArchiveStream(pass, personalization, passTemplate, signingInformation, byteArrayOutputStream);
return byteArrayOutputStream.toByteArray();
}

@Override
public void createSignedAndZippedPersonalizedPkPassArchiveStream(PKPass pass, PKPersonalization personalization, IPKPassTemplate passTemplate, PKSigningInformation signingInformation, OutputStream outputStream) throws PKSigningException {

File tempPassDir = Files.createTempDir();
try {
Expand All @@ -90,21 +102,20 @@ public byte[] createSignedAndZippedPersonalizedPkPassArchive(PKPass pass, PKPers

createPassJSONFile(pass, tempPassDir);

if(personalization != null) {
if (personalization != null) {
createPersonalizationJSONFile(personalization, tempPassDir);
}

File manifestJSONFile = createManifestJSONFile(tempPassDir);
signManifestFileAndWriteToDirectory(tempPassDir, manifestJSONFile, signingInformation);

byte[] zippedPass = createZippedPassAndReturnAsByteArray(tempPassDir);
createZippedPassAndWriteToStream(tempPassDir, outputStream);

try {
FileUtils.deleteDirectory(tempPassDir);
} catch (IOException e) {
LOGGER.warn("Removing the temporary directory failed", e);
}
return zippedPass;
}

public byte[] createSignedAndZippedPkPassArchive(final PKPass pass, final URL fileUrlOfTemplateDirectory,
Expand Down Expand Up @@ -181,9 +192,8 @@ private Map<String, String> hashFiles(final File tempPassDir, final HashFunction
return fileWithHashMap;
}

private byte[] createZippedPassAndReturnAsByteArray(final File tempPassDir) throws PKSigningException {
ByteArrayOutputStream byteArrayOutputStreamForZippedPass = new ByteArrayOutputStream(); // closed with the parent ZipOutputStream
try (ZipOutputStream zipOutputStream = new ZipOutputStream(byteArrayOutputStreamForZippedPass)) {
private void createZippedPassAndWriteToStream(final File tempPassDir, final OutputStream outputStream) throws PKSigningException {
try (ZipOutputStream zipOutputStream = new ZipOutputStream(outputStream)) {
String base = tempPassDir.getCanonicalPath() + File.separator;
ZipEntry entry;
for (File file : FileUtils.listFiles(tempPassDir, new RegexFileFilter("^(?!\\.).*"), TrueFileFilter.TRUE)) {
Expand All @@ -196,6 +206,5 @@ private byte[] createZippedPassAndReturnAsByteArray(final File tempPassDir) thro
} catch (IOException e) {
throw new PKSigningException("Error when creating a zip package", e);
}
return byteArrayOutputStreamForZippedPass.toByteArray();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.invoke.MethodHandles;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
Expand Down Expand Up @@ -71,9 +72,23 @@ public byte[] createSignedAndZippedPkPassArchive(PKPass pass, IPKPassTemplate pa
return createSignedAndZippedPersonalizedPkPassArchive(pass, null, passTemplate, signingInformation);
}

@Override
public void createSignedAndZippedPkPassArchiveStream(PKPass pass, IPKPassTemplate passTemplate, PKSigningInformation signingInformation, OutputStream outputStream)
throws PKSigningException {
createSignedAndZippedPersonalizedPkPassArchiveStream(pass, null, passTemplate, signingInformation, outputStream);
}

@Override
public byte[] createSignedAndZippedPersonalizedPkPassArchive(PKPass pass, PKPersonalization personalization, IPKPassTemplate passTemplate,
PKSigningInformation signingInformation) throws PKSigningException {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
createSignedAndZippedPersonalizedPkPassArchiveStream(pass, personalization, passTemplate, signingInformation, byteArrayOutputStream);
return byteArrayOutputStream.toByteArray();
}

@Override
public void createSignedAndZippedPersonalizedPkPassArchiveStream(PKPass pass, PKPersonalization personalization, IPKPassTemplate passTemplate,
PKSigningInformation signingInformation, OutputStream outputStream) throws PKSigningException {
Map<String, ByteBuffer> allFiles;
try {
allFiles = passTemplate.getAllFiles();
Expand Down Expand Up @@ -104,7 +119,7 @@ public byte[] createSignedAndZippedPersonalizedPkPassArchive(PKPass pass, PKPers
ByteBuffer signature = ByteBuffer.wrap(signManifestFile(manifestJSONFile.array(), signingInformation));
allFiles.put(SIGNATURE_FILE_NAME, signature);

return createZippedPassAndReturnAsByteArray(allFiles);
createZippedPassAndWriteToStream(allFiles, outputStream);
}

private ByteBuffer createPassJSONFile(final PKPass pass) throws PKSigningException {
Expand Down Expand Up @@ -144,9 +159,8 @@ private Map<String, String> hashFiles(Map<String, ByteBuffer> files, final HashF
return fileWithHashMap;
}

private byte[] createZippedPassAndReturnAsByteArray(final Map<String, ByteBuffer> files) throws PKSigningException {
ByteArrayOutputStream byteArrayOutputStreamForZippedPass = new ByteArrayOutputStream();
try (ZipOutputStream zipOutputStream = new ZipOutputStream(byteArrayOutputStreamForZippedPass)) {
private void createZippedPassAndWriteToStream(final Map<String, ByteBuffer> files, final OutputStream outputStream) throws PKSigningException {
try (ZipOutputStream zipOutputStream = new ZipOutputStream(outputStream)) {
for (Entry<String, ByteBuffer> passResourceFile : files.entrySet()) {
ZipEntry entry = new ZipEntry(getRelativePathOfZipEntry(passResourceFile.getKey(), ""));
zipOutputStream.putNextEntry(entry);
Expand All @@ -155,6 +169,5 @@ private byte[] createZippedPassAndReturnAsByteArray(final Map<String, ByteBuffer
} catch (IOException e) {
throw new PKSigningException("Error while creating a zip package", e);
}
return byteArrayOutputStreamForZippedPass.toByteArray();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,81 @@ private String getPathFromClasspath(String path) throws Exception {
return Paths.get(ClassLoader.getSystemResource(path).toURI()).toString();
}

@Test
public void testFileBasedStreamingWithGeneratedPass() throws Exception {
PKPassBuilder passBuilder = PKPass.builder()
.barcodeBuilder(
PKBarcode.builder()
.format(PKBarcodeFormat.PKBarcodeFormatQR)
.message("abcdefg")
.messageEncoding(Charset.forName("UTF-8"))
)
.passTypeIdentifier("pti")
.teamIdentifier("ti");

File passfile = File.createTempFile("passFileBasedStreamGenerated", ".zip");
createZipAndAssertStream(passBuilder.build(), passfile);
}

@Test
public void testFileBasedStreamingWithGeneratedPassAndPersonalization() throws Exception {
PKPassBuilder passBuilder = PKPass.builder()
.barcodeBuilder(
PKBarcode.builder()
.format(PKBarcodeFormat.PKBarcodeFormatQR)
.message("abcdefg")
.messageEncoding(Charset.forName("UTF-8"))
)
.passTypeIdentifier("pti")
.teamIdentifier("ti");

PKPersonalizationBuilder personalization = PKPersonalization.builder()
.description("desc")
.termsAndConditions("T&C")
.requiredPersonalizationField(PKPassPersonalizationField.PKPassPersonalizationFieldName);

File passfile = File.createTempFile("passFileBasedStreamGenerated", ".zip");
createZipAndAssertStream(passBuilder.build(), personalization.build(), passfile);
}

private void createZipAndAssertStream(PKPass pkPass, File passZipFile) throws Exception {
createZipAndAssertStream(pkPass, null, passZipFile);
}

private void createZipAndAssertStream(PKPass pkPass, PKPersonalization personalization, File passZipFile) throws Exception {
PKSigningInformation pkSigningInformation =
new PKSigningInformationUtil().loadSigningInformationFromPKCS12AndIntermediateCertificate(
KEYSTORE_PATH, KEYSTORE_PASSWORD, APPLE_WWDRCA);
PKPassTemplateFolder pkPassTemplate = new PKPassTemplateFolder(getPathFromClasspath(PASS_TEMPLATE_FOLDER));
IPKSigningUtil pkSigningUtil = new PKFileBasedSigningUtil();

if (passZipFile.exists()) {
passZipFile.delete();
}

try (FileOutputStream outputStream = new FileOutputStream(passZipFile)) {
if (personalization != null) {
pkSigningUtil.createSignedAndZippedPersonalizedPkPassArchiveStream(pkPass,
personalization, pkPassTemplate,
pkSigningInformation, outputStream);
} else {
pkSigningUtil.createSignedAndZippedPkPassArchiveStream(pkPass, pkPassTemplate,
pkSigningInformation, outputStream);
}
}

Assert.assertTrue(passZipFile.exists());
Assert.assertTrue(passZipFile.length() > 0);
AssertZip.assertValid(passZipFile);

Path pkpassFile = passZipFile.toPath();
FileSystem fs = FileSystems.newFileSystem(pkpassFile, (ClassLoader) null);
Path bgFilePath = fs.getPath(PKPassTemplateInMemory.PK_ICON);
Assert.assertTrue(Files.exists(bgFilePath));
Path ignoredFilePath = fs.getPath(".ignored_file");
Assert.assertFalse(Files.exists(ignoredFilePath));
}

private ObjectMapper getObjectMapper() {
ObjectMapper objectMapper = new ObjectMapper();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,73 @@ private void createZipAndAssert(IPKPassTemplate pkPassTemplate, PKPass pkPass, P
AssertZip.assertValid(passZipFile);
}

@Test
public void testWithInMemoryTemplateStreaming() throws Exception {
PKPassTemplateInMemory pkPassTemplateInMemory = new PKPassTemplateInMemory();

// icon
URL iconFileURL = PKInMemorySigningUtilTest.class.getClassLoader().getResource("StoreCard.raw/icon@2x.png");
File iconFile = new File(iconFileURL.getFile());
pkPassTemplateInMemory.addFile(PKPassTemplateInMemory.PK_ICON_RETINA, iconFile);
// icon for language
pkPassTemplateInMemory.addFile(PKPassTemplateInMemory.PK_ICON_RETINA, Locale.ENGLISH, iconFile);

PKPass pass = new ObjectMapper().readValue(new File(getPathFromClasspath("pass.json")), PKPass.class);

File passfile = File.createTempFile("passInMemoryStreamOutput", ".zip");
createZipAndAssertStream(pkPassTemplateInMemory, pass, passfile);
}

@Test
public void testWithInMemoryTemplateStreamingAndPersonalization() throws Exception {
PKPassTemplateInMemory pkPassTemplateInMemory = new PKPassTemplateInMemory();

// icon
URL iconFileURL = PKInMemorySigningUtilTest.class.getClassLoader().getResource("StoreCard.raw/icon@2x.png");
File iconFile = new File(iconFileURL.getFile());
pkPassTemplateInMemory.addFile(PKPassTemplateInMemory.PK_ICON_RETINA, iconFile);
// icon for language
pkPassTemplateInMemory.addFile(PKPassTemplateInMemory.PK_ICON_RETINA, Locale.ENGLISH, iconFile);

PKPass pass = new ObjectMapper().readValue(new File(getPathFromClasspath("pass.json")), PKPass.class);

PKPersonalizationBuilder personalization = PKPersonalization.builder()
.description("desc")
.termsAndConditions("T&C")
.requiredPersonalizationField(PKPassPersonalizationField.PKPassPersonalizationFieldName);

File passfile = File.createTempFile("passInMemoryStreamOutput", ".zip");
createZipAndAssertStream(pkPassTemplateInMemory, pass, personalization.build(), passfile);
}

private void createZipAndAssertStream(IPKPassTemplate pkPassTemplate, PKPass pkPass, File passZipFile) throws Exception {
createZipAndAssertStream(pkPassTemplate, pkPass, null, passZipFile);
}

private void createZipAndAssertStream(IPKPassTemplate pkPassTemplate, PKPass pkPass, PKPersonalization personalization, File passZipFile)
throws Exception {
PKSigningInformation pkSigningInformation = new PKSigningInformationUtil().loadSigningInformationFromPKCS12AndIntermediateCertificate(
KEYSTORE_PATH, KEYSTORE_PASSWORD, APPLE_WWDRCA);

if (passZipFile.exists()) {
passZipFile.delete();
}

try (FileOutputStream outputStream = new FileOutputStream(passZipFile)) {
if (personalization != null) {
pkInMemorySigningUtil.createSignedAndZippedPersonalizedPkPassArchiveStream(pkPass, personalization,
pkPassTemplate, pkSigningInformation, outputStream);
} else {
pkInMemorySigningUtil.createSignedAndZippedPkPassArchiveStream(pkPass,
pkPassTemplate, pkSigningInformation, outputStream);
}
}

Assert.assertTrue(passZipFile.exists());
Assert.assertTrue(passZipFile.length() > 0);
AssertZip.assertValid(passZipFile);
}

private String getPathFromClasspath(String path) throws Exception {
return Paths.get(ClassLoader.getSystemResource(path).toURI()).toString();
}
Expand Down
Loading