Add custom QZ Tray fork with pairing key authentication

- Custom fork of QZ Tray 2.2.x with certificate validation bypassed
- Implemented pairing key (HMAC) authentication as replacement
- Modified files: PrintSocketClient.java (certificate check disabled)
- New files: PairingAuth.java, PairingConfigDialog.java
- Excluded build artifacts (out/, lib/javafx*) from repository
- Library JARs included for dependency management
This commit is contained in:
2025-10-02 02:27:45 +03:00
parent 755400a269
commit c7266c32ee
444 changed files with 63195 additions and 1 deletions

View File

@@ -0,0 +1,230 @@
package qz.installer;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openssl.PEMParser;
import qz.installer.certificate.CertificateChainBuilder;
import qz.installer.certificate.ExpiryTask;
import qz.installer.certificate.CertificateManager;
import java.io.IOException;
import java.io.StringReader;
import java.security.Security;
import java.security.cert.X509Certificate;
import java.util.HashMap;
public class InstallerTests {
public static void main(String ... args) throws Exception {
// runInstallerTests();
runExpiryTests();
}
public static void runInstallerTests() throws Exception {
CertificateChainBuilder.SSL_CERT_AGE = 1;
Installer installer = Installer.getInstance();
// installer.install();
CertificateManager certificateManager = installer.certGen(true);
new ExpiryTask(certificateManager).schedule(1000, 1000);
Thread.sleep(5000);
installer.removeCerts();
}
public static void runExpiryTests() throws Exception {
Security.addProvider(new BouncyCastleProvider());
String[] testCerts = { QZ_INDUSTRIES_CERT, CA_CERT_ORG_CERT, LETS_ENCRYPT_CERT };
HashMap<ExpiryTask.CertProvider, String> certmap = new HashMap<>();
certmap.put(ExpiryTask.CertProvider.INTERNAL, QZ_INDUSTRIES_CERT);
certmap.put(ExpiryTask.CertProvider.CA_CERT_ORG, CA_CERT_ORG_CERT);
certmap.put(ExpiryTask.CertProvider.LETS_ENCRYPT, LETS_ENCRYPT_CERT);
for(String testCert : testCerts) {
X509Certificate cert = loadCert(testCert);
ExpiryTask.findCertProvider(cert);
ExpiryTask.getExpiry(cert);
ExpiryTask.parseHostNames(cert);
}
}
public static X509Certificate loadCert(String cert) throws IOException {
PEMParser reader = new PEMParser(new StringReader(cert));
return (X509Certificate)reader.readObject();
}
private static String QZ_INDUSTRIES_CERT = "-----BEGIN CERTIFICATE-----\n" +
"MIIFDjCCA/agAwIBAgIGAW3W19xeMA0GCSqGSIb3DQEBCwUAMIGaMQswCQYDVQQG\n" +
"EwJVUzELMAkGA1UECAwCTlkxEjAQBgNVBAcMCUNhbmFzdG90YTEbMBkGA1UECgwS\n" +
"UVogSW5kdXN0cmllcywgTExDMRswGQYDVQQLDBJRWiBJbmR1c3RyaWVzLCBMTEMx\n" +
"HDAaBgkqhkiG9w0BCQEWDXN1cHBvcnRAcXouaW8xEjAQBgNVBAMMCWxvY2FsaG9z\n" +
"dDAeFw0xOTEwMTUyMzEyMTNaFw0yMjAxMTgwMDEyMTNaMIGaMQswCQYDVQQGEwJV\n" +
"UzELMAkGA1UECAwCTlkxEjAQBgNVBAcMCUNhbmFzdG90YTEbMBkGA1UECgwSUVog\n" +
"SW5kdXN0cmllcywgTExDMRswGQYDVQQLDBJRWiBJbmR1c3RyaWVzLCBMTEMxHDAa\n" +
"BgkqhkiG9w0BCQEWDXN1cHBvcnRAcXouaW8xEjAQBgNVBAMMCWxvY2FsaG9zdDCC\n" +
"ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK8Hfp8Hujhr6OCTJYLPnluv\n" +
"XgDi92eX8nkW+HkpWjgDwjv59VqIiycSGTxp5GCozvDF7zHbrSICVOlHa1iFXv3w\n" +
"8EpWTIKxfqiNDZohnq38R1lVGwfPC97pzaqu5CWvjTmUD5T/Cl5RnZEvnKoXvxAA\n" +
"9/Eikzz7TGr2BL56rJFmwYRosEd2tvyxV4o/m1t/PSU9cAi1GzWpuwRbmFl34cvV\n" +
"tMPeWUz315zy8Qw9cz4ktb1O/H+5BWXdpb9DRUS9QG6sS1Esi9jIZ7rPjm+Gqj3P\n" +
"mcsev9jVlex7C0eMG3QVLpOiurPxKYkGHH9F9W6PXvKEk/jWjFFxbpy380iqTb8C\n" +
"AwEAAaOCAVYwggFSMIHMBgNVHSMEgcQwgcGAFCNVfcjxztjhZUuVHS5vsRDzVvhb\n" +
"oYGgpIGdMIGaMQswCQYDVQQGEwJVUzELMAkGA1UECAwCTlkxEjAQBgNVBAcMCUNh\n" +
"bmFzdG90YTEbMBkGA1UECgwSUVogSW5kdXN0cmllcywgTExDMRswGQYDVQQLDBJR\n" +
"WiBJbmR1c3RyaWVzLCBMTEMxHDAaBgkqhkiG9w0BCQEWDXN1cHBvcnRAcXouaW8x\n" +
"EjAQBgNVBAMMCWxvY2FsaG9zdIIGAW3W19ucMAwGA1UdEwEB/wQCMAAwDgYDVR0P\n" +
"AQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAlBgNVHREE\n" +
"HjAcgglsb2NhbGhvc3SCD2xvY2FsaG9zdC5xei5pbzAdBgNVHQ4EFgQUf2fwQ8IJ\n" +
"pdlT4+ghS0BP/V91ix0wDQYJKoZIhvcNAQELBQADggEBAHFiDZ7jItbHjpxxOHYF\n" +
"g6O61+7ETEPy0JGIPWxiysNCDfKyxuaVQ0UZ3/r6g5uQs3GjiQRIFxTmBk0hFTYB\n" +
"ONS2P0ugyED+C5wJADDcILa8SAF0EwrFX/6f3TnG+Qvn3jBRUCnjKTMfpnSlgMTk\n" +
"/wm1Jg10gUEXGHWGagw4YPVwMvBaWWYEFPC/emlONcAkZv4gfPZJ61bZgstqF+bZ\n" +
"WQM1GF1TOO8x/2KgguTknxc1EI4SmWN3Zl58BY8sf95yribLmKFW2VwbOHqfs0/d\n" +
"lFDMhix3cTURGvpyt+ZM4KXD9VkFpLIqRe1Qj02BPXS4GDNPQ+3xPbFOpvIKeYhf\n" +
"cGk=\n" +
"-----END CERTIFICATE-----";
private static String CA_CERT_ORG_CERT = "-----BEGIN CERTIFICATE-----\n" +
"MIIHnjCCBYagAwIBAgIDE4H4MA0GCSqGSIb3DQEBDQUAMHkxEDAOBgNVBAoTB1Jv\n" +
"b3QgQ0ExHjAcBgNVBAsTFWh0dHA6Ly93d3cuY2FjZXJ0Lm9yZzEiMCAGA1UEAxMZ\n" +
"Q0EgQ2VydCBTaWduaW5nIEF1dGhvcml0eTEhMB8GCSqGSIb3DQEJARYSc3VwcG9y\n" +
"dEBjYWNlcnQub3JnMB4XDTE4MDMxNzExMTMxNloXDTIwMDMxNjExMTMxNlowYTEL\n" +
"MAkGA1UEBhMCQVUxDDAKBgNVBAgTA05TVzEPMA0GA1UEBxMGU3lkbmV5MRQwEgYD\n" +
"VQQKEwtDQWNlcnQgSW5jLjEdMBsGA1UEAxMUY29tbXVuaXR5LmNhY2VydC5vcmcw\n" +
"ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKY4Bz8s5f0AK56dGIl8y1\n" +
"qnLyNhJr2pxJF9PInO33meBiCqpoTWpPHyIO51NGeySrlW35ZXUzp6tBMptXQict\n" +
"J7PkQcSf+lEn1AmRtWHIFNf/uM5IlgoomKktbAkkK+PLOtDBuZ40sKnRY1ooJ9ZK\n" +
"UnOrb5puz1D+JHp8JYxkPfknCNAZLeNPXqn9QqnpFKk8/c2CrVF8hShk/k5t2Dpr\n" +
"Q0Et9FkPOYBru9p5LQXQBA5QKPg1ESAVKYxRLbR4tJ02we6rOKWgLCnETlMmdjky\n" +
"NgaDG6dg79wNKu/uuYyQSXaAnJU67RGXNxIpudOlZ0c2+467mWDFaUHY4yzGTquq\n" +
"OGhMDXJu2fe7kDcBP8qH9YeIhN1WSLSnN4cbIP9UVxZXNfZ0WnA2Drj8iGlpL48v\n" +
"vBzuUD6EZ+WTeOkoapb0CRGAB+wdMQ6Tg+87tx8vUkhilk3NZ3kKRzOoDKiDisK9\n" +
"/WFh8aU7Eq62V15TmzOOkCHmXME1KH2CuzG4MQzalFz8ahRQQnezEMt91uHvCZya\n" +
"t5lcGr9W57FnYcxG6KqUO4iV6HWmJYXYhl5PfpEKzKktceH1PnuDptnE8mtdJW1T\n" +
"8p43ubgcAGxEvsq6nbeY76b1xlIkq1/NEL3BPDSoz+Tnz5MwLKjHQcqA7Av/KRH3\n" +
"VBnw4YI0VtGxZnz4wjyA8wIDAQABo4ICRTCCAkEwDAYDVR0TAQH/BAIwADAOBgNV\n" +
"HQ8BAf8EBAMCA6gwNAYDVR0lBC0wKwYIKwYBBQUHAwIGCCsGAQUFBwMBBglghkgB\n" +
"hvhCBAEGCisGAQQBgjcKAwMwMwYIKwYBBQUHAQEEJzAlMCMGCCsGAQUFBzABhhdo\n" +
"dHRwOi8vb2NzcC5jYWNlcnQub3JnLzAxBgNVHR8EKjAoMCagJKAihiBodHRwOi8v\n" +
"Y3JsLmNhY2VydC5vcmcvcmV2b2tlLmNybDCCAYEGA1UdEQSCAXgwggF0ghRjb21t\n" +
"dW5pdHkuY2FjZXJ0Lm9yZ6AiBggrBgEFBQcIBaAWDBRjb21tdW5pdHkuY2FjZXJ0\n" +
"Lm9yZ4Ibbm9jZXJ0LmNvbW11bml0eS5jYWNlcnQub3JnoCkGCCsGAQUFBwgFoB0M\n" +
"G25vY2VydC5jb21tdW5pdHkuY2FjZXJ0Lm9yZ4IZY2VydC5jb21tdW5pdHkuY2Fj\n" +
"ZXJ0Lm9yZ6AnBggrBgEFBQcIBaAbDBljZXJ0LmNvbW11bml0eS5jYWNlcnQub3Jn\n" +
"ghBlbWFpbC5jYWNlcnQub3JnoB4GCCsGAQUFBwgFoBIMEGVtYWlsLmNhY2VydC5v\n" +
"cmeCF25vY2VydC5lbWFpbC5jYWNlcnQub3JnoCUGCCsGAQUFBwgFoBkMF25vY2Vy\n" +
"dC5lbWFpbC5jYWNlcnQub3JnghVjZXJ0LmVtYWlsLmNhY2VydC5vcmegIwYIKwYB\n" +
"BQUHCAWgFwwVY2VydC5lbWFpbC5jYWNlcnQub3JnMA0GCSqGSIb3DQEBDQUAA4IC\n" +
"AQBWaOcDYaF25eP9eJTBUItFKkK3ppq7eN0qT9qyrWVxhRMWtAYcjW8hfSOx5xPS\n" +
"4bYL8RJz+1NNyzZqbyhvHt9JnCn1g2HllSD1HTHSMxZZrdjWq/9XxnmG55u2CUfo\n" +
"hN1M0qmUJvvWv0T4YWMwhv94tKrThDXnvqa4S+JfnTZQTLPAVq+iTKr+bsdB7pkI\n" +
"D59SJdE9tRsrb1wfbBbEpYw2LBZo7Jje4E9FmtnMraGxZtFsHhpZvYAnEt80eFts\n" +
"ccSOlhqowW9Hqx0pg55Sq9Wrj9T+AxTx/6sAJL4qxm7CRjeIAqW5fksvA4yXgYaq\n" +
"g6M2uIcRMEeafN8bHy1LOXkZDAcbusPfAGenMdE/p5B0K45Rlx3+dfNUjHyF4+ob\n" +
"FOVNxgPcfCZ2lJrgvJbw9tBGqC13yPUlkywQ+7QSJgTPbWrnXLIu7fz5SmCxk5KD\n" +
"zsq4F4YsaeBIYeHOsJLbqeqftm3eNBESphOvXlZKMGRMiThVWIaX5PIZB5OKgyE3\n" +
"C5CvKcv5qv1CeI7qFtLkq28QKCqJJIfTDvArEq/O5P2d+yQetYkWN5mzCJqT/kB+\n" +
"y74nu6kCBoZNWBZHDKeM6NkZD1/wI47S2A4cmE7SiGx3AcNRhmrXhvnSD7u7cGVD\n" +
"b5yw6z+JqFRMqMm0SuSx5X2oKNKfnqY77fIx6dtY8F5Scg==\n" +
"-----END CERTIFICATE-----\n" +
" 1 s:/O=Root CA/OU=http://www.cacert.org/CN=CA Cert Signing Authority/emailAddress=support@cacert.org\n" +
" i:/O=Root CA/OU=http://www.cacert.org/CN=CA Cert Signing Authority/emailAddress=support@cacert.org\n" +
"-----BEGIN CERTIFICATE-----\n" +
"MIIHPTCCBSWgAwIBAgIBADANBgkqhkiG9w0BAQQFADB5MRAwDgYDVQQKEwdSb290\n" +
"IENBMR4wHAYDVQQLExVodHRwOi8vd3d3LmNhY2VydC5vcmcxIjAgBgNVBAMTGUNB\n" +
"IENlcnQgU2lnbmluZyBBdXRob3JpdHkxITAfBgkqhkiG9w0BCQEWEnN1cHBvcnRA\n" +
"Y2FjZXJ0Lm9yZzAeFw0wMzAzMzAxMjI5NDlaFw0zMzAzMjkxMjI5NDlaMHkxEDAO\n" +
"BgNVBAoTB1Jvb3QgQ0ExHjAcBgNVBAsTFWh0dHA6Ly93d3cuY2FjZXJ0Lm9yZzEi\n" +
"MCAGA1UEAxMZQ0EgQ2VydCBTaWduaW5nIEF1dGhvcml0eTEhMB8GCSqGSIb3DQEJ\n" +
"ARYSc3VwcG9ydEBjYWNlcnQub3JnMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC\n" +
"CgKCAgEAziLA4kZ97DYoB1CW8qAzQIxL8TtmPzHlawI229Z89vGIj053NgVBlfkJ\n" +
"8BLPRoZzYLdufujAWGSuzbCtRRcMY/pnCujW0r8+55jE8Ez64AO7NV1sId6eINm6\n" +
"zWYyN3L69wj1x81YyY7nDl7qPv4coRQKFWyGhFtkZip6qUtTefWIonvuLwphK42y\n" +
"fk1WpRPs6tqSnqxEQR5YYGUFZvjARL3LlPdCfgv3ZWiYUQXw8wWRBB0bF4LsyFe7\n" +
"w2t6iPGwcswlWyCR7BYCEo8y6RcYSNDHBS4CMEK4JZwFaz+qOqfrU0j36NK2B5jc\n" +
"G8Y0f3/JHIJ6BVgrCFvzOKKrF11myZjXnhCLotLddJr3cQxyYN/Nb5gznZY0dj4k\n" +
"epKwDpUeb+agRThHqtdB7Uq3EvbXG4OKDy7YCbZZ16oE/9KTfWgu3YtLq1i6L43q\n" +
"laegw1SJpfvbi1EinbLDvhG+LJGGi5Z4rSDTii8aP8bQUWWHIbEZAWV/RRyH9XzQ\n" +
"QUxPKZgh/TMfdQwEUfoZd9vUFBzugcMd9Zi3aQaRIt0AUMyBMawSB3s42mhb5ivU\n" +
"fslfrejrckzzAeVLIL+aplfKkQABi6F1ITe1Yw1nPkZPcCBnzsXWWdsC4PDSy826\n" +
"YreQQejdIOQpvGQpQsgi3Hia/0PsmBsJUUtaWsJx8cTLc6nloQsCAwEAAaOCAc4w\n" +
"ggHKMB0GA1UdDgQWBBQWtTIb1Mfz4OaO873SsDrusjkY0TCBowYDVR0jBIGbMIGY\n" +
"gBQWtTIb1Mfz4OaO873SsDrusjkY0aF9pHsweTEQMA4GA1UEChMHUm9vdCBDQTEe\n" +
"MBwGA1UECxMVaHR0cDovL3d3dy5jYWNlcnQub3JnMSIwIAYDVQQDExlDQSBDZXJ0\n" +
"IFNpZ25pbmcgQXV0aG9yaXR5MSEwHwYJKoZIhvcNAQkBFhJzdXBwb3J0QGNhY2Vy\n" +
"dC5vcmeCAQAwDwYDVR0TAQH/BAUwAwEB/zAyBgNVHR8EKzApMCegJaAjhiFodHRw\n" +
"czovL3d3dy5jYWNlcnQub3JnL3Jldm9rZS5jcmwwMAYJYIZIAYb4QgEEBCMWIWh0\n" +
"dHBzOi8vd3d3LmNhY2VydC5vcmcvcmV2b2tlLmNybDA0BglghkgBhvhCAQgEJxYl\n" +
"aHR0cDovL3d3dy5jYWNlcnQub3JnL2luZGV4LnBocD9pZD0xMDBWBglghkgBhvhC\n" +
"AQ0ESRZHVG8gZ2V0IHlvdXIgb3duIGNlcnRpZmljYXRlIGZvciBGUkVFIGhlYWQg\n" +
"b3ZlciB0byBodHRwOi8vd3d3LmNhY2VydC5vcmcwDQYJKoZIhvcNAQEEBQADggIB\n" +
"ACjH7pyCArpcgBLKNQodgW+JapnM8mgPf6fhjViVPr3yBsOQWqy1YPaZQwGjiHCc\n" +
"nWKdpIevZ1gNMDY75q1I08t0AoZxPuIrA2jxNGJARjtT6ij0rPtmlVOKTV39O9lg\n" +
"18p5aTuxZZKmxoGCXJzN600BiqXfEVWqFcofN8CCmHBh22p8lqOOLlQ+TyGpkO/c\n" +
"gr/c6EWtTZBzCDyUZbAEmXZ/4rzCahWqlwQ3JNgelE5tDlG+1sSPypZt90Pf6DBl\n" +
"Jzt7u0NDY8RD97LsaMzhGY4i+5jhe1o+ATc7iwiwovOVThrLm82asduycPAtStvY\n" +
"sONvRUgzEv/+PDIqVPfE94rwiCPCR/5kenHA0R6mY7AHfqQv0wGP3J8rtsYIqQ+T\n" +
"SCX8Ev2fQtzzxD72V7DX3WnRBnc0CkvSyqD/HMaMyRa+xMwyN2hzXwj7UfdJUzYF\n" +
"CpUCTPJ5GhD22Dp1nPMd8aINcGeGG7MW9S/lpOt5hvk9C8JzC6WZrG/8Z7jlLwum\n" +
"GCSNe9FINSkYQKyTYOGWhlC0elnYjyELn8+CkcY7v2vcB5G5l1YjqrZslMZIBjzk\n" +
"zk6q5PYvCdxTby78dOs6Y5nCpqyJvKeyRKANihDjbPIky/qbn3BHLt4Ui9SyIAmW\n" +
"omTxJBzcoTWcFbLUvFUufQb1nA5V9FrWk9p2rSVzTMVD\n" +
"-----END CERTIFICATE-----";
private static String LETS_ENCRYPT_CERT = "-----BEGIN CERTIFICATE-----\n" +
"MIIFTTCCBDWgAwIBAgISA/Qu8kKrD8kLzdY+/WPM8whbMA0GCSqGSIb3DQEBCwUA\n" +
"MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD\n" +
"ExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0xOTA4MjgxMzQ0MzdaFw0x\n" +
"OTExMjYxMzQ0MzdaMBYxFDASBgNVBAMTC2J1aWxkLnF6LmlvMIIBIjANBgkqhkiG\n" +
"9w0BAQEFAAOCAQ8AMIIBCgKCAQEA9Q/StADlpSnsShayw4SV4dIbiOiiEYwqBlB7\n" +
"FYFF7LfZdREXlYBaTH46hUJI1ooUfsfnNTnYHac6tCEwr9wQnnobO7ACtuYENrVN\n" +
"HiuzYtMGN90mqf2+PXhHb+xGpBrD36fmq4Ix3aIc5o4lKxFY4IstfbTbYDanF1Q4\n" +
"qUIRUSdAJdgJqmJB2hwlFvjzeBGV4h6vgmiEsATawGoSDMLdWsFpiEnYLTfyvvhY\n" +
"5L4e2O9roBOEQ/YJbWVrewh6LYs6s6SbbNkKttQNSGUFVeW6u8q5+yHi2chSXlwW\n" +
"+o1SdjE6yw9laHp/nog5gyg95O2xm36YA3mRgfoAEfimwFwf2wIDAQABo4ICXzCC\n" +
"AlswDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcD\n" +
"AjAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBTRuEPSdvHr2SkCIpArJG34rUOPLzAf\n" +
"BgNVHSMEGDAWgBSoSmpjBH3duubRObemRWXv86jsoTBvBggrBgEFBQcBAQRjMGEw\n" +
"LgYIKwYBBQUHMAGGImh0dHA6Ly9vY3NwLmludC14My5sZXRzZW5jcnlwdC5vcmcw\n" +
"LwYIKwYBBQUHMAKGI2h0dHA6Ly9jZXJ0LmludC14My5sZXRzZW5jcnlwdC5vcmcv\n" +
"MBYGA1UdEQQPMA2CC2J1aWxkLnF6LmlvMEwGA1UdIARFMEMwCAYGZ4EMAQIBMDcG\n" +
"CysGAQQBgt8TAQEBMCgwJgYIKwYBBQUHAgEWGmh0dHA6Ly9jcHMubGV0c2VuY3J5\n" +
"cHQub3JnMIIBAwYKKwYBBAHWeQIEAgSB9ASB8QDvAHYAb1N2rDHwMRnYmQCkURX/\n" +
"dxUcEdkCwQApBo2yCJo32RMAAAFs2K+GMAAABAMARzBFAiAI6WH6tspPGgp6W3KI\n" +
"n3Ihkb5OqS4KjGFbWNxsJq+/FgIhAJ0zLvFPdlivXpJd/Vn/+xKIBeAs9Ens2uxS\n" +
"A34B35oyAHUAY/Lbzeg7zCzPC3KEJ1drM6SNYXePvXWmOLHHaFRL2I0AAAFs2K+F\n" +
"FwAABAMARjBEAiAEYpsT6YoIByfh2SHOjuvICRUejlAHVS6bbPN+hvV+4gIgS6pt\n" +
"7MtF6GA83AF3lVZPCSnUKp3VvqcEjchf493wHAowDQYJKoZIhvcNAQELBQADggEB\n" +
"AH1Nr3BfiCG6iRUtGpaxoIv1J2XDmxAfz5kEtoErwo/oPTz2xY8UyYa1WFlCyJU1\n" +
"JWvGrbpT3MQXbdrLsSyT2HQRwEKzXr/u8rRSj18cqggwi8T/f9HgZXjf4ly19uYU\n" +
"5GqLBsPwO8BVzawr/bnI0viH1uVpcIQA/rW63LkOL8bMv16zW27mnoEAo8NG1YZU\n" +
"IEuCfMH/wFfkbmcw549l2PqIidVqSvWPltLlGdkNJYobFvyg5ThWXNb57cNIMb1k\n" +
"Egy5O7RqmVycOdt6//M5KrluWDUS/qi+7oAllGJ9AnFVDttmKuklrhGmwRv/ezN7\n" +
"gUtpN5eb5M1XxvExz3fXxfM=\n" +
"-----END CERTIFICATE-----\n" +
"-----BEGIN CERTIFICATE-----\n" +
"MIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/\n" +
"MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT\n" +
"DkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow\n" +
"SjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT\n" +
"GkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC\n" +
"AQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF\n" +
"q6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8\n" +
"SMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0\n" +
"Z8h/pZq4UmEUEz9l6YKHy9v6Dlb2honzhT+Xhq+w3Brvaw2VFn3EK6BlspkENnWA\n" +
"a6xK8xuQSXgvopZPKiAlKQTGdMDQMc2PMTiVFrqoM7hD8bEfwzB/onkxEz0tNvjj\n" +
"/PIzark5McWvxI0NHWQWM6r6hCm21AvA2H3DkwIDAQABo4IBfTCCAXkwEgYDVR0T\n" +
"AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwfwYIKwYBBQUHAQEEczBxMDIG\n" +
"CCsGAQUFBzABhiZodHRwOi8vaXNyZy50cnVzdGlkLm9jc3AuaWRlbnRydXN0LmNv\n" +
"bTA7BggrBgEFBQcwAoYvaHR0cDovL2FwcHMuaWRlbnRydXN0LmNvbS9yb290cy9k\n" +
"c3Ryb290Y2F4My5wN2MwHwYDVR0jBBgwFoAUxKexpHsscfrb4UuQdf/EFWCFiRAw\n" +
"VAYDVR0gBE0wSzAIBgZngQwBAgEwPwYLKwYBBAGC3xMBAQEwMDAuBggrBgEFBQcC\n" +
"ARYiaHR0cDovL2Nwcy5yb290LXgxLmxldHNlbmNyeXB0Lm9yZzA8BgNVHR8ENTAz\n" +
"MDGgL6AthitodHRwOi8vY3JsLmlkZW50cnVzdC5jb20vRFNUUk9PVENBWDNDUkwu\n" +
"Y3JsMB0GA1UdDgQWBBSoSmpjBH3duubRObemRWXv86jsoTANBgkqhkiG9w0BAQsF\n" +
"AAOCAQEA3TPXEfNjWDjdGBX7CVW+dla5cEilaUcne8IkCJLxWh9KEik3JHRRHGJo\n" +
"uM2VcGfl96S8TihRzZvoroed6ti6WqEBmtzw3Wodatg+VyOeph4EYpr/1wXKtx8/\n" +
"wApIvJSwtmVi4MFU5aMqrSDE6ea73Mj2tcMyo5jMd6jmeWUHK8so/joWUoHOUgwu\n" +
"X4Po1QYz+3dszkDqMp4fklxBwXRsW10KXzPMTZ+sOPAveyxindmjkW8lGy+QsRlG\n" +
"PfZ+G6Z6h7mjem0Y+iWlkYcV4PIWL1iwBi8saCbGS5jN2p8M+X+Q7UNKEkROb3N6\n" +
"KOqkqm57TH2H3eDJAkSnh6/DNFu0Qg==\n" +
"-----END CERTIFICATE-----";
}

