Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package icedtea-web for openSUSE:Factory checked in at 2026-10-15 12:19:25 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/icedtea-web (Old) and /work/SRC/openSUSE:Factory/.icedtea-web.new.3698736 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "icedtea-web" Thu Oct 15 12:19:25 2026 rev:46 rq:1384851 version:2.0.0~alpha36 Changes: -------- --- /work/SRC/openSUSE:Factory/icedtea-web/icedtea-web.changes 2026-07-21 23:00:47.314511695 +0200 +++ /work/SRC/openSUSE:Factory/.icedtea-web.new.3698736/icedtea-web.changes 2026-10-15 12:20:21.266606353 +0200 @@ -1,0 +2,33 @@ +Wed Oct 7 12:36:35 UTC 2026 - Fridrich Strba <[email protected]> + +- Upgrade to version 2.0.0-alpha36 + * no structured changelog provided + * the 2.0.0 code-stream is built using maven now +- Removed patches: + * commons-compress-pack200.patch + * java17.patch + * java21.patch + * javaws-policy.patch + * more-java-versions.patch + * remove-pack200-support.patch + + not necessary or reimplemented differently +- Modified patches: + * icedtea-web-suse-desktop-files.patch + * reproducible-timestamps.patch + + rediff to the new context +- Added patches: + * 0001-Make-IcedTea-Web-build-and-run-on-Java-8-through-25.patch + * 0002-Port-to-jacoco-0.8.14-and-surefire-3.6.0-to-be-able-.patch + * 0003-Bring-back-Pack200-support-on-newer-Java-using-commo.patch + * 0004-Grey-out-the-advanced-policy-editor-button-when-poli.patch + * 0005-Stop-relying-on-hidden-JDK-certificate-classes-where.patch + * 0006-Address-SonarCloud-findings-and-fix-JaCoCo-report-in.patch + * 0007-Stop-opening-JDK-packages-that-no-longer-exist-or-ar.patch + * 0008-Fix-the-shell-launchers-silently-failing-when-java-c.patch + * 0009-Ignore-an-invalid-JNLP-file-version-instead-of-refus.patch + * 0010-Drop-modules-missing-from-this-JVM-from-java-vm-args.patch + * 0011-Make-the-exception-dialog-test-independent-of-the-cl.patch + + commits of our pull request porting the IcedTea-Web to run + with Javas from 8 to 25 + +------------------------------------------------------------------- Old: ---- commons-compress-pack200.patch icedtea-web-1.8.8.tar.xz java17.patch java21.patch javaws-policy.patch more-java-versions.patch remove-pack200-support.patch New: ---- 0001-Make-IcedTea-Web-build-and-run-on-Java-8-through-25.patch 0002-Port-to-jacoco-0.8.14-and-surefire-3.6.0-to-be-able-.patch 0003-Bring-back-Pack200-support-on-newer-Java-using-commo.patch 0004-Grey-out-the-advanced-policy-editor-button-when-poli.patch 0005-Stop-relying-on-hidden-JDK-certificate-classes-where.patch 0006-Address-SonarCloud-findings-and-fix-JaCoCo-report-in.patch 0007-Stop-opening-JDK-packages-that-no-longer-exist-or-ar.patch 0008-Fix-the-shell-launchers-silently-failing-when-java-c.patch 0009-Ignore-an-invalid-JNLP-file-version-instead-of-refus.patch 0010-Drop-modules-missing-from-this-JVM-from-java-vm-args.patch 0011-Make-the-exception-dialog-test-independent-of-the-cl.patch icedtea-web-2.0.0~alpha36.tar.xz icedtea-web.conf ----------(Old B)---------- Old:- Removed patches: * commons-compress-pack200.patch * java17.patch Old: * commons-compress-pack200.patch * java17.patch * java21.patch Old: * java17.patch * java21.patch * javaws-policy.patch Old: * java21.patch * javaws-policy.patch * more-java-versions.patch Old: * javaws-policy.patch * more-java-versions.patch * remove-pack200-support.patch Old: * more-java-versions.patch * remove-pack200-support.patch + not necessary or reimplemented differently ----------(Old E)---------- ----------(New B)---------- New:- Added patches: * 0001-Make-IcedTea-Web-build-and-run-on-Java-8-through-25.patch * 0002-Port-to-jacoco-0.8.14-and-surefire-3.6.0-to-be-able-.patch New: * 0001-Make-IcedTea-Web-build-and-run-on-Java-8-through-25.patch * 0002-Port-to-jacoco-0.8.14-and-surefire-3.6.0-to-be-able-.patch * 0003-Bring-back-Pack200-support-on-newer-Java-using-commo.patch New: * 0002-Port-to-jacoco-0.8.14-and-surefire-3.6.0-to-be-able-.patch * 0003-Bring-back-Pack200-support-on-newer-Java-using-commo.patch * 0004-Grey-out-the-advanced-policy-editor-button-when-poli.patch New: * 0003-Bring-back-Pack200-support-on-newer-Java-using-commo.patch * 0004-Grey-out-the-advanced-policy-editor-button-when-poli.patch * 0005-Stop-relying-on-hidden-JDK-certificate-classes-where.patch New: * 0004-Grey-out-the-advanced-policy-editor-button-when-poli.patch * 0005-Stop-relying-on-hidden-JDK-certificate-classes-where.patch * 0006-Address-SonarCloud-findings-and-fix-JaCoCo-report-in.patch New: * 0005-Stop-relying-on-hidden-JDK-certificate-classes-where.patch * 0006-Address-SonarCloud-findings-and-fix-JaCoCo-report-in.patch * 0007-Stop-opening-JDK-packages-that-no-longer-exist-or-ar.patch New: * 0006-Address-SonarCloud-findings-and-fix-JaCoCo-report-in.patch * 0007-Stop-opening-JDK-packages-that-no-longer-exist-or-ar.patch * 0008-Fix-the-shell-launchers-silently-failing-when-java-c.patch New: * 0007-Stop-opening-JDK-packages-that-no-longer-exist-or-ar.patch * 0008-Fix-the-shell-launchers-silently-failing-when-java-c.patch * 0009-Ignore-an-invalid-JNLP-file-version-instead-of-refus.patch New: * 0008-Fix-the-shell-launchers-silently-failing-when-java-c.patch * 0009-Ignore-an-invalid-JNLP-file-version-instead-of-refus.patch * 0010-Drop-modules-missing-from-this-JVM-from-java-vm-args.patch New: * 0009-Ignore-an-invalid-JNLP-file-version-instead-of-refus.patch * 0010-Drop-modules-missing-from-this-JVM-from-java-vm-args.patch * 0011-Make-the-exception-dialog-test-independent-of-the-cl.patch New: * 0010-Drop-modules-missing-from-this-JVM-from-java-vm-args.patch * 0011-Make-the-exception-dialog-test-independent-of-the-cl.patch + commits of our pull request porting the IcedTea-Web to run ----------(New E)---------- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ icedtea-web.spec ++++++ --- /var/tmp/diff_new_pack.5Bxooq/_old 2026-10-15 12:20:22.189644961 +0200 +++ /var/tmp/diff_new_pack.5Bxooq/_new 2026-10-15 12:20:22.191645045 +0200 @@ -16,46 +16,39 @@ # -%{!?make_build:%global make_build make %{?_smp_mflags} V=1} -%bcond_without pack200 Name: icedtea-web -Version: 1.8.8 +Version: 2.0.0~alpha36 Release: 0 Summary: Java Web Start implementation License: GPL-2.0-only WITH Classpath-exception-2.0 Group: Development/Languages/Java URL: https://github.com/AdoptOpenJDK/IcedTea-Web Source0: %{name}-%{version}.tar.xz +Source1: icedtea-web.conf Patch0: icedtea-web-suse-desktop-files.patch -Patch1: more-java-versions.patch -Patch2: reproducible-timestamps.patch -Patch3: commons-compress-pack200.patch -Patch4: remove-pack200-support.patch -Patch5: java17.patch -Patch6: java21.patch -Patch7: javaws-policy.patch -BuildRequires: autoconf -BuildRequires: automake -BuildRequires: bc +Patch1: 0001-Make-IcedTea-Web-build-and-run-on-Java-8-through-25.patch +Patch2: 0002-Port-to-jacoco-0.8.14-and-surefire-3.6.0-to-be-able-.patch +Patch3: 0003-Bring-back-Pack200-support-on-newer-Java-using-commo.patch +Patch4: 0004-Grey-out-the-advanced-policy-editor-button-when-poli.patch +Patch5: 0005-Stop-relying-on-hidden-JDK-certificate-classes-where.patch +Patch6: 0006-Address-SonarCloud-findings-and-fix-JaCoCo-report-in.patch +Patch7: 0007-Stop-opening-JDK-packages-that-no-longer-exist-or-ar.patch +Patch8: 0008-Fix-the-shell-launchers-silently-failing-when-java-c.patch +Patch9: 0009-Ignore-an-invalid-JNLP-file-version-instead-of-refus.patch +Patch10: 0010-Drop-modules-missing-from-this-JVM-from-java-vm-args.patch +Patch11: 0011-Make-the-exception-dialog-test-independent-of-the-cl.patch +Patch100: reproducible-timestamps.patch BuildRequires: desktop-file-utils BuildRequires: fdupes -BuildRequires: hamcrest BuildRequires: java-devel >= 1.8 -BuildRequires: javapackages-tools -BuildRequires: junit -BuildRequires: libtool -BuildRequires: pkgconfig >= 0.9.0 -BuildRequires: procps -BuildRequires: rhino -BuildRequires: tagsoup -BuildRequires: zip -BuildConflicts: java >= 22 -BuildConflicts: java-devel >= 22 -BuildConflicts: java-headless >= 22 +BuildRequires: maven-local +BuildRequires: mvn(com.github.seancfoley:ipaddress) +BuildRequires: mvn(com.github.vatbub:mslinks) +BuildRequires: mvn(org.apache.commons:commons-compress) +BuildRequires: mvn(org.ccil.cowan.tagsoup:tagsoup) +BuildRequires: mvn(org.mozilla:rhino) Requires: java >= 1.8 -Requires: rhino -Requires: tagsoup -Suggests: %{name}-javadoc +Requires: javapackages-tools Obsoletes: java-1_6_0-openjdk-plugin < %{version}-%{release} Obsoletes: java-1_7_0-openjdk-plugin < %{version}-%{release} Obsoletes: java-1_8_0-openjdk-plugin < %{version}-%{release} @@ -67,10 +60,6 @@ Provides: java-1_9_0-openjdk-plugin = %{version}-%{release} Provides: java-plugin = 1.8.0 BuildArch: noarch -%if %{with pack200} -BuildRequires: apache-commons-compress -Requires: apache-commons-compress -%endif %description The IcedTea-Web project provides a Free Software web browser plugin running @@ -89,64 +78,60 @@ and plugin implementation. %prep -%setup -q -%patch -P 0 -p1 -%patch -P 1 -p1 -%patch -P 2 -p1 -%if %{with pack200} -%patch -P 3 -p1 -%else -%patch -P 4 -p1 -%endif -%patch -P 5 -p1 -%patch -P 6 -p1 -%patch -P 7 -p1 +%autosetup -p1 -rm -rf netx/net/sourceforge/jnlp/NetxPanel.java netx/sun - -rm -f netx/net/sourceforge/jnlp/util/WindowsDesktopEntry.java +%pom_remove_plugin -r :jacoco-maven-plugin +%pom_remove_plugin -r :buildnumber-maven-plugin +%pom_remove_plugin -r :maven-source-plugin +%pom_remove_plugin -r :maven-javadoc-plugin +%pom_remove_plugin -r :maven-shade-plugin + +%pom_disable_module test-extensions +%pom_disable_module artifact-no-dependencies +%pom_disable_module artifact-all-dependencies +%pom_disable_module integration %build -autoreconf -fiv -export bashcompdir=%{_datadir}/bash-completion/completions -%configure \ - --with-jdk-home=${JAVA_HOME} \ - --bindir=%{_datadir}/%{name} \ - --disable-native-plugin \ - --disable-pluginjar \ - --docdir=%{_javadocdir}/%{name} \ - --enable-docs \ - --enable-shell-launchers \ - --with-itw-libs=BUNDLED \ - --with-modularjdk-file=%{_datadir}/%{name} - -%make_build +%{mvn_build} -f -%install -%make_install +itw_cp=$(ls {jnlp-api,common,xml-parser,core}/target/*.jar | grep -v -e sources -e javadoc | tr '\n' :) +itw_cp=${itw_cp%:}:$(build-classpath rhino tagsoup IPAddress commons-compress commons-io commons-lang3) -# Install desktop files. -install -dm 0755 %{buildroot}%{_datadir}/applications -desktop-file-install --vendor ''\ - --dir %{buildroot}%{_datadir}/applications javaws.desktop -desktop-file-install --vendor ''\ - --dir %{buildroot}%{_datadir}/applications itweb-settings.desktop -desktop-file-install --vendor ''\ - --dir %{buildroot}%{_datadir}/applications policyeditor.desktop - -# Symlink the scripts to bin directory -install -dm 0755 %{buildroot}%{_bindir} -for i in javaws itweb-settings policyeditor; do - ln -sf %{_datadir}/%{name}/${i}.sh %{buildroot}%{_bindir}/${i} +# WARN/ERROR go to syslog via util-linux `logger`, absent from Factory build root +export XDG_CONFIG_HOME=$PWD/gen/config +mkdir -p $XDG_CONFIG_HOME/icedtea-web +echo deployment.log.system=false > $XDG_CONFIG_HOME/icedtea-web/deployment.properties + +mkdir -p gen/completions gen/man +for n in javaws itweb-settings policyeditor ; do + sed "s/@OPTIONS@/$(java -cp $itw_cp net.adoptopenjdk.icedteaweb.commandline.CommandLineOptionsDefinition $n)/" \ + launchers/completion.in/$n.bash.in > gen/completions/$n.bash + sed "s#PATH_TO_$(echo $n | tr a-z- A-Z_)#%{_bindir}/$n#" \ + launchers/xdesktop.in/$n.desktop.in > gen/$n.desktop +done +# user.language instead of LANG: works without glibc locales in the build root +for l in en_US cs_CZ de_DE pl_PL ; do + d=gen/man/${l%%_*}/man1 ; [ $l = en_US ] && d=gen/man/man1 + mkdir -p $d + java -Duser.language=${l%%_*} -Duser.country=${l##*_} -Dfile.encoding=UTF-8 -cp $itw_cp \ + net.sourceforge.jnlp.util.docprovider.TextsProvider man UTF-8 $d false %{version} \ + "-authorString=https://github.com/AdoptOpenJDK/icedtea-web/graphs/contributors" done -# Default security policy file -install -dm 0755 %{buildroot}%{_sysconfdir}/%{name} -install -pm 0644 javaws.policy %{buildroot}%{_sysconfdir}/%{name}/ - -%fdupes %{buildroot}%{_javadocdir}/%{name} +%install +%mvn_install +%fdupes -s %{buildroot}%{_javadocdir} -rm -rf %{buildroot}%{_mandir}/*/man1 +%jpackage_script net.sourceforge.jnlp.runtime.Boot "" "" icedtea-web javaws true +%jpackage_script net.adoptopenjdk.icedteaweb.client.commandline.CommandLine "" "" icedtea-web itweb-settings true +%jpackage_script net.adoptopenjdk.icedteaweb.client.policyeditor.PolicyEditor "" "" icedtea-web policyeditor true +install -Dpm 644 %{SOURCE1} %{buildroot}%{_sysconfdir}/java/icedtea-web.conf +install -Dpm 644 -t %{buildroot}%{_datadir}/icedtea-web launchers/itw-modularjdk.args core/src/main/resources/javaws_splash.png +install -Dpm 644 -t %{buildroot}%{_datadir}/applications gen/*.desktop +install -Dpm 644 -t %{buildroot}%{_datadir}/bash-completion/completions gen/completions/*.bash +install -Dpm 644 launchers/javaws.png %{buildroot}%{_datadir}/pixmaps/javaws.png +install -dm 755 %{buildroot}%{_mandir} +cp -r gen/man/* %{buildroot}%{_mandir}/ %posttrans update-desktop-database &> /dev/null || : @@ -157,21 +142,22 @@ exit 0 %files -%{_bindir}/itweb-settings* -%{_bindir}/javaws* -%{_bindir}/policyeditor* -%{_mandir}/man1/* -%{_datadir}/applications/itweb-settings.desktop -%{_datadir}/applications/javaws.desktop -%{_datadir}/applications/policyeditor.desktop -%dir %{_sysconfdir}/%{name} -%config %{_sysconfdir}/%{name}/* -%{_datadir}/%{name} + +%files -f .mfiles +%{_bindir}/javaws +%{_bindir}/itweb-settings +%{_bindir}/policyeditor +%config(noreplace) %{_sysconfdir}/java/icedtea-web.conf +%{_datadir}/icedtea-web +%{_datadir}/applications/*.desktop +%{_datadir}/bash-completion/completions/*.bash %{_datadir}/pixmaps/javaws.png -%{_datadir}/bash-completion/completions +%{_mandir}/man1/* +%{_mandir}/*/man1/* +%license LICENSE +%doc LICENCE_DETAILS.md README.md %files javadoc -%license COPYING -%doc NEWS README +%license LICENSE %{_javadocdir}/%{name} ++++++ 0001-Make-IcedTea-Web-build-and-run-on-Java-8-through-25.patch ++++++ ++++ 2317 lines (skipped) ++++++ 0002-Port-to-jacoco-0.8.14-and-surefire-3.6.0-to-be-able-.patch ++++++ >From 30739efbb5ddf390527208314c0f278511302604 Mon Sep 17 00:00:00 2001 From: Fridrich Strba <[email protected]> Date: Tue, 6 Oct 2026 11:15:17 +0200 Subject: [PATCH 2/8] Port to jacoco 0.8.14 and surefire 3.6.0 to be able to run on Java 25 Also includes test adaptations (KeyStoresTest, JNLPFileTest, UnsignedAppletTrustConfirmationTest, JNLPPolicy debug log, root pom profiles); integration-test fixes (MaxPermSize removal, ItwLauncher flags, headless prompt loop fix). --- .../SecurityDialogMessageHandler.java | 3 +- .../sourceforge/jnlp/runtime/JNLPPolicy.java | 4 +++ .../UnsignedAppletTrustConfirmationTest.java | 14 ++++++--- .../net/sourceforge/jnlp/JNLPFileTest.java | 3 +- .../jnlp/security/KeyStoresTest.java | 20 +++++++++---- integration/pom.xml | 2 +- .../icedteaweb/integration/ItwLauncher.java | 25 +++++++++++++++- pom.xml | 30 +++++++++++++++++-- 8 files changed, 85 insertions(+), 16 deletions(-) diff --git a/core/src/main/java/net/adoptopenjdk/icedteaweb/client/parts/dialogs/security/SecurityDialogMessageHandler.java b/core/src/main/java/net/adoptopenjdk/icedteaweb/client/parts/dialogs/security/SecurityDialogMessageHandler.java index 6be4f0c76..2918ff807 100644 --- a/core/src/main/java/net/adoptopenjdk/icedteaweb/client/parts/dialogs/security/SecurityDialogMessageHandler.java +++ b/core/src/main/java/net/adoptopenjdk/icedteaweb/client/parts/dialogs/security/SecurityDialogMessageHandler.java @@ -224,8 +224,9 @@ public class SecurityDialogMessageHandler implements Runnable { LOG.error("Probably wrong value?", eeex); repeatAll = false; } catch (Exception ex) { + // retrying would fail the same way forever (e.g. NPE on a panel-less dialog); null response = deny LOG.error(IcedTeaWebConstants.DEFAULT_ERROR_MESSAGE, ex); - repeatAll = true; + keepGoing = false; } } while (keepGoing); } finally { diff --git a/core/src/main/java/net/sourceforge/jnlp/runtime/JNLPPolicy.java b/core/src/main/java/net/sourceforge/jnlp/runtime/JNLPPolicy.java index fc5c8f465..74cb4fd64 100644 --- a/core/src/main/java/net/sourceforge/jnlp/runtime/JNLPPolicy.java +++ b/core/src/main/java/net/sourceforge/jnlp/runtime/JNLPPolicy.java @@ -32,6 +32,7 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.security.AllPermission; import java.security.CodeSource; +import java.security.NoSuchAlgorithmException; import java.security.Permission; import java.security.PermissionCollection; import java.security.Permissions; @@ -242,6 +243,9 @@ public class JNLPPolicy extends Policy { policyUri = new URI(policyLocation.replace("\\", "/")); } policy = getInstance("JavaPolicy", new URIParameter(policyUri)); + } catch (NoSuchAlgorithmException e) { + // JDK 24+: no policy support, nothing to enforce it with anyway + LOG.debug("Policy files not supported by this JVM, ignoring {}", policyLocation); } catch (Exception e) { LOG.error("Error while loading the policy from URL " + policyLocation, e); } diff --git a/core/src/test/java/net/adoptopenjdk/icedteaweb/client/parts/dialogs/security/appletextendedsecurity/UnsignedAppletTrustConfirmationTest.java b/core/src/test/java/net/adoptopenjdk/icedteaweb/client/parts/dialogs/security/appletextendedsecurity/UnsignedAppletTrustConfirmationTest.java index 72c2b9f4e..55db5e70e 100644 --- a/core/src/test/java/net/adoptopenjdk/icedteaweb/client/parts/dialogs/security/appletextendedsecurity/UnsignedAppletTrustConfirmationTest.java +++ b/core/src/test/java/net/adoptopenjdk/icedteaweb/client/parts/dialogs/security/appletextendedsecurity/UnsignedAppletTrustConfirmationTest.java @@ -53,6 +53,7 @@ import net.adoptopenjdk.icedteaweb.io.FileUtils; import net.sourceforge.jnlp.util.UrlUtils; import org.junit.AfterClass; import org.junit.Assert; +import org.junit.Assume; import org.junit.BeforeClass; import org.junit.Test; @@ -219,10 +220,14 @@ public class UnsignedAppletTrustConfirmationTest { @BeforeClass public static void initUrlsY12345678() throws MalformedURLException, IOException { - urlY1 = new URL("http://som\\EeUrl.cz/aa"); - urlY2 = new URL("http://some\\QUrl.cz/aa"); - urlY3 = new URL("http://so\\QmeU\\Erl.cz/aa"); - urlY4 = new URL("http://so\\EmeU\\Qrl.cz/aa"); + try { + urlY1 = new URL("http://som\\EeUrl.cz/aa"); + urlY2 = new URL("http://some\\QUrl.cz/aa"); + urlY3 = new URL("http://so\\QmeU\\Erl.cz/aa"); + urlY4 = new URL("http://so\\EmeU\\Qrl.cz/aa"); + } catch (MalformedURLException ex) { // backslash in host rejected by newer JDKs + ServerAccess.logException(ex); + } urlY5 = new URL("http://someUrl.cz/aa\\Ebb/cc"); urlY6 = new URL("http://someUrl.cz/aa\\Qbb/cc"); @@ -232,6 +237,7 @@ public class UnsignedAppletTrustConfirmationTest { @Test public void updateAppletActionTestYQN1234saveAndLoadFine() throws Exception { + Assume.assumeNotNull(urlY1); PathsAndFiles.APPLET_TRUST_SETTINGS_USER.getFile().delete(); //clean file to examine later UnsignedAppletTrustConfirmation.updateAppletAction( new DummyJnlpWithTitleAndUrlsWithOverwrite(urlY1), diff --git a/core/src/test/java/net/sourceforge/jnlp/JNLPFileTest.java b/core/src/test/java/net/sourceforge/jnlp/JNLPFileTest.java index 4b3bd15eb..7ffeb9248 100644 --- a/core/src/test/java/net/sourceforge/jnlp/JNLPFileTest.java +++ b/core/src/test/java/net/sourceforge/jnlp/JNLPFileTest.java @@ -39,6 +39,7 @@ import net.adoptopenjdk.icedteaweb.jnlp.element.resource.ResourcesDesc; import net.adoptopenjdk.icedteaweb.jnlp.element.security.ApplicationPermissionLevel; import net.adoptopenjdk.icedteaweb.testing.annotations.Bug; import net.adoptopenjdk.icedteaweb.testing.mock.MockJNLPFile; +import net.adoptopenjdk.icedteaweb.resources.downloader.PackGzipUnpacker; import net.adoptopenjdk.icedteaweb.xmlparser.ParseException; import net.sourceforge.jnlp.util.logging.NoStdOutErrTest; import org.junit.Assert; @@ -188,7 +189,7 @@ public class JNLPFileTest extends NoStdOutErrTest{ JNLPFile jnlpFile = new JNLPFile(is, codeBase, new ParserSettings(false,false,false)); DownloadOptions downloadOptions = jnlpFile.getDownloadOptions(); - Assert.assertTrue(downloadOptions.useExplicitPack()); + Assert.assertEquals(PackGzipUnpacker.isSupported(), downloadOptions.useExplicitPack()); // no Pack200 since JDK 14 Assert.assertTrue(downloadOptions.useExplicitVersion()); } diff --git a/core/src/test/java/net/sourceforge/jnlp/security/KeyStoresTest.java b/core/src/test/java/net/sourceforge/jnlp/security/KeyStoresTest.java index 2f4475fda..3e24155aa 100644 --- a/core/src/test/java/net/sourceforge/jnlp/security/KeyStoresTest.java +++ b/core/src/test/java/net/sourceforge/jnlp/security/KeyStoresTest.java @@ -37,6 +37,7 @@ import net.sourceforge.jnlp.config.InfrastructureFileDescriptor; import net.sourceforge.jnlp.config.PathsAndFiles; import org.junit.AfterClass; import org.junit.Assert; +import org.junit.Assume; import org.junit.Test; import java.security.Permission; @@ -53,15 +54,24 @@ public class KeyStoresTest { } + // JDK 24+ (or 18-23 without -Djava.security.manager=allow) refuse any SecurityManager change + private static void setSecurityManager(SecurityManager sm) { + try { + System.setSecurityManager(sm); + } catch (UnsupportedOperationException e) { + Assume.assumeTrue("SecurityManager not supported", sm == null); + } + } + @AfterClass public static void removeClassLoader() { - System.setSecurityManager(null); + setSecurityManager(null); } @Test public void getKeyStoreUserLocationTest() { InfrastructureFileDescriptor s; - System.setSecurityManager(null); + setSecurityManager(null); s = KeyStores.getKeyStoreLocation(KeyStores.Level.USER, KeyStores.Type.CA_CERTS); Assert.assertEquals(s.getFile(), PathsAndFiles.USER_CACERTS.getFile()); s = KeyStores.getKeyStoreLocation(KeyStores.Level.USER, KeyStores.Type.CERTS); @@ -77,7 +87,7 @@ public class KeyStoresTest { @Test public void getKeyStoreSystemLocationTest() { InfrastructureFileDescriptor s; - System.setSecurityManager(null); + setSecurityManager(null); s = KeyStores.getKeyStoreLocation(KeyStores.Level.SYSTEM, KeyStores.Type.CA_CERTS); Assert.assertEquals(s.getFile(), PathsAndFiles.SYS_CACERT.getFile()); s = KeyStores.getKeyStoreLocation(KeyStores.Level.SYSTEM, KeyStores.Type.CERTS); @@ -93,7 +103,7 @@ public class KeyStoresTest { @Test public void getKeyStoreUserLocationTestSM() { DummySM dm = new DummySM(); - System.setSecurityManager(dm); + setSecurityManager(dm); InfrastructureFileDescriptor s; s = KeyStores.getKeyStoreLocation(KeyStores.Level.USER, KeyStores.Type.CA_CERTS); Assert.assertEquals(s.getFile(), PathsAndFiles.USER_CACERTS.getFile()); @@ -111,7 +121,7 @@ public class KeyStoresTest { @Test public void getKeyStoreSystemLocationTestSM() { DummySM dm = new DummySM(); - System.setSecurityManager(dm); + setSecurityManager(dm); InfrastructureFileDescriptor s; s = KeyStores.getKeyStoreLocation(KeyStores.Level.SYSTEM, KeyStores.Type.CA_CERTS); Assert.assertEquals(s.getFile(), PathsAndFiles.SYS_CACERT.getFile()); diff --git a/integration/pom.xml b/integration/pom.xml index 514c223f3..0851cec3d 100644 --- a/integration/pom.xml +++ b/integration/pom.xml @@ -219,7 +219,7 @@ <reuseForks>false</reuseForks> <!-- limiting memory for travis which uses docker to run builds --> <!-- if memory is not limited the forked JVMs use too much memory and are killed by the OS --> - <argLine>-Xmx1024m -XX:MaxPermSize=256m</argLine> + <argLine>@{argLine} ${itw.test.moduleArgs} ${itw.test.smArgs} -Xmx1024m</argLine> </configuration> </plugin> diff --git a/integration/src/main/java/net/adoptopenjdk/icedteaweb/integration/ItwLauncher.java b/integration/src/main/java/net/adoptopenjdk/icedteaweb/integration/ItwLauncher.java index 19a02a3d2..965238213 100644 --- a/integration/src/main/java/net/adoptopenjdk/icedteaweb/integration/ItwLauncher.java +++ b/integration/src/main/java/net/adoptopenjdk/icedteaweb/integration/ItwLauncher.java @@ -6,14 +6,17 @@ import net.adoptopenjdk.icedteaweb.commandline.CommandLineOptions; import net.sourceforge.jnlp.runtime.Boot; import java.io.File; +import java.lang.management.ManagementFactory; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.LinkedList; import java.util.List; +import java.util.stream.Collectors; import static net.adoptopenjdk.icedteaweb.commandline.CommandLineOptions.HEADLESS; import static net.adoptopenjdk.icedteaweb.commandline.CommandLineOptions.NOFORK; +import static net.adoptopenjdk.icedteaweb.commandline.CommandLineOptions.NOSEC; import static net.adoptopenjdk.icedteaweb.commandline.CommandLineOptions.VERBOSE; /** @@ -39,10 +42,30 @@ public class ItwLauncher { args.add("-jnlp"); args.add(jnlpUrl); additionalArgs.stream().map(CommandLineOptions::getOption).forEach(args::add); + if (javaMajorVersion() >= 24) { + // no SecurityManager: test apps are unsigned and would be refused + args.add(NOSEC.getOption()); + } Collections.addAll(args, arguments); - return launchExternal(pathToJavaBinary, pathToJavawsJar, Collections.emptyList(), args); + return launchExternal(pathToJavaBinary, pathToJavawsJar, launcherVmArgs(), args); + } + + private static int javaMajorVersion() { + final String[] parts = JavaSystemProperties.getJavaVersion().split("[^0-9]+"); + final int major = Integer.parseInt(parts[0]); + return major == 1 ? Integer.parseInt(parts[1]) : major; + } + + /** + * Module and SecurityManager flags the real launchers add; taken from this (surefire) JVM, + * which gets them from the parent pom's JDK profiles. + */ + private static List<String> launcherVmArgs() { + return ManagementFactory.getRuntimeMXBean().getInputArguments().stream() + .filter(a -> a.startsWith("--add-") || a.startsWith("-Djava.security.manager")) + .collect(Collectors.toList()); } /** diff --git a/pom.xml b/pom.xml index d2601660b..3fc450153 100644 --- a/pom.xml +++ b/pom.xml @@ -26,15 +26,39 @@ <maven-jar-plugin.version>3.1.2</maven-jar-plugin.version> <maven-source-plugin.version>3.1.0</maven-source-plugin.version> - <maven-surefire-plugin.version>3.0.0-M3</maven-surefire-plugin.version> - <jacoco-maven-plugin.version>0.8.4</jacoco-maven-plugin.version> + <maven-surefire-plugin.version>3.6.0</maven-surefire-plugin.version> + <jacoco-maven-plugin.version>0.8.14</jacoco-maven-plugin.version> <maven-resources-plugin.version>3.1.0</maven-resources-plugin.version> <maven-javadoc-plugin.version>3.1.0</maven-javadoc-plugin.version> <skip.javadoc>true</skip.javadoc> + <!-- set by jacoco prepare-agent; empty for modules without it --> + <argLine></argLine> + <!-- extra test JVM args, set by JDK profiles below --> + <itw.test.moduleArgs></itw.test.moduleArgs> + <itw.test.smArgs></itw.test.smArgs> </properties> <profiles> + <profile> + <id>jdk9+</id> + <activation> + <jdk>[9,)</jdk> + </activation> + <properties> + <!-- runtime exports as in the launchers, plus internals used by tests only --> + <itw.test.moduleArgs>@${maven.multiModuleProjectDirectory}/launchers/itw-modularjdk.args --add-exports=java.base/sun.security.tools.keytool=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED</itw.test.moduleArgs> + </properties> + </profile> + <profile> + <id>jdk18-23</id> + <activation> + <jdk>[18,24)</jdk> + </activation> + <properties> + <itw.test.smArgs>-Djava.security.manager=allow</itw.test.smArgs> + </properties> + </profile> <profile> <id>javaDoc</id> <properties> @@ -111,7 +135,7 @@ <artifactId>maven-surefire-plugin</artifactId> <version>${maven-surefire-plugin.version}</version> <configuration> - <argLine>-Dfile.encoding=${project.build.sourceEncoding} -Duser.language=en</argLine> + <argLine>@{argLine} ${itw.test.moduleArgs} ${itw.test.smArgs} -Dfile.encoding=${project.build.sourceEncoding} -Duser.language=en</argLine> <environmentVariables> <ICEDTEA_WEB_SPLASH>DEFAULT</ICEDTEA_WEB_SPLASH> </environmentVariables> -- 2.55.0 ++++++ 0003-Bring-back-Pack200-support-on-newer-Java-using-commo.patch ++++++ >From 4ae2a63755a253957e6ae46d7e48dc1121fdd0b4 Mon Sep 17 00:00:00 2001 From: Fridrich Strba <[email protected]> Date: Tue, 6 Oct 2026 13:16:02 +0200 Subject: [PATCH 3/8] Bring back Pack200 support on newer Java using commons-compress --- artifact-all-dependencies/pom.xml | 4 ++ core/pom.xml | 19 +++++++++ .../JnlpDownloadProtocolConstants.java | 4 +- .../downloader/PackGzipUnpacker.java | 41 ++++--------------- .../java/net/sourceforge/jnlp/JNLPFile.java | 3 +- .../resources/ResourceHandlerTest.java | 10 +---- .../net/sourceforge/jnlp/JNLPFileTest.java | 3 +- launchers/configure.sh | 27 +++++++++--- .../rust-launcher/src/hardcoded_paths.rs | 6 +++ launchers/rust-launcher/src/jars_helper.rs | 3 ++ launchers/shell-launcher/launchers.bat.in | 11 ++++- launchers/shell-launcher/launchers.sh.in | 11 ++++- launchers/utils.sh | 6 +++ 13 files changed, 92 insertions(+), 56 deletions(-) diff --git a/artifact-all-dependencies/pom.xml b/artifact-all-dependencies/pom.xml index c2f1a96ba..668c1c159 100644 --- a/artifact-all-dependencies/pom.xml +++ b/artifact-all-dependencies/pom.xml @@ -53,6 +53,10 @@ <pattern>org.ccil.cowan.tagsoup</pattern> <shadedPattern>net.adoptopenjdk.icedteaweb.shaded.tagsoup</shadedPattern> </relocation> + <relocation> + <pattern>org.apache.commons</pattern> + <shadedPattern>net.adoptopenjdk.icedteaweb.shaded.apache.commons</shadedPattern> + </relocation> <relocation> <pattern>mslinks</pattern> <shadedPattern>net.adoptopenjdk.icedteaweb.shaded.mslinks</shadedPattern> diff --git a/core/pom.xml b/core/pom.xml index 1672ee94e..4de58593f 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -49,6 +49,18 @@ <artifactId>rhino</artifactId> <version>1.7.15.1</version> </dependency> + <!-- Pack200 (removed from JDK 14) --> + <dependency> + <groupId>org.apache.commons</groupId> + <artifactId>commons-compress</artifactId> + <version>1.28.0</version> + <exclusions> + <exclusion> + <groupId>commons-codec</groupId> + <artifactId>commons-codec</artifactId> + </exclusion> + </exclusions> + </dependency> <dependency> <groupId>${project.groupId}</groupId> @@ -56,6 +68,13 @@ <version>${project.version}</version> <scope>test</scope> </dependency> + <!-- commons-compress Pack200 packer (tests only; unpacking needs no ASM) --> + <dependency> + <groupId>org.ow2.asm</groupId> + <artifactId>asm</artifactId> + <version>9.10.1</version> + <scope>test</scope> + </dependency> </dependencies> <build> diff --git a/core/src/main/java/net/adoptopenjdk/icedteaweb/resources/JnlpDownloadProtocolConstants.java b/core/src/main/java/net/adoptopenjdk/icedteaweb/resources/JnlpDownloadProtocolConstants.java index 899b7e09c..18ff9aa74 100644 --- a/core/src/main/java/net/adoptopenjdk/icedteaweb/resources/JnlpDownloadProtocolConstants.java +++ b/core/src/main/java/net/adoptopenjdk/icedteaweb/resources/JnlpDownloadProtocolConstants.java @@ -1,7 +1,5 @@ package net.adoptopenjdk.icedteaweb.resources; -import net.adoptopenjdk.icedteaweb.resources.downloader.PackGzipUnpacker; - /** * ... */ @@ -16,7 +14,7 @@ public interface JnlpDownloadProtocolConstants { String ERROR_MIME_TYPE = "application/x-java-jnlp-error"; String JAR_DIFF_MIME_TYPE = "application/x-java-archive-dif"; - String PACK_200_OR_GZIP = PackGzipUnpacker.isSupported() ? "pack200-gzip, gzip" : "gzip"; + String PACK_200_OR_GZIP = "pack200-gzip, gzip"; String INVALID_HTTP_RESPONSE = "Invalid Http response"; String VERSION_ID_QUERY_PARAM = "version-id"; diff --git a/core/src/main/java/net/adoptopenjdk/icedteaweb/resources/downloader/PackGzipUnpacker.java b/core/src/main/java/net/adoptopenjdk/icedteaweb/resources/downloader/PackGzipUnpacker.java index b361288f9..b62c47ec2 100644 --- a/core/src/main/java/net/adoptopenjdk/icedteaweb/resources/downloader/PackGzipUnpacker.java +++ b/core/src/main/java/net/adoptopenjdk/icedteaweb/resources/downloader/PackGzipUnpacker.java @@ -16,55 +16,28 @@ package net.adoptopenjdk.icedteaweb.resources.downloader; +import org.apache.commons.compress.java.util.jar.Pack200; +import org.apache.commons.io.IOUtils; + import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; import java.util.jar.JarOutputStream; import java.util.zip.GZIPInputStream; /** * Unpacker for PACK200 and Gzip streams. - * java.util.jar.Pack200 was removed in JDK 14, hence reflection. + * Pack200 from commons-compress: java.util.jar.Pack200 was removed in JDK 14. */ public class PackGzipUnpacker implements StreamUnpacker { - - private static final Method NEW_UNPACKER; - private static final Method UNPACK; - - static { - Method newUnpacker = null; - Method unpack = null; - try { - newUnpacker = Class.forName("java.util.jar.Pack200").getMethod("newUnpacker"); - unpack = Class.forName("java.util.jar.Pack200$Unpacker").getMethod("unpack", InputStream.class, JarOutputStream.class); - } catch (ReflectiveOperationException ignored) { - } - NEW_UNPACKER = newUnpacker; - UNPACK = unpack; - } - - public static boolean isSupported() { - return UNPACK != null; - } - @Override public InputStream unpack(InputStream input) throws IOException { - if (!isSupported()) { - throw new IOException("pack200 is not supported by this JVM"); - } final ByteArrayOutputStream buffer = new ByteArrayOutputStream(); try (final JarOutputStream outputStream = new JarOutputStream(buffer)) { - UNPACK.invoke(NEW_UNPACKER.invoke(null), new GZIPInputStream(input), outputStream); - } catch (IllegalAccessException e) { - throw new IOException(e); - } catch (InvocationTargetException e) { - if (e.getCause() instanceof IOException) { - throw (IOException) e.getCause(); - } - throw new IOException(e.getCause()); + // not a FilterInputStream: unpacker would reflectively unwrap it, denied on JDK 17+ + final InputStream packed = new ByteArrayInputStream(IOUtils.toByteArray(new GZIPInputStream(input))); + Pack200.newUnpacker().unpack(packed, outputStream); } return new ByteArrayInputStream(buffer.toByteArray()); } diff --git a/core/src/main/java/net/sourceforge/jnlp/JNLPFile.java b/core/src/main/java/net/sourceforge/jnlp/JNLPFile.java index 4a7f495b8..125d3b17b 100644 --- a/core/src/main/java/net/sourceforge/jnlp/JNLPFile.java +++ b/core/src/main/java/net/sourceforge/jnlp/JNLPFile.java @@ -39,7 +39,6 @@ import net.adoptopenjdk.icedteaweb.jnlp.version.VersionString; import net.adoptopenjdk.icedteaweb.logging.Logger; import net.adoptopenjdk.icedteaweb.logging.LoggerFactory; import net.adoptopenjdk.icedteaweb.manifest.ManifestAttributesReader; -import net.adoptopenjdk.icedteaweb.resources.downloader.PackGzipUnpacker; import net.adoptopenjdk.icedteaweb.xmlparser.ParseException; import net.adoptopenjdk.icedteaweb.xmlparser.XMLParser; import net.adoptopenjdk.icedteaweb.xmlparser.XmlNode; @@ -828,7 +827,7 @@ public class JNLPFile { */ public DownloadOptions getDownloadOptions() { final ResourcesDesc desc = getResources(); - final boolean usePack = parseBoolean(desc.getPropertiesMap().get("jnlp.packEnabled")) && PackGzipUnpacker.isSupported(); + final boolean usePack = parseBoolean(desc.getPropertiesMap().get("jnlp.packEnabled")); final boolean useVersion = parseBoolean(desc.getPropertiesMap().get("jnlp.versionEnabled")); return new DownloadOptions(usePack, useVersion); } diff --git a/core/src/test/java/net/adoptopenjdk/icedteaweb/resources/ResourceHandlerTest.java b/core/src/test/java/net/adoptopenjdk/icedteaweb/resources/ResourceHandlerTest.java index 6db57116e..c1cc28f61 100644 --- a/core/src/test/java/net/adoptopenjdk/icedteaweb/resources/ResourceHandlerTest.java +++ b/core/src/test/java/net/adoptopenjdk/icedteaweb/resources/ResourceHandlerTest.java @@ -1,7 +1,6 @@ package net.adoptopenjdk.icedteaweb.resources; import net.adoptopenjdk.icedteaweb.jnlp.version.VersionString; -import net.adoptopenjdk.icedteaweb.resources.downloader.PackGzipUnpacker; import net.adoptopenjdk.icedteaweb.testing.ServerAccess; import net.adoptopenjdk.icedteaweb.testing.ServerLauncher; import net.jcip.annotations.NotThreadSafe; @@ -12,8 +11,8 @@ import net.sourceforge.jnlp.util.JarFile; import net.sourceforge.jnlp.util.logging.NoStdOutErrTest; import net.sourceforge.jnlp.util.logging.OutputController; import net.sourceforge.jnlp.util.logging.StdInOutErrController; +import org.apache.commons.compress.java.util.jar.Pack200; import org.junit.After; -import org.junit.Assume; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; @@ -24,7 +23,6 @@ import org.junit.rules.TemporaryFolder; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileOutputStream; -import java.io.OutputStream; import java.net.URL; import java.nio.file.Files; import java.util.concurrent.ExecutorService; @@ -211,11 +209,7 @@ public class ResourceHandlerTest extends NoStdOutErrTest { final JarFile jarFile = new JarFile(jar.getAbsolutePath()); final FileOutputStream fos = new FileOutputStream(pack); - // Pack200 removed in JDK 14 - Assume.assumeTrue(PackGzipUnpacker.isSupported()); - final Object packer = Class.forName("java.util.jar.Pack200").getMethod("newPacker").invoke(null); - Class.forName("java.util.jar.Pack200$Packer").getMethod("pack", java.util.jar.JarFile.class, OutputStream.class) - .invoke(packer, jarFile.getNative(), fos); + Pack200.newPacker().pack(jarFile.getNative(), fos); fos.close(); final File packgz = new File(downloadDir, fileName + ".jar.pack.gz"); diff --git a/core/src/test/java/net/sourceforge/jnlp/JNLPFileTest.java b/core/src/test/java/net/sourceforge/jnlp/JNLPFileTest.java index 7ffeb9248..4b3bd15eb 100644 --- a/core/src/test/java/net/sourceforge/jnlp/JNLPFileTest.java +++ b/core/src/test/java/net/sourceforge/jnlp/JNLPFileTest.java @@ -39,7 +39,6 @@ import net.adoptopenjdk.icedteaweb.jnlp.element.resource.ResourcesDesc; import net.adoptopenjdk.icedteaweb.jnlp.element.security.ApplicationPermissionLevel; import net.adoptopenjdk.icedteaweb.testing.annotations.Bug; import net.adoptopenjdk.icedteaweb.testing.mock.MockJNLPFile; -import net.adoptopenjdk.icedteaweb.resources.downloader.PackGzipUnpacker; import net.adoptopenjdk.icedteaweb.xmlparser.ParseException; import net.sourceforge.jnlp.util.logging.NoStdOutErrTest; import org.junit.Assert; @@ -189,7 +188,7 @@ public class JNLPFileTest extends NoStdOutErrTest{ JNLPFile jnlpFile = new JNLPFile(is, codeBase, new ParserSettings(false,false,false)); DownloadOptions downloadOptions = jnlpFile.getDownloadOptions(); - Assert.assertEquals(PackGzipUnpacker.isSupported(), downloadOptions.useExplicitPack()); // no Pack200 since JDK 14 + Assert.assertTrue(downloadOptions.useExplicitPack()); Assert.assertTrue(downloadOptions.useExplicitVersion()); } diff --git a/launchers/configure.sh b/launchers/configure.sh index a188d0097..2794aba24 100644 --- a/launchers/configure.sh +++ b/launchers/configure.sh @@ -94,9 +94,11 @@ function findJar() { } +# $1 jar name, $2 maven groupId:artifactId function getJar() { if [ "x$ITW_LIBS" == "xDISTRIBUTION" ] ; then - findJar "$SYSTEM_JARS" "$1" + # javapackages-tools knows the canonical jar (coordinates need xmvn-resolve); plain find may hit private copies (e.g. xmvn's) + find-jar "$2" 2>/dev/null || find-jar "$1" 2>/dev/null || findJar "$SYSTEM_JARS" "$1" else # Dependent jars for non distribution builds have no sense with fat javaws.jar echo "" @@ -104,25 +106,40 @@ function getJar() { } if [ "x$RHINO_SRC" == "x" ] ; then - readonly RHINO_SRC=`getJar "rhino"` + readonly RHINO_SRC=`getJar "rhino" "org.mozilla:rhino"` else readonly RHINO_SRC=$RHINO_SRC fi if [ "x$TAGSOUP_SRC" == "x" ] ; then - readonly TAGSOUP_SRC=`getJar "tagsoup"` + readonly TAGSOUP_SRC=`getJar "tagsoup" "org.ccil.cowan.tagsoup:tagsoup"` else readonly TAGSOUP_SRC=$TAGSOUP_SRC fi if [ "x$MSLINKS_SRC" == "x" ] ; then - readonly MSLINKS_SRC=`getJar "mslinks"` + readonly MSLINKS_SRC=`getJar "mslinks" "com.github.vatbub:mslinks"` else readonly MSLINKS_SRC=$MSLINKS_SRC fi if [ "x$IPADDRESS_SRC" == "x" ] ; then - readonly IPADDRESS_SRC=`getJar "ipaddress"` + readonly IPADDRESS_SRC=`getJar "ipaddress" "com.github.seancfoley:ipaddress"` else readonly IPADDRESS_SRC=$IPADDRESS_SRC fi +if [ "x$COMMONS_COMPRESS_SRC" == "x" ] ; then + readonly COMMONS_COMPRESS_SRC=`getJar "commons-compress" "org.apache.commons:commons-compress"` +else + readonly COMMONS_COMPRESS_SRC=$COMMONS_COMPRESS_SRC +fi +if [ "x$COMMONS_IO_SRC" == "x" ] ; then + readonly COMMONS_IO_SRC=`getJar "commons-io" "commons-io:commons-io"` +else + readonly COMMONS_IO_SRC=$COMMONS_IO_SRC +fi +if [ "x$COMMONS_LANG3_SRC" == "x" ] ; then + readonly COMMONS_LANG3_SRC=`getJar "commons-lang3" "org.apache.commons:commons-lang3"` +else + readonly COMMONS_LANG3_SRC=$COMMONS_LANG3_SRC +fi readonly SPLASH_PNG_SRC=`find $PROJECT_TOP/core/src | grep /javaws_splash.png$` diff --git a/launchers/rust-launcher/src/hardcoded_paths.rs b/launchers/rust-launcher/src/hardcoded_paths.rs index adffdf206..0e5f1df84 100644 --- a/launchers/rust-launcher/src/hardcoded_paths.rs +++ b/launchers/rust-launcher/src/hardcoded_paths.rs @@ -15,6 +15,9 @@ const ITW_LIBS: Option<&'static str> = option_env!("ITW_LIBS"); const MODULARJDK_ARGS_LOCATION: Option<&'static str> = option_env!("MODULARJDK_ARGS_LOCATION"); const MSLINKS_JAR: Option<&'static str> = option_env!("MSLINKS_JAR"); const IPADDRESS_JAR: Option<&'static str> = option_env!("IPADDRESS_JAR"); +const COMMONS_COMPRESS_JAR: Option<&'static str> = option_env!("COMMONS_COMPRESS_JAR"); +const COMMONS_IO_JAR: Option<&'static str> = option_env!("COMMONS_IO_JAR"); +const COMMONS_LANG3_JAR: Option<&'static str> = option_env!("COMMONS_LANG3_JAR"); pub fn get_jre() -> &'static str { @@ -40,6 +43,9 @@ pub fn get_rhino() -> Option<&'static str> { sanitize(RHINO_JAR) } pub fn get_mslinks() -> Option<&'static str> { sanitize(MSLINKS_JAR) } pub fn get_ipaddress() -> Option<&'static str> { sanitize(IPADDRESS_JAR) } +pub fn get_commons_compress() -> Option<&'static str> { sanitize(COMMONS_COMPRESS_JAR) } +pub fn get_commons_io() -> Option<&'static str> { sanitize(COMMONS_IO_JAR) } +pub fn get_commons_lang3() -> Option<&'static str> { sanitize(COMMONS_LANG3_JAR) } pub fn get_argsfile() -> &'static str { MODULARJDK_ARGS_LOCATION.unwrap_or("MODULARJDK_ARGS_LOCATION-dev-unspecified") diff --git a/launchers/rust-launcher/src/jars_helper.rs b/launchers/rust-launcher/src/jars_helper.rs index 8de8c5eb6..1c61b8de1 100644 --- a/launchers/rust-launcher/src/jars_helper.rs +++ b/launchers/rust-launcher/src/jars_helper.rs @@ -154,6 +154,9 @@ fn get_bootcp_members(jre_path: &std::path::PathBuf, os: &os_access::Os) -> Vec< append_if_exists(hardcoded_paths::get_tagsoup(), os, &mut cp_parts); append_if_exists(hardcoded_paths::get_mslinks(), os, &mut cp_parts); append_if_exists(hardcoded_paths::get_ipaddress(), os, &mut cp_parts); + append_if_exists(hardcoded_paths::get_commons_compress(), os, &mut cp_parts); + append_if_exists(hardcoded_paths::get_commons_io(), os, &mut cp_parts); + append_if_exists(hardcoded_paths::get_commons_lang3(), os, &mut cp_parts); let mut nashorn_jar = jre_path.clone(); nashorn_jar.push("lib"); nashorn_jar.push("ext"); diff --git a/launchers/shell-launcher/launchers.bat.in b/launchers/shell-launcher/launchers.bat.in index 8a4a5aa9e..4d828a938 100644 --- a/launchers/shell-launcher/launchers.bat.in +++ b/launchers/shell-launcher/launchers.bat.in @@ -30,6 +30,9 @@ set "TAGSOUP_SRC=@TAGSOUP_JAR@" set "RHINO_SRC=@RHINO_JAR@" set "MSLINKS_SRC=@MSLINKS_JAR@" set "IPADDRESS_SRC=@IPADDRESS_JAR@" +set "COMMONS_COMPRESS_SRC=@COMMONS_COMPRESS_JAR@" +set "COMMONS_IO_SRC=@COMMONS_IO_JAR@" +set "COMMONS_LANG3_SRC=@COMMONS_LANG3_JAR@" rem resolve folder of this script: @@ -108,6 +111,9 @@ if "%ITW_LIBS%" == "BUNDLED" ( set "TAGSOUP_JAR=" set "MSLINKS_JAR=" set "IPADDRESS_JAR=" + set "COMMONS_COMPRESS_JAR=" + set "COMMONS_IO_JAR=" + set "COMMONS_LANG3_JAR=" ) else ( set "JAVAWS_JAR=!JAVAWS_SRC!" @@ -115,8 +121,11 @@ if "%ITW_LIBS%" == "BUNDLED" ( set "TAGSOUP_JAR=!TAGSOUP_SRC!" set "MSLINKS_JAR=!MSLINKS_SRC!" set "IPADDRESS_JAR=!IPADDRESS_SRC!" + set "COMMONS_COMPRESS_JAR=!COMMONS_COMPRESS_SRC!" + set "COMMONS_IO_JAR=!COMMONS_IO_SRC!" + set "COMMONS_LANG3_JAR=!COMMONS_LANG3_SRC!" ) -set "LAUNCHER_BOOTCLASSPATH=-Xbootclasspath/a:%JAVAWS_JAR%;%RHINO_JAR%;%TAGSOUP_JAR%;%MSLINKS_JAR%;%IPADDRESS_JAR%" +set "LAUNCHER_BOOTCLASSPATH=-Xbootclasspath/a:%JAVAWS_JAR%;%RHINO_JAR%;%TAGSOUP_JAR%;%MSLINKS_JAR%;%IPADDRESS_JAR%;%COMMONS_COMPRESS_JAR%;%COMMONS_IO_JAR%;%COMMONS_LANG3_JAR%" rem Fix classpaths for custom JRE: diff --git a/launchers/shell-launcher/launchers.sh.in b/launchers/shell-launcher/launchers.sh.in index bee618b81..617bc86ad 100644 --- a/launchers/shell-launcher/launchers.sh.in +++ b/launchers/shell-launcher/launchers.sh.in @@ -21,6 +21,9 @@ readonly JAVAWS_SRC=@JAVAWS_JAR@ readonly TAGSOUP_SRC=@TAGSOUP_JAR@ readonly RHINO_SRC=@RHINO_JAR@ readonly IPADDRESS_SRC=@IPADDRESS_JAR@ +readonly COMMONS_COMPRESS_SRC=@COMMONS_COMPRESS_JAR@ +readonly COMMONS_IO_SRC=@COMMONS_IO_JAR@ +readonly COMMONS_LANG3_SRC=@COMMONS_LANG3_JAR@ # windows only: (cywin usage?); need to declare it anyway readonly MSLINKS_SRC=@MSLINKS_JAR@ @@ -110,6 +113,9 @@ if [ "x$ITW_LIBS" == "xBUNDLED" -o ! "x$ITW_HOME" = "x" ] ; then readonly TAGSOUP_JAR="" readonly MSLINKS_JAR="" readonly IPADDRESS_JAR="" + readonly COMMONS_COMPRESS_JAR="" + readonly COMMONS_IO_JAR="" + readonly COMMONS_LANG3_JAR="" echo "warning, using portable itw from $ITW_HOME" else readonly JAVAWS_JAR="$JAVAWS_SRC" @@ -118,9 +124,12 @@ else readonly TAGSOUP_JAR="$TAGSOUP_SRC" readonly MSLINKS_JAR="$MSLINKS_SRC" readonly IPADDRESS_JAR="$IPADDRESS_SRC" + readonly COMMONS_COMPRESS_JAR="$COMMONS_COMPRESS_SRC" + readonly COMMONS_IO_JAR="$COMMONS_IO_SRC" + readonly COMMONS_LANG3_JAR="$COMMONS_LANG3_SRC" fi set -u -LAUNCHER_BOOTCLASSPATH="-Xbootclasspath/a:$JAVAWS_JAR:$TAGSOUP_JAR:$RHINO_JAR:$MSLINKS_JAR:$IPADDRESS_JAR" +LAUNCHER_BOOTCLASSPATH="-Xbootclasspath/a:$JAVAWS_JAR:$TAGSOUP_JAR:$RHINO_JAR:$MSLINKS_JAR:$IPADDRESS_JAR:$COMMONS_COMPRESS_JAR:$COMMONS_IO_JAR:$COMMONS_LANG3_JAR" # Fix classpaths for custom JRE: if [ "x$CUSTOM_JRE" != "x" ] ; then diff --git a/launchers/utils.sh b/launchers/utils.sh index ef773997b..79c495179 100644 --- a/launchers/utils.sh +++ b/launchers/utils.sh @@ -23,6 +23,9 @@ function build() { export RHINO_JAR=$RHINO_SRC export MSLINKS_JAR=$MSLINKS_SRC export IPADDRESS_JAR=$IPADDRESS_SRC + export COMMONS_COMPRESS_JAR=$COMMONS_COMPRESS_SRC + export COMMONS_IO_JAR=$COMMONS_IO_SRC + export COMMONS_LANG3_JAR=$COMMONS_LANG3_SRC fi export JRE export ITW_LIBS @@ -55,6 +58,9 @@ function build() { -e "s|[@]RHINO_JAR[@]|$RHINO_JAR|g" \ -e "s|[@]MSLINKS_JAR[@]|$MSLINKS_JAR|g" \ -e "s|[@]IPADDRESS_JAR[@]|$IPADDRESS_JAR|g" \ + -e "s|[@]COMMONS_COMPRESS_JAR[@]|$COMMONS_COMPRESS_JAR|g" \ + -e "s|[@]COMMONS_IO_JAR[@]|$COMMONS_IO_JAR|g" \ + -e "s|[@]COMMONS_LANG3_JAR[@]|$COMMONS_LANG3_JAR|g" \ -e "s|[@]JAVAWS_JAR[@]|$JAVAWS_JAR|g" \ -e "s|[@]SPLASH_PNG[@]|$SPLASH_PNG|g" \ -e "s|[@]MODULARJDK_ARGS_LOCATION[@]|$MODULARJDK_ARGS_LOCATION|g" \ -- 2.55.0 ++++++ 0004-Grey-out-the-advanced-policy-editor-button-when-poli.patch ++++++ >From 448285ace570372bdd00c963f75494ff6371de36 Mon Sep 17 00:00:00 2001 From: Fridrich Strba <[email protected]> Date: Tue, 6 Oct 2026 13:26:24 +0200 Subject: [PATCH 4/8] Grey out the advanced policy editor button when policytool is missing --- .../controlpanel/panels/PolicyPanel.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/core/src/main/java/net/adoptopenjdk/icedteaweb/client/controlpanel/panels/PolicyPanel.java b/core/src/main/java/net/adoptopenjdk/icedteaweb/client/controlpanel/panels/PolicyPanel.java index 944e1602f..3089191c3 100644 --- a/core/src/main/java/net/adoptopenjdk/icedteaweb/client/controlpanel/panels/PolicyPanel.java +++ b/core/src/main/java/net/adoptopenjdk/icedteaweb/client/controlpanel/panels/PolicyPanel.java @@ -40,6 +40,7 @@ import net.adoptopenjdk.icedteaweb.client.parts.dialogs.FileDialogFactory; import net.adoptopenjdk.icedteaweb.client.policyeditor.PolicyEditor; import net.adoptopenjdk.icedteaweb.client.policyeditor.PolicyEditor.PolicyEditorWindow; import net.adoptopenjdk.icedteaweb.io.FileUtils; +import net.adoptopenjdk.icedteaweb.jvm.JvmUtils; import net.adoptopenjdk.icedteaweb.io.FileUtils.OpenFileResult; import net.adoptopenjdk.icedteaweb.logging.Logger; import net.adoptopenjdk.icedteaweb.logging.LoggerFactory; @@ -90,6 +91,11 @@ public class PolicyPanel extends NamedBorderPanel { final JButton advancedEditorButton = new JButton(R("CPButAdvancedEditor")); advancedEditorButton.addActionListener(new LaunchPolicyToolAction(fileUrlString)); + if (!isPolicyToolAvailable()) { + // policytool removed in JDK 10 + advancedEditorButton.setEnabled(false); + advancedEditorButton.setToolTipText(R("CPPolicyEditorNotFound")); + } final String pathPart = localFilePathFromUrlString(fileUrlString); simpleEditorButton.setToolTipText(R("CPPolicyTooltip", FileUtils.displayablePath(pathPart, 60))); @@ -229,6 +235,18 @@ public class PolicyPanel extends NamedBorderPanel { main.invoke(null, (Object) args); } + private static boolean isPolicyToolAvailable() { + if (JvmUtils.findOnPath(new String[]{"policytool", "policytool.exe"}) != null) { + return true; + } + try { + Class.forName("sun.security.tools.policytool.PolicyTool"); + return true; + } catch (ClassNotFoundException e) { + return false; + } + } + /** * Loosely attempt to get the path part of a file URL string. If this fails, * simply return back the input. This is only intended to be used for displaying -- 2.55.0 ++++++ 0005-Stop-relying-on-hidden-JDK-certificate-classes-where.patch ++++++ >From 09fd5844eb46f75e278fa0e616c5f05f6f9f7b94 Mon Sep 17 00:00:00 2001 From: Fridrich Strba <[email protected]> Date: Tue, 6 Oct 2026 13:45:40 +0200 Subject: [PATCH 5/8] Stop relying on hidden JDK certificate classes where the public Java API does the job --- .../parts/dialogs/security/CertsInfoPane.java | 42 +++-------- .../jnlp/element/security/SecurityDesc.java | 6 +- .../proxy/pac/RhinoBasedPacEvaluator.java | 4 +- .../runtime/classloader/JNLPClassLoader.java | 4 +- .../jnlp/security/HttpsCertVerifier.java | 29 +++++--- .../jnlp/tools/JarCertVerifier.java | 47 ++++-------- .../dialogs/security/CertsInfoPaneTest.java | 17 +++++ .../security/TemporaryPermissionsTest.java | 6 +- .../jnlp/security/HttpsCertVerifierTest.java | 23 ++++++ .../jnlp/tools/JarCertVerifierTest.java | 12 +++ pom.xml | 2 +- test-extensions/pom.xml | 6 ++ .../testing/tools/CodeSignerCreator.java | 73 ++++++------------- 13 files changed, 141 insertions(+), 130 deletions(-) create mode 100644 core/src/test/java/net/adoptopenjdk/icedteaweb/client/parts/dialogs/security/CertsInfoPaneTest.java create mode 100644 core/src/test/java/net/sourceforge/jnlp/security/HttpsCertVerifierTest.java diff --git a/core/src/main/java/net/adoptopenjdk/icedteaweb/client/parts/dialogs/security/CertsInfoPane.java b/core/src/main/java/net/adoptopenjdk/icedteaweb/client/parts/dialogs/security/CertsInfoPane.java index 6d1f5b328..db7e44ba4 100644 --- a/core/src/main/java/net/adoptopenjdk/icedteaweb/client/parts/dialogs/security/CertsInfoPane.java +++ b/core/src/main/java/net/adoptopenjdk/icedteaweb/client/parts/dialogs/security/CertsInfoPane.java @@ -40,7 +40,6 @@ import net.adoptopenjdk.icedteaweb.ui.swing.dialogresults.DialogResult; import net.adoptopenjdk.icedteaweb.ui.swing.dialogresults.Yes; import net.sourceforge.jnlp.security.CertVerifier; import net.sourceforge.jnlp.security.SecurityUtil; -import sun.security.x509.CertificateValidity; import javax.swing.BorderFactory; import javax.swing.JButton; @@ -66,7 +65,6 @@ import java.awt.datatransfer.Clipboard; import java.awt.datatransfer.StringSelection; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; -import java.lang.reflect.Method; import java.security.MessageDigest; import java.security.cert.CertPath; import java.security.cert.Certificate; @@ -170,11 +168,11 @@ public class CertsInfoPane extends SecurityDialogPanel { String serialNumber = c.getSerialNumber().toString(); String signatureAlg = c.getSigAlgName(); String issuer = c.getIssuerX500Principal().toString(); - String validity = new CertificateValidity(c.getNotBefore(), - c.getNotAfter()).toString(); + // same text as sun.security.x509.CertificateValidity + String validity = "Validity: [From: " + c.getNotBefore() + ",\n To: " + c.getNotAfter() + "]"; String subject = c.getSubjectX500Principal().toString(); - String signature = jdkIndependentHexEncoder(c.getSignature()); + String signature = hexDump(c.getSignature()); String md5Hash = ""; String sha1Hash = ""; @@ -203,32 +201,16 @@ public class CertsInfoPane extends SecurityDialogPanel { return cert; } - private String jdkIndependentHexEncoder(byte[] signature) { - try { - return jdkIndependentHexEncoderImpl(signature); - } catch (Exception ex) { - String s = "Failed to encode signature: " + ex.toString(); - LOG.error("Failed to encode signature", ex); - return s; - } - } - - private String jdkIndependentHexEncoderImpl(byte[] signature) throws Exception { - try { - LOG.debug("trying jdk9's HexDumpEncoder"); - Class clazz = Class.forName("sun.security.util.HexDumpEncoder"); - Object encoder = clazz.newInstance(); - Method m = clazz.getDeclaredMethod("encodeBuffer", byte[].class); - //convert our signature into a nice human-readable form. - return (String) m.invoke(encoder, signature); - } catch (Exception ex) { - LOG.debug("trying jdk8's HexDumpEncoder"); - Class clazz = Class.forName("sun.misc.HexDumpEncoder"); - Object encoder = clazz.newInstance(); - Method m = clazz.getMethod("encode", byte[].class); - //convert our signature into a nice human-readable form. - return (String) m.invoke(encoder, signature); + /** 16 bytes per line, offset prefixed; like the JDK-internal HexDumpEncoder minus the ASCII column */ + static String hexDump(final byte[] bytes) { + final StringBuilder sb = new StringBuilder(); + for (int i = 0; i < bytes.length; i++) { + if (i % 16 == 0) { + sb.append(i == 0 ? "" : "\n").append(String.format("%04X:", i)); + } + sb.append(String.format(" %02X", bytes[i] & 0xFF)); } + return sb.toString(); } /** diff --git a/core/src/main/java/net/adoptopenjdk/icedteaweb/jnlp/element/security/SecurityDesc.java b/core/src/main/java/net/adoptopenjdk/icedteaweb/jnlp/element/security/SecurityDesc.java index 3cf7bef31..d8aed6f16 100644 --- a/core/src/main/java/net/adoptopenjdk/icedteaweb/jnlp/element/security/SecurityDesc.java +++ b/core/src/main/java/net/adoptopenjdk/icedteaweb/jnlp/element/security/SecurityDesc.java @@ -91,8 +91,6 @@ import static net.adoptopenjdk.icedteaweb.JavaSystemPropertiesConstants.VM_VENDO import static net.adoptopenjdk.icedteaweb.JavaSystemPropertiesConstants.VM_VERSION; import static net.adoptopenjdk.icedteaweb.JavaSystemPropertiesConstants.WEBSTART_JAUTHENTICATOR; import static net.adoptopenjdk.icedteaweb.JavaSystemPropertiesConstants.WEBSTART_VERSION; -import static sun.security.util.SecurityConstants.PROPERTY_READ_ACTION; -import static sun.security.util.SecurityConstants.PROPERTY_RW_ACTION; /** * The security element. @@ -101,6 +99,10 @@ import static sun.security.util.SecurityConstants.PROPERTY_RW_ACTION; * @version $Revision: 1.7 $ */ public class SecurityDesc { + + // values of sun.security.util.SecurityConstants + private static final String PROPERTY_READ_ACTION = "read"; + private static final String PROPERTY_RW_ACTION = "read,write"; private final static Logger LOG = LoggerFactory.getLogger(SecurityDesc.class); public static final String SECURITY_ELEMENT = "security"; diff --git a/core/src/main/java/net/sourceforge/jnlp/proxy/pac/RhinoBasedPacEvaluator.java b/core/src/main/java/net/sourceforge/jnlp/proxy/pac/RhinoBasedPacEvaluator.java index 11cedc335..1b2d1a6b1 100644 --- a/core/src/main/java/net/sourceforge/jnlp/proxy/pac/RhinoBasedPacEvaluator.java +++ b/core/src/main/java/net/sourceforge/jnlp/proxy/pac/RhinoBasedPacEvaluator.java @@ -56,7 +56,6 @@ import java.security.ProtectionDomain; import java.util.PropertyPermission; import static net.adoptopenjdk.icedteaweb.JavaSystemPropertiesConstants.VM_NAME; -import static sun.security.util.SecurityConstants.PROPERTY_READ_ACTION; /** * Represents a Proxy Auto Config file. This object can be used to evaluate the @@ -66,6 +65,9 @@ import static sun.security.util.SecurityConstants.PROPERTY_READ_ACTION; */ public class RhinoBasedPacEvaluator implements PacEvaluator { + // values of sun.security.util.SecurityConstants + private static final String PROPERTY_READ_ACTION = "read"; + private final static Logger LOG = LoggerFactory.getLogger(RhinoBasedPacEvaluator.class); private final String pacHelperFunctionContents; diff --git a/core/src/main/java/net/sourceforge/jnlp/runtime/classloader/JNLPClassLoader.java b/core/src/main/java/net/sourceforge/jnlp/runtime/classloader/JNLPClassLoader.java index bb12b020c..de2a7e68e 100644 --- a/core/src/main/java/net/sourceforge/jnlp/runtime/classloader/JNLPClassLoader.java +++ b/core/src/main/java/net/sourceforge/jnlp/runtime/classloader/JNLPClassLoader.java @@ -103,7 +103,6 @@ import static net.sourceforge.jnlp.LaunchException.FATAL; import static net.sourceforge.jnlp.cache.NativeLibraryStorage.NATIVE_LIB_EXT_DYLIB; import static net.sourceforge.jnlp.cache.NativeLibraryStorage.NATIVE_LIB_EXT_JNILIB; import static net.sourceforge.jnlp.util.UrlUtils.FILE_PROTOCOL; -import static sun.security.util.SecurityConstants.FILE_READ_ACTION; /** * Classloader that takes it's resources from a JNLP file. If the JNLP file @@ -117,6 +116,9 @@ import static sun.security.util.SecurityConstants.FILE_READ_ACTION; */ public class JNLPClassLoader extends URLClassLoader { + // values of sun.security.util.SecurityConstants + private static final String FILE_READ_ACTION = "read"; + private static final Logger LOG = LoggerFactory.getLogger(JNLPClassLoader.class); // todo: initializePermissions should get the permissions from diff --git a/core/src/main/java/net/sourceforge/jnlp/security/HttpsCertVerifier.java b/core/src/main/java/net/sourceforge/jnlp/security/HttpsCertVerifier.java index 59f6c1b17..b5b9f4ff6 100644 --- a/core/src/main/java/net/sourceforge/jnlp/security/HttpsCertVerifier.java +++ b/core/src/main/java/net/sourceforge/jnlp/security/HttpsCertVerifier.java @@ -36,10 +36,10 @@ package net.sourceforge.jnlp.security; import net.adoptopenjdk.icedteaweb.logging.Logger; import net.adoptopenjdk.icedteaweb.logging.LoggerFactory; -import sun.security.util.DerValue; -import sun.security.util.HostnameChecker; -import sun.security.x509.X500Name; +import javax.naming.InvalidNameException; +import javax.naming.ldap.LdapName; +import javax.naming.ldap.Rdn; import java.security.KeyStore; import java.security.cert.CertPath; import java.security.cert.Certificate; @@ -137,6 +137,20 @@ public class HttpsCertVerifier implements CertVerifier { return details; } + /** + * @return the last (most specific) CN of the subject, or null + */ + static String getMostSpecificCommonName(final X509Certificate c) throws InvalidNameException { + String commonName = null; + // getRdns() is ordered least to most specific + for (final Rdn rdn : new LdapName(c.getSubjectX500Principal().getName()).getRdns()) { + if ("CN".equalsIgnoreCase(rdn.getType()) && rdn.getValue() instanceof String) { + commonName = (String) rdn.getValue(); + } + } + return commonName; + } + private String getNamesForCert(final X509Certificate c) { final List<String> names = new ArrayList<>(); @@ -148,12 +162,9 @@ public class HttpsCertVerifier implements CertVerifier { final int ALTNAME_IP = 7; try { - final X500Name subjectName = HostnameChecker.getSubjectX500Name(c); - if (subjectName != null) { - final DerValue derValue = subjectName.findMostSpecificAttribute(X500Name.commonName_oid); - if (derValue != null) { - names.add(derValue.getAsString()); - } + final String commonName = getMostSpecificCommonName(c); + if (commonName != null) { + names.add(commonName); } final Collection<List<?>> subjAltNames = c.getSubjectAlternativeNames(); diff --git a/core/src/main/java/net/sourceforge/jnlp/tools/JarCertVerifier.java b/core/src/main/java/net/sourceforge/jnlp/tools/JarCertVerifier.java index 2ef1eae2e..f004cc576 100644 --- a/core/src/main/java/net/sourceforge/jnlp/tools/JarCertVerifier.java +++ b/core/src/main/java/net/sourceforge/jnlp/tools/JarCertVerifier.java @@ -37,14 +37,9 @@ import net.sourceforge.jnlp.security.CertVerifier; import net.sourceforge.jnlp.security.CertificateUtils; import net.sourceforge.jnlp.security.KeyStores; import net.sourceforge.jnlp.util.JarFile; -import sun.security.util.DerInputStream; -import sun.security.util.DerValue; -import sun.security.x509.NetscapeCertTypeExtension; import java.io.File; -import java.io.IOException; import java.io.InputStream; -import java.lang.reflect.Method; import java.security.CodeSigner; import java.security.InvalidAlgorithmParameterException; import java.security.KeyStore; @@ -74,7 +69,6 @@ import java.util.jar.JarEntry; import java.util.regex.Pattern; import java.util.zip.ZipException; -import static java.lang.Boolean.TRUE; import static java.time.temporal.ChronoUnit.MONTHS; /** @@ -648,35 +642,24 @@ public class JarCertVerifier implements CertVerifier { // shouldn't happen } - try { - // OID_NETSCAPE_CERT_TYPE - final byte[] netscapeEx = userCert.getExtensionValue("2.16.840.1.113730.1.1"); - if (netscapeEx != null) { - final DerInputStream in = new DerInputStream(netscapeEx); - final byte[] raw = in.getOctetString(); - final byte[] encoded = new DerValue(raw).getUnalignedBitString().toByteArray(); - - final NetscapeCertTypeExtension extn = new NetscapeCertTypeExtension(encoded); - - if (!hasObjectSigningExtension(extn)) { - certs.get(certPath).setBadNetscapeCertType(); - } - } - } catch (IOException e) { - // + // OID_NETSCAPE_CERT_TYPE + final byte[] netscapeEx = userCert.getExtensionValue("2.16.840.1.113730.1.1"); + if (netscapeEx != null && !hasObjectSigningBit(netscapeEx)) { + certs.get(certPath).setBadNetscapeCertType(); } } - private static boolean hasObjectSigningExtension(NetscapeCertTypeExtension extn) throws IOException { - // method return type of "NetscapeCertTypeExtension.get()" has changed from Boolean to boolean with Java 21 - try { - final Method getMethod = NetscapeCertTypeExtension.class.getDeclaredMethod("get", String.class); - final Object result = getMethod.invoke(extn, NetscapeCertTypeExtension.OBJECT_SIGNING); - return result == TRUE; - } catch (Exception e) { - LOG.error("Failed to get object_signing from extension", e); - return false; - } + /** + * @param netscapeEx DER value of the Netscape cert type extension: OCTET STRING { BIT STRING } + * @return whether bit 3 (object signing) is set; false if malformed + */ + static boolean hasObjectSigningBit(final byte[] netscapeEx) { + // lengths are always short form here: a few bits at most + return netscapeEx.length >= 6 + && netscapeEx[0] == 0x04 // OCTET STRING + && netscapeEx[2] == 0x03 // BIT STRING + && netscapeEx[3] >= 2 // unused-bits byte + at least one content byte + && (netscapeEx[5] & 0x10) != 0; } /** diff --git a/core/src/test/java/net/adoptopenjdk/icedteaweb/client/parts/dialogs/security/CertsInfoPaneTest.java b/core/src/test/java/net/adoptopenjdk/icedteaweb/client/parts/dialogs/security/CertsInfoPaneTest.java new file mode 100644 index 000000000..57b364444 --- /dev/null +++ b/core/src/test/java/net/adoptopenjdk/icedteaweb/client/parts/dialogs/security/CertsInfoPaneTest.java @@ -0,0 +1,17 @@ +package net.adoptopenjdk.icedteaweb.client.parts.dialogs.security; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +public class CertsInfoPaneTest { + + @Test + public void hexDump() { + assertEquals("", CertsInfoPane.hexDump(new byte[0])); + assertEquals("0000: 0A FF", CertsInfoPane.hexDump(new byte[]{0x0A, (byte) 0xFF})); + final byte[] seventeen = new byte[17]; + seventeen[16] = 0x01; + assertEquals("0000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00\n0010: 01", CertsInfoPane.hexDump(seventeen)); + } +} diff --git a/core/src/test/java/net/adoptopenjdk/icedteaweb/client/parts/dialogs/security/TemporaryPermissionsTest.java b/core/src/test/java/net/adoptopenjdk/icedteaweb/client/parts/dialogs/security/TemporaryPermissionsTest.java index 7ba11736a..fe65b116c 100644 --- a/core/src/test/java/net/adoptopenjdk/icedteaweb/client/parts/dialogs/security/TemporaryPermissionsTest.java +++ b/core/src/test/java/net/adoptopenjdk/icedteaweb/client/parts/dialogs/security/TemporaryPermissionsTest.java @@ -47,11 +47,13 @@ import java.util.HashSet; import java.util.Set; import static org.junit.Assert.assertEquals; -import static sun.security.util.SecurityConstants.FILE_READ_ACTION; -import static sun.security.util.SecurityConstants.FILE_WRITE_ACTION; public class TemporaryPermissionsTest { + // values of sun.security.util.SecurityConstants + private static final String FILE_READ_ACTION = "read"; + private static final String FILE_WRITE_ACTION = "write"; + @Test public void testGetPermission() throws Exception { final Permission expected = new FilePermission(JavaSystemProperties.getJavaTempDir(), FILE_READ_ACTION); diff --git a/core/src/test/java/net/sourceforge/jnlp/security/HttpsCertVerifierTest.java b/core/src/test/java/net/sourceforge/jnlp/security/HttpsCertVerifierTest.java new file mode 100644 index 000000000..e2b2f03c5 --- /dev/null +++ b/core/src/test/java/net/sourceforge/jnlp/security/HttpsCertVerifierTest.java @@ -0,0 +1,23 @@ +package net.sourceforge.jnlp.security; + +import net.adoptopenjdk.icedteaweb.testing.tools.CodeSignerCreator; +import org.junit.Test; + +import java.util.Date; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +public class HttpsCertVerifierTest { + + @Test + public void mostSpecificCommonNameIsLastInDerOrder() throws Exception { + // BC keeps the written order as DER order; the last CN is the most specific + assertEquals("inner", HttpsCertVerifier.getMostSpecificCommonName( + CodeSignerCreator.createCert("C=CZ, O=Org, CN=outer, CN=inner", new Date(), 1))); + assertEquals("example.com", HttpsCertVerifier.getMostSpecificCommonName( + CodeSignerCreator.createCert("CN=example.com, O=Org", new Date(), 1))); + assertNull(HttpsCertVerifier.getMostSpecificCommonName( + CodeSignerCreator.createCert("O=Org", new Date(), 1))); + } +} diff --git a/core/src/test/java/net/sourceforge/jnlp/tools/JarCertVerifierTest.java b/core/src/test/java/net/sourceforge/jnlp/tools/JarCertVerifierTest.java index 0ab30325a..72eb6a1d5 100644 --- a/core/src/test/java/net/sourceforge/jnlp/tools/JarCertVerifierTest.java +++ b/core/src/test/java/net/sourceforge/jnlp/tools/JarCertVerifierTest.java @@ -42,6 +42,8 @@ import java.util.jar.JarEntry; import net.adoptopenjdk.icedteaweb.jnlp.element.resource.JARDesc; import net.adoptopenjdk.icedteaweb.testing.tools.CodeSignerCreator; import net.sourceforge.jnlp.tools.JarCertVerifier.VerifyResult; +import org.bouncycastle.asn1.DEROctetString; +import org.bouncycastle.asn1.misc.NetscapeCertType; import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; @@ -526,4 +528,14 @@ public class JarCertVerifierTest { jcv.getCertsList().contains(alphaSigner.getSignerCertPath())); } + @Test + public void testHasObjectSigningBit() throws Exception { + // extension values as found in certificates: OCTET STRING { BIT STRING }, encoded by BC + final byte[] objectSigning = new DEROctetString(new NetscapeCertType(NetscapeCertType.objectSigning | NetscapeCertType.sslClient)).getEncoded(); + final byte[] sslServerOnly = new DEROctetString(new NetscapeCertType(NetscapeCertType.sslServer)).getEncoded(); + assertTrue(JarCertVerifier.hasObjectSigningBit(objectSigning)); + assertFalse(JarCertVerifier.hasObjectSigningBit(sslServerOnly)); + assertFalse(JarCertVerifier.hasObjectSigningBit(new byte[]{0x04, 0x02, 0x03, 0x01})); + assertFalse(JarCertVerifier.hasObjectSigningBit(new byte[0])); + } } diff --git a/pom.xml b/pom.xml index 3fc450153..25c1dbf01 100644 --- a/pom.xml +++ b/pom.xml @@ -47,7 +47,7 @@ </activation> <properties> <!-- runtime exports as in the launchers, plus internals used by tests only --> - <itw.test.moduleArgs>@${maven.multiModuleProjectDirectory}/launchers/itw-modularjdk.args --add-exports=java.base/sun.security.tools.keytool=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED</itw.test.moduleArgs> + <itw.test.moduleArgs>@${maven.multiModuleProjectDirectory}/launchers/itw-modularjdk.args --add-opens=java.base/java.util=ALL-UNNAMED</itw.test.moduleArgs> </properties> </profile> <profile> diff --git a/test-extensions/pom.xml b/test-extensions/pom.xml index c608dcdb5..8c63bf16f 100644 --- a/test-extensions/pom.xml +++ b/test-extensions/pom.xml @@ -16,6 +16,12 @@ <description>This module contains common classes that are used in unit and integration tests.</description> <dependencies> + <!-- test certificates without JDK-internal CertAndKeyGen --> + <dependency> + <groupId>org.bouncycastle</groupId> + <artifactId>bcpkix-jdk18on</artifactId> + <version>1.86</version> + </dependency> <dependency> <groupId>${project.groupId}</groupId> <artifactId>icedtea-web-common</artifactId> diff --git a/test-extensions/src/main/java/net/adoptopenjdk/icedteaweb/testing/tools/CodeSignerCreator.java b/test-extensions/src/main/java/net/adoptopenjdk/icedteaweb/testing/tools/CodeSignerCreator.java index 85e8f1ee3..d4afead0e 100644 --- a/test-extensions/src/main/java/net/adoptopenjdk/icedteaweb/testing/tools/CodeSignerCreator.java +++ b/test-extensions/src/main/java/net/adoptopenjdk/icedteaweb/testing/tools/CodeSignerCreator.java @@ -25,12 +25,16 @@ package net.adoptopenjdk.icedteaweb.testing.tools; -import sun.security.x509.X500Name; +import org.bouncycastle.asn1.x500.X500Name; +import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; +import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder; +import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; +import java.math.BigInteger; import java.security.CodeSigner; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.SecureRandom; import java.security.Timestamp; import java.security.cert.CertPath; import java.security.cert.CertificateFactory; @@ -42,7 +46,7 @@ import java.util.Date; public class CodeSignerCreator { /** - * Create an X509 Certificate signed using SHA1withRSA with a 2048 bit key. + * Create a self-signed X509 Certificate signed using SHA256withRSA with a 2048 bit key. * * @param dname Domain Name to represent the certificate * @param notBefore The date by which the certificate starts being valid. Cannot be null. @@ -50,12 +54,8 @@ public class CodeSignerCreator { * @return An X509 certificate setup with properties using the specified parameters. * @throws Exception */ - private static X509Certificate createCert(final String dname, final Date notBefore, final int validity) + public static X509Certificate createCert(final String dname, final Date notBefore, final int validity) throws Exception { - final int keysize = 2048; - final String keyAlgName = "RSA"; - final String sigAlgName = "SHA1withRSA"; - if (dname == null) { throw new Exception("Required DN is null. Please specify cert Domain Name via dname"); } @@ -66,9 +66,17 @@ public class CodeSignerCreator { throw new Exception("Required validity is negative. Please specify the number of days for which the cert is valid after the start date."); } - // CertAndKeyGen self-signs with given validity and random serial; no need to patch X509CertInfo (API changed in 21) - final KeyPair keyPair = new KeyPair(keyAlgName, sigAlgName, keysize); - return keyPair.getSelfCertificate(new X500Name(dname), notBefore, validity); + final KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA"); + generator.initialize(2048); + final KeyPair keyPair = generator.generateKeyPair(); + + final X500Name name = new X500Name(dname); + final Date notAfter = new Date(notBefore.getTime() + validity * 24L * 60L * 60L * 1000L); + final BigInteger serial = BigInteger.valueOf(new SecureRandom().nextInt() & 0x7fffffff); + + return new JcaX509CertificateConverter().getCertificate( + new JcaX509v3CertificateBuilder(name, serial, notBefore, notAfter, name, keyPair.getPublic()) + .build(new JcaContentSignerBuilder("SHA256withRSA").build(keyPair.getPrivate()))); } /** @@ -91,43 +99,4 @@ public class CodeSignerCreator { final Timestamp certTimestamp = new Timestamp(jarEntryCert.getNotBefore(), certPath); return new CodeSigner(certPath, certTimestamp); } - - /** - * A wrapper over JDK-internal CertAndKeyGen Class. - * <p> - * Reflection: not exported, keeps compile independent of JDK version. - */ - public static class KeyPair { - - private /* CertAndKeyGen */ Object keyPair; - - public KeyPair(final String keyAlgName, final String sigAlgName, final int keySize) { - try { - // keyPair = new CertAndKeyGen(keyAlgName, sigAlgName); - final Class<?> certAndKeyGenClass = Class.forName("sun.security.tools.keytool.CertAndKeyGen"); - final Constructor<?> constructor = certAndKeyGenClass.getDeclaredConstructor(String.class, String.class); - keyPair = constructor.newInstance(keyAlgName, sigAlgName); - - // keyPair.generate(keySize); - final Method generate = certAndKeyGenClass.getMethod("generate", int.class); - generate.invoke(keyPair, keySize); - } catch (final ClassNotFoundException | NoSuchMethodException | SecurityException | InstantiationException | - IllegalAccessException | IllegalArgumentException | InvocationTargetException certAndKeyGenClassError) { - throw new AssertionError("Unable to use CertAndKeyGen class", certAndKeyGenClassError); - } - } - - public X509Certificate getSelfCertificate(final X500Name name, final Date notBefore, final long validityInDays) { - try { - // return keyPair.getSelfCertificate(name, notBefore, validityInDays * 24L * 60L * 60L); - final Class<?> klass = keyPair.getClass(); - final Method method = klass.getMethod("getSelfCertificate", X500Name.class, Date.class, long.class); - return (X509Certificate) method.invoke(keyPair, name, notBefore, validityInDays * 24L * 60L * 60L); - } catch (final InvocationTargetException ite) { - throw new RuntimeException(ite.getCause()); - } catch (final NoSuchMethodException | IllegalAccessException | IllegalArgumentException error) { - throw new AssertionError(error); - } - } - } } -- 2.55.0 ++++++ 0006-Address-SonarCloud-findings-and-fix-JaCoCo-report-in.patch ++++++ >From d63bea6070464e1b4f35083e70e78cb3a1f45ad2 Mon Sep 17 00:00:00 2001 From: Fridrich Strba <[email protected]> Date: Tue, 6 Oct 2026 14:48:12 +0200 Subject: [PATCH 6/8] Address SonarCloud findings and fix JaCoCo report in integration tests --- .sonarcloud.properties | 2 ++ .../client/policyeditor/PolicyIdentifier.java | 11 +++++------ .../UnsignedAppletTrustConfirmationTest.java | 18 +++++++++++------- .../classloader/JNLPClassLoaderTest.java | 14 +++----------- integration/pom.xml | 3 ++- .../testing/tools/CodeSignerCreator.java | 4 +++- 6 files changed, 26 insertions(+), 26 deletions(-) create mode 100644 .sonarcloud.properties diff --git a/.sonarcloud.properties b/.sonarcloud.properties new file mode 100644 index 000000000..d8cb8d407 --- /dev/null +++ b/.sonarcloud.properties @@ -0,0 +1,2 @@ +# Copied from OpenJDK, kept close to upstream; its internal duplication is not ours to fix +sonar.cpd.exclusions=core/src/main/java/net/adoptopenjdk/icedteaweb/client/policyeditor/PolicyParser.java diff --git a/core/src/main/java/net/adoptopenjdk/icedteaweb/client/policyeditor/PolicyIdentifier.java b/core/src/main/java/net/adoptopenjdk/icedteaweb/client/policyeditor/PolicyIdentifier.java index 2a178e75b..36d324cca 100644 --- a/core/src/main/java/net/adoptopenjdk/icedteaweb/client/policyeditor/PolicyIdentifier.java +++ b/core/src/main/java/net/adoptopenjdk/icedteaweb/client/policyeditor/PolicyIdentifier.java @@ -167,14 +167,13 @@ public class PolicyIdentifier implements Comparable<PolicyIdentifier>, Serializa } private static <T extends Comparable<T>> int compareComparable(T a, T b) { - if (a == null && b != null) { + if (a == b) { + return 0; + } else if (a == null) { return 1; - } else if (a != null && b == null) { + } else if (b == null) { return -1; - } else if (a == b) { - return 0; - } else { - return a.compareTo(b); } + return a.compareTo(b); } } diff --git a/core/src/test/java/net/adoptopenjdk/icedteaweb/client/parts/dialogs/security/appletextendedsecurity/UnsignedAppletTrustConfirmationTest.java b/core/src/test/java/net/adoptopenjdk/icedteaweb/client/parts/dialogs/security/appletextendedsecurity/UnsignedAppletTrustConfirmationTest.java index 55db5e70e..50b240ad9 100644 --- a/core/src/test/java/net/adoptopenjdk/icedteaweb/client/parts/dialogs/security/appletextendedsecurity/UnsignedAppletTrustConfirmationTest.java +++ b/core/src/test/java/net/adoptopenjdk/icedteaweb/client/parts/dialogs/security/appletextendedsecurity/UnsignedAppletTrustConfirmationTest.java @@ -98,15 +98,21 @@ public class UnsignedAppletTrustConfirmationTest { }; @BeforeClass - public static void initUrl() throws MalformedURLException { + public static void setUpClass() throws IOException { + backupAppTrust(); // first, so restoreAppTrust works even if URL setup fails + initUrl(); + initUrlsX123(); + initUrlsY12345678(); + } + + private static void initUrl() throws MalformedURLException { url=new URL(surl1); url4=new URL(url41+url42); } private static File backup; - @BeforeClass - public static void backupAppTrust() throws IOException{ + private static void backupAppTrust() throws IOException{ PathsAndFiles.APPLET_TRUST_SETTINGS_USER.getFile().createNewFile(); backup = File.createTempFile("appletExtendedSecurity", "itwUnittest"); backup.deleteOnExit(); @@ -205,8 +211,7 @@ public class UnsignedAppletTrustConfirmationTest { private static URL urlY7; private static URL urlY8; - @BeforeClass - public static void initUrlsX123() throws MalformedURLException, IOException { + private static void initUrlsX123() throws MalformedURLException, IOException { urlX1 = new URL("http:// does not matter is ok"); try { urlX2 = new URL("http://\ndoes not matter is harmful"); @@ -218,8 +223,7 @@ public class UnsignedAppletTrustConfirmationTest { } } - @BeforeClass - public static void initUrlsY12345678() throws MalformedURLException, IOException { + private static void initUrlsY12345678() throws MalformedURLException, IOException { try { urlY1 = new URL("http://som\\EeUrl.cz/aa"); urlY2 = new URL("http://some\\QUrl.cz/aa"); diff --git a/core/src/test/java/net/sourceforge/jnlp/runtime/classloader/JNLPClassLoaderTest.java b/core/src/test/java/net/sourceforge/jnlp/runtime/classloader/JNLPClassLoaderTest.java index 04b60981f..9c4523be5 100644 --- a/core/src/test/java/net/sourceforge/jnlp/runtime/classloader/JNLPClassLoaderTest.java +++ b/core/src/test/java/net/sourceforge/jnlp/runtime/classloader/JNLPClassLoaderTest.java @@ -98,24 +98,16 @@ public class JNLPClassLoaderTest extends NoStdOutErrTest { private static String askUser; @BeforeClass - public static void setPermissions() { + public static void setPermissionsAndNoDialogs() { level = AppletStartupSecuritySettings.getInstance().getSecurityLevel(); getConfiguration().setProperty(ConfigurationConstants.KEY_SECURITY_LEVEL, AppletSecurityLevel.ALLOW_UNSIGNED.toChars()); - } - - @AfterClass - public static void resetPermissions() { - getConfiguration().setProperty(ConfigurationConstants.KEY_SECURITY_LEVEL, level.toChars()); - } - - @BeforeClass - public static void noDialogs() { askUser = getConfiguration().getProperty(ConfigurationConstants.KEY_SECURITY_PROMPT_USER); getConfiguration().setProperty(ConfigurationConstants.KEY_SECURITY_PROMPT_USER, Boolean.toString(false)); } @AfterClass - public static void restoreDialogs() { + public static void resetPermissionsAndDialogs() { + getConfiguration().setProperty(ConfigurationConstants.KEY_SECURITY_LEVEL, level.toChars()); getConfiguration().setProperty(ConfigurationConstants.KEY_SECURITY_PROMPT_USER, askUser); } diff --git a/integration/pom.xml b/integration/pom.xml index 0851cec3d..5a9d02e60 100644 --- a/integration/pom.xml +++ b/integration/pom.xml @@ -219,7 +219,8 @@ <reuseForks>false</reuseForks> <!-- limiting memory for travis which uses docker to run builds --> <!-- if memory is not limited the forked JVMs use too much memory and are killed by the OS --> - <argLine>@{argLine} ${itw.test.moduleArgs} ${itw.test.smArgs} -Xmx1024m</argLine> + <!-- no @{argLine}: parallel forks corrupt the shared jacoco.exec, and the tested code runs in child JVMs anyway --> + <argLine>${itw.test.moduleArgs} ${itw.test.smArgs} -Xmx1024m</argLine> </configuration> </plugin> diff --git a/test-extensions/src/main/java/net/adoptopenjdk/icedteaweb/testing/tools/CodeSignerCreator.java b/test-extensions/src/main/java/net/adoptopenjdk/icedteaweb/testing/tools/CodeSignerCreator.java index d4afead0e..a930c8ce1 100644 --- a/test-extensions/src/main/java/net/adoptopenjdk/icedteaweb/testing/tools/CodeSignerCreator.java +++ b/test-extensions/src/main/java/net/adoptopenjdk/icedteaweb/testing/tools/CodeSignerCreator.java @@ -45,6 +45,8 @@ import java.util.Date; public class CodeSignerCreator { + private static final SecureRandom RANDOM = new SecureRandom(); + /** * Create a self-signed X509 Certificate signed using SHA256withRSA with a 2048 bit key. * @@ -72,7 +74,7 @@ public class CodeSignerCreator { final X500Name name = new X500Name(dname); final Date notAfter = new Date(notBefore.getTime() + validity * 24L * 60L * 60L * 1000L); - final BigInteger serial = BigInteger.valueOf(new SecureRandom().nextInt() & 0x7fffffff); + final BigInteger serial = BigInteger.valueOf(RANDOM.nextInt() & 0x7fffffff); return new JcaX509CertificateConverter().getCertificate( new JcaX509v3CertificateBuilder(name, serial, notBefore, notAfter, name, keyPair.getPublic()) -- 2.55.0 ++++++ 0007-Stop-opening-JDK-packages-that-no-longer-exist-or-ar.patch ++++++ >From 35b7561aec427b04f6723287bdd8cd3b50228e94 Mon Sep 17 00:00:00 2001 From: Fridrich Strba <[email protected]> Date: Tue, 6 Oct 2026 16:20:18 +0200 Subject: [PATCH 7/8] Stop opening JDK packages that no longer exist or are not used Drop Java 8 era nashorn, rt.jar and jfxrt.jar paths from the launchers --- .../adoptopenjdk/icedteaweb/jvm/JvmUtils.java | 4 --- .../icedteaweb/jvm/JvmUtilsTest.java | 2 +- launchers/itw-modularjdk.args | 5 ---- launchers/rust-launcher/src/jars_helper.rs | 29 ++++--------------- launchers/rust-launcher/src/main.rs | 4 +-- launchers/shell-launcher/launchers.bat.in | 9 ++---- launchers/shell-launcher/launchers.sh.in | 11 ++----- 7 files changed, 14 insertions(+), 50 deletions(-) diff --git a/core/src/main/java/net/adoptopenjdk/icedteaweb/jvm/JvmUtils.java b/core/src/main/java/net/adoptopenjdk/icedteaweb/jvm/JvmUtils.java index d40b400ee..5479042a9 100644 --- a/core/src/main/java/net/adoptopenjdk/icedteaweb/jvm/JvmUtils.java +++ b/core/src/main/java/net/adoptopenjdk/icedteaweb/jvm/JvmUtils.java @@ -399,11 +399,8 @@ public class JvmUtils { put("--add-reads=java.naming", moduleArgs("ALL-UNNAMED", "java.desktop")); put("--add-exports=java.desktop/sun.awt", moduleArgs("ALL-UNNAMED", "java.desktop")); - put("--add-exports=java.desktop/javax.jnlp", moduleArgs("ALL-UNNAMED", "java.desktop")); - put("--add-exports=java.base/com.sun.net.ssl.internal.ssl", moduleArgs("ALL-UNNAMED", "java.desktop")); put("--add-exports=java.base/sun.net.www.protocol.jar", moduleArgs("ALL-UNNAMED", "java.desktop")); - put("--add-exports=java.base/sun.security.action", moduleArgs("ALL-UNNAMED", "java.desktop")); put("--add-exports=java.base/sun.security.provider", moduleArgs("ALL-UNNAMED", "java.desktop")); put("--add-exports=java.base/sun.security.util", moduleArgs("ALL-UNNAMED", "java.desktop")); put("--add-exports=java.base/sun.security.validator", moduleArgs("ALL-UNNAMED", "java.desktop")); @@ -412,7 +409,6 @@ public class JvmUtils { put("--add-exports=java.base/sun.net.www.protocol.http", moduleArgs("ALL-UNNAMED", "java.desktop")); put("--add-exports=java.desktop/sun.awt.X11", moduleArgs("ALL-UNNAMED", "java.desktop")); - put("--add-exports=java.desktop/sun.applet", moduleArgs("ALL-UNNAMED", "java.desktop", "jdk.jsobject")); put("--add-exports=java.naming/com.sun.jndi.toolkit.url", moduleArgs("ALL-UNNAMED", "java.desktop")); }}; } diff --git a/core/src/test/java/net/adoptopenjdk/icedteaweb/jvm/JvmUtilsTest.java b/core/src/test/java/net/adoptopenjdk/icedteaweb/jvm/JvmUtilsTest.java index a19d6f8ba..78302cf7a 100644 --- a/core/src/test/java/net/adoptopenjdk/icedteaweb/jvm/JvmUtilsTest.java +++ b/core/src/test/java/net/adoptopenjdk/icedteaweb/jvm/JvmUtilsTest.java @@ -144,7 +144,7 @@ public class JvmUtilsTest { assertEquals(JvmUtils.getPredefinedJavaModulesVMArgumentsMap().size(), result.size()); assertTrue(result.contains("--add-reads=java.base=ALL-UNNAMED,java.desktop")); - assertTrue(result.contains("--add-exports=java.desktop/sun.applet=ALL-UNNAMED,java.desktop,jdk.jsobject")); + assertTrue(result.contains("--add-exports=java.desktop/sun.awt=ALL-UNNAMED,java.desktop")); } @Test diff --git a/launchers/itw-modularjdk.args b/launchers/itw-modularjdk.args index aad01485c..065b27bce 100644 --- a/launchers/itw-modularjdk.args +++ b/launchers/itw-modularjdk.args @@ -7,11 +7,8 @@ --add-reads=java.naming=ALL-UNNAMED,java.desktop --add-exports=java.desktop/sun.awt=ALL-UNNAMED,java.desktop ---add-exports=java.desktop/javax.jnlp=ALL-UNNAMED,java.desktop ---add-exports=java.base/com.sun.net.ssl.internal.ssl=ALL-UNNAMED,java.desktop --add-exports=java.base/sun.net.www.protocol.jar=ALL-UNNAMED,java.desktop ---add-exports=java.base/sun.security.action=ALL-UNNAMED,java.desktop --add-exports=java.base/sun.security.provider=ALL-UNNAMED,java.desktop --add-exports=java.base/sun.security.util=ALL-UNNAMED,java.desktop --add-exports=java.base/sun.security.validator=ALL-UNNAMED,java.desktop @@ -20,8 +17,6 @@ --add-exports=java.base/sun.net.www.protocol.http=ALL-UNNAMED,java.desktop --add-exports=java.desktop/sun.awt.X11=ALL-UNNAMED,java.desktop ---add-exports=java.desktop/sun.applet=ALL-UNNAMED,java.desktop ---add-exports=java.desktop/sun.applet=ALL-UNNAMED,jdk.jsobject --add-exports=java.naming/com.sun.jndi.toolkit.url=ALL-UNNAMED,java.desktop diff --git a/launchers/rust-launcher/src/jars_helper.rs b/launchers/rust-launcher/src/jars_helper.rs index 1c61b8de1..1fb7c3611 100644 --- a/launchers/rust-launcher/src/jars_helper.rs +++ b/launchers/rust-launcher/src/jars_helper.rs @@ -146,8 +146,7 @@ fn filter_in_key(key: &str, os: &os_access::Os, vec: &mut Vec<std::path::PathBuf filter_in_val(val, vec) } -//TODO what to do with rt.jar, nashorn and javafx.jar with jdk11 and up? -fn get_bootcp_members(jre_path: &std::path::PathBuf, os: &os_access::Os) -> Vec<std::path::PathBuf> { +fn get_bootcp_members(os: &os_access::Os) -> Vec<std::path::PathBuf> { let mut cp_parts = Vec::new(); cp_parts.push(resolve_jar(hardcoded_paths::get_javaws(), os)); append_if_exists(hardcoded_paths::get_rhino(), os, &mut cp_parts); @@ -157,29 +156,13 @@ fn get_bootcp_members(jre_path: &std::path::PathBuf, os: &os_access::Os) -> Vec< append_if_exists(hardcoded_paths::get_commons_compress(), os, &mut cp_parts); append_if_exists(hardcoded_paths::get_commons_io(), os, &mut cp_parts); append_if_exists(hardcoded_paths::get_commons_lang3(), os, &mut cp_parts); - let mut nashorn_jar = jre_path.clone(); - nashorn_jar.push("lib"); - nashorn_jar.push("ext"); - nashorn_jar.push("nashorn.jar"); - cp_parts.push(nashorn_jar); filter_out_key("deployment.launcher.rust.bootcp.remove", os, &mut cp_parts, ); filter_in_key("deployment.launcher.rust.bootcp.add", os, &mut cp_parts); cp_parts } -//can this be buggy? Shouldnt jfxrt.jar be in boot classapth? Copied from shell launchers... -//see eg: http://mail.openjdk.java.net/pipermail/distro-pkg-dev/2018-November/040492.html -fn get_cp_members(jre_path: &std::path::PathBuf, os: &os_access::Os) -> Vec<std::path::PathBuf> { +fn get_cp_members(os: &os_access::Os) -> Vec<std::path::PathBuf> { let mut cp_parts = Vec::new(); - let mut rt_jar = jre_path.clone(); - rt_jar.push("lib"); - rt_jar.push("rt.jar"); - cp_parts.push(rt_jar); - let mut jfxrt_jar = jre_path.clone(); - jfxrt_jar.push("lib"); - jfxrt_jar.push("ext"); - jfxrt_jar.push("jfxrt.jar"); - cp_parts.push(jfxrt_jar); filter_out_key("deployment.launcher.rust.cp.remove", os, &mut cp_parts, ); filter_in_key("deployment.launcher.rust.cp.add", os, &mut cp_parts); cp_parts @@ -196,13 +179,13 @@ fn compose_class_path(members: Vec<std::path::PathBuf>, os: &os_access::Os) -> S result } -pub fn get_classpath(jre_path: &std::path::PathBuf, os: &os_access::Os) -> String { - compose_class_path(get_cp_members(jre_path, os), os) +pub fn get_classpath(os: &os_access::Os) -> String { + compose_class_path(get_cp_members(os), os) } -pub fn get_bootclasspath(jre_path: &std::path::PathBuf, os: &os_access::Os) -> String { +pub fn get_bootclasspath(os: &os_access::Os) -> String { let mut result = String::from("-Xbootclasspath/a:"); - result.push_str(&compose_class_path(get_bootcp_members(jre_path, os), os)); + result.push_str(&compose_class_path(get_bootcp_members(os), os)); result } diff --git a/launchers/rust-launcher/src/main.rs b/launchers/rust-launcher/src/main.rs index 2c56be318..b21f92b34 100644 --- a/launchers/rust-launcher/src/main.rs +++ b/launchers/rust-launcher/src/main.rs @@ -136,8 +136,8 @@ fn main() { } fn compose_arguments(java_dir: &std::path::PathBuf, original_args: &std::vec::Vec<String>, os: &os_access::Os) -> Vec<String> { - let bootcp = jars_helper::get_bootclasspath(&java_dir, os); - let cp = jars_helper::get_classpath(&java_dir, os); + let bootcp = jars_helper::get_bootclasspath(os); + let cp = jars_helper::get_classpath(os); let current_name = dirs_paths_helper::current_program_name(); let current_bin = dirs_paths_helper::current_program(); let mut info2 = String::new(); diff --git a/launchers/shell-launcher/launchers.bat.in b/launchers/shell-launcher/launchers.bat.in index 4d828a938..cc9ed5893 100644 --- a/launchers/shell-launcher/launchers.bat.in +++ b/launchers/shell-launcher/launchers.bat.in @@ -15,7 +15,6 @@ rem maybe set "VAR=value" is working better? rem Warning for if blocks: variables using %my_var% do not work (interpreter), use !my_var! with ENABLEDELAYEDEXPANSION instead rem convention to use for temporary variables use '_' prefix -set "NASHORN=lib/ext/nashorn.jar" set "JRE=@JRE@" set "LAUNCHER_FLAGS=-Xms8m" set "MAIN_CLASS=@MAIN_CLASS@" @@ -128,15 +127,11 @@ if "%ITW_LIBS%" == "BUNDLED" ( set "LAUNCHER_BOOTCLASSPATH=-Xbootclasspath/a:%JAVAWS_JAR%;%RHINO_JAR%;%TAGSOUP_JAR%;%MSLINKS_JAR%;%IPADDRESS_JAR%;%COMMONS_COMPRESS_JAR%;%COMMONS_IO_JAR%;%COMMONS_LANG3_JAR%" -rem Fix classpaths for custom JRE: +rem Select java (custom JRE or default): if not "%CUSTOM_JRE%" == "" ( set "JAVA=%CUSTOM_JRE%/bin/java" - set "CP=%CUSTOM_JRE%/lib/rt.jar;%CUSTOM_JRE%/lib/ext/jfxrt.jar" - set "LAUNCHER_BOOTCLASSPATH=%LAUNCHER_BOOTCLASSPATH%;%CUSTOM_JRE%/%NASHORN%" ) else ( set "JAVA=%JRE%/bin/java" - set "CP=%JRE%/lib/rt.jar;%JRE%/lib/ext/jfxrt.jar" - set "LAUNCHER_BOOTCLASSPATH=%LAUNCHER_BOOTCLASSPATH%;%JRE%/%NASHORN%" ) @@ -232,7 +227,7 @@ if "%SPLASH%" == "true" ( set "SPLASH=" ) -"%JAVA%" %SPLASH% "%LAUNCHER_BOOTCLASSPATH%" %LAUNCHER_FLAGS% %MODULAR_ARGS% %JAVAWS_J_OPTIONS% %JAVA_ARGS% -classpath "%CP%" "-Dicedtea-web.bin.name=%PROGRAM_NAME%" "-Dicedtea-web.bin.location=%BINARY_LOCATION%" %NATIVE_DEBUG% "%MAIN_CLASS%" %ARGS% +"%JAVA%" %SPLASH% "%LAUNCHER_BOOTCLASSPATH%" %LAUNCHER_FLAGS% %MODULAR_ARGS% %JAVAWS_J_OPTIONS% %JAVA_ARGS% -classpath "" "-Dicedtea-web.bin.name=%PROGRAM_NAME%" "-Dicedtea-web.bin.location=%BINARY_LOCATION%" %NATIVE_DEBUG% "%MAIN_CLASS%" %ARGS% SET "errno=%ERRORLEVEL%" diff --git a/launchers/shell-launcher/launchers.sh.in b/launchers/shell-launcher/launchers.sh.in index 617bc86ad..18c27be04 100644 --- a/launchers/shell-launcher/launchers.sh.in +++ b/launchers/shell-launcher/launchers.sh.in @@ -8,7 +8,6 @@ if echo "'$*'" | grep -e "-verbose" ; then set -x fi -NASHORN=lib/ext/nashorn.jar JRE=@JRE@ LAUNCHER_FLAGS=-Xms8m MAIN_CLASS=@MAIN_CLASS@ @@ -131,19 +130,15 @@ fi set -u LAUNCHER_BOOTCLASSPATH="-Xbootclasspath/a:$JAVAWS_JAR:$TAGSOUP_JAR:$RHINO_JAR:$MSLINKS_JAR:$IPADDRESS_JAR:$COMMONS_COMPRESS_JAR:$COMMONS_IO_JAR:$COMMONS_LANG3_JAR" -# Fix classpaths for custom JRE: +# Select java (custom JRE or default): if [ "x$CUSTOM_JRE" != "x" ] ; then if [ -e "$CUSTOM_JRE" -a -e "$CUSTOM_JRE/bin/java" ] ; then JAVA=$CUSTOM_JRE/bin/java - CP=$CUSTOM_JRE/lib/rt.jar:$CUSTOM_JRE/lib/ext/jfxrt.jar - LAUNCHER_BOOTCLASSPATH=$LAUNCHER_BOOTCLASSPATH:$CUSTOM_JRE/$NASHORN else - echo "Your custom JRE $CUSTOM_JRE read from deployment.properties under key $PROPERTY_NAME as $CUSTOM_JRE is not valid. Using default ($JRE, $CP) in attempt to start. Please fix this." + echo "Your custom JRE $CUSTOM_JRE read from deployment.properties under key $PROPERTY_NAME as $CUSTOM_JRE is not valid. Using default ($JRE) in attempt to start. Please fix this." fi else JAVA=$JRE/bin/java - CP=$JRE/lib/rt.jar:$JRE/lib/ext/jfxrt.jar - LAUNCHER_BOOTCLASSPATH="$LAUNCHER_BOOTCLASSPATH:$JRE/$NASHORN" fi; @@ -236,7 +231,7 @@ done COMMAND[k]="-classpath" k=$((k+1)) -COMMAND[k]="${CP}" +COMMAND[k]="" k=$((k+1)) COMMAND[k]="-Dicedtea-web.bin.name=`basename $SCRIPT_SOURCE`" -- 2.55.0 ++++++ 0008-Fix-the-shell-launchers-silently-failing-when-java-c.patch ++++++ >From 921f4106b4549b20af37e7a276a8ae12180923da Mon Sep 17 00:00:00 2001 From: Fridrich Strba <[email protected]> Date: Tue, 6 Oct 2026 16:34:49 +0200 Subject: [PATCH 8/8] Fix the shell launchers silently failing when java comes from openSUSE libalternatives --- launchers/shell-launcher/launchers.sh.in | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/launchers/shell-launcher/launchers.sh.in b/launchers/shell-launcher/launchers.sh.in index 18c27be04..27fc9fc4c 100644 --- a/launchers/shell-launcher/launchers.sh.in +++ b/launchers/shell-launcher/launchers.sh.in @@ -74,11 +74,20 @@ if [ ! "x$JAVA_HOME" = "x" ] ; then echo "Warning! JAVA_HOME of $JAVA_HOME in play!" CUSTOM_JRE=$JAVA_HOME fi +# openSUSE alljava.sh sets JRE_HOME always, JAVA_HOME only with a JDK +if [ "x$CUSTOM_JRE" = "x" -a ! "x$JRE_HOME" = "x" ] ; then + CUSTOM_JRE=$JRE_HOME +fi #check in $path if [ "x$CUSTOM_JRE" = "x" ] ; then while IFS=: read -d: -r path_entry; do if [ -e "${path_entry}/java" ] ; then - CUSTOM_JRE=$(dirname $(dirname $(readlink -f "$path_entry/java"))) + JAVA_BIN=$(readlink -f "$path_entry/java") + # openSUSE libalternatives: java -> alts, ask alts for the real binary + if [ "$(basename "$JAVA_BIN")" == "alts" ] ; then + JAVA_BIN=$(readlink -f "$(alts -t java)") + fi + CUSTOM_JRE=$(dirname $(dirname "$JAVA_BIN")) fi; done <<< "${PATH}" -- 2.55.0 ++++++ 0009-Ignore-an-invalid-JNLP-file-version-instead-of-refus.patch ++++++ >From 4856c946efa0b0eb0f6e26d8faea5c16f2b849e0 Mon Sep 17 00:00:00 2001 From: Fridrich Strba <[email protected]> Date: Wed, 7 Oct 2026 15:34:15 +0200 Subject: [PATCH 9/9] Ignore an invalid JNLP file version instead of refusing to launch --- .../java/net/sourceforge/jnlp/Parser.java | 14 ++++++++++++- .../jnlp/ParserVersionStringTest.java | 20 +++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/net/sourceforge/jnlp/Parser.java b/core/src/main/java/net/sourceforge/jnlp/Parser.java index 32f2133eb..cfaa0dc4c 100644 --- a/core/src/main/java/net/sourceforge/jnlp/Parser.java +++ b/core/src/main/java/net/sourceforge/jnlp/Parser.java @@ -293,7 +293,19 @@ public final class Parser { */ public VersionId getFileVersion() { final String version = getAttribute(root, JNLPFile.VERSION_ATTRIBUTE, null); - return (version == null) ? null : VersionId.fromString(version.trim()); + if (version == null) { + return null; + } + try { + return VersionId.fromString(version.trim()); + } catch (IllegalArgumentException e) { + if (strict) { + throw e; + } + // Oracle javaws took any text here (e.g. USPTO's "v.1.1.0.7.148 1487950053221"); only a cache/lock key + LOG.warn("Ignoring invalid jnlp version attribute: {}", e.getMessage()); + return null; + } } /** diff --git a/core/src/test/java/net/sourceforge/jnlp/ParserVersionStringTest.java b/core/src/test/java/net/sourceforge/jnlp/ParserVersionStringTest.java index e8da514ac..a80623187 100644 --- a/core/src/test/java/net/sourceforge/jnlp/ParserVersionStringTest.java +++ b/core/src/test/java/net/sourceforge/jnlp/ParserVersionStringTest.java @@ -30,7 +30,9 @@ import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; +import java.io.ByteArrayInputStream; import java.io.InputStream; +import java.nio.charset.StandardCharsets; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.hasItemInArray; @@ -67,6 +69,24 @@ public class ParserVersionStringTest extends NoStdOutErrTest { Assert.assertEquals("2.1.1-rc1", parser.getFileVersion().toString()); } + @Test + public void testInvalidJnlpFileVersionIgnoredUnlessStrict() throws ParseException { + final String jnlp = "<jnlp spec=\"1.0+\" version=\"v.1.1.0.7.148 1487950053221\"></jnlp>"; + Assert.assertNull(parserFor(jnlp, new ParserSettings()).getFileVersion()); + try { + parserFor(jnlp, new ParserSettings(true, true, true)).getFileVersion(); + Assert.fail("strict parser must reject the version"); + } catch (IllegalArgumentException expected) { + // ok + } + } + + private static Parser parserFor(final String jnlp, final ParserSettings settings) throws ParseException { + final XmlNode node = XmlParserFactory.getParser(settings.getParserType()) + .getRootNode(new ByteArrayInputStream(jnlp.getBytes(StandardCharsets.UTF_8))); + return new Parser(new DummyJNLPFile(), null, node, settings); + } + @Test public void testExactVersionOfMainJarResource() throws ParseException { final ResourcesDesc resources = parser.getResources(root, false).get(0); -- 2.55.0 ++++++ 0010-Drop-modules-missing-from-this-JVM-from-java-vm-args.patch ++++++ >From a714291866af7003a66ff6996f7d8333056d1b8f Mon Sep 17 00:00:00 2001 From: Fridrich Strba <[email protected]> Date: Wed, 7 Oct 2026 15:52:22 +0200 Subject: [PATCH 10/10] Drop modules missing from this JVM from java-vm-args --add-modules on relaunch --- .../adoptopenjdk/icedteaweb/jvm/JvmUtils.java | 62 +++++++++++++++++++ .../net/sourceforge/jnlp/ItwJvmLauncher.java | 3 +- .../icedteaweb/jvm/JvmUtilsTest.java | 9 +++ 3 files changed, 73 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/net/adoptopenjdk/icedteaweb/jvm/JvmUtils.java b/core/src/main/java/net/adoptopenjdk/icedteaweb/jvm/JvmUtils.java index 5479042a9..85a49885c 100644 --- a/core/src/main/java/net/adoptopenjdk/icedteaweb/jvm/JvmUtils.java +++ b/core/src/main/java/net/adoptopenjdk/icedteaweb/jvm/JvmUtils.java @@ -1,5 +1,7 @@ package net.adoptopenjdk.icedteaweb.jvm; +import net.adoptopenjdk.icedteaweb.logging.Logger; +import net.adoptopenjdk.icedteaweb.logging.LoggerFactory; import net.adoptopenjdk.icedteaweb.xmlparser.ParseException; import net.sourceforge.jnlp.runtime.JNLPRuntime; @@ -11,6 +13,7 @@ import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Set; import static java.lang.Character.isWhitespace; @@ -25,6 +28,8 @@ import static net.adoptopenjdk.icedteaweb.StringUtils.isBlank; import static net.sourceforge.jnlp.config.ConfigurationConstants.KEY_JVM_ARGS_WHITELIST; public class JvmUtils { + + private static final Logger LOG = LoggerFactory.getLogger(JvmUtils.class); private static final Set<String> VALID_VM_ARGUMENTS = unmodifiableSet(new HashSet<>(asList(getValidVMArguments()))); private static final List<String> VALID_STARTING_ARGUMENTS = unmodifiableList(asList(getValidStartingVMArguments())); private static final List<String> VALID_STARTING_JAVA_MODULES_ARGUMENTS = unmodifiableList(asList(getValidStartingJavaModuleVMArguments())); @@ -417,6 +422,63 @@ public class JvmUtils { return new LinkedHashSet<>(asList(args)); } + /** + * Removes modules this JVM lacks from --add-modules: a missing one aborts JVM startup, + * while --add-exports/--add-opens to a missing module only warn. + * E.g. JOSM's JNLP asks for javafx.* which plain OpenJDK does not have. + */ + public static List<String> dropMissingModules(final List<String> vmArgs) { + final List<String> result = new ArrayList<>(); + boolean valueFollows = false; + for (final String arg : vmArgs) { + if (valueFollows) { + valueFollows = false; + final String kept = presentModules(arg); + if (kept.isEmpty()) { + result.remove(result.size() - 1); // the bare --add-modules + } else { + result.add(kept); + } + } else if (arg.equals(ADD_MODULES)) { + valueFollows = true; + result.add(arg); + } else if (arg.startsWith(ADD_MODULES + "=")) { + final String kept = presentModules(arg.substring(ADD_MODULES.length() + 1)); + if (!kept.isEmpty()) { + result.add(ADD_MODULES + "=" + kept); + } + } else { + result.add(arg); + } + } + return result; + } + + private static final String ADD_MODULES = "--add-modules"; + + private static String presentModules(final String commaList) { + final StringBuilder kept = new StringBuilder(); + for (final String module : commaList.split(",")) { + if (module.startsWith("ALL-") || isSystemModule(module)) { + kept.append(kept.length() == 0 ? "" : ",").append(module); + } else { + LOG.warn("Dropping module {} from --add-modules, not present in this JVM", module); + } + } + return kept.toString(); + } + + // reflection: compiled for Java 8, which has no modules (and no --add-modules either) + static boolean isSystemModule(final String name) { + try { + final Class<?> finderClass = Class.forName("java.lang.module.ModuleFinder"); + final Object finder = finderClass.getMethod("ofSystem").invoke(null); + return ((Optional<?>) finderClass.getMethod("find", String.class).invoke(finder, name)).isPresent(); + } catch (ReflectiveOperationException e) { + return true; + } + } + /** * Combines PREDEFINED_JAVA_MODULES_VM_ARGUMENTS with the Java Module VM Args in the input vmargs. * Does not check legality of args, this is done by {@link #checkVMArgs(String)}check diff --git a/core/src/main/java/net/sourceforge/jnlp/ItwJvmLauncher.java b/core/src/main/java/net/sourceforge/jnlp/ItwJvmLauncher.java index 9cdd0b43c..72fc9c994 100644 --- a/core/src/main/java/net/sourceforge/jnlp/ItwJvmLauncher.java +++ b/core/src/main/java/net/sourceforge/jnlp/ItwJvmLauncher.java @@ -16,6 +16,7 @@ // package net.sourceforge.jnlp; +import net.adoptopenjdk.icedteaweb.jvm.JvmUtils; import net.adoptopenjdk.icedteaweb.ProcessUtils; import net.adoptopenjdk.icedteaweb.launch.JvmLauncher; import net.adoptopenjdk.icedteaweb.logging.Logger; @@ -57,7 +58,7 @@ public class ItwJvmLauncher implements JvmLauncher { commands.add(pathToItwBinary); // use -Jargument format to pass arguments to the JVM through the launcher - for (String arg : vmArgs) { + for (String arg : JvmUtils.dropMissingModules(vmArgs)) { commands.add("-J" + arg); } diff --git a/core/src/test/java/net/adoptopenjdk/icedteaweb/jvm/JvmUtilsTest.java b/core/src/test/java/net/adoptopenjdk/icedteaweb/jvm/JvmUtilsTest.java index 78302cf7a..8a928c794 100644 --- a/core/src/test/java/net/adoptopenjdk/icedteaweb/jvm/JvmUtilsTest.java +++ b/core/src/test/java/net/adoptopenjdk/icedteaweb/jvm/JvmUtilsTest.java @@ -17,6 +17,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import static org.junit.Assume.assumeFalse; public class JvmUtilsTest { @@ -276,4 +277,12 @@ public class JvmUtilsTest { public void parsingWrongQuotedArguments() throws ParseException { JvmUtils.parseArguments(" some arguments \"with Quotes\"AndMissingSpace after quote "); } + + @Test + public void testDropMissingModules() { + assumeFalse(JvmUtils.isSystemModule("no.such.mod")); // Java 8: no modules, all count as present + assertEquals(Arrays.asList("--add-modules=java.sql,ALL-SYSTEM", "-Xmx1g", "--add-modules", "java.sql"), + JvmUtils.dropMissingModules(Arrays.asList("--add-modules=java.sql,no.such.mod,ALL-SYSTEM", "-Xmx1g", + "--add-modules", "java.sql,no.such.mod", "--add-modules=no.such.mod", "--add-modules", "no.such.mod"))); + } } -- 2.55.0 ++++++ 0011-Make-the-exception-dialog-test-independent-of-the-cl.patch ++++++ >From cf9d7f330f71c7bf913a451851d21b2fff04e160 Mon Sep 17 00:00:00 2001 From: Fridrich Strba <[email protected]> Date: Wed, 7 Oct 2026 16:31:38 +0200 Subject: [PATCH 11/11] Make the exception dialog test independent of the clock minute --- .../parts/JEditorPaneBasedExceptionDialog.java | 2 +- .../parts/JEditorPaneBasedExceptionDialogTest.java | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/core/src/main/java/net/adoptopenjdk/icedteaweb/client/parts/splashscreen/parts/JEditorPaneBasedExceptionDialog.java b/core/src/main/java/net/adoptopenjdk/icedteaweb/client/parts/splashscreen/parts/JEditorPaneBasedExceptionDialog.java index a1f61e6b6..268fe0c6f 100644 --- a/core/src/main/java/net/adoptopenjdk/icedteaweb/client/parts/splashscreen/parts/JEditorPaneBasedExceptionDialog.java +++ b/core/src/main/java/net/adoptopenjdk/icedteaweb/client/parts/splashscreen/parts/JEditorPaneBasedExceptionDialog.java @@ -89,7 +89,7 @@ public class JEditorPaneBasedExceptionDialog extends JDialog implements Hyperlin // End of components declaration private final String message; private final Throwable exception; - private final Date shown; + final Date shown; private final String anotherInfo; /** Creates new form JEditorPaneBasedExceptionDialog */ diff --git a/core/src/test/java/net/adoptopenjdk/icedteaweb/client/parts/splashscreen/parts/JEditorPaneBasedExceptionDialogTest.java b/core/src/test/java/net/adoptopenjdk/icedteaweb/client/parts/splashscreen/parts/JEditorPaneBasedExceptionDialogTest.java index 5f1d90d66..b21838b8a 100644 --- a/core/src/test/java/net/adoptopenjdk/icedteaweb/client/parts/splashscreen/parts/JEditorPaneBasedExceptionDialogTest.java +++ b/core/src/test/java/net/adoptopenjdk/icedteaweb/client/parts/splashscreen/parts/JEditorPaneBasedExceptionDialogTest.java @@ -126,10 +126,10 @@ public class JEditorPaneBasedExceptionDialogTest { JEditorPaneBasedExceptionDialog d2 = new JEditorPaneBasedExceptionDialog(null, false, ex, ec, null); JEditorPaneBasedExceptionDialog d3 = new JEditorPaneBasedExceptionDialog(null, false, ex, null, ai); JEditorPaneBasedExceptionDialog d4 = new JEditorPaneBasedExceptionDialog(null, false, null, ec, ai); - Assert.assertTrue("message from dialog must be same as pattern", d1.getMessage().equals(s1)); - Assert.assertTrue("message from dialog must be same as pattern", d2.getMessage().equals(s2)); - Assert.assertTrue("message from dialog must be same as pattern", d3.getMessage().equals(s3)); - Assert.assertTrue("message from dialog must be same as pattern", d4.getMessage().equals(s4)); + Assert.assertEquals("message from dialog must be same as pattern", JEditorPaneBasedExceptionDialog.getText(ex, l, ai, d1.shown), d1.getMessage()); + Assert.assertEquals("message from dialog must be same as pattern", JEditorPaneBasedExceptionDialog.getText(ex, l, null, d2.shown), d2.getMessage()); + Assert.assertEquals("message from dialog must be same as pattern", JEditorPaneBasedExceptionDialog.getText(ex, null, ai, d3.shown), d3.getMessage()); + Assert.assertEquals("message from dialog must be same as pattern", JEditorPaneBasedExceptionDialog.getText(null, l, ai, d4.shown), d4.getMessage()); } -- 2.55.0 ++++++ _scmsync.obsinfo ++++++ --- /var/tmp/diff_new_pack.5Bxooq/_old 2026-10-15 12:20:22.390653369 +0200 +++ /var/tmp/diff_new_pack.5Bxooq/_new 2026-10-15 12:20:22.395653578 +0200 @@ -1,6 +1,6 @@ -mtime: 1784546147 -commit: 3a4152574852d7be503142a5e016ca1277d8ea751bf6cbb61abca2662ef22c30 +mtime: 1792006867 +commit: b9e76f178e83fe462231f22325a673de486a77ca063d51d8273bf70ad656fa10 url: https://src.opensuse.org/java-packages/icedtea-web -revision: 3a4152574852d7be503142a5e016ca1277d8ea751bf6cbb61abca2662ef22c30 +revision: b9e76f178e83fe462231f22325a673de486a77ca063d51d8273bf70ad656fa10 projectscmsync: https://src.opensuse.org/java-packages/_ObsPrj ++++++ _service ++++++ --- /var/tmp/diff_new_pack.5Bxooq/_old 2026-10-15 12:20:22.428654958 +0200 +++ /var/tmp/diff_new_pack.5Bxooq/_new 2026-10-15 12:20:22.432655125 +0200 @@ -2,10 +2,11 @@ <service name="tar_scm" mode="disabled"> <param name="scm">git</param> <param name="url">https://github.com/AdoptOpenJDK/IcedTea-Web.git</param> - <param name="revision">icedtea-web-1.8.8</param> + <param name="revision">icedtea-web-2.0.0-alpha36</param> <param name="match-tag">icedtea-web-*</param> <param name="versionformat">@PARENT_TAG@</param> - <param name="versionrewrite-pattern">icedtea-web-(.*)</param> + <param name="versionrewrite-pattern">icedtea-web-(\d+)\.(\d+)\.(\d+)-(.*)</param> + <param name="versionrewrite-replacement">\1.\2.\3~\4</param> <param name="filename">icedtea-web</param> </service> <service name="recompress" mode="disabled"> ++++++ build.specials.obscpio ++++++ ++++++ build.specials.obscpio ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/.gitignore new/.gitignore --- old/.gitignore 1970-01-01 01:00:00.000000000 +0100 +++ new/.gitignore 2026-10-14 21:41:07.000000000 +0200 @@ -0,0 +1 @@ +.osc ++++++ icedtea-web-suse-desktop-files.patch ++++++ --- /var/tmp/diff_new_pack.5Bxooq/_old 2026-10-15 12:20:22.622663073 +0200 +++ /var/tmp/diff_new_pack.5Bxooq/_new 2026-10-15 12:20:22.628663324 +0200 @@ -1,15 +1,19 @@ ---- icedtea-web-1.8.8/itweb-settings.desktop.in 2025-06-19 09:02:33.535860174 +0200 -+++ icedtea-web-1.8.8/itweb-settings.desktop.in 2025-06-19 09:03:04.077944330 +0200 -@@ -12,5 +12,5 @@ +diff --git a/launchers/xdesktop.in/itweb-settings.desktop.in b/launchers/xdesktop.in/itweb-settings.desktop.in +index 31d519181..feebcfee1 100644 +--- a/launchers/xdesktop.in/itweb-settings.desktop.in ++++ b/launchers/xdesktop.in/itweb-settings.desktop.in +@@ -12,5 +12,5 @@ Exec=PATH_TO_ITWEB_SETTINGS Icon=javaws Terminal=false Type=Application -Categories=Settings; +Categories=Settings;DesktopSettings;X-GNOME-DesktopSettings;X-GNOME-Sundry; Keywords=IcedTea;IcedTea-Web;java;javaws;web;start;webstart;jnlp; ---- icedtea-web-1.8.8/policyeditor.desktop.in 2025-06-19 09:02:33.558286892 +0200 -+++ icedtea-web-1.8.8/policyeditor.desktop.in 2025-06-19 09:03:04.078136016 +0200 -@@ -6,5 +6,5 @@ +diff --git a/launchers/xdesktop.in/policyeditor.desktop.in b/launchers/xdesktop.in/policyeditor.desktop.in +index 0155da6f6..38e554f0b 100644 +--- a/launchers/xdesktop.in/policyeditor.desktop.in ++++ b/launchers/xdesktop.in/policyeditor.desktop.in +@@ -6,5 +6,5 @@ Exec=PATH_TO_POLICYEDITOR Icon=javaws Terminal=false Type=Application ++++++ icedtea-web.conf ++++++ # Sourced by the icedtea-web launchers (java-functions); appends JVM flags. # ITW jars go on the boot class path: JNLPPolicy trusts only code there or its own jar. ADDITIONAL_FLAGS="-Xbootclasspath/a:$(build-classpath icedtea-web rhino tagsoup IPAddress commons-compress commons-io commons-lang3) -Dicedtea-web.bin.name=${0##*/} -Dicedtea-web.bin.location=$0 ${ADDITIONAL_FLAGS}" set_javacmd _itw_v=$("$JAVACMD" -version 2>&1 | sed -n '1s/.*version "\(1\.\)\{0,1\}\([0-9]*\).*/\2/p') # --add-exports etc. are rejected by Java 8 [ "${_itw_v:-0}" -ge 9 ] && ADDITIONAL_FLAGS="$ADDITIONAL_FLAGS @/usr/share/icedtea-web/itw-modularjdk.args" # SecurityManager: opt-in needed on 18-23; 24+ refuses the flag [ "${_itw_v:-0}" -ge 18 ] && [ "$_itw_v" -le 23 ] && ADDITIONAL_FLAGS="$ADDITIONAL_FLAGS -Djava.security.manager=allow" unset _itw_v # splash as in the upstream launchers: off with ICEDTEA_WEB_SPLASH set, -headless or -Xnosplash if [ -z "$ICEDTEA_WEB_SPLASH" ] && [[ ! " $* " =~ \ -+(headless|Xnosplash) ]] ; then ADDITIONAL_FLAGS="$ADDITIONAL_FLAGS -splash:/usr/share/icedtea-web/javaws_splash.png" fi # -J<flag> goes to the JVM: ITW relaunches itself this way for JNLP java-vm-args _itw_args=() for _itw_a in "$@" ; do case "$_itw_a" in -J*) ADDITIONAL_FLAGS="$ADDITIONAL_FLAGS ${_itw_a#-J}" ;; *) _itw_args+=("$_itw_a") ;; esac done set -- "${_itw_args[@]}" unset _itw_a _itw_args ++++++ reproducible-timestamps.patch ++++++ --- /var/tmp/diff_new_pack.5Bxooq/_old 2026-10-15 12:20:22.696666168 +0200 +++ /var/tmp/diff_new_pack.5Bxooq/_new 2026-10-15 12:20:22.699666294 +0200 @@ -1,35 +1,68 @@ ---- icedtea-web-1.8.8/netx/net/sourceforge/jnlp/util/docprovider/formatters/formatters/HtmlFormatter.java 2025-06-19 10:58:20.778943754 +0200 -+++ icedtea-web-1.8.8/netx/net/sourceforge/jnlp/util/docprovider/formatters/formatters/HtmlFormatter.java 2025-06-19 10:58:35.151598324 +0200 -@@ -95,6 +95,10 @@ - if (includeXmlHeader) { - xml = "<?xml version=\"1.0\" encoding=\"" + encoding + "\"?>\n"; - } -+ Date now = new Date(); -+ if (System.getenv("SOURCE_DATE_EPOCH") != null) { -+ now = new Date(1000 * Long.parseLong(System.getenv("SOURCE_DATE_EPOCH"))); -+ } - return xml + "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n" - + "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\">\n" - + " <head>\n" -@@ -102,7 +106,7 @@ +diff --git a/artifact-all-dependencies/pom.xml b/artifact-all-dependencies/pom.xml +index 73236c6e5..ae0a65d74 100644 +--- a/artifact-all-dependencies/pom.xml ++++ b/artifact-all-dependencies/pom.xml +@@ -82,7 +82,7 @@ + <mainClass>net.adoptopenjdk.icedteaweb.client.commandline.CommandLine</mainClass> + <manifestEntries> + <Scm-Commit>${buildNumber}</Scm-Commit> +- <Build-Time>${maven.build.timestamp}</Build-Time> ++ <Build-Time>${project.build.outputTimestamp}</Build-Time> + </manifestEntries> + </transformer> + </transformers> +diff --git a/artifact-no-dependencies/pom.xml b/artifact-no-dependencies/pom.xml +index 50a1db3d5..74a701b94 100644 +--- a/artifact-no-dependencies/pom.xml ++++ b/artifact-no-dependencies/pom.xml +@@ -52,7 +52,7 @@ + <mainClass>net.adoptopenjdk.icedteaweb.client.commandline.CommandLine</mainClass> + <manifestEntries> + <Scm-Commit>${buildNumber}</Scm-Commit> +- <Build-Time>${maven.build.timestamp}</Build-Time> ++ <Build-Time>${project.build.outputTimestamp}</Build-Time> + </manifestEntries> + </transformer> + </transformers> +diff --git a/core/src/main/java/net/sourceforge/jnlp/util/docprovider/formatters/formatters/HtmlFormatter.java b/core/src/main/java/net/sourceforge/jnlp/util/docprovider/formatters/formatters/HtmlFormatter.java +index c98f335ee..83cb41a24 100644 +--- a/core/src/main/java/net/sourceforge/jnlp/util/docprovider/formatters/formatters/HtmlFormatter.java ++++ b/core/src/main/java/net/sourceforge/jnlp/util/docprovider/formatters/formatters/HtmlFormatter.java +@@ -36,7 +36,6 @@ package net.sourceforge.jnlp.util.docprovider.formatters.formatters; + import net.sourceforge.jnlp.runtime.JNLPRuntime; + + import java.nio.charset.Charset; +-import java.util.Date; + import java.util.Map; + import java.util.Set; + import java.util.TreeMap; +@@ -99,7 +98,7 @@ public class HtmlFormatter extends ReplacingTextFormatter { + " <meta http-equiv=\"content-type\" content=\"application/xhtml+xml; charset=" + encoding + "\" />\n" + " </head>\n" + " <body>\n" - + " <H5 align=\"right\">" + id + ": " + getVersion() + ", " + JNLPRuntime.getLocalisedTimeStamp(new Date()) + "</H5>"; -+ + " <H5 align=\"right\">" + id + ": " + getVersion() + ", " + JNLPRuntime.getLocalisedTimeStamp(now) + "</H5>"; ++ + " <H5 align=\"right\">" + id + ": " + getVersion() + ", " + JNLPRuntime.getLocalisedTimeStamp(ManFormatter.buildDate()) + "</H5>"; } @Override ---- icedtea-web-1.8.8/netx/net/sourceforge/jnlp/util/docprovider/formatters/formatters/ManFormatter.java 2025-06-19 10:58:20.778977773 +0200 -+++ icedtea-web-1.8.8/netx/net/sourceforge/jnlp/util/docprovider/formatters/formatters/ManFormatter.java 2025-06-19 10:58:35.152120367 +0200 -@@ -118,6 +118,9 @@ +diff --git a/core/src/main/java/net/sourceforge/jnlp/util/docprovider/formatters/formatters/ManFormatter.java b/core/src/main/java/net/sourceforge/jnlp/util/docprovider/formatters/formatters/ManFormatter.java +index f0de85ea6..6ad06e594 100644 +--- a/core/src/main/java/net/sourceforge/jnlp/util/docprovider/formatters/formatters/ManFormatter.java ++++ b/core/src/main/java/net/sourceforge/jnlp/util/docprovider/formatters/formatters/ManFormatter.java +@@ -108,8 +108,14 @@ public class ManFormatter extends ReplacingTextFormatter { + return ""; + } - private String getManPageDate(boolean localize) { - Date now = new Date(); -+ if (System.getenv("SOURCE_DATE_EPOCH") != null) { -+ now = new Date(1000 * Long.parseLong(System.getenv("SOURCE_DATE_EPOCH"))); -+ } - Calendar c = Calendar.getInstance(); ++ /** SOURCE_DATE_EPOCH if set, for reproducible docs */ ++ static Date buildDate() { ++ final String epoch = System.getenv("SOURCE_DATE_EPOCH"); ++ return epoch == null ? new Date() : new Date(1000L * Long.parseLong(epoch.trim())); ++ } ++ + private String getManPageDate() { +- final Date now = new Date(); ++ final Date now = buildDate(); + final Calendar c = Calendar.getInstance(); c.setTime(now); - int day = c.get(Calendar.DAY_OF_MONTH); + final int day = c.get(Calendar.DAY_OF_MONTH);