View File

@@ -0,0 +1,44 @@
package qz.installer.browser;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import qz.installer.certificate.firefox.FirefoxCertificateInstaller;
import qz.installer.certificate.firefox.locator.AppAlias;
import qz.installer.certificate.firefox.locator.AppInfo;
import qz.installer.certificate.firefox.locator.AppLocator;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Date;
public class AppFinderTests {
private static final Logger log = LogManager.getLogger(AppFinderTests.class);
public static void main(String ... args) throws Exception {
runTest(AppAlias.FIREFOX);
}
private static void runTest(AppAlias app) {
Date begin = new Date();
ArrayList<AppInfo> appList = AppLocator.getInstance().locate(app);
ArrayList<Path> runningPaths = AppLocator.getRunningPaths(appList);
StringBuilder output = new StringBuilder("Found apps:\n");
for (AppInfo appInfo : appList) {
output.append(String.format(" name: '%s', path: '%s', exePath: '%s', version: '%s'\n",
appInfo.getAlias().getName(),
appInfo.getPath(),
appInfo.getExePath(),
appInfo.getVersion()
));
if(runningPaths.contains(appInfo.getExePath())) {
FirefoxCertificateInstaller.issueRestartWarning(runningPaths, appInfo);
}
}
Date end = new Date();
log.debug(output.toString());
log.debug("Time to find and execute {}: {}s", app.name(), (end.getTime() - begin.getTime())/1000.0f);
}
}

View File

@@ -0,0 +1,20 @@
package qz.installer.provision;
import org.codehaus.jettison.json.JSONException;
import qz.common.Constants;
import java.io.IOException;
import java.io.InputStream;
public class ProvisionerInstallerTests {
public static void main(String ... args) throws JSONException, IOException {
InputStream in = ProvisionerInstallerTests.class.getResourceAsStream("resources/" + Constants.PROVISION_FILE);
// Parse the JSON
ProvisionInstaller provisionInstaller = new ProvisionInstaller(ProvisionerInstallerTests.class, in);
// Invoke all parsed steps
provisionInstaller.invoke();
}
}

View File

@@ -0,0 +1,60 @@
-----BEGIN CERTIFICATE-----
MIIFAzCCAuugAwIBAgICEAIwDQYJKoZIhvcNAQEFBQAwgZgxCzAJBgNVBAYTAlVT
MQswCQYDVQQIDAJOWTEbMBkGA1UECgwSUVogSW5kdXN0cmllcywgTExDMRswGQYD
VQQLDBJRWiBJbmR1c3RyaWVzLCBMTEMxGTAXBgNVBAMMEHF6aW5kdXN0cmllcy5j
b20xJzAlBgkqhkiG9w0BCQEWGHN1cHBvcnRAcXppbmR1c3RyaWVzLmNvbTAeFw0x
NTAzMTkwMjM4NDVaFw0yNTAzMTkwMjM4NDVaMHMxCzAJBgNVBAYTAkFBMRMwEQYD
VQQIDApTb21lIFN0YXRlMQ0wCwYDVQQKDAREZW1vMQ0wCwYDVQQLDAREZW1vMRIw
EAYDVQQDDAlsb2NhbGhvc3QxHTAbBgkqhkiG9w0BCQEWDnJvb3RAbG9jYWxob3N0
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtFzbBDRTDHHmlSVQLqjY
aoGax7ql3XgRGdhZlNEJPZDs5482ty34J4sI2ZK2yC8YkZ/x+WCSveUgDQIVJ8oK
D4jtAPxqHnfSr9RAbvB1GQoiYLxhfxEp/+zfB9dBKDTRZR2nJm/mMsavY2DnSzLp
t7PJOjt3BdtISRtGMRsWmRHRfy882msBxsYug22odnT1OdaJQ54bWJT5iJnceBV2
1oOqWSg5hU1MupZRxxHbzI61EpTLlxXJQ7YNSwwiDzjaxGrufxc4eZnzGQ1A8h1u
jTaG84S1MWvG7BfcPLW+sya+PkrQWMOCIgXrQnAsUgqQrgxQ8Ocq3G4X9UvBy5VR
CwIDAQABo3sweTAJBgNVHRMEAjAAMCwGCWCGSAGG+EIBDQQfFh1PcGVuU1NMIEdl
bmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQUpG420UhvfwAFMr+8vf3pJunQ
gH4wHwYDVR0jBBgwFoAUkKZQt4TUuepf8gWEE3hF6Kl1VFwwDQYJKoZIhvcNAQEF
BQADggIBAFXr6G1g7yYVHg6uGfh1nK2jhpKBAOA+OtZQLNHYlBgoAuRRNWdE9/v4
J/3Jeid2DAyihm2j92qsQJXkyxBgdTLG+ncILlRElXvG7IrOh3tq/TttdzLcMjaR
8w/AkVDLNL0z35shNXih2F9JlbNRGqbVhC7qZl+V1BITfx6mGc4ayke7C9Hm57X0
ak/NerAC/QXNs/bF17b+zsUt2ja5NVS8dDSC4JAkM1dD64Y26leYbPybB+FgOxFu
wou9gFxzwbdGLCGboi0lNLjEysHJBi90KjPUETbzMmoilHNJXw7egIo8yS5eq8RH
i2lS0GsQjYFMvplNVMATDXUPm9MKpCbZ7IlJ5eekhWqvErddcHbzCuUBkDZ7wX/j
unk/3DyXdTsSGuZk3/fLEsc4/YTujpAjVXiA1LCooQJ7SmNOpUa66TPz9O7Ufkng
+CoTSACmnlHdP7U9WLr5TYnmL9eoHwtb0hwENe1oFC5zClJoSX/7DRexSJfB7YBf
vn6JA2xy4C6PqximyCPisErNp85GUcZfo33Np1aywFv9H+a83rSUcV6kpE/jAZio
5qLpgIOisArj1HTM6goDWzKhLiR/AeG3IJvgbpr9Gr7uZmfFyQzUjvkJ9cybZRd+
G8azmpBBotmKsbtbAU/I/LVk8saeXznshOVVpDRYtVnjZeAneso7
-----END CERTIFICATE-----
--START INTERMEDIATE CERT--
-----BEGIN CERTIFICATE-----
MIIFEjCCA/qgAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwgawxCzAJBgNVBAYTAlVT
MQswCQYDVQQIDAJOWTESMBAGA1UEBwwJQ2FuYXN0b3RhMRswGQYDVQQKDBJRWiBJ
bmR1c3RyaWVzLCBMTEMxGzAZBgNVBAsMElFaIEluZHVzdHJpZXMsIExMQzEZMBcG
A1UEAwwQcXppbmR1c3RyaWVzLmNvbTEnMCUGCSqGSIb3DQEJARYYc3VwcG9ydEBx
emluZHVzdHJpZXMuY29tMB4XDTE1MDMwMjAwNTAxOFoXDTM1MDMwMjAwNTAxOFow
gZgxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJOWTEbMBkGA1UECgwSUVogSW5kdXN0
cmllcywgTExDMRswGQYDVQQLDBJRWiBJbmR1c3RyaWVzLCBMTEMxGTAXBgNVBAMM
EHF6aW5kdXN0cmllcy5jb20xJzAlBgkqhkiG9w0BCQEWGHN1cHBvcnRAcXppbmR1
c3RyaWVzLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANTDgNLU
iohl/rQoZ2bTMHVEk1mA020LYhgfWjO0+GsLlbg5SvWVFWkv4ZgffuVRXLHrwz1H
YpMyo+Zh8ksJF9ssJWCwQGO5ciM6dmoryyB0VZHGY1blewdMuxieXP7Kr6XD3GRM
GAhEwTxjUzI3ksuRunX4IcnRXKYkg5pjs4nLEhXtIZWDLiXPUsyUAEq1U1qdL1AH
EtdK/L3zLATnhPB6ZiM+HzNG4aAPynSA38fpeeZ4R0tINMpFThwNgGUsxYKsP9kh
0gxGl8YHL6ZzC7BC8FXIB/0Wteng0+XLAVto56Pyxt7BdxtNVuVNNXgkCi9tMqVX
xOk3oIvODDt0UoQUZ/umUuoMuOLekYUpZVk4utCqXXlB4mVfS5/zWB6nVxFX8Io1
9FOiDLTwZVtBmzmeikzb6o1QLp9F2TAvlf8+DIGDOo0DpPQUtOUyLPCh5hBaDGFE
ZhE56qPCBiQIc4T2klWX/80C5NZnd/tJNxjyUyk7bjdDzhzT10CGRAsqxAnsjvMD
2KcMf3oXN4PNgyfpbfq2ipxJ1u777Gpbzyf0xoKwH9FYigmqfRH2N2pEdiYawKrX
6pyXzGM4cvQ5X1Yxf2x/+xdTLdVaLnZgwrdqwFYmDejGAldXlYDl3jbBHVM1v+uY
5ItGTjk+3vLrxmvGy5XFVG+8fF/xaVfo5TW5AgMBAAGjUDBOMB0GA1UdDgQWBBSQ
plC3hNS56l/yBYQTeEXoqXVUXDAfBgNVHSMEGDAWgBQDRcZNwPqOqQvagw9BpW0S
BkOpXjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAJIO8SiNr9jpLQ
eUsFUmbueoxyI5L+P5eV92ceVOJ2tAlBA13vzF1NWlpSlrMmQcVUE/K4D01qtr0k
gDs6LUHvj2XXLpyEogitbBgipkQpwCTJVfC9bWYBwEotC7Y8mVjjEV7uXAT71GKT
x8XlB9maf+BTZGgyoulA5pTYJ++7s/xX9gzSWCa+eXGcjguBtYYXaAjjAqFGRAvu
pz1yrDWcA6H94HeErJKUXBakS0Jm/V33JDuVXY+aZ8EQi2kV82aZbNdXll/R6iGw
2ur4rDErnHsiphBgZB71C5FD4cdfSONTsYxmPmyUb5T+KLUouxZ9B0Wh28ucc1Lp
rbO7BnjW
-----END CERTIFICATE-----

View File

@@ -0,0 +1,158 @@
[
{
"description": "[ERROR EXPECTED] missing 'type' and 'phase'",
"os": "*",
"data": "foo.bar=1"
},
{
"description": "[ERROR EXPECTED] invalid 'remover' id",
"type": "remover",
"os": "*",
"phase": "install",
"data": "bbb"
},
{
"description": "[ERROR EXPECTED] missing 'type'",
"os": "*",
"phase": "install",
"data": "this_file_does_not_exist"
},
{
"description": "[ERROR EXPECTED] 'data' file missing",
"type": "script",
"os": "*",
"phase": "install",
"data": "this_file_does_not_exist"
},
{
"description": "[ERROR EXPECTED] 'arch' is invalid",
"type": "property",
"os": "*",
"arch": "sparc",
"data": "bar.foo=2"
},
{
"description": "[ERROR EXPECTED] 'os' is invalid",
"type": "property",
"os": "quake",
"arch": "*",
"data": "bar.foo=2"
},
{
"description": "[WINDOWS SCRIPT] powershell at 'install'",
"type": "script",
"os": "windows",
"phase": "install",
"data": "script1.ps1"
},
{
"description": "[MAC SCRIPT] powershell at 'install'",
"type": "script",
"os": "mac",
"phase": "install",
"data": "script1.ps1"
},
{
"description": "[LINUX SCRIPT] python at 'startup'",
"type": "script",
"os": "linux",
"phase": "startup",
"data": "script4.py"
},
{
"description": "[LINUX & MAC SCRIPT] bash without extension at 'install'",
"type": "script",
"os": "linux|mac",
"phase": "install",
"data": "script2"
},
{
"description": "[ALL OS SCRIPT] with '.sh' extension at 'install'",
"type": "script",
"os": "*",
"phase": "install",
"data": "script3.sh"
},
{
"description": "[AARCH64 ONLY SCRIPT] with '.sh' extension at 'install'",
"type": "script",
"os": "*",
"arch": "aarch64",
"phase": "install",
"data": "script2"
},
{
"description": "[CERTIFICATE] at 'startup' (allowed.dat)",
"type": "cert",
"os": "*",
"data": "cert1.crt"
},
{
"description": "[PROPERTY] at wrong phase (qz-tray.properties)",
"type": "property",
"phase": "startup",
"os": "*",
"data": "foo=bar"
},
{
"description": "[PROPERTY] at 'install' (qz-tray.properties)",
"type": "property",
"phase": "install",
"os": "*",
"data": "websocket.secure.ports=9191,9292,9393,9494"
},
{
"description": "[PROPERTY] at 'certgen' (qz-tray.properties)",
"type": "property",
"phase": "install",
"os": "*",
"data": "websocket.insecure.ports=9192,9293,9394,9495"
},
{
"description": "[PROPERTY] at 'certgen' (qz-tray.properties)",
"type": "property",
"os": "*",
"data": "log.size=2097152"
},
{
"description": "[PREFERENCE] at 'startup' (prefs.properties)",
"type": "preference",
"os": "*",
"data": "tray.notifications=true"
},
{
"description": "[REMOVER] at 'install' ('QZ Tray' rebranded 'Cherry Connect')",
"type": "remover",
"os": "*",
"phase": "install",
"data": "Cherry Connect,cc-util,cc"
},
{
"description": "[REMOVER] at 'install' QZ-branded version",
"type": "remover",
"os": "*",
"phase": "install",
"data": "qz"
},
{
"description": "[CA] at 'install'",
"type": "ca",
"os": "*",
"data": "selfsigned1.crt"
},
{
"description": "[CONF] at 'install'",
"type": "conf",
"os": "*",
"data": "java.net.useSystemProxies=true",
"path": "net.properties"
},
{
"description": "[SOFTWARE] at 'install'",
"type": "software",
"os": "windows",
"data": "DCDSetup1.5.0.17.exe",
"args": "/S /v/qn"
}
]

View File

@@ -0,0 +1,5 @@
$shell="PowerShell"
$date="$(Get-Date -format "yyyy-MM-dd HH:mm:ss")"
$script="$($myInvocation.MyCommand.Name)"
# FIXME: ~/Desktop may try to write to /root/Desktop on Linux
echo "$date Successful provisioning test from '$shell': $script" >> ~/Desktop/provision.log

View File

@@ -0,0 +1,9 @@
#!/bin/bash
shell=$(ps -p $$ -oargs=|awk '{print $1}')
date=$(date "+%F %T")
script=$(basename "$0")
user="$(eval echo ~$(logname))"
echo "$date Successful provisioning test from '$shell': $script" >> "$user/Desktop/provision.log"
chmod 555 "$user/Desktop/provision.log"

View File

@@ -0,0 +1,7 @@
shell=$(ps -p $$ -oargs=|awk '{print $1}')
date=$(date "+%F %T")
script=$(basename "$0")
user="$(eval echo ~$(logname))"
echo "$date Successful provisioning test from '$shell': $script" >> "$user/Desktop/provision.log"
chmod 555 "$user/Desktop/provision.log"

View File

@@ -0,0 +1,15 @@
#!/usr/bin/env python3
import os
def notify(title, message):
os.system(f"notify-send '{title}' '{message}'")
title=os.getenv('APP_TITLE')
version=os.getenv('APP_VERSION')
printer="\U0001F5A8"
tada="\U0001F389"
notify("{} {}".format(printer, title), """{} This is a sample message from {} {}.
This message indicates that provisioning startup tasks are working.""".format(tada, title, version))

View File

@@ -0,0 +1,24 @@
-----BEGIN CERTIFICATE-----
MIID+TCCAuGgAwIBAgIUf1NN9L3Tw6UVqPiHcFsnS+sdm1kwDQYJKoZIhvcNAQEL
BQAwgaQxCzAJBgNVBAYTAlVTMREwDwYDVQQIDAhOZXcgWW9yazESMBAGA1UEBwwJ
Q2FuYXN0b3RhMRswGQYDVQQKDBJRWiBJbmR1c3RyaWVzLCBMTEMxGzAZBgNVBAsM
ElFaIEluZHVzdHJpZXMsIExMQzEZMBcGA1UEAwwQVHJlcyBGaW5vY2NoaWFybzEZ
MBcGCSqGSIb3DQEJARYKdHJlc0Bxei5pbzAeFw0yNTAyMTAxODQxNDlaFw0yNTAz
MTIxODQxNDlaMIGkMQswCQYDVQQGEwJVUzERMA8GA1UECAwITmV3IFlvcmsxEjAQ
BgNVBAcMCUNhbmFzdG90YTEbMBkGA1UECgwSUVogSW5kdXN0cmllcywgTExDMRsw
GQYDVQQLDBJRWiBJbmR1c3RyaWVzLCBMTEMxGTAXBgNVBAMMEFRyZXMgRmlub2Nj
aGlhcm8xGTAXBgkqhkiG9w0BCQEWCnRyZXNAcXouaW8wggEiMA0GCSqGSIb3DQEB
AQUAA4IBDwAwggEKAoIBAQCyLio0KuXpKr7rmFRP9UpbKvmMZlUytKeYKfiffJub
7V4kcD2dAWnl2DL6IK8MNVM6SuTOGUIl8XDV1MTxKhtZoIF2tFtG3UpX2heL76Ai
Q7A3cqXiNzZAIxxfppgIZZSZlEjr1r+OCsJEpTJJA6Dm0xOKBcC7c4C3fi7xPvEM
hu4EOmzO1EczFF3/mpgO+RG4MFNDPa8zz8SFZN6e9LRkPiPupiapvklgHikkRm3L
V7ktP/jmA0zp7JVKDvfNBVR8iZQ3Fbhtk06Iv0t/a0bov4NtyItD1O1oftLS7jEK
Erop9NMAofk/MAduevQTHkKLwwAGXXEtHnpaXx7FDpnLAgMBAAGjITAfMB0GA1Ud
DgQWBBTcQETEM4iqTfFf6Tq5GvzbhnA7bzANBgkqhkiG9w0BAQsFAAOCAQEASY6v
ep8asCIbdDjj1knYEMUMaHsvPbXQYY60Zt1HeQxACrUHCBZ375A+sl/INrH7gRJj
KygYKbI/LGM2lDErLTyOzWu1CBTIUUbaDwY5Fc+xl39N+EDctU82Gg8ddUoJDb6f
8w/gy2FtcCiRUKdIR5rYxIDl1izkBHPoV3jgUe5ydhlfHUjBZdIWWnZs2+fETG5B
62sG9MBwOlPJkE7Wdsf6Q7lQwnpUpnj08IY9+T7c3SA3pGKi2/e7di3G/47riMOd
vnldRfCl5erR0qR6J3Ksk6oZCYngLj3zR8R9qjUgEaiC76DGZd9s9wT867SMJJLs
iu9NclpILl4aZRJg0w==
-----END CERTIFICATE-----

View File

@@ -0,0 +1,266 @@
package qz.printer.action;
import javafx.print.*;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import qz.common.Constants;
import qz.printer.action.html.WebApp;
import qz.printer.action.html.WebAppModel;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
public class WebAppTest {
private static final Logger log = LogManager.getLogger(WebAppTest.class);
private static final int SPOOLER_WAIT = 2000; // millis
private static final Path RASTER_OUTPUT_DIR = Paths.get("./out"); // see ant ${out.dir}
private static final String RASTER_OUTPUT_FORMAT = "png";
public static void main(String[] args) {
try {
WebApp.initialize();
cleanup();
// RASTER//
int rasterKnownHeightTests = 1000;
if (args.length > 1) { rasterKnownHeightTests = Integer.parseInt(args[1]); }
int rasterFittedHeightTests = 1000;
if (args.length > 2) { rasterFittedHeightTests = Integer.parseInt(args[2]); }
if (!testRasterKnownSize(rasterKnownHeightTests)) {
log.error("Testing well defined sizes failed");
} else if (!testRasterFittedSize(rasterFittedHeightTests)) {
log.error("Testing fit to height sizing failed");
} else {
log.info("All raster tests passed");
}
// VECTOR //
int vectorKnownHeightPrints = 100;
if (args.length > 3) { vectorKnownHeightPrints = Integer.parseInt(args[3]); }
int vectorFittedHeightPrints = 100;
if (args.length > 4) { vectorFittedHeightPrints = Integer.parseInt(args[4]); }
if (!testVectorKnownPrints(vectorKnownHeightPrints)) {
log.error("Failed vector prints with defined heights");
} else if (!testVectorFittedPrints(vectorFittedHeightPrints)) {
log.error("Failed vector prints with fit to height sizing");
} else {
log.info("All vector prints completed");
}
}
catch(Throwable t) {
log.error("Tests failed due to an exception", t);
}
System.exit(0); //explicit exit since jfx is running in background
}
public static boolean testRasterKnownSize(int trials) throws Throwable {
for(int i = 0; i < trials; i++) {
//new size every run
double printW = Math.max(2, (int)(Math.random() * 110) / 10d) * 72d;
double printH = Math.max(3, (int)(Math.random() * 110) / 10d) * 72d;
double zoom = Math.max(0.5d, (int)(Math.random() * 30) / 10d);
String id = "known-" + i;
WebAppModel model = buildModel(id, printW, printH, zoom, true, (int)(Math.random() * 360));
BufferedImage sample = WebApp.raster(model);
if (sample == null) {
log.error("Failed to create capture");
return false;
}
//TODO - check bottom right matches expected color
//check capture for dimensional accuracy within 1 pixel of expected (due to int rounding)
int expectedWidth = (int)Math.round(printW * (96d / 72d) * zoom);
int expectedHeight = (int)Math.round(printH * (96d / 72d) * zoom);
boolean passed = true;
if (!Arrays.asList(expectedWidth, expectedWidth + 1, expectedWidth - 1).contains(sample.getWidth())) {
log.error("Expected width to be {} but got {}", expectedWidth, sample.getWidth());
passed = false;
}
if (!Arrays.asList(expectedHeight, expectedHeight + 1, expectedHeight - 1).contains(sample.getHeight())) {
log.error("Expected height to be {} but got {}", expectedHeight, sample.getHeight());
passed = false;
}
saveAudit(passed? id:"invalid", sample);
if (!passed) {
return false;
}
}
return true;
}
public static boolean testRasterFittedSize(int trials) throws Throwable {
for(int i = 0; i < trials; i++) {
//new size every run (height always starts at 0)
double printW = Math.max(2, (int)(Math.random() * 110) / 10d) * 72d;
double zoom = Math.max(0.5d, (int)(Math.random() * 30) / 10d);
String id = "fitted-" + i;
WebAppModel model = buildModel(id, printW, 0, zoom, true, (int)(Math.random() * 360));
BufferedImage sample = WebApp.raster(model);
if (sample == null) {
log.error("Failed to create capture");
return false;
}
//TODO - check bottom right matches expected color
//check capture for dimensional accuracy within 1 pixel of expected (due to int rounding)
//expected height is not known for these tests
int expectedWidth = (int)Math.round(printW * (96d / 72d) * zoom);
boolean passed = true;
if (!Arrays.asList(expectedWidth, expectedWidth + 1, expectedWidth - 1).contains(sample.getWidth())) {
log.error("Expected width to be {} but got {}", expectedWidth, sample.getWidth());
passed = false;
}
saveAudit(passed? id:"invalid", sample);
if (!passed) {
return false;
}
}
return true;
}
public static boolean testVectorKnownPrints(int trials) throws Throwable {
PrinterJob job = buildVectorJob("vector-test-known");
for(int i = 0; i < trials; i++) {
//new size every run
double printW = Math.max(2, (int)(Math.random() * 85) / 10d) * 72d;
double printH = Math.max(3, (int)(Math.random() * 110) / 10d) * 72d;
String id = "known-" + i;
WebAppModel model = buildModel(id, printW, printH, 1, false, (int)(Math.random() * 360));
WebApp.print(job, model);
}
job.endJob();
try {
log.info("Waiting {} seconds for the spooler to catch up.", SPOOLER_WAIT / 1000);
Thread.sleep(SPOOLER_WAIT);
}
catch(InterruptedException ignore) {}
return job.getJobStatus() != PrinterJob.JobStatus.ERROR;
}
public static boolean testVectorFittedPrints(int trials) throws Throwable {
PrinterJob job = buildVectorJob("vector-test-fitted");
for(int i = 0; i < trials; i++) {
//new size every run
double printW = Math.max(2, (int)(Math.random() * 85) / 10d) * 72d;
String id = "fitted-" + i;
WebAppModel model = buildModel(id, printW, 0, 1, false, (int)(Math.random() * 360));
WebApp.print(job, model);
}
job.endJob();
try {
log.info("Waiting {} seconds for the spooler to catch up.", SPOOLER_WAIT / 1000);
Thread.sleep(SPOOLER_WAIT);
}
catch(InterruptedException ignore) {}
return job.getJobStatus() != PrinterJob.JobStatus.ERROR;
}
private static WebAppModel buildModel(String index, double width, double height, double zoom, boolean scale, int hue) {
int level = (int)(Math.random() * 50) + 25;
WebAppModel model = new WebAppModel("<html>" +
"<body style='background-color: hsl(" + hue + "," + level + "%," + level + "%);'>" +
" <table style='font-family: monospace; border: 1px;'>" +
" <tr style='height: 6cm;'>" +
" <td valign='top'>Generated content:</td>" +
" <td valign='top'><b>" + index + "</b></td>" +
" </tr>" +
" <tr>" +
" <td>Content size:</td>" +
" <td>" + width + "x" + height + "</td>" +
" </tr>" +
" <tr>" +
" <td>Physical size:</td>" +
" <td>" + (width / 72d) + "x" + (height / 72d) + "</td>" +
" </tr>" +
" <tr>" +
" <td>Zoomed to</td>" +
" <td>x " + zoom + "</td>" +
" </tr>" +
" </table>" +
"</body>" +
"</html>",
true, width, height, scale, zoom);
log.trace("Generating #{} = [({},{}), x{}]", index, model.getWidth(), model.getHeight(), model.getZoom());
return model;
}
private static PrinterJob buildVectorJob(String name) throws Throwable {
Printer defaultPrinter = Printer.getDefaultPrinter();
PrinterJob job = PrinterJob.createPrinterJob(defaultPrinter);
// All this to remove margins
Constructor<PageLayout> plCon = PageLayout.class.getDeclaredConstructor(Paper.class, PageOrientation.class, double.class, double.class, double.class, double.class);
plCon.setAccessible(true);
Paper paper = defaultPrinter.getDefaultPageLayout().getPaper();
PageLayout layout = plCon.newInstance(paper, PageOrientation.PORTRAIT, 0, 0, 0, 0);
Field field = defaultPrinter.getClass().getDeclaredField("defPageLayout");
field.setAccessible(true);
field.set(defaultPrinter, layout);
JobSettings settings = job.getJobSettings();
settings.setPageLayout(layout);
settings.setJobName(name);
return job;
}
private static void cleanup() {
File[] files;
if ((files = RASTER_OUTPUT_DIR.toFile().listFiles()).length > 0) {
for(File file : files) {
if (file.getName().endsWith("." + RASTER_OUTPUT_FORMAT)
&& file.getName().startsWith(String.format("%s-", Constants.DATA_DIR))) {
if (!file.delete()) {
log.warn("Could not delete {}", file);
}
}
}
}
}
private static void saveAudit(String id, BufferedImage capture) throws IOException {
Path image = RASTER_OUTPUT_DIR.resolve(String.format("%s-%s.%s", Constants.DATA_DIR, id, RASTER_OUTPUT_FORMAT));
ImageIO.write(capture, RASTER_OUTPUT_FORMAT, image.toFile());
log.info("Wrote {}: {}", id, image);
}
}

View File

@@ -0,0 +1,39 @@
package tests.qz.printer.info;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import qz.printer.PrintServiceMatcher;
import qz.printer.info.NativePrinter;
import qz.printer.info.NativePrinterMap;
import java.util.Date;
public class NativePrinterTests {
private static final Logger log = LogManager.getLogger(NativePrinterTests.class);
public static void main(String ... args) {
for (int i = 0; i < 10; i++) {
runTest();
}
}
private static void runTest() {
Date begin = new Date();
NativePrinterMap printers = PrintServiceMatcher.getNativePrinterList();
StringBuilder output = new StringBuilder("Found printers:\n");
for (NativePrinter printer : printers.values()) {
output.append(String.format(" printerId: '%s', description: '%s', driverFile: '%s', " +
"resolution: '%s', driver: '%s'\n",
printer.getPrinterId(),
printer.getDescription(),
printer.getDriverFile(),
printer.getResolution(),
printer.getDriver()
));
}
Date end = new Date();
log.debug(output.toString());
log.debug("Time to find printers: " + (end.getTime() - begin.getTime()));
}
}

View File

@@ -0,0 +1,46 @@
package qz.utils;
import org.codehaus.jettison.json.JSONException;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.IOException;
public class JsonWriterTests {
private static final Logger log = LogManager.getLogger(JsonWriterTests.class);
private static String DEFAULT_PATH = "/Applications/Firefox.app/Contents/Resources/distribution/policies.json";
private static String DEFAULT_DATA = "{ \"policies\": { \"Certificates\": { \"ImportEnterpriseRoots\": true } } }";
private static boolean DEFAULT_OVERWRITE = false;
private static boolean DEFAULT_DELETE = false;
public static void main(String... args) {
String usingPath = DEFAULT_PATH;
if (args.length > 0) {
usingPath = args[0];
}
String usingData = DEFAULT_DATA;
if (args.length > 1) {
usingData = args[1];
}
boolean usingOverwrite = DEFAULT_OVERWRITE;
if (args.length > 2) {
usingOverwrite = Boolean.parseBoolean(args[2]);
}
boolean usingDeletion = DEFAULT_DELETE;
if (args.length > 3) {
usingDeletion = Boolean.parseBoolean(args[3]);
}
try {
JsonWriter.write(usingPath, usingData, usingOverwrite, usingDeletion);
}
catch(JSONException jsone) {
log.error("Failed to read JSON", jsone);
}
catch(IOException ioe) {
log.error("Failed to access file", ioe);
}
}
}

View File

@@ -0,0 +1,19 @@
package qz.ws.substitutions;
import org.codehaus.jettison.json.JSONException;
import org.codehaus.jettison.json.JSONObject;
import java.io.IOException;
public class SubstitutionsTests {
public static void main(String ... args) throws JSONException, IOException {
Substitutions substitutions = new Substitutions(
SubstitutionsTests.class.getResourceAsStream("resources/substitutions.json")
);
JSONObject base = substitutions.replace(
SubstitutionsTests.class.getResourceAsStream("resources/printRequest.json")
);
System.out.println(base);
}
}

View File

@@ -0,0 +1,67 @@
{
"call": "print",
"params": {
"printer": {
"name": "PDFwriter"
},
"options": {
"bounds": null,
"colorType": "color",
"copies": 1,
"density": 0,
"duplex": false,
"fallbackDensity": null,
"interpolation": "bicubic",
"jobName": null,
"legacy": false,
"margins": 0,
"orientation": null,
"paperThickness": null,
"printerTray": null,
"rasterize": false,
"rotation": 0,
"scaleContent": true,
"size": {
"width": "4",
"height": "6"
},
"units": "in",
"forceRaw": false,
"encoding": null,
"spool": {}
},
"data": [
{
"type": "pixel",
"format": "pdf",
"flavor": "file",
"data": "https://demo.qz.io/assets/pdf_sample.pdf",
"options": {
"pageWidth": "8.5",
"pageHeight": "11",
"pageRanges": "",
"ignoreTransparency": false,
"altFontRendering": false
}
},
{
"type": "pixel",
"format": "image",
"flavor": "file",
"data": "https://demo.qz.io/assets/img/image_sample.png",
},
"^XA\n",
"^FO50,50^ADN,36,20^FDPRINTED WITH QZ 2.2.4-SNAPSHOT\n",
"^FS\n",
"^XZ\n"
]
},
"signature": "",
"timestamp": 1713895560783,
"uid": "64t63d",
"position": {
"x": 720,
"y": 462.5
},
"signAlgorithm": "SHA512"
}

View File

@@ -0,0 +1,109 @@
[
{
"use":{
"config": {
"size": {
"width": 100,
"height": 150
},
"units": "mm"
}
},
"for": {
"config": {
"size": {
"width": 4,
"height": 6
},
"units": "in"
}
}
},
{
"use": {
"printer": "PDF"
},
"for": {
"printer": "PDFwriter"
}
},
{
"use": {
"data": {
"options": {
"pageWidth": 8.5,
"pageHeight": 14
}
}
},
"for": {
"data": {
"options": {
"pageWidth": "8.5",
"pageHeight": "11"
}
}
}
},
{
"use": {
"query": "pdf"
},
"for": {
"query": "zzz"
}
},
{
"use": {
"config": {
"copies": 3
}
},
"for": {
"config": {
"copies": 1
}
}
},
{
"use": {
"printer": "PDFwriter"
},
"for": {
"caseSensitive": true,
"printer": "xps document writer"
}
},
{
"use": {
"data": {
"data": "https://yahoo.com"
}
},
"for": {
"data": {
"data": "https://demo.qz.io/assets/pdf_sample.pdf"
}
}
},
{
"use": {
"printer": "ZDesigner"
},
"for": {
"data": [ "^XA\n" ]
}
},
{
"use": {
"data": {
"type": "PIXEL"
}
},
"for": {
"data": {
"type": "pixel"
}
}
}
]