From 37e5c75cc6454f90be96f3b3a021c52fce43c8a3 Mon Sep 17 00:00:00 2001 From: Vitor Mattos Date: Tue, 26 Mar 2024 10:22:48 -0300 Subject: [PATCH 01/50] feat: Sign setup Make possible sign downloaded files to be possible delete compated files after install. Signed-off-by: Vitor Mattos --- appinfo/info.xml | 1 + appinfo/install-signature.json | 282 ++++++++++++++++++++++++++++ lib/Command/Developer/SignSetup.php | 96 ++++++++++ lib/Service/Install/SignFiles.php | 203 ++++++++++++++++++++ 4 files changed, 582 insertions(+) create mode 100644 appinfo/install-signature.json create mode 100644 lib/Command/Developer/SignSetup.php create mode 100644 lib/Service/Install/SignFiles.php diff --git a/appinfo/info.xml b/appinfo/info.xml index 99e697f238..552625f8f5 100644 --- a/appinfo/info.xml +++ b/appinfo/info.xml @@ -52,6 +52,7 @@ Developed with ❤️ by [LibreCode](https://librecode.coop). Help us transform OCA\Libresign\Command\Configure\Cfssl OCA\Libresign\Command\Configure\OpenSsl OCA\Libresign\Command\Developer\Reset + OCA\Libresign\Command\Developer\SignSetup OCA\Libresign\Command\Install OCA\Libresign\Command\Uninstall diff --git a/appinfo/install-signature.json b/appinfo/install-signature.json new file mode 100644 index 0000000000..10d4b56a59 --- /dev/null +++ b/appinfo/install-signature.json @@ -0,0 +1,282 @@ +{ + "hashes": { + "checksums_java_21.0.2_13.txt": "7110bab6ee73702be77ee966b3a1ec13812d012fa981e68e189d0f126a10acee7a86ecadd584dcf091c6f0f76ca4a97d5a331e7307b1e49da7f70165cb8923b5", + "java\/OpenJDK21U-jre_x64_linux_hotspot_21.0.2_13.tar.gz": "3dc4f78e235aed4be20b5f20bdcdef48bbc1ca18fff08d109e055945503ae32c86cdfb3bdb95196bc3ab55b336011e6f55503c55b940b1e4362cadb978d6c02a", + "java\/jdk-21.0.2+13-jre\/NOTICE": "e0c38f15ba79febedf49941bb772b99e12d8da3748e60891f3bd02ff157691b545f9a5c910197ab08b61a93c62616d98206391b2200fa4294047f35c883ac08f", + "java\/jdk-21.0.2+13-jre\/bin\/java": "02c868f7a62fba5e56ad29e5f99e4d4e8cabdeea9be72fcf7025b838d108311ccd2df08404d43b1983042e7a80d31f69d7550d507e1539ff873072be4e56bca5", + "java\/jdk-21.0.2+13-jre\/bin\/jfr": "546a00d8bbea4640f615f87ef702ac752e84e0c26d507f2b47ef68e39c46fffd82876c40e9ee9cba98495d947c189fb1e85ea21f9aac4463a02330d7f777d69c", + "java\/jdk-21.0.2+13-jre\/bin\/jrunscript": "830e426ad5b6cc3ed046d160f653e31a93497ca500c64922596e3ad1678a96912b788b9f074f9b5d4e501d32710e9b05bc5e8450148433a375016f2526595bf1", + "java\/jdk-21.0.2+13-jre\/bin\/jwebserver": "a02726a89255c301c4035cc91f2511089b56a9034244d69e5610068e5c2cb243b1bd1ec933f4f7ddda49903eabbf9f5d776e2f12c3b66a494c4399f30a4d0c3d", + "java\/jdk-21.0.2+13-jre\/bin\/keytool": "76a6ce792c3ac07163ab80e3bcc73eb01e457a47cc4fe25321c2115ce72dd634ae108a0b44133fd6de1b2934ac9d4537cd3496b91d1937cf6c8748b59ba4e1c2", + "java\/jdk-21.0.2+13-jre\/bin\/rmiregistry": "64263c3eb1e0f75adb5d3f12b56bff4e5aebcb44d674f23564bd0c796dd591c4bf5fc2b58f6c829f197fcd346abd684f8caed6b30962aa3095651c52935bfedc", + "java\/jdk-21.0.2+13-jre\/conf\/jaxp.properties": "37163a66138973c586c4d59394a1b7f2ed82c9c76a82ed0354fc3a0c96f52abb5d7f8bb3141a747953a4984b62b7efe8f2a3c40b7339ebd81d4a59413403a3a0", + "java\/jdk-21.0.2+13-jre\/conf\/logging.properties": "e869f4a3b821a9933796dc9a56ee00483493369dfbfe07b3b1d895cb8318c6821cd44134eb37513f15b830c25861b596646824ed56672d08b678fefe6a4c7504", + "java\/jdk-21.0.2+13-jre\/conf\/management\/jmxremote.access": "64d33add796d2d3df7ad37aa452ee1d106174be1ade3063d73ba416211629a9a9b05177969404fdc92fcee8458450c9de4a6195744b93131303208cb6f1416ad", + "java\/jdk-21.0.2+13-jre\/conf\/management\/jmxremote.password.template": "e6794168ba80a8ff733d8c1771930ae8c8fc33030e5e9ca02700f326c88a2f68ff09bc734bfd1e492ef15705b288c7918ce1f3f7174742dee6a62dfe086abd65", + "java\/jdk-21.0.2+13-jre\/conf\/management\/management.properties": "4fae4e2b5f7122cd80c03b3d04fca5c4b9586be6c712dfdb729f5e85d6e71a86addfdb975be4ee7e250e28643222687f834a6456054e38331bd978aba79dae71", + "java\/jdk-21.0.2+13-jre\/conf\/net.properties": "397d39f852fe94e6b384f3924e7676c252ab7ceaab2b0ebb8bc4e6244f487830c786ba327ac4ec6dadbcb31be78ebeff0d3c0fde2b02b0f1963e924fe399afba", + "java\/jdk-21.0.2+13-jre\/conf\/sdp\/sdp.conf.template": "645e30897684300d163086eea1477e5262b1fe05adc0053b26cd07898f3de6c147285acfd0fac9007022692d93b347ac321fa054ab7464b07c32f86b8c2419b1", + "java\/jdk-21.0.2+13-jre\/conf\/security\/java.policy": "d2b6ea94bc3becc531926239a77c9995c543bf48232484fa0036c4e09e42ab7ee5facc10e0eed64556950980ffc9c8e56c556f34e74985c09f2384216ca461ab", + "java\/jdk-21.0.2+13-jre\/conf\/security\/java.security": "695cd8a173dac2d92bbe723082f4940b9ba920f8be7220f4abb06ee84c3fd664ed6ba5e9ad93cdffd804c78dac68dfb3a999da17f4dae9499b74304de565476b", + "java\/jdk-21.0.2+13-jre\/conf\/security\/policy\/README.txt": "68a031264cf9442526307364ca74b336af55564c233c2f514cac48e910022767562f8ff6a64bb9cfcbf0fb5e755289273382c9246418a4b9207fc7761d03c64e", + "java\/jdk-21.0.2+13-jre\/conf\/security\/policy\/limited\/default_US_export.policy": "4cfca5b10cd7addcff887c8f3621d2fbec1b5632436326377b0ce5af1ae3e8b68ac5a743ca6082fc79991b8eec703a6e1dfd5b896153407ad72327753222fdb3", + "java\/jdk-21.0.2+13-jre\/conf\/security\/policy\/limited\/default_local.policy": "a0b98cbbb49184df973bb2c4a506e9bc6e025a696bc0c8054a6352cc3f9b4a38e3baf117c6834ddaddc38498556607ed4eda8f1bc683f662d61da50e0db0c8c2", + "java\/jdk-21.0.2+13-jre\/conf\/security\/policy\/limited\/exempt_local.policy": "2bd70518aed6b0e01c520c446830c5f567fa72974548818cac3e1e5c2be6f03db78ce6012f5463b1e19c36243d04cbaad38ec79524635eaae2e427eb1875ccdb", + "java\/jdk-21.0.2+13-jre\/conf\/security\/policy\/unlimited\/default_US_export.policy": "4cfca5b10cd7addcff887c8f3621d2fbec1b5632436326377b0ce5af1ae3e8b68ac5a743ca6082fc79991b8eec703a6e1dfd5b896153407ad72327753222fdb3", + "java\/jdk-21.0.2+13-jre\/conf\/security\/policy\/unlimited\/default_local.policy": "2b0385417a3fc2af58b1cbb186dd3e0b0875e42923884153deee0efcb390ca00b326ed5b266b3892d31bf7d40e10969a0b51daa6d0b4ca3183770786925d3cde", + "java\/jdk-21.0.2+13-jre\/conf\/sound.properties": "99fdd75b8ce71622f85f957ae52b85e6646763f7864b670e993df0c2c77363ef9cfce2727badee03503cda41abe6eb8a278142766bf66f00b4eb39d0d4fc4a87", + "java\/jdk-21.0.2+13-jre\/legal\/java.base\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", + "java\/jdk-21.0.2+13-jre\/legal\/java.base\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", + "java\/jdk-21.0.2+13-jre\/legal\/java.base\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", + "java\/jdk-21.0.2+13-jre\/legal\/java.base\/aes.md": "4d14b5ddbb4d09797264ed29ba71fab6986b4a9e75efb9402c1476e0a9e2884813d6a922dea125643b4f74e1f3e458f4e48d6c840e0f4d16ed72ffbc4611dbb2", + "java\/jdk-21.0.2+13-jre\/legal\/java.base\/asm.md": "2fcf1da50a53858e5e68db51996b59ebeb8f07b698f72b67a827d4fd302f757c5c0d0479b37128d239268b635b20177a27557c1dba920fa9f12f1bec2b7f6d40", + "java\/jdk-21.0.2+13-jre\/legal\/java.base\/c-libutl.md": "ae459d8ce5581ea57e203088373c1ce86d122d0e27eb871ee1383e0e64cd8a184fa207eee0e835347316e70afa24a1c95aec30def3e09d15ee19a0b2c3ad2095", + "java\/jdk-21.0.2+13-jre\/legal\/java.base\/cldr.md": "8ab32a80deb12dd1f3a54a38b3335a76feb44e20fcf5ee897d47511e0acedbbedf51a241768441c56259a54c7303ddf7b57be7693c5cddb30f90741ca3257190", + "java\/jdk-21.0.2+13-jre\/legal\/java.base\/icu.md": "0b31bcbdb578ac448dd145c0160c83e24ff4f1b48cada692d213e026155f5a44fc0e7b01444c5af0649e49ffd100421a890a6ed0c60722b15c4a4938a0c99b67", + "java\/jdk-21.0.2+13-jre\/legal\/java.base\/public_suffix.md": "cbd16c4c29a51669f51ff9817ed33e29b871df215fb252a946c3b4e80fc83d4f0e4e1b32d46c2998924092e4b14585666f748b598708773dc6d2432701d6f627", + "java\/jdk-21.0.2+13-jre\/legal\/java.base\/unicode.md": "06f8cd7233ab0e6d2db403765aa543f153b611fa6d1cdc571fa98dc8ff9a908c14034e31305b14c6f80ee8de5bb5e6e49dcd18c030d5b5772dc93153ea16fc19", + "java\/jdk-21.0.2+13-jre\/legal\/java.base\/zlib.md": "c516403a109630b79998f3bea6b698247a0b5367cc9873defa75014e8c98c690d34d0810d32792d80fde1333980ac6c5f19324743795cb6455ef0ee4979496bb", + "java\/jdk-21.0.2+13-jre\/legal\/java.compiler\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", + "java\/jdk-21.0.2+13-jre\/legal\/java.compiler\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", + "java\/jdk-21.0.2+13-jre\/legal\/java.compiler\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", + "java\/jdk-21.0.2+13-jre\/legal\/java.datatransfer\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", + "java\/jdk-21.0.2+13-jre\/legal\/java.datatransfer\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", + "java\/jdk-21.0.2+13-jre\/legal\/java.datatransfer\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", + "java\/jdk-21.0.2+13-jre\/legal\/java.desktop\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", + "java\/jdk-21.0.2+13-jre\/legal\/java.desktop\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", + "java\/jdk-21.0.2+13-jre\/legal\/java.desktop\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", + "java\/jdk-21.0.2+13-jre\/legal\/java.desktop\/colorimaging.md": "f5872960470810cdbdc2db1dfb216cab88203b23400b16e157c8654c2eecff8d9b26ce066ec18718c8e6d54ee1c54533fdade395c454210fed5159fd4a7a0adb", + "java\/jdk-21.0.2+13-jre\/legal\/java.desktop\/freetype.md": "67a686550414a6b878869b7280708d8a428cfbf803e1462929e65e6c6e1a265562149a2e23ac82488ae96f1e856d2f23470b5335021865fc499fbee520f0c079", + "java\/jdk-21.0.2+13-jre\/legal\/java.desktop\/giflib.md": "dafac31d75a7ab4ddd7666799a24abf22c1583ca22554a738cc26a77bf927b20dde52f12194670a5196bce3a43bd58de46944291727c8877fee1fe4a38a1f1ca", + "java\/jdk-21.0.2+13-jre\/legal\/java.desktop\/harfbuzz.md": "8fc9822bb15a0008055882976510258287cedc81de390cc01fe0869fc8a2c2d876241470c5bffb96cb5d4460544e893ac8077d6dcc8ec523e02050807b946adf", + "java\/jdk-21.0.2+13-jre\/legal\/java.desktop\/jpeg.md": "7e82da825499b1b4c5ddb09d17bdda584f52739b504786f8126df2fe914d97111189fb7829ebb5285d11cf2a18977f377e0d89a16c82d5e574a5b5b83aca1b3a", + "java\/jdk-21.0.2+13-jre\/legal\/java.desktop\/lcms.md": "a91faa243a09bdfe62714859b9b4420e8434dd09693a6a280e1c8ef6694fb7858d0171fae4ca36721b685e3ab8bc8000c5635bf3789250a5b9081130eb4ff57c", + "java\/jdk-21.0.2+13-jre\/legal\/java.desktop\/libpng.md": "6a35e221deb422ef690354d04183bd51ebda349c0ceb768d16f935cdfaac78cbc7fa5afc022b1b933abf52ea46d95b2cccf4976aaa0bf010647d96ec1d31b397", + "java\/jdk-21.0.2+13-jre\/legal\/java.desktop\/mesa3d.md": "9c4111728ab9472f0b160cb11ce1e4ebd75a83cfddca0b3cb87243d15afc5a7fa34dc6006e6b92084648cbad1426f70b405259f589cdef758442643e1618dff4", + "java\/jdk-21.0.2+13-jre\/legal\/java.desktop\/pipewire.md": "7eb9d8dfa8a2c8f234f5a545e890906b6f0ddb5088f0a5631a2f7515d5dbaa7a6e2563fd789db3de43be2503d97245cae5192f0f9a9992d71c8ce7f8fa32e34f", + "java\/jdk-21.0.2+13-jre\/legal\/java.desktop\/xwd.md": "42fc3783e35ca37525611767b7cfd5ae541ddace22af7102f36c1550d39f994c94e6c0b241153a2b9bae228f3944f7ad3400d6f9db384d104c452f6a07054aed", + "java\/jdk-21.0.2+13-jre\/legal\/java.instrument\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", + "java\/jdk-21.0.2+13-jre\/legal\/java.instrument\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", + "java\/jdk-21.0.2+13-jre\/legal\/java.instrument\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", + "java\/jdk-21.0.2+13-jre\/legal\/java.logging\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", + "java\/jdk-21.0.2+13-jre\/legal\/java.logging\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", + "java\/jdk-21.0.2+13-jre\/legal\/java.logging\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", + "java\/jdk-21.0.2+13-jre\/legal\/java.management.rmi\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", + "java\/jdk-21.0.2+13-jre\/legal\/java.management.rmi\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", + "java\/jdk-21.0.2+13-jre\/legal\/java.management.rmi\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", + "java\/jdk-21.0.2+13-jre\/legal\/java.management\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", + "java\/jdk-21.0.2+13-jre\/legal\/java.management\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", + "java\/jdk-21.0.2+13-jre\/legal\/java.management\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", + "java\/jdk-21.0.2+13-jre\/legal\/java.naming\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", + "java\/jdk-21.0.2+13-jre\/legal\/java.naming\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", + "java\/jdk-21.0.2+13-jre\/legal\/java.naming\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", + "java\/jdk-21.0.2+13-jre\/legal\/java.net.http\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", + "java\/jdk-21.0.2+13-jre\/legal\/java.net.http\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", + "java\/jdk-21.0.2+13-jre\/legal\/java.net.http\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", + "java\/jdk-21.0.2+13-jre\/legal\/java.prefs\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", + "java\/jdk-21.0.2+13-jre\/legal\/java.prefs\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", + "java\/jdk-21.0.2+13-jre\/legal\/java.prefs\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", + "java\/jdk-21.0.2+13-jre\/legal\/java.rmi\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", + "java\/jdk-21.0.2+13-jre\/legal\/java.rmi\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", + "java\/jdk-21.0.2+13-jre\/legal\/java.rmi\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", + "java\/jdk-21.0.2+13-jre\/legal\/java.scripting\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", + "java\/jdk-21.0.2+13-jre\/legal\/java.scripting\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", + "java\/jdk-21.0.2+13-jre\/legal\/java.scripting\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", + "java\/jdk-21.0.2+13-jre\/legal\/java.se\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", + "java\/jdk-21.0.2+13-jre\/legal\/java.se\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", + "java\/jdk-21.0.2+13-jre\/legal\/java.se\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", + "java\/jdk-21.0.2+13-jre\/legal\/java.security.jgss\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", + "java\/jdk-21.0.2+13-jre\/legal\/java.security.jgss\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", + "java\/jdk-21.0.2+13-jre\/legal\/java.security.jgss\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", + "java\/jdk-21.0.2+13-jre\/legal\/java.security.sasl\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", + "java\/jdk-21.0.2+13-jre\/legal\/java.security.sasl\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", + "java\/jdk-21.0.2+13-jre\/legal\/java.security.sasl\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", + "java\/jdk-21.0.2+13-jre\/legal\/java.smartcardio\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", + "java\/jdk-21.0.2+13-jre\/legal\/java.smartcardio\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", + "java\/jdk-21.0.2+13-jre\/legal\/java.smartcardio\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", + "java\/jdk-21.0.2+13-jre\/legal\/java.smartcardio\/pcsclite.md": "19eb5494e32e1276d87153f06dbcfe513a3df5355ca7a7c576fdaf200aeb5698a92b4e113ca3191b22c742e66226cbdba9d1ae8c2a0d1bfa0f7206baf9bb5fc9", + "java\/jdk-21.0.2+13-jre\/legal\/java.sql.rowset\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", + "java\/jdk-21.0.2+13-jre\/legal\/java.sql.rowset\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", + "java\/jdk-21.0.2+13-jre\/legal\/java.sql.rowset\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", + "java\/jdk-21.0.2+13-jre\/legal\/java.sql\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", + "java\/jdk-21.0.2+13-jre\/legal\/java.sql\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", + "java\/jdk-21.0.2+13-jre\/legal\/java.sql\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", + "java\/jdk-21.0.2+13-jre\/legal\/java.transaction.xa\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", + "java\/jdk-21.0.2+13-jre\/legal\/java.transaction.xa\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", + "java\/jdk-21.0.2+13-jre\/legal\/java.transaction.xa\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", + "java\/jdk-21.0.2+13-jre\/legal\/java.xml.crypto\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", + "java\/jdk-21.0.2+13-jre\/legal\/java.xml.crypto\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", + "java\/jdk-21.0.2+13-jre\/legal\/java.xml.crypto\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", + "java\/jdk-21.0.2+13-jre\/legal\/java.xml.crypto\/santuario.md": "108bafd2f15cf3b46df2495c164fda196b2e72194e03368d18442abd8924bf920f2e1343329d54f83e77dedfd9143769543e2459a36b5610f85103cfe7fd5296", + "java\/jdk-21.0.2+13-jre\/legal\/java.xml\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", + "java\/jdk-21.0.2+13-jre\/legal\/java.xml\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", + "java\/jdk-21.0.2+13-jre\/legal\/java.xml\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", + "java\/jdk-21.0.2+13-jre\/legal\/java.xml\/bcel.md": "25f2189643a113616f53cd87fc96df01b55602bfc3f6653e48c310de03f6d79ccbbec58936d54b88052e32d68c646017bf75b8a179f59fb9d2c5f6938e351a4d", + "java\/jdk-21.0.2+13-jre\/legal\/java.xml\/dom.md": "8c71f226f0f07b471aea6b8e715434b5eaa6b4a59a653ec22c2489e743e9288a0c4537f479719f9d58737d0257470c9cceff9ce647a96e79fd757a4cdcfed499", + "java\/jdk-21.0.2+13-jre\/legal\/java.xml\/jcup.md": "7ed3e58f189f2922f7543d4617308d0c35f8adc2e7cbbb6fbba49d33cdd5da64c6edc022ae9842c28e58d97b056a245245c816003978f1e0152236636ca72ba5", + "java\/jdk-21.0.2+13-jre\/legal\/java.xml\/xalan.md": "db99644e83bf0d0f7573e520f5381b038810afd7de1a881d7d752273ec2584d9aca3eb1f3ae47f0402ec6a49116cb581019cbb9c82278f99c37bb7b01b09457e", + "java\/jdk-21.0.2+13-jre\/legal\/java.xml\/xerces.md": "26972bb1fe75ff78ed4afef538e389556ccca2d04af0c50bc6fd0d3dbfa2be6610d259b307cefe29dafb613fa3d324e7734e83873b16a61c90bf6e2514d92566", + "java\/jdk-21.0.2+13-jre\/legal\/jdk.accessibility\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", + "java\/jdk-21.0.2+13-jre\/legal\/jdk.accessibility\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", + "java\/jdk-21.0.2+13-jre\/legal\/jdk.accessibility\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", + "java\/jdk-21.0.2+13-jre\/legal\/jdk.charsets\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", + "java\/jdk-21.0.2+13-jre\/legal\/jdk.charsets\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", + "java\/jdk-21.0.2+13-jre\/legal\/jdk.charsets\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", + "java\/jdk-21.0.2+13-jre\/legal\/jdk.crypto.cryptoki\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", + "java\/jdk-21.0.2+13-jre\/legal\/jdk.crypto.cryptoki\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", + "java\/jdk-21.0.2+13-jre\/legal\/jdk.crypto.cryptoki\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", + "java\/jdk-21.0.2+13-jre\/legal\/jdk.crypto.cryptoki\/pkcs11cryptotoken.md": "2676cfdfd61762c7b6171985e8cfe1068c36683ca43753a1ffb10241ac61a74c9be1c00be22903df85ba6954fd908d77de60903c316506fd88b9679672ada968", + "java\/jdk-21.0.2+13-jre\/legal\/jdk.crypto.cryptoki\/pkcs11wrapper.md": "759c75f87309b67c56a5b7088045e04be7c023ecdbaea80842e22b81b0bfb36026191070471f8b08fef47ec73664611ce0453b4a9818f7708c95663733ee5ce9", + "java\/jdk-21.0.2+13-jre\/legal\/jdk.crypto.ec\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", + "java\/jdk-21.0.2+13-jre\/legal\/jdk.crypto.ec\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", + "java\/jdk-21.0.2+13-jre\/legal\/jdk.crypto.ec\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", + "java\/jdk-21.0.2+13-jre\/legal\/jdk.dynalink\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", + "java\/jdk-21.0.2+13-jre\/legal\/jdk.dynalink\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", + "java\/jdk-21.0.2+13-jre\/legal\/jdk.dynalink\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", + "java\/jdk-21.0.2+13-jre\/legal\/jdk.dynalink\/dynalink.md": "86ee77d8e129b78173964461cd27200aeab7fb6417fe0f4982d9b126ed2292216d08212be91b53eccb26dd6a8b3e1aab1d1dbab85c2133872ac0027dc87a8223", + "java\/jdk-21.0.2+13-jre\/legal\/jdk.httpserver\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", + "java\/jdk-21.0.2+13-jre\/legal\/jdk.httpserver\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", + "java\/jdk-21.0.2+13-jre\/legal\/jdk.httpserver\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", + "java\/jdk-21.0.2+13-jre\/legal\/jdk.incubator.vector\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", + "java\/jdk-21.0.2+13-jre\/legal\/jdk.incubator.vector\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", + "java\/jdk-21.0.2+13-jre\/legal\/jdk.incubator.vector\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", + "java\/jdk-21.0.2+13-jre\/legal\/jdk.internal.vm.ci\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", + "java\/jdk-21.0.2+13-jre\/legal\/jdk.internal.vm.ci\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", + "java\/jdk-21.0.2+13-jre\/legal\/jdk.internal.vm.ci\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", + "java\/jdk-21.0.2+13-jre\/legal\/jdk.internal.vm.compiler.management\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", + "java\/jdk-21.0.2+13-jre\/legal\/jdk.internal.vm.compiler.management\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", + "java\/jdk-21.0.2+13-jre\/legal\/jdk.internal.vm.compiler.management\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", + "java\/jdk-21.0.2+13-jre\/legal\/jdk.internal.vm.compiler\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", + "java\/jdk-21.0.2+13-jre\/legal\/jdk.internal.vm.compiler\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", + "java\/jdk-21.0.2+13-jre\/legal\/jdk.internal.vm.compiler\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", + "java\/jdk-21.0.2+13-jre\/legal\/jdk.jdwp.agent\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", + "java\/jdk-21.0.2+13-jre\/legal\/jdk.jdwp.agent\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", + "java\/jdk-21.0.2+13-jre\/legal\/jdk.jdwp.agent\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", + "java\/jdk-21.0.2+13-jre\/legal\/jdk.jfr\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", + "java\/jdk-21.0.2+13-jre\/legal\/jdk.jfr\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", + "java\/jdk-21.0.2+13-jre\/legal\/jdk.jfr\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", + "java\/jdk-21.0.2+13-jre\/legal\/jdk.jsobject\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", + "java\/jdk-21.0.2+13-jre\/legal\/jdk.jsobject\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", + "java\/jdk-21.0.2+13-jre\/legal\/jdk.jsobject\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", + "java\/jdk-21.0.2+13-jre\/legal\/jdk.localedata\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", + "java\/jdk-21.0.2+13-jre\/legal\/jdk.localedata\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", + "java\/jdk-21.0.2+13-jre\/legal\/jdk.localedata\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", + "java\/jdk-21.0.2+13-jre\/legal\/jdk.localedata\/cldr.md": "8ab32a80deb12dd1f3a54a38b3335a76feb44e20fcf5ee897d47511e0acedbbedf51a241768441c56259a54c7303ddf7b57be7693c5cddb30f90741ca3257190", + "java\/jdk-21.0.2+13-jre\/legal\/jdk.localedata\/thaidict.md": "5221112cd8ef83b636dc4364f53b72c5484a5885acb55c2c071c88d23058093caee38578f7e424ecafdb483ccc0bc8e78d7ac13add536ec824a8eac171a576cb", + "java\/jdk-21.0.2+13-jre\/legal\/jdk.management.agent\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", + "java\/jdk-21.0.2+13-jre\/legal\/jdk.management.agent\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", + "java\/jdk-21.0.2+13-jre\/legal\/jdk.management.agent\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", + "java\/jdk-21.0.2+13-jre\/legal\/jdk.management.jfr\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", + "java\/jdk-21.0.2+13-jre\/legal\/jdk.management.jfr\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", + "java\/jdk-21.0.2+13-jre\/legal\/jdk.management.jfr\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", + "java\/jdk-21.0.2+13-jre\/legal\/jdk.management\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", + "java\/jdk-21.0.2+13-jre\/legal\/jdk.management\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", + "java\/jdk-21.0.2+13-jre\/legal\/jdk.management\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", + "java\/jdk-21.0.2+13-jre\/legal\/jdk.naming.dns\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", + "java\/jdk-21.0.2+13-jre\/legal\/jdk.naming.dns\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", + "java\/jdk-21.0.2+13-jre\/legal\/jdk.naming.dns\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", + "java\/jdk-21.0.2+13-jre\/legal\/jdk.naming.rmi\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", + "java\/jdk-21.0.2+13-jre\/legal\/jdk.naming.rmi\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", + "java\/jdk-21.0.2+13-jre\/legal\/jdk.naming.rmi\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", + "java\/jdk-21.0.2+13-jre\/legal\/jdk.net\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", + "java\/jdk-21.0.2+13-jre\/legal\/jdk.net\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", + "java\/jdk-21.0.2+13-jre\/legal\/jdk.net\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", + "java\/jdk-21.0.2+13-jre\/legal\/jdk.nio.mapmode\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", + "java\/jdk-21.0.2+13-jre\/legal\/jdk.nio.mapmode\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", + "java\/jdk-21.0.2+13-jre\/legal\/jdk.nio.mapmode\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", + "java\/jdk-21.0.2+13-jre\/legal\/jdk.sctp\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", + "java\/jdk-21.0.2+13-jre\/legal\/jdk.sctp\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", + "java\/jdk-21.0.2+13-jre\/legal\/jdk.sctp\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", + "java\/jdk-21.0.2+13-jre\/legal\/jdk.security.auth\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", + "java\/jdk-21.0.2+13-jre\/legal\/jdk.security.auth\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", + "java\/jdk-21.0.2+13-jre\/legal\/jdk.security.auth\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", + "java\/jdk-21.0.2+13-jre\/legal\/jdk.security.jgss\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", + "java\/jdk-21.0.2+13-jre\/legal\/jdk.security.jgss\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", + "java\/jdk-21.0.2+13-jre\/legal\/jdk.security.jgss\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", + "java\/jdk-21.0.2+13-jre\/legal\/jdk.unsupported\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", + "java\/jdk-21.0.2+13-jre\/legal\/jdk.unsupported\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", + "java\/jdk-21.0.2+13-jre\/legal\/jdk.unsupported\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", + "java\/jdk-21.0.2+13-jre\/legal\/jdk.xml.dom\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", + "java\/jdk-21.0.2+13-jre\/legal\/jdk.xml.dom\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", + "java\/jdk-21.0.2+13-jre\/legal\/jdk.xml.dom\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", + "java\/jdk-21.0.2+13-jre\/legal\/jdk.zipfs\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", + "java\/jdk-21.0.2+13-jre\/legal\/jdk.zipfs\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", + "java\/jdk-21.0.2+13-jre\/legal\/jdk.zipfs\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", + "java\/jdk-21.0.2+13-jre\/lib\/classlist": "fa075d07032562204684a85ef801757efb30f2e51dece3f985dbec029181ed4cd508522fb3d57c13455d8d49dfcc32e576ee657048e7e2d134d8acbacf82edc3", + "java\/jdk-21.0.2+13-jre\/lib\/jexec": "9d598da3edba0218c1a9920bc218f869028afc509b128daaeb1711bbc6ab10062b0dde05d9d8bcc1581a9f9b3f50ecf304ef8945562c6a06dde58e6e7807ff21", + "java\/jdk-21.0.2+13-jre\/lib\/jfr\/default.jfc": "f34c0543e2654cd7cf5180d3c0c8a9b77616049493c1e344ab974e76baeff37244f075fafef854ade49ab4d9ba0bbc07a83e4733fc6ef31afadf3d359fd820e6", + "java\/jdk-21.0.2+13-jre\/lib\/jfr\/profile.jfc": "b8abe37dab4ec4b9adacf3b5aab4dbc4ff706e70d1cc45471d6829b8b08651c3f1c6c267462f208e1b8bb0a7054cfe018927d3309b44870551d8282d4ea1895f", + "java\/jdk-21.0.2+13-jre\/lib\/jrt-fs.jar": "25641ecb09cfb703f72dd99dab58fde80b8c0636386eae57a08c7bf2db5e3d35f84fe583acb145c1aad99770354098d729adbf11cfbd7a753df0f30c16dbb77a", + "java\/jdk-21.0.2+13-jre\/lib\/jspawnhelper": "0719bbe098509538c6a0f4b26b40e484e7c810b5fe38dc83666dbee139a3bbcb4ff23a03b7b33b8a0347fede5d72080d56c65909b06777b5631ed5bcb9aa3b7f", + "java\/jdk-21.0.2+13-jre\/lib\/jvm.cfg": "8b37a1a5600e0a4e5832021c4db50569e33f1ddc8ac4fc2f38d5439272b955b0e3028ea10dec0743b197aa0def32d9e185066d2bac451f81b99539d34006074b", + "java\/jdk-21.0.2+13-jre\/lib\/libawt.so": "ae37c93ac242bd2dbfc7fb3d3e9f4991b9668819b42de8a4a0fec03bc9189d2138bf573d5100385dfa306907c25991090f1ce6c0b326e40600a2aade1912c208", + "java\/jdk-21.0.2+13-jre\/lib\/libawt_headless.so": "a02c26ddad2c6d23fa73d9b508e4332d07e8853d471179ea658ef9d6fb8fc5f503d5feeb8839a14b4bfaa73c211b8ed2b9c4642a33b34784f213dc0531d7d113", + "java\/jdk-21.0.2+13-jre\/lib\/libawt_xawt.so": "c0f68c55a0fb44fdd31545a0ead22fa069ce4cc0963dbfea5db786e57f1ab331a12cc3a093e81944b95d825d36c47bc6e8370e3fb138813dd530304387d0763a", + "java\/jdk-21.0.2+13-jre\/lib\/libdt_socket.so": "2c88b58210dd5a2a95233ebd284421ef1c739a9e567194f2db2b218eee16be7933829a5646bdbacfb0ec79c82bfbef35d72f0275dce51b07b1dd9fafcb96622c", + "java\/jdk-21.0.2+13-jre\/lib\/libextnet.so": "c191aa130e3cc4a13c425524d3216bf7b844ffa5c1c3ec6259f57bd23a13f9166be8a780af6ada14e054d495caae5c8eb0259c16c3d593f723853f1d8495973c", + "java\/jdk-21.0.2+13-jre\/lib\/libfontmanager.so": "eec80dfc544e7bfa02a51672d7d3b4ddd8e7cef2349d195d6fc8e13ea11ccc4f74fd0cc69a7ddb4f7eccaf3517b0e3b4e53425da772b81dc7d1e91d60ad80063", + "java\/jdk-21.0.2+13-jre\/lib\/libfreetype.so": "5c81ce6ca56d3fe46088720747fdaeb0adcb3643a9f7d31d5aaa54c8e1d80de3285e839381f1ddaefb36fe7c4e29a78bf0091480d566b8fbd873bfccbc7ae306", + "java\/jdk-21.0.2+13-jre\/lib\/libinstrument.so": "fec9990e02d5b541f602ac0584e02af7dea1e76fe0fc6ce5fa54567826f4c078189a63a1fd2094e5b28a2c6ccf9a2e3a4f5b5e0d9b436e30be286a85c60cecb0", + "java\/jdk-21.0.2+13-jre\/lib\/libj2gss.so": "e174e096da4ed44f5d75eaf4dbf408699362518dbf60d18473736b5750245c03206ae21697541bc96601c708cb72799e5bd4c4d2568d5b8f13838cb6d287c281", + "java\/jdk-21.0.2+13-jre\/lib\/libj2pcsc.so": "a5ff7d35a4cb2865a227ae1ad95eef110adf8bd9c6ba705800a5f26dbb50f1091c53b2349d4502a52a1b83c3ccee1c841f5d91d27886a67cdd8950b13ecb4f4d", + "java\/jdk-21.0.2+13-jre\/lib\/libj2pkcs11.so": "82b3cb4450899cf556bdcc9c9e0b7f929b6cd928c51d86b5fd1a78c53934b1a874702ff179f37e91ceef662fd98102c120ba79b86565cfe6a4ee379f05760938", + "java\/jdk-21.0.2+13-jre\/lib\/libjaas.so": "2996d617a4394a3c94fe189fb320e110dac119ce28b1f7ab94d1c6a7e33e6ad14fcaddd3d27d7da8b9cc43a4bd2407e2cd3d7e4a13cace1e403b95b81bbe0b0b", + "java\/jdk-21.0.2+13-jre\/lib\/libjava.so": "1bb9dafb9501570b562e7e7f3372c38240a68a0ecc1c290982f5a575c36408be563ad9b648f7860a0693e7b5b1dddc537890d3862de4e1abff550e72ad83c6fb", + "java\/jdk-21.0.2+13-jre\/lib\/libjavajpeg.so": "d7914c3e57ebf44b69f426eaad86bdea925b913045e778d22653837c70e816a7e8eed339d4ea5426c9fbd47279e5594965b7abef88f08f5499ca930cba9448ca", + "java\/jdk-21.0.2+13-jre\/lib\/libjawt.so": "7929c31ce9e1a215017fe36145bb9ee80c995d2e53e5f1d7dd36b251efee327e91df97368f136bdc0bc8833014e7b8bdb5d064371c5a93dc2516e9d102af782f", + "java\/jdk-21.0.2+13-jre\/lib\/libjdwp.so": "46e79d5181f96ed0b5a45395ca804832f492e351a2cd4e79dad6285a1b79e631c934690d0c68c47a339f57900daead29c39445eacfd231f0c74d1f6415a5f483", + "java\/jdk-21.0.2+13-jre\/lib\/libjimage.so": "66e33a7398a057937a904e372576f6486ce4274639e79363d9bfd54474a39645af879ad8b8b5b848f917efb16196e876caf28f540db1dfa18f5b513a1ba029cb", + "java\/jdk-21.0.2+13-jre\/lib\/libjli.so": "1687e9ba3ca18664f92bdc84e342414d96abf3a1029e47d73b11d7af237499545961ff00d0cef824feaea91bcf2c4dfa67bb982bd1c3b82aefc5a4d87f8ed2f9", + "java\/jdk-21.0.2+13-jre\/lib\/libjsig.so": "659cd0b0ed9426d26224373f85d0addd80349e2a76ad69df725dbaf3b613c11dd24260744051fcbf89116a1cae193d80708d70a4a468071ecf5b5ca80a76274f", + "java\/jdk-21.0.2+13-jre\/lib\/libjsound.so": "65f4708e89382f949292ea658da67f8cc794e35b4637a5781eefcd09ff30de6b7495d9d90cb26ac1f4589fbf0f1897f9fe9e611448cf3dd912f604e225e0538c", + "java\/jdk-21.0.2+13-jre\/lib\/libjsvml.so": "ad0c7a0f7191e6dea75c87f309da66905207b35de71914444f0ab8b34136a699f43798c8c9c5c430ff6a9194027557d0bd5e68d2cb90ef5df4df9bb27255cffb", + "java\/jdk-21.0.2+13-jre\/lib\/liblcms.so": "092fbc7cf3bc5c8b762b0960966e1e46160240e5757af9e1980822f6d717ab20ded782bbb8e9c3424d2164471cc8b6fb32612b798aae2c7b9842aa0d6c933903", + "java\/jdk-21.0.2+13-jre\/lib\/libmanagement.so": "2b02ac889aabd460f638f735349b9ecdf95a3df4471a35ded7313405e59c91973f67567a165fe915059b575a72880d6be28eed20ad08e20814a385a87c3d4d43", + "java\/jdk-21.0.2+13-jre\/lib\/libmanagement_agent.so": "6b98e9e505ee98bcf6901c39c27b53fbc1f60121d2d194edc7893c5b17186761fc3d66de5543f047746d88fed55f4ce8e3fa7f7ae1881f1f9f895825e9374a95", + "java\/jdk-21.0.2+13-jre\/lib\/libmanagement_ext.so": "55fc6bddefc826a8cd3f66624625900cfa5de7c7ea0e14f7106ba509d935a26904193ba7d0be4149b17dcb87c8729a235175137cb7f0847c07a4c3e5c9cea824", + "java\/jdk-21.0.2+13-jre\/lib\/libmlib_image.so": "f4617bec60984379f6cbe81eb1d4be9fdc4277fddd8c1d381c9cf3121ddec27a9d50bca1e70c9146cc6f314f3e38d42fd7835b79a919abb4484a49f6d27938f9", + "java\/jdk-21.0.2+13-jre\/lib\/libnet.so": "fe0023af3c3b183c13b091fb8608ce09e47d6fb209d5cd0334d6811ede4f41806e2077a43578d26a82acbdf2459dd7ef8596ebb0950b7e94542a6146d2163149", + "java\/jdk-21.0.2+13-jre\/lib\/libnio.so": "26539ed73e685977c4cc4b97da4edd346501019f8180daeafd894f835778777f67eeb52fde45f9d303436359678b0a04b07dfd7402c0f664a0f6fa6c5095823a", + "java\/jdk-21.0.2+13-jre\/lib\/libprefs.so": "4d31f33b5e905a0d2655dd1bb572ec0788181c9a4cf6f28482acaaa89f0959786b8c603a1a4b2e343b4d97d108f2a2041294798b07e209a242e11392f14387e9", + "java\/jdk-21.0.2+13-jre\/lib\/librmi.so": "11f106bbf97d7b8dafc10da95acfa8878131fd557c8c438efa6ca77defca7ba7e821c28d3b77089593a130ca5eeb99babb0cba5b2fa7d34825ba015dcae18930", + "java\/jdk-21.0.2+13-jre\/lib\/libsctp.so": "27ed970b13bcb535fb423e37d7826af640c7be833b730de00c9d759972b41650616c7f9c9251295c2a072a78c3456a3aa92e818f0d0b1402053313262aece324", + "java\/jdk-21.0.2+13-jre\/lib\/libsplashscreen.so": "a999eb715e9beeefa6e6844a93c595a9374e2194ebcbf384626c5cb002c36bc4f4eced091bf5db520f7f9ff225471ff08b8e2aed1cc2a2b8357a2f7fecf4d0e5", + "java\/jdk-21.0.2+13-jre\/lib\/libsyslookup.so": "7cee79233d7f997bb804c72766ed54def3e0e74769f8938858e65bfba584984d8b24ef15b5e6f6eb4ff87ed0d63682a0b4e444d03491c45e1351538597ed795d", + "java\/jdk-21.0.2+13-jre\/lib\/libverify.so": "22372ab221cb4b26b439abdd704d9828501ef2876e08152c46279bc9203e23ca93ec05dfe07c3eec24ae2ca4a4b22e1258b55af823aa3d7fe90159d6ecfeae1f", + "java\/jdk-21.0.2+13-jre\/lib\/libzip.so": "4f9502ec0d51b43dd2d37aea06df0fe86bf2fcc76f41b5dabb1ed78da286aebe5ec198c7bcf03e220cd1923d2d010408c01a8a95bcc64633bb9af69146a987cc", + "java\/jdk-21.0.2+13-jre\/lib\/modules": "f3bd47f9feaecdcb4797d332b7b3886722dced66790ca7bedd54f073113844499457e9ff66ba6f3c5c88e2bc604ad67a1a2aab5e937c183be7fd26c278d06ff7", + "java\/jdk-21.0.2+13-jre\/lib\/psfont.properties.ja": "8124b25decfa64a65433ff2ce1f0f7bdf304abe2997568abc35264a705f07152aa993b543da37c4132b4b1b606743c825c90a0eb17b268518d478f5cf0889062", + "java\/jdk-21.0.2+13-jre\/lib\/psfontj2d.properties": "e4ee92d4598385cb2f6f3a4db91ddabd7e615dc105ed26cdc5b5598d01c526cea7726ff93f92a308350229f2e5a5dd64cc0c38865dd97666368a330b410d4892", + "java\/jdk-21.0.2+13-jre\/lib\/security\/blocked.certs": "c6d8d4ee0eb7eeb14532512ff4310dff9dd4f31d112716fc67a1052d37eef18d4bd6eb58301c76167ad35d31e73f5b28993f4da8c5de2dbe3836a5ef7e9c8b7e", + "java\/jdk-21.0.2+13-jre\/lib\/security\/cacerts": "a01185b26d6921ba639790904a7a7f37bcc39f931d4c959d489580fc4e0d38ae33033c1afe5fb926e27c526225b634cf2817e73e539875f91491fb04e01c0465", + "java\/jdk-21.0.2+13-jre\/lib\/security\/default.policy": "ba7ca64aee530cc36aa7bb556c44f976cc636750d31d8d8fa3d8c3d0070dfa83cb85f56be9ddc0e8418852b3a70c2716343f832973a753d4debe30042f4bc1ed", + "java\/jdk-21.0.2+13-jre\/lib\/security\/public_suffix_list.dat": "6caaa3c2a53782fd286ab8db4a6a2470cd0150608c33b27aa506735d37185d26eedd27ef95fe0ade83d8301fdb8ac1c4b972a87b3714c303181f5cd67bc64815", + "java\/jdk-21.0.2+13-jre\/lib\/server\/classes.jsa": "23df528e05459e6cd96cd3e2977e750e64693b5e75cc766eee6f262e7e8abb8635b166ef3b7f57f0a8b2a352a12ce8c9d59092d1abecd4457e4f16c1e2f60e36", + "java\/jdk-21.0.2+13-jre\/lib\/server\/classes_nocoops.jsa": "9c6a4f9dea7d78cf399b64012196bced503001047f232d151e68eebf9765718f497d3a11f39cf6f58f2b8e4dd33d8ee621b7e1e9de13b269251a06807b973a9f", + "java\/jdk-21.0.2+13-jre\/lib\/server\/libjsig.so": "659cd0b0ed9426d26224373f85d0addd80349e2a76ad69df725dbaf3b613c11dd24260744051fcbf89116a1cae193d80708d70a4a468071ecf5b5ca80a76274f", + "java\/jdk-21.0.2+13-jre\/lib\/server\/libjvm.so": "8df080e567f3a2017395f6e542fdccd57515dbfcd5047bf8696855408670b2f0faa2ffc3b0651ca5306d507a77d737092fd450a87f0e9afbdb8c8e06b585fc59", + "java\/jdk-21.0.2+13-jre\/lib\/tzdb.dat": "958f835407e4a10a268bf76bc2ef0196ecd5fa92e139de4c3760544dbdf76f95e67865bac22406aef8ac5ae7508fe63cd1a688c8328e46b73a5867efa4f18d47", + "java\/jdk-21.0.2+13-jre\/release": "9424659912a18e1e6368d62240542b4e821672ec4c3fa557665b1fbf3060d763c9de4edf525e80cea1ae2fb259821b98b3854f65f1beab080beeb0802ad43f98", + "jsignpdf-2.2.2.zip": "dac3fc83ea6ffede68f53e9db33161075db7b9b4028b5216522501b5cdf5f9815adb966c1af7a80d42ba09edad6efbf71d4b7ec4236cd5d7236d3868178022a5", + "jsignpdf-2.2.2\/InstallCert.jar": "748afcd66d2cb10d996ee83df4b7354f3cde9d73e8f5388b89107bd82a046cebd7982f38745c61b8dd1a5ca2099eb0e290281ea699dd6f2ebd32bc13a2794569", + "jsignpdf-2.2.2\/JSignPdf.jar": "dbc0bb7af34cc1c034cae7f5c0e05702260a26684a56ab6254025fe7a0afbf01e68f8664d73bab4b71b97142373143d1159068181ae6e137740485c38c475572", + "jsignpdf-2.2.2\/conf\/conf.properties": "9867ca50e21f620a85aeb77b1eeada52998ff5bed05c98e34365d78d38b5df9716e1e1cb0c316f26fbbac799faad7e73c6ccb8e8ecb3422f085da5b33b89862d", + "jsignpdf-2.2.2\/conf\/pkcs11.cfg": "7755a14ea0a9486948d25799134bdaa34a2bc9807b7470dbfd88fadd7eb1a3cb2d40dba830320ed864598b70f5fa4c7f426a3d992f9ce80298471b5346a890ca", + "jsignpdf-2.2.2\/docs\/JSignPdf.pdf": "fcf4cc584f7aaf039cf458bad5cf8165de586bb124088945ad0f293efca7c2803457e40ced4e20ed050d3fb98625f038e65533a8d3adb84d73a8a42f07b1a592", + "jsignpdf-2.2.2\/jsignpdf.sh": "6f7e547d846b8f74abff2f6a85fe30ce6be98779565f2eed1714ad2363ccf4bd6bb999a4de08d201e55d2c6ab21475b9afba259716e99c3cb673fe175c59c4e5", + "jsignpdf-2.2.2\/licenses\/MPL-2.0.txt": "7479c0cc9df5359cfffcb421e108dfbb4a5493589bbb3ff998f4c0c0499be3d974e608939f07c9644ae3936f008d299f0da80d4b181367284299f4ac3841eb73", + "jsignpdf-2.2.2\/licenses\/ThirdPartyLicenses\/DejaVu-font.license": "eb1b3f39d42d7a9a00c31ed6e97608b693fd9e519d5775ad83dd10f5af1172aa450eda6a1ec301e7dc348cfeb4c279067388ad88e76fbf2073fb100b648209e0", + "jsignpdf-2.2.2\/licenses\/ThirdPartyLicenses\/InstallCert.license": "ded0e324601bf2826998bfaf5c0aeb854cdb2fcad3b5046e901612372dafcf45e41b59a0c43d341d98edeec4ef7a078797f91abba104d3193d996677f2307a00", + "jsignpdf-2.2.2\/licenses\/ThirdPartyLicenses\/PdfRenderer.license": "c929152d51e8db633124dc8ec3272b8f76172c4820a587ebba0fcdb0c2ffa5eb90bc795696a2a8a863521b347822856b0e44d576649a3e85af21c17f28a7e437", + "jsignpdf-2.2.2\/licenses\/ThirdPartyLicenses\/apache-commons.license": "d43a0e998d3e817e71501086f4d6a46f1f18b46791c491932887ee15efd51426c606f92620766ba2688276406be970b32dbd18b4a54483a8466e05a6cd81d1c1", + "jsignpdf-2.2.2\/licenses\/ThirdPartyLicenses\/bouncycastle.license": "806473fdb2d8ea53e4f812a50ecd450bdb187e2fbd469e75ccd71142830d544417300bfed99967db39eea0e950978b012b9a48b5f73f4fe732759234ae05016d", + "jsignpdf-2.2.2\/licenses\/ThirdPartyLicenses\/icu4j.license": "085545902048420cddc84a6474238075ecb0839c158683256b939292f9067a49593714ac58eec4c445e36ea5a511e254f63fb97b4f9fa100d3f61437b5d2ef7b", + "jsignpdf-2.2.2\/licenses\/ThirdPartyLicenses\/pdfbox.license": "d43a0e998d3e817e71501086f4d6a46f1f18b46791c491932887ee15efd51426c606f92620766ba2688276406be970b32dbd18b4a54483a8466e05a6cd81d1c1", + "jsignpdf-2.2.2\/licenses\/ThirdPartyLicenses\/pokrytie_font.license": "ead14823e799bb46e4aa5ab0a2fb3efdc5d6bf73ccb4fdce892445d1852c0e6599c9e2fd2f83a953878eb34af3750920642275d83798364f134b78340582948c", + "jsignpdf-2.2.2\/licenses\/ThirdPartyLicenses\/splashscreen.info": "2be843531ec9d89bb953e03f26d550d9e3e6b567f63d0abbe9ed81f61e8967e53e096b63cacc681561a2006dbf498ef8eaa0ffbd1f60bcc14907c8222bf6db1c", + "jsignpdf-2.2.2\/licenses\/lgpl-2.1.txt": "c929152d51e8db633124dc8ec3272b8f76172c4820a587ebba0fcdb0c2ffa5eb90bc795696a2a8a863521b347822856b0e44d576649a3e85af21c17f28a7e437", + "pdftk.jar": "9ac70daf30c98209892895c05782bf08f69251e321887d3e30b3a8b0868d0e749da5a8f35584d46441c8b83090d0c4228bfe2185862c58231dc929b25b9d6b57" + }, + "signature": "ZcGk0YXYabX\/mjUJqBbAKYmzjXkTxvOEBpbx4\/QWih1XfXLBhbplttW7n+Pszjz2rWU9tNCt7guwHP2xdcev3ZWFx\/iCHp7rUc67zF+9Nw8LGYiVbeG+7M0zqwiqUtlyNpuNG8dyL5ePzqkcxK91W8AzWoth4ceShKwZNORAAJh5T4SAgzc+ThCbB0jDk+F957s0ZGfdPxxXc9Pd\/xqk1kvfQ3YMSkpC6bceulosZQUJFIREkQKTdLN\/FKAkLFcuURCKWuDMqBZ7qKF7uxFba3KIwDf+Bjd4zQL9DEoixQNuo2XXpg3dBAU6aqkN0BYvdgDkT7G7i0C2UdgSsQbTgNisq5oaUpf3ZAhu2iXo+5orUCv4fa1kWnJojmi4Gqlih4IY65oBYPQVBzgxJms\/VFpgFqnwms2moAGmXjxe+DyJ6O0reJHC8PlZBuIudvdIk5vMVB1fBuHFY4m5WP572oUOsrCtvRMMnc2xR1VPmeieVmatAQNr3Uj9vLnYfVmQyNDv1D9vXCq0oda2W4PYOd8vLI04O1YRoiM5lEyZJanVPQZKCOFb8nV6mApD1Zn0Hida3n3cVi\/O6E456DjAk3rj1wxQJEB8d6HoZ6myKpiBVoncdkQbnQX6KhItLIe5rr5VdBZ6mOENeLw7rLY+ORwznbVuXm\/gWCcT\/tjiupo=", + "certificate": "-----BEGIN CERTIFICATE-----\r\nMIIEBDCCAuwCAhF4MA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD\r\nVQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI\r\nMTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB\r\ndXRob3JpdHkwHhcNMjEwMzA0MTk1NzQ1WhcNMzEwNjEwMTk1NzQ1WjAUMRIwEAYD\r\nVQQDDAlsaWJyZXNpZ24wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDq\r\nNU7W4kX445A4yMlADzxuNCouzzIYJBDRZXrKuz5OtbApKY5mPqfXGEpc8N04+eAJ\r\n5EJz5f9r0WxVcWGtyFN1sPObAsoMGyhOzNvAGaveL40xBsc7LdQgCR2JraInHH\/e\r\nMNtkgHQcWL5nihqYIEWvMeVt3uMTiI05F3SjW4+u\/NaRRw\/5y5l5W4Fy6VPzPW0P\r\n22Wmllkb3BFG16C6hHG\/+qE8pf12AcxQZ3B21MbPkHjOjxSz6NS74jGIVRtcn6dO\r\ny26XZ1XoeNUPZDyLFluYCBw5fgTIIU+721mkkA7EjP9RighygVGk4WII7l9Pc+Sf\r\nNwcxQykNdEnZ67ETSr4v1CpArAeXZ2dEZ\/b9QqI\/MCGw0Aa\/Pv2vDc8McFFBBTrt\r\nPDvn0TG0RdfuFAkYdOpFjH3urGUEvcJ\/+lFvRVUu203PHLfx72zNI3XVXui\/slf3\r\noK4LsQrbvj+heYnNXyr5UQAzgXW9JDiXE0sBxfzUz2XKlbuuNpLLE9EkFFQ5LyZJ\r\nG3l1f\/yO3CvGLancbhCvRjo6Lts38GjmkWQT+0BNBpwYhoAd4wopnMYphI9qldbp\r\n1XPWBqb+0w1p6bkIHmci8D\/whC0\/BEHoCs+DpRciRZM0FqW7frZcEGeO6YOoDWJ2\r\nCAhwXGodT4iV8RtVUC6\/arGGUal\/YqBk2M\/9zK6eMwIDAQABMA0GCSqGSIb3DQEB\r\nCwUAA4IBAQBWMFEq++xjRqFsWNPpoTtkfuj0PUajfRHBGzSUXccz0hw8kdR4C2xx\r\nhkYlJ9kqyWNxO1h4urQL5cM1sbl4xf5CI9xf7iuOcB06\/kn3umLmruRec32WG2bS\r\nqAWnnljGCX4sVY8oSbdaUopXE9o9pl966XQ5858c+w9ydkjMDnfOmzrCpgHrJefN\r\n94hIttjJsV8te15VcKoNUxsrZBlPIrpueUQRc13Z9CWp8eRXl4J4CZfVFSY7T4ho\r\nBlNtdPas2R9HJJDYEGS+fg5dfLLvTL4qPSxLjm753pJprfrDxfE9qQl0xtIe8aaw\r\nKFJ\/AK3JTRBkBwsgAE5OYEXTUV9oNS2j\r\n-----END CERTIFICATE-----" +} \ No newline at end of file diff --git a/lib/Command/Developer/SignSetup.php b/lib/Command/Developer/SignSetup.php new file mode 100644 index 0000000000..2b8e7746d9 --- /dev/null +++ b/lib/Command/Developer/SignSetup.php @@ -0,0 +1,96 @@ + + * + * @author Vitor Mattos + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +namespace OCA\Libresign\Command\Developer; + +use OC\Core\Command\Base; +use OC\IntegrityCheck\Helpers\FileAccessHelper; +use OCA\Libresign\Service\Install\SignFiles; +use OCP\IConfig; +use phpseclib\Crypt\RSA; +use phpseclib\File\X509; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Output\OutputInterface; + +class SignSetup extends Base { + public function __construct( + private IConfig $config, + private FileAccessHelper $fileAccessHelper, + private SignFiles $signFiles, + ) { + parent::__construct(); + } + + public function isEnabled(): bool { + return $this->config->getSystemValue('debug', false) === true; + } + + protected function configure(): void { + $this + ->setName('libresign:developer:sign-setup') + ->setDescription('Clean all LibreSign data') + ->addOption('privateKey', null, InputOption::VALUE_REQUIRED, 'Path to private key to use for signing') + ->addOption('certificate', null, InputOption::VALUE_REQUIRED, 'Path to certificate to use for signing') + ; + } + + protected function execute(InputInterface $input, OutputInterface $output): int { + $privateKeyPath = $input->getOption('privateKey'); + $keyBundlePath = $input->getOption('certificate'); + if (is_null($privateKeyPath) || is_null($keyBundlePath)) { + $output->writeln('This command requires the --path, --privateKey and --certificate.'); + $output->writeln('Example: ./occ libresign:developer:sign-setup --privateKey="/libresign/private/myapp.key" --certificate="/libresign/public/mycert.crt"'); + return 1; + } + + $privateKey = $this->fileAccessHelper->file_get_contents((string) $privateKeyPath); + $keyBundle = $this->fileAccessHelper->file_get_contents((string) $keyBundlePath); + if ($privateKey === false) { + $output->writeln(sprintf('Private key "%s" does not exists.', $privateKeyPath)); + return 1; + } + + if ($keyBundle === false) { + $output->writeln(sprintf('Certificate "%s" does not exists.', $keyBundlePath)); + return 1; + } + + $rsa = new RSA(); + $rsa->loadKey($privateKey); + $x509 = new X509(); + $x509->loadX509($keyBundle); + $x509->setPrivateKey($rsa); + try { + foreach ($this->signFiles->getArchitectures() as $architecture) { + $this->signFiles->writeAppSignature($x509, $rsa, $architecture); + } + $output->writeln('Successfully signed'); + } catch (\Exception $e) { + $output->writeln('Error: ' . $e->getMessage()); + return 1; + } + return 0; + } +} diff --git a/lib/Service/Install/SignFiles.php b/lib/Service/Install/SignFiles.php new file mode 100644 index 0000000000..2813ccf0a4 --- /dev/null +++ b/lib/Service/Install/SignFiles.php @@ -0,0 +1,203 @@ + + * + * @author Vitor Mattos + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +namespace OCA\Libresign\Service\Install; + +use OC\IntegrityCheck\Helpers\FileAccessHelper; +use OCA\Libresign\AppInfo\Application; +use OCP\App\IAppManager; +use OCP\Files\AppData\IAppDataFactory; +use OCP\Files\IAppData; +use OCP\Files\SimpleFS\ISimpleFolder; +use OCP\IConfig; +use phpseclib\Crypt\RSA; +use phpseclib\File\X509; + +class SignFiles { + private IAppData $appData; + private array $exclude = [ + 'openssl_config', + 'cfssl_config', + 'unauthetnicated', + ]; + public function __construct( + private FileAccessHelper $fileAccessHelper, + private IConfig $config, + private IAppDataFactory $appDataFactory, + private IAppManager $appManager, + ) { + $this->appData = $appDataFactory->get('libresign'); + } + + public function getArchitectures(): array { + $appInfo = $this->appManager->getAppInfo(Application::APP_ID); + if (!isset($appInfo['dependencies']['architecture'])) { + throw new \Exception('dependencies>architecture not found at info.xml'); + } + return $appInfo['dependencies']['architecture']; + } + + /** + * Write the signature of the app in the specified folder + * + * @param string $path + * @param X509 $certificate + * @param RSA $privateKey + * @throws \Exception + */ + public function writeAppSignature( + X509 $certificate, + RSA $privateKey, + string $architecture, + ) { + $appInfoDir = __DIR__ . '/../../../appinfo'; + try { + $this->fileAccessHelper->assertDirectoryExists($appInfoDir); + + $iterator = $this->getFolderIterator(); + $hashes = $this->generateHashes($iterator); + $signature = $this->createSignatureData($hashes, $certificate, $privateKey); + $this->fileAccessHelper->file_put_contents( + $appInfoDir . '/install-' . $architecture . '.json', + json_encode($signature, JSON_PRETTY_PRINT) + ); + } catch (\Exception $e) { + if (!$this->fileAccessHelper->is_writable($appInfoDir)) { + throw new \Exception($appInfoDir . ' is not writable'); + } + throw $e; + } + } + + private function getDataDir(): string { + $dataDir = $this->config->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data/'); + return $dataDir; + } + + /** + * @todo check a best solution to don't use reflection + */ + private function getInternalPathOfFolder(ISimpleFolder $node): string { + $reflection = new \ReflectionClass($node); + $reflectionProperty = $reflection->getProperty('folder'); + $reflectionProperty->setAccessible(true); + $folder = $reflectionProperty->getValue($node); + $path = $folder->getInternalPath(); + return $path; + } + + private function getInstallPath(): string { + $folder = $this->getDataDir() . '/' . + $this->getInternalPathOfFolder($this->appData->getFolder('/')); + return $folder; + } + + + /** + * Enumerates all files belonging to the folder. Sensible defaults are excluded. + * + * @param string $folderToIterate + * @param string $root + * @return \RecursiveIteratorIterator + * @throws \Exception + */ + private function getFolderIterator(): \RecursiveIteratorIterator { + $dirItr = new \RecursiveDirectoryIterator( + $this->getInstallPath(), + \RecursiveDirectoryIterator::SKIP_DOTS + ); + + return new \RecursiveIteratorIterator( + $dirItr, + \RecursiveIteratorIterator::SELF_FIRST + ); + } + + /** + * Returns an array of ['filename' => 'SHA512-hash-of-file'] for all files found + * in the iterator. + * + * @param \RecursiveIteratorIterator $iterator + * @param string $path + * @return array Array of hashes. + */ + private function generateHashes(\RecursiveIteratorIterator $iterator): array { + $hashes = []; + + $baseDirectoryLength = \strlen($this->getInstallPath()); + foreach ($iterator as $filename => $data) { + /** @var \DirectoryIterator $data */ + if ($data->isDir()) { + continue; + } + + $relativeFileName = substr($filename, $baseDirectoryLength); + $relativeFileName = ltrim($relativeFileName, '/'); + + if ($this->isExcluded($relativeFileName)) { + continue; + } + + $hashes[$relativeFileName] = hash_file('sha512', $filename); + } + + return $hashes; + } + + private function isExcluded(string $filename): bool { + foreach ($this->exclude as $prefix) { + if (str_starts_with($filename, $prefix)) { + return true; + } + } + return false; + } + + /** + * Creates the signature data + * + * @param array $hashes + * @param X509 $certificate + * @param RSA $privateKey + * @return array + */ + private function createSignatureData(array $hashes, + X509 $certificate, + RSA $privateKey): array { + ksort($hashes); + + $privateKey->setSignatureMode(RSA::SIGNATURE_PSS); + $privateKey->setMGFHash('sha512'); + // See https://tools.ietf.org/html/rfc3447#page-38 + $privateKey->setSaltLength(0); + $signature = $privateKey->sign(json_encode($hashes)); + + return [ + 'hashes' => $hashes, + 'signature' => base64_encode($signature), + 'certificate' => $certificate->saveX509($certificate->currentCert), + ]; + } +} From 40a8269f249e91279aea12e729a9adbd29223e6c Mon Sep 17 00:00:00 2001 From: Vitor Mattos Date: Mon, 22 Apr 2024 09:01:10 -0300 Subject: [PATCH 02/50] chore: Update baseline Signed-off-by: Vitor Mattos --- tests/psalm-baseline.xml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/psalm-baseline.xml b/tests/psalm-baseline.xml index ea9182bf53..affdcd1d51 100644 --- a/tests/psalm-baseline.xml +++ b/tests/psalm-baseline.xml @@ -126,6 +126,14 @@ + + + RSA + RSA + X509 + X509 + + From 061f6554d3635ac0f5f455569bc0199d41099ee6 Mon Sep 17 00:00:00 2001 From: Vitor Mattos Date: Fri, 31 May 2024 13:53:53 -0300 Subject: [PATCH 03/50] chore: ignore appinfo/install-signature.json file Signed-off-by: Vitor Mattos --- .gitignore | 1 + appinfo/install-signature.json | 282 --------------------------------- 2 files changed, 1 insertion(+), 282 deletions(-) delete mode 100644 appinfo/install-signature.json diff --git a/.gitignore b/.gitignore index e2d8da0ba8..2c66f643ae 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,4 @@ node_modules/ .phpunit.result.cache *.phar /src/__test__/coverage +/appinfo/install-signature.json diff --git a/appinfo/install-signature.json b/appinfo/install-signature.json deleted file mode 100644 index 10d4b56a59..0000000000 --- a/appinfo/install-signature.json +++ /dev/null @@ -1,282 +0,0 @@ -{ - "hashes": { - "checksums_java_21.0.2_13.txt": "7110bab6ee73702be77ee966b3a1ec13812d012fa981e68e189d0f126a10acee7a86ecadd584dcf091c6f0f76ca4a97d5a331e7307b1e49da7f70165cb8923b5", - "java\/OpenJDK21U-jre_x64_linux_hotspot_21.0.2_13.tar.gz": "3dc4f78e235aed4be20b5f20bdcdef48bbc1ca18fff08d109e055945503ae32c86cdfb3bdb95196bc3ab55b336011e6f55503c55b940b1e4362cadb978d6c02a", - "java\/jdk-21.0.2+13-jre\/NOTICE": "e0c38f15ba79febedf49941bb772b99e12d8da3748e60891f3bd02ff157691b545f9a5c910197ab08b61a93c62616d98206391b2200fa4294047f35c883ac08f", - "java\/jdk-21.0.2+13-jre\/bin\/java": "02c868f7a62fba5e56ad29e5f99e4d4e8cabdeea9be72fcf7025b838d108311ccd2df08404d43b1983042e7a80d31f69d7550d507e1539ff873072be4e56bca5", - "java\/jdk-21.0.2+13-jre\/bin\/jfr": "546a00d8bbea4640f615f87ef702ac752e84e0c26d507f2b47ef68e39c46fffd82876c40e9ee9cba98495d947c189fb1e85ea21f9aac4463a02330d7f777d69c", - "java\/jdk-21.0.2+13-jre\/bin\/jrunscript": "830e426ad5b6cc3ed046d160f653e31a93497ca500c64922596e3ad1678a96912b788b9f074f9b5d4e501d32710e9b05bc5e8450148433a375016f2526595bf1", - "java\/jdk-21.0.2+13-jre\/bin\/jwebserver": "a02726a89255c301c4035cc91f2511089b56a9034244d69e5610068e5c2cb243b1bd1ec933f4f7ddda49903eabbf9f5d776e2f12c3b66a494c4399f30a4d0c3d", - "java\/jdk-21.0.2+13-jre\/bin\/keytool": "76a6ce792c3ac07163ab80e3bcc73eb01e457a47cc4fe25321c2115ce72dd634ae108a0b44133fd6de1b2934ac9d4537cd3496b91d1937cf6c8748b59ba4e1c2", - "java\/jdk-21.0.2+13-jre\/bin\/rmiregistry": "64263c3eb1e0f75adb5d3f12b56bff4e5aebcb44d674f23564bd0c796dd591c4bf5fc2b58f6c829f197fcd346abd684f8caed6b30962aa3095651c52935bfedc", - "java\/jdk-21.0.2+13-jre\/conf\/jaxp.properties": "37163a66138973c586c4d59394a1b7f2ed82c9c76a82ed0354fc3a0c96f52abb5d7f8bb3141a747953a4984b62b7efe8f2a3c40b7339ebd81d4a59413403a3a0", - "java\/jdk-21.0.2+13-jre\/conf\/logging.properties": "e869f4a3b821a9933796dc9a56ee00483493369dfbfe07b3b1d895cb8318c6821cd44134eb37513f15b830c25861b596646824ed56672d08b678fefe6a4c7504", - "java\/jdk-21.0.2+13-jre\/conf\/management\/jmxremote.access": "64d33add796d2d3df7ad37aa452ee1d106174be1ade3063d73ba416211629a9a9b05177969404fdc92fcee8458450c9de4a6195744b93131303208cb6f1416ad", - "java\/jdk-21.0.2+13-jre\/conf\/management\/jmxremote.password.template": "e6794168ba80a8ff733d8c1771930ae8c8fc33030e5e9ca02700f326c88a2f68ff09bc734bfd1e492ef15705b288c7918ce1f3f7174742dee6a62dfe086abd65", - "java\/jdk-21.0.2+13-jre\/conf\/management\/management.properties": "4fae4e2b5f7122cd80c03b3d04fca5c4b9586be6c712dfdb729f5e85d6e71a86addfdb975be4ee7e250e28643222687f834a6456054e38331bd978aba79dae71", - "java\/jdk-21.0.2+13-jre\/conf\/net.properties": "397d39f852fe94e6b384f3924e7676c252ab7ceaab2b0ebb8bc4e6244f487830c786ba327ac4ec6dadbcb31be78ebeff0d3c0fde2b02b0f1963e924fe399afba", - "java\/jdk-21.0.2+13-jre\/conf\/sdp\/sdp.conf.template": "645e30897684300d163086eea1477e5262b1fe05adc0053b26cd07898f3de6c147285acfd0fac9007022692d93b347ac321fa054ab7464b07c32f86b8c2419b1", - "java\/jdk-21.0.2+13-jre\/conf\/security\/java.policy": "d2b6ea94bc3becc531926239a77c9995c543bf48232484fa0036c4e09e42ab7ee5facc10e0eed64556950980ffc9c8e56c556f34e74985c09f2384216ca461ab", - "java\/jdk-21.0.2+13-jre\/conf\/security\/java.security": "695cd8a173dac2d92bbe723082f4940b9ba920f8be7220f4abb06ee84c3fd664ed6ba5e9ad93cdffd804c78dac68dfb3a999da17f4dae9499b74304de565476b", - "java\/jdk-21.0.2+13-jre\/conf\/security\/policy\/README.txt": "68a031264cf9442526307364ca74b336af55564c233c2f514cac48e910022767562f8ff6a64bb9cfcbf0fb5e755289273382c9246418a4b9207fc7761d03c64e", - "java\/jdk-21.0.2+13-jre\/conf\/security\/policy\/limited\/default_US_export.policy": "4cfca5b10cd7addcff887c8f3621d2fbec1b5632436326377b0ce5af1ae3e8b68ac5a743ca6082fc79991b8eec703a6e1dfd5b896153407ad72327753222fdb3", - "java\/jdk-21.0.2+13-jre\/conf\/security\/policy\/limited\/default_local.policy": "a0b98cbbb49184df973bb2c4a506e9bc6e025a696bc0c8054a6352cc3f9b4a38e3baf117c6834ddaddc38498556607ed4eda8f1bc683f662d61da50e0db0c8c2", - "java\/jdk-21.0.2+13-jre\/conf\/security\/policy\/limited\/exempt_local.policy": "2bd70518aed6b0e01c520c446830c5f567fa72974548818cac3e1e5c2be6f03db78ce6012f5463b1e19c36243d04cbaad38ec79524635eaae2e427eb1875ccdb", - "java\/jdk-21.0.2+13-jre\/conf\/security\/policy\/unlimited\/default_US_export.policy": "4cfca5b10cd7addcff887c8f3621d2fbec1b5632436326377b0ce5af1ae3e8b68ac5a743ca6082fc79991b8eec703a6e1dfd5b896153407ad72327753222fdb3", - "java\/jdk-21.0.2+13-jre\/conf\/security\/policy\/unlimited\/default_local.policy": "2b0385417a3fc2af58b1cbb186dd3e0b0875e42923884153deee0efcb390ca00b326ed5b266b3892d31bf7d40e10969a0b51daa6d0b4ca3183770786925d3cde", - "java\/jdk-21.0.2+13-jre\/conf\/sound.properties": "99fdd75b8ce71622f85f957ae52b85e6646763f7864b670e993df0c2c77363ef9cfce2727badee03503cda41abe6eb8a278142766bf66f00b4eb39d0d4fc4a87", - "java\/jdk-21.0.2+13-jre\/legal\/java.base\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", - "java\/jdk-21.0.2+13-jre\/legal\/java.base\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", - "java\/jdk-21.0.2+13-jre\/legal\/java.base\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", - "java\/jdk-21.0.2+13-jre\/legal\/java.base\/aes.md": "4d14b5ddbb4d09797264ed29ba71fab6986b4a9e75efb9402c1476e0a9e2884813d6a922dea125643b4f74e1f3e458f4e48d6c840e0f4d16ed72ffbc4611dbb2", - "java\/jdk-21.0.2+13-jre\/legal\/java.base\/asm.md": "2fcf1da50a53858e5e68db51996b59ebeb8f07b698f72b67a827d4fd302f757c5c0d0479b37128d239268b635b20177a27557c1dba920fa9f12f1bec2b7f6d40", - "java\/jdk-21.0.2+13-jre\/legal\/java.base\/c-libutl.md": "ae459d8ce5581ea57e203088373c1ce86d122d0e27eb871ee1383e0e64cd8a184fa207eee0e835347316e70afa24a1c95aec30def3e09d15ee19a0b2c3ad2095", - "java\/jdk-21.0.2+13-jre\/legal\/java.base\/cldr.md": "8ab32a80deb12dd1f3a54a38b3335a76feb44e20fcf5ee897d47511e0acedbbedf51a241768441c56259a54c7303ddf7b57be7693c5cddb30f90741ca3257190", - "java\/jdk-21.0.2+13-jre\/legal\/java.base\/icu.md": "0b31bcbdb578ac448dd145c0160c83e24ff4f1b48cada692d213e026155f5a44fc0e7b01444c5af0649e49ffd100421a890a6ed0c60722b15c4a4938a0c99b67", - "java\/jdk-21.0.2+13-jre\/legal\/java.base\/public_suffix.md": "cbd16c4c29a51669f51ff9817ed33e29b871df215fb252a946c3b4e80fc83d4f0e4e1b32d46c2998924092e4b14585666f748b598708773dc6d2432701d6f627", - "java\/jdk-21.0.2+13-jre\/legal\/java.base\/unicode.md": "06f8cd7233ab0e6d2db403765aa543f153b611fa6d1cdc571fa98dc8ff9a908c14034e31305b14c6f80ee8de5bb5e6e49dcd18c030d5b5772dc93153ea16fc19", - "java\/jdk-21.0.2+13-jre\/legal\/java.base\/zlib.md": "c516403a109630b79998f3bea6b698247a0b5367cc9873defa75014e8c98c690d34d0810d32792d80fde1333980ac6c5f19324743795cb6455ef0ee4979496bb", - "java\/jdk-21.0.2+13-jre\/legal\/java.compiler\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", - "java\/jdk-21.0.2+13-jre\/legal\/java.compiler\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", - "java\/jdk-21.0.2+13-jre\/legal\/java.compiler\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", - "java\/jdk-21.0.2+13-jre\/legal\/java.datatransfer\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", - "java\/jdk-21.0.2+13-jre\/legal\/java.datatransfer\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", - "java\/jdk-21.0.2+13-jre\/legal\/java.datatransfer\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", - "java\/jdk-21.0.2+13-jre\/legal\/java.desktop\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", - "java\/jdk-21.0.2+13-jre\/legal\/java.desktop\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", - "java\/jdk-21.0.2+13-jre\/legal\/java.desktop\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", - "java\/jdk-21.0.2+13-jre\/legal\/java.desktop\/colorimaging.md": "f5872960470810cdbdc2db1dfb216cab88203b23400b16e157c8654c2eecff8d9b26ce066ec18718c8e6d54ee1c54533fdade395c454210fed5159fd4a7a0adb", - "java\/jdk-21.0.2+13-jre\/legal\/java.desktop\/freetype.md": "67a686550414a6b878869b7280708d8a428cfbf803e1462929e65e6c6e1a265562149a2e23ac82488ae96f1e856d2f23470b5335021865fc499fbee520f0c079", - "java\/jdk-21.0.2+13-jre\/legal\/java.desktop\/giflib.md": "dafac31d75a7ab4ddd7666799a24abf22c1583ca22554a738cc26a77bf927b20dde52f12194670a5196bce3a43bd58de46944291727c8877fee1fe4a38a1f1ca", - "java\/jdk-21.0.2+13-jre\/legal\/java.desktop\/harfbuzz.md": "8fc9822bb15a0008055882976510258287cedc81de390cc01fe0869fc8a2c2d876241470c5bffb96cb5d4460544e893ac8077d6dcc8ec523e02050807b946adf", - "java\/jdk-21.0.2+13-jre\/legal\/java.desktop\/jpeg.md": "7e82da825499b1b4c5ddb09d17bdda584f52739b504786f8126df2fe914d97111189fb7829ebb5285d11cf2a18977f377e0d89a16c82d5e574a5b5b83aca1b3a", - "java\/jdk-21.0.2+13-jre\/legal\/java.desktop\/lcms.md": "a91faa243a09bdfe62714859b9b4420e8434dd09693a6a280e1c8ef6694fb7858d0171fae4ca36721b685e3ab8bc8000c5635bf3789250a5b9081130eb4ff57c", - "java\/jdk-21.0.2+13-jre\/legal\/java.desktop\/libpng.md": "6a35e221deb422ef690354d04183bd51ebda349c0ceb768d16f935cdfaac78cbc7fa5afc022b1b933abf52ea46d95b2cccf4976aaa0bf010647d96ec1d31b397", - "java\/jdk-21.0.2+13-jre\/legal\/java.desktop\/mesa3d.md": "9c4111728ab9472f0b160cb11ce1e4ebd75a83cfddca0b3cb87243d15afc5a7fa34dc6006e6b92084648cbad1426f70b405259f589cdef758442643e1618dff4", - "java\/jdk-21.0.2+13-jre\/legal\/java.desktop\/pipewire.md": "7eb9d8dfa8a2c8f234f5a545e890906b6f0ddb5088f0a5631a2f7515d5dbaa7a6e2563fd789db3de43be2503d97245cae5192f0f9a9992d71c8ce7f8fa32e34f", - "java\/jdk-21.0.2+13-jre\/legal\/java.desktop\/xwd.md": "42fc3783e35ca37525611767b7cfd5ae541ddace22af7102f36c1550d39f994c94e6c0b241153a2b9bae228f3944f7ad3400d6f9db384d104c452f6a07054aed", - "java\/jdk-21.0.2+13-jre\/legal\/java.instrument\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", - "java\/jdk-21.0.2+13-jre\/legal\/java.instrument\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", - "java\/jdk-21.0.2+13-jre\/legal\/java.instrument\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", - "java\/jdk-21.0.2+13-jre\/legal\/java.logging\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", - "java\/jdk-21.0.2+13-jre\/legal\/java.logging\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", - "java\/jdk-21.0.2+13-jre\/legal\/java.logging\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", - "java\/jdk-21.0.2+13-jre\/legal\/java.management.rmi\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", - "java\/jdk-21.0.2+13-jre\/legal\/java.management.rmi\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", - "java\/jdk-21.0.2+13-jre\/legal\/java.management.rmi\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", - "java\/jdk-21.0.2+13-jre\/legal\/java.management\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", - "java\/jdk-21.0.2+13-jre\/legal\/java.management\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", - "java\/jdk-21.0.2+13-jre\/legal\/java.management\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", - "java\/jdk-21.0.2+13-jre\/legal\/java.naming\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", - "java\/jdk-21.0.2+13-jre\/legal\/java.naming\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", - "java\/jdk-21.0.2+13-jre\/legal\/java.naming\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", - "java\/jdk-21.0.2+13-jre\/legal\/java.net.http\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", - "java\/jdk-21.0.2+13-jre\/legal\/java.net.http\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", - "java\/jdk-21.0.2+13-jre\/legal\/java.net.http\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", - "java\/jdk-21.0.2+13-jre\/legal\/java.prefs\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", - "java\/jdk-21.0.2+13-jre\/legal\/java.prefs\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", - "java\/jdk-21.0.2+13-jre\/legal\/java.prefs\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", - "java\/jdk-21.0.2+13-jre\/legal\/java.rmi\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", - "java\/jdk-21.0.2+13-jre\/legal\/java.rmi\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", - "java\/jdk-21.0.2+13-jre\/legal\/java.rmi\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", - "java\/jdk-21.0.2+13-jre\/legal\/java.scripting\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", - "java\/jdk-21.0.2+13-jre\/legal\/java.scripting\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", - "java\/jdk-21.0.2+13-jre\/legal\/java.scripting\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", - "java\/jdk-21.0.2+13-jre\/legal\/java.se\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", - "java\/jdk-21.0.2+13-jre\/legal\/java.se\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", - "java\/jdk-21.0.2+13-jre\/legal\/java.se\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", - "java\/jdk-21.0.2+13-jre\/legal\/java.security.jgss\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", - "java\/jdk-21.0.2+13-jre\/legal\/java.security.jgss\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", - "java\/jdk-21.0.2+13-jre\/legal\/java.security.jgss\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", - "java\/jdk-21.0.2+13-jre\/legal\/java.security.sasl\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", - "java\/jdk-21.0.2+13-jre\/legal\/java.security.sasl\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", - "java\/jdk-21.0.2+13-jre\/legal\/java.security.sasl\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", - "java\/jdk-21.0.2+13-jre\/legal\/java.smartcardio\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", - "java\/jdk-21.0.2+13-jre\/legal\/java.smartcardio\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", - "java\/jdk-21.0.2+13-jre\/legal\/java.smartcardio\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", - "java\/jdk-21.0.2+13-jre\/legal\/java.smartcardio\/pcsclite.md": "19eb5494e32e1276d87153f06dbcfe513a3df5355ca7a7c576fdaf200aeb5698a92b4e113ca3191b22c742e66226cbdba9d1ae8c2a0d1bfa0f7206baf9bb5fc9", - "java\/jdk-21.0.2+13-jre\/legal\/java.sql.rowset\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", - "java\/jdk-21.0.2+13-jre\/legal\/java.sql.rowset\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", - "java\/jdk-21.0.2+13-jre\/legal\/java.sql.rowset\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", - "java\/jdk-21.0.2+13-jre\/legal\/java.sql\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", - "java\/jdk-21.0.2+13-jre\/legal\/java.sql\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", - "java\/jdk-21.0.2+13-jre\/legal\/java.sql\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", - "java\/jdk-21.0.2+13-jre\/legal\/java.transaction.xa\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", - "java\/jdk-21.0.2+13-jre\/legal\/java.transaction.xa\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", - "java\/jdk-21.0.2+13-jre\/legal\/java.transaction.xa\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", - "java\/jdk-21.0.2+13-jre\/legal\/java.xml.crypto\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", - "java\/jdk-21.0.2+13-jre\/legal\/java.xml.crypto\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", - "java\/jdk-21.0.2+13-jre\/legal\/java.xml.crypto\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", - "java\/jdk-21.0.2+13-jre\/legal\/java.xml.crypto\/santuario.md": "108bafd2f15cf3b46df2495c164fda196b2e72194e03368d18442abd8924bf920f2e1343329d54f83e77dedfd9143769543e2459a36b5610f85103cfe7fd5296", - "java\/jdk-21.0.2+13-jre\/legal\/java.xml\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", - "java\/jdk-21.0.2+13-jre\/legal\/java.xml\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", - "java\/jdk-21.0.2+13-jre\/legal\/java.xml\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", - "java\/jdk-21.0.2+13-jre\/legal\/java.xml\/bcel.md": "25f2189643a113616f53cd87fc96df01b55602bfc3f6653e48c310de03f6d79ccbbec58936d54b88052e32d68c646017bf75b8a179f59fb9d2c5f6938e351a4d", - "java\/jdk-21.0.2+13-jre\/legal\/java.xml\/dom.md": "8c71f226f0f07b471aea6b8e715434b5eaa6b4a59a653ec22c2489e743e9288a0c4537f479719f9d58737d0257470c9cceff9ce647a96e79fd757a4cdcfed499", - "java\/jdk-21.0.2+13-jre\/legal\/java.xml\/jcup.md": "7ed3e58f189f2922f7543d4617308d0c35f8adc2e7cbbb6fbba49d33cdd5da64c6edc022ae9842c28e58d97b056a245245c816003978f1e0152236636ca72ba5", - "java\/jdk-21.0.2+13-jre\/legal\/java.xml\/xalan.md": "db99644e83bf0d0f7573e520f5381b038810afd7de1a881d7d752273ec2584d9aca3eb1f3ae47f0402ec6a49116cb581019cbb9c82278f99c37bb7b01b09457e", - "java\/jdk-21.0.2+13-jre\/legal\/java.xml\/xerces.md": "26972bb1fe75ff78ed4afef538e389556ccca2d04af0c50bc6fd0d3dbfa2be6610d259b307cefe29dafb613fa3d324e7734e83873b16a61c90bf6e2514d92566", - "java\/jdk-21.0.2+13-jre\/legal\/jdk.accessibility\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", - "java\/jdk-21.0.2+13-jre\/legal\/jdk.accessibility\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", - "java\/jdk-21.0.2+13-jre\/legal\/jdk.accessibility\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", - "java\/jdk-21.0.2+13-jre\/legal\/jdk.charsets\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", - "java\/jdk-21.0.2+13-jre\/legal\/jdk.charsets\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", - "java\/jdk-21.0.2+13-jre\/legal\/jdk.charsets\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", - "java\/jdk-21.0.2+13-jre\/legal\/jdk.crypto.cryptoki\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", - "java\/jdk-21.0.2+13-jre\/legal\/jdk.crypto.cryptoki\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", - "java\/jdk-21.0.2+13-jre\/legal\/jdk.crypto.cryptoki\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", - "java\/jdk-21.0.2+13-jre\/legal\/jdk.crypto.cryptoki\/pkcs11cryptotoken.md": "2676cfdfd61762c7b6171985e8cfe1068c36683ca43753a1ffb10241ac61a74c9be1c00be22903df85ba6954fd908d77de60903c316506fd88b9679672ada968", - "java\/jdk-21.0.2+13-jre\/legal\/jdk.crypto.cryptoki\/pkcs11wrapper.md": "759c75f87309b67c56a5b7088045e04be7c023ecdbaea80842e22b81b0bfb36026191070471f8b08fef47ec73664611ce0453b4a9818f7708c95663733ee5ce9", - "java\/jdk-21.0.2+13-jre\/legal\/jdk.crypto.ec\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", - "java\/jdk-21.0.2+13-jre\/legal\/jdk.crypto.ec\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", - "java\/jdk-21.0.2+13-jre\/legal\/jdk.crypto.ec\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", - "java\/jdk-21.0.2+13-jre\/legal\/jdk.dynalink\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", - "java\/jdk-21.0.2+13-jre\/legal\/jdk.dynalink\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", - "java\/jdk-21.0.2+13-jre\/legal\/jdk.dynalink\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", - "java\/jdk-21.0.2+13-jre\/legal\/jdk.dynalink\/dynalink.md": "86ee77d8e129b78173964461cd27200aeab7fb6417fe0f4982d9b126ed2292216d08212be91b53eccb26dd6a8b3e1aab1d1dbab85c2133872ac0027dc87a8223", - "java\/jdk-21.0.2+13-jre\/legal\/jdk.httpserver\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", - "java\/jdk-21.0.2+13-jre\/legal\/jdk.httpserver\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", - "java\/jdk-21.0.2+13-jre\/legal\/jdk.httpserver\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", - "java\/jdk-21.0.2+13-jre\/legal\/jdk.incubator.vector\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", - "java\/jdk-21.0.2+13-jre\/legal\/jdk.incubator.vector\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", - "java\/jdk-21.0.2+13-jre\/legal\/jdk.incubator.vector\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", - "java\/jdk-21.0.2+13-jre\/legal\/jdk.internal.vm.ci\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", - "java\/jdk-21.0.2+13-jre\/legal\/jdk.internal.vm.ci\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", - "java\/jdk-21.0.2+13-jre\/legal\/jdk.internal.vm.ci\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", - "java\/jdk-21.0.2+13-jre\/legal\/jdk.internal.vm.compiler.management\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", - "java\/jdk-21.0.2+13-jre\/legal\/jdk.internal.vm.compiler.management\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", - "java\/jdk-21.0.2+13-jre\/legal\/jdk.internal.vm.compiler.management\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", - "java\/jdk-21.0.2+13-jre\/legal\/jdk.internal.vm.compiler\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", - "java\/jdk-21.0.2+13-jre\/legal\/jdk.internal.vm.compiler\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", - "java\/jdk-21.0.2+13-jre\/legal\/jdk.internal.vm.compiler\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", - "java\/jdk-21.0.2+13-jre\/legal\/jdk.jdwp.agent\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", - "java\/jdk-21.0.2+13-jre\/legal\/jdk.jdwp.agent\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", - "java\/jdk-21.0.2+13-jre\/legal\/jdk.jdwp.agent\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", - "java\/jdk-21.0.2+13-jre\/legal\/jdk.jfr\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", - "java\/jdk-21.0.2+13-jre\/legal\/jdk.jfr\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", - "java\/jdk-21.0.2+13-jre\/legal\/jdk.jfr\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", - "java\/jdk-21.0.2+13-jre\/legal\/jdk.jsobject\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", - "java\/jdk-21.0.2+13-jre\/legal\/jdk.jsobject\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", - "java\/jdk-21.0.2+13-jre\/legal\/jdk.jsobject\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", - "java\/jdk-21.0.2+13-jre\/legal\/jdk.localedata\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", - "java\/jdk-21.0.2+13-jre\/legal\/jdk.localedata\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", - "java\/jdk-21.0.2+13-jre\/legal\/jdk.localedata\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", - "java\/jdk-21.0.2+13-jre\/legal\/jdk.localedata\/cldr.md": "8ab32a80deb12dd1f3a54a38b3335a76feb44e20fcf5ee897d47511e0acedbbedf51a241768441c56259a54c7303ddf7b57be7693c5cddb30f90741ca3257190", - "java\/jdk-21.0.2+13-jre\/legal\/jdk.localedata\/thaidict.md": "5221112cd8ef83b636dc4364f53b72c5484a5885acb55c2c071c88d23058093caee38578f7e424ecafdb483ccc0bc8e78d7ac13add536ec824a8eac171a576cb", - "java\/jdk-21.0.2+13-jre\/legal\/jdk.management.agent\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", - "java\/jdk-21.0.2+13-jre\/legal\/jdk.management.agent\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", - "java\/jdk-21.0.2+13-jre\/legal\/jdk.management.agent\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", - "java\/jdk-21.0.2+13-jre\/legal\/jdk.management.jfr\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", - "java\/jdk-21.0.2+13-jre\/legal\/jdk.management.jfr\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", - "java\/jdk-21.0.2+13-jre\/legal\/jdk.management.jfr\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", - "java\/jdk-21.0.2+13-jre\/legal\/jdk.management\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", - "java\/jdk-21.0.2+13-jre\/legal\/jdk.management\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", - "java\/jdk-21.0.2+13-jre\/legal\/jdk.management\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", - "java\/jdk-21.0.2+13-jre\/legal\/jdk.naming.dns\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", - "java\/jdk-21.0.2+13-jre\/legal\/jdk.naming.dns\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", - "java\/jdk-21.0.2+13-jre\/legal\/jdk.naming.dns\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", - "java\/jdk-21.0.2+13-jre\/legal\/jdk.naming.rmi\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", - "java\/jdk-21.0.2+13-jre\/legal\/jdk.naming.rmi\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", - "java\/jdk-21.0.2+13-jre\/legal\/jdk.naming.rmi\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", - "java\/jdk-21.0.2+13-jre\/legal\/jdk.net\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", - "java\/jdk-21.0.2+13-jre\/legal\/jdk.net\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", - "java\/jdk-21.0.2+13-jre\/legal\/jdk.net\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", - "java\/jdk-21.0.2+13-jre\/legal\/jdk.nio.mapmode\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", - "java\/jdk-21.0.2+13-jre\/legal\/jdk.nio.mapmode\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", - "java\/jdk-21.0.2+13-jre\/legal\/jdk.nio.mapmode\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", - "java\/jdk-21.0.2+13-jre\/legal\/jdk.sctp\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", - "java\/jdk-21.0.2+13-jre\/legal\/jdk.sctp\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", - "java\/jdk-21.0.2+13-jre\/legal\/jdk.sctp\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", - "java\/jdk-21.0.2+13-jre\/legal\/jdk.security.auth\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", - "java\/jdk-21.0.2+13-jre\/legal\/jdk.security.auth\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", - "java\/jdk-21.0.2+13-jre\/legal\/jdk.security.auth\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", - "java\/jdk-21.0.2+13-jre\/legal\/jdk.security.jgss\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", - "java\/jdk-21.0.2+13-jre\/legal\/jdk.security.jgss\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", - "java\/jdk-21.0.2+13-jre\/legal\/jdk.security.jgss\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", - "java\/jdk-21.0.2+13-jre\/legal\/jdk.unsupported\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", - "java\/jdk-21.0.2+13-jre\/legal\/jdk.unsupported\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", - "java\/jdk-21.0.2+13-jre\/legal\/jdk.unsupported\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", - "java\/jdk-21.0.2+13-jre\/legal\/jdk.xml.dom\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", - "java\/jdk-21.0.2+13-jre\/legal\/jdk.xml.dom\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", - "java\/jdk-21.0.2+13-jre\/legal\/jdk.xml.dom\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", - "java\/jdk-21.0.2+13-jre\/legal\/jdk.zipfs\/ADDITIONAL_LICENSE_INFO": "9f658dfea71bdc3cc1549edfb5ad3171dbfa0082b2d91e820c09abe0b376b6bcd8b5170442a5e25e72274e98f130176bbdecfa7997c59705782b214f02136a20", - "java\/jdk-21.0.2+13-jre\/legal\/jdk.zipfs\/ASSEMBLY_EXCEPTION": "5516e2e9eb3a555562f600cc3cd85ae01004962a8af8c49d2598281ce622bcbee7a4bc513b94b05e3b611bb50611360171e21bae9c1b3ed7d05a0867de7d3bb2", - "java\/jdk-21.0.2+13-jre\/legal\/jdk.zipfs\/LICENSE": "6732288c682a39ed9edf11a151f6f48e742696f4a762c0c7d8872b99b9f6d5ab6c305064d4910b1a254862a873129f11fd0fa56ff11bc577d29303f4fb492673", - "java\/jdk-21.0.2+13-jre\/lib\/classlist": "fa075d07032562204684a85ef801757efb30f2e51dece3f985dbec029181ed4cd508522fb3d57c13455d8d49dfcc32e576ee657048e7e2d134d8acbacf82edc3", - "java\/jdk-21.0.2+13-jre\/lib\/jexec": "9d598da3edba0218c1a9920bc218f869028afc509b128daaeb1711bbc6ab10062b0dde05d9d8bcc1581a9f9b3f50ecf304ef8945562c6a06dde58e6e7807ff21", - "java\/jdk-21.0.2+13-jre\/lib\/jfr\/default.jfc": "f34c0543e2654cd7cf5180d3c0c8a9b77616049493c1e344ab974e76baeff37244f075fafef854ade49ab4d9ba0bbc07a83e4733fc6ef31afadf3d359fd820e6", - "java\/jdk-21.0.2+13-jre\/lib\/jfr\/profile.jfc": "b8abe37dab4ec4b9adacf3b5aab4dbc4ff706e70d1cc45471d6829b8b08651c3f1c6c267462f208e1b8bb0a7054cfe018927d3309b44870551d8282d4ea1895f", - "java\/jdk-21.0.2+13-jre\/lib\/jrt-fs.jar": "25641ecb09cfb703f72dd99dab58fde80b8c0636386eae57a08c7bf2db5e3d35f84fe583acb145c1aad99770354098d729adbf11cfbd7a753df0f30c16dbb77a", - "java\/jdk-21.0.2+13-jre\/lib\/jspawnhelper": "0719bbe098509538c6a0f4b26b40e484e7c810b5fe38dc83666dbee139a3bbcb4ff23a03b7b33b8a0347fede5d72080d56c65909b06777b5631ed5bcb9aa3b7f", - "java\/jdk-21.0.2+13-jre\/lib\/jvm.cfg": "8b37a1a5600e0a4e5832021c4db50569e33f1ddc8ac4fc2f38d5439272b955b0e3028ea10dec0743b197aa0def32d9e185066d2bac451f81b99539d34006074b", - "java\/jdk-21.0.2+13-jre\/lib\/libawt.so": "ae37c93ac242bd2dbfc7fb3d3e9f4991b9668819b42de8a4a0fec03bc9189d2138bf573d5100385dfa306907c25991090f1ce6c0b326e40600a2aade1912c208", - "java\/jdk-21.0.2+13-jre\/lib\/libawt_headless.so": "a02c26ddad2c6d23fa73d9b508e4332d07e8853d471179ea658ef9d6fb8fc5f503d5feeb8839a14b4bfaa73c211b8ed2b9c4642a33b34784f213dc0531d7d113", - "java\/jdk-21.0.2+13-jre\/lib\/libawt_xawt.so": "c0f68c55a0fb44fdd31545a0ead22fa069ce4cc0963dbfea5db786e57f1ab331a12cc3a093e81944b95d825d36c47bc6e8370e3fb138813dd530304387d0763a", - "java\/jdk-21.0.2+13-jre\/lib\/libdt_socket.so": "2c88b58210dd5a2a95233ebd284421ef1c739a9e567194f2db2b218eee16be7933829a5646bdbacfb0ec79c82bfbef35d72f0275dce51b07b1dd9fafcb96622c", - "java\/jdk-21.0.2+13-jre\/lib\/libextnet.so": "c191aa130e3cc4a13c425524d3216bf7b844ffa5c1c3ec6259f57bd23a13f9166be8a780af6ada14e054d495caae5c8eb0259c16c3d593f723853f1d8495973c", - "java\/jdk-21.0.2+13-jre\/lib\/libfontmanager.so": "eec80dfc544e7bfa02a51672d7d3b4ddd8e7cef2349d195d6fc8e13ea11ccc4f74fd0cc69a7ddb4f7eccaf3517b0e3b4e53425da772b81dc7d1e91d60ad80063", - "java\/jdk-21.0.2+13-jre\/lib\/libfreetype.so": "5c81ce6ca56d3fe46088720747fdaeb0adcb3643a9f7d31d5aaa54c8e1d80de3285e839381f1ddaefb36fe7c4e29a78bf0091480d566b8fbd873bfccbc7ae306", - "java\/jdk-21.0.2+13-jre\/lib\/libinstrument.so": "fec9990e02d5b541f602ac0584e02af7dea1e76fe0fc6ce5fa54567826f4c078189a63a1fd2094e5b28a2c6ccf9a2e3a4f5b5e0d9b436e30be286a85c60cecb0", - "java\/jdk-21.0.2+13-jre\/lib\/libj2gss.so": "e174e096da4ed44f5d75eaf4dbf408699362518dbf60d18473736b5750245c03206ae21697541bc96601c708cb72799e5bd4c4d2568d5b8f13838cb6d287c281", - "java\/jdk-21.0.2+13-jre\/lib\/libj2pcsc.so": "a5ff7d35a4cb2865a227ae1ad95eef110adf8bd9c6ba705800a5f26dbb50f1091c53b2349d4502a52a1b83c3ccee1c841f5d91d27886a67cdd8950b13ecb4f4d", - "java\/jdk-21.0.2+13-jre\/lib\/libj2pkcs11.so": "82b3cb4450899cf556bdcc9c9e0b7f929b6cd928c51d86b5fd1a78c53934b1a874702ff179f37e91ceef662fd98102c120ba79b86565cfe6a4ee379f05760938", - "java\/jdk-21.0.2+13-jre\/lib\/libjaas.so": "2996d617a4394a3c94fe189fb320e110dac119ce28b1f7ab94d1c6a7e33e6ad14fcaddd3d27d7da8b9cc43a4bd2407e2cd3d7e4a13cace1e403b95b81bbe0b0b", - "java\/jdk-21.0.2+13-jre\/lib\/libjava.so": "1bb9dafb9501570b562e7e7f3372c38240a68a0ecc1c290982f5a575c36408be563ad9b648f7860a0693e7b5b1dddc537890d3862de4e1abff550e72ad83c6fb", - "java\/jdk-21.0.2+13-jre\/lib\/libjavajpeg.so": "d7914c3e57ebf44b69f426eaad86bdea925b913045e778d22653837c70e816a7e8eed339d4ea5426c9fbd47279e5594965b7abef88f08f5499ca930cba9448ca", - "java\/jdk-21.0.2+13-jre\/lib\/libjawt.so": "7929c31ce9e1a215017fe36145bb9ee80c995d2e53e5f1d7dd36b251efee327e91df97368f136bdc0bc8833014e7b8bdb5d064371c5a93dc2516e9d102af782f", - "java\/jdk-21.0.2+13-jre\/lib\/libjdwp.so": "46e79d5181f96ed0b5a45395ca804832f492e351a2cd4e79dad6285a1b79e631c934690d0c68c47a339f57900daead29c39445eacfd231f0c74d1f6415a5f483", - "java\/jdk-21.0.2+13-jre\/lib\/libjimage.so": "66e33a7398a057937a904e372576f6486ce4274639e79363d9bfd54474a39645af879ad8b8b5b848f917efb16196e876caf28f540db1dfa18f5b513a1ba029cb", - "java\/jdk-21.0.2+13-jre\/lib\/libjli.so": "1687e9ba3ca18664f92bdc84e342414d96abf3a1029e47d73b11d7af237499545961ff00d0cef824feaea91bcf2c4dfa67bb982bd1c3b82aefc5a4d87f8ed2f9", - "java\/jdk-21.0.2+13-jre\/lib\/libjsig.so": "659cd0b0ed9426d26224373f85d0addd80349e2a76ad69df725dbaf3b613c11dd24260744051fcbf89116a1cae193d80708d70a4a468071ecf5b5ca80a76274f", - "java\/jdk-21.0.2+13-jre\/lib\/libjsound.so": "65f4708e89382f949292ea658da67f8cc794e35b4637a5781eefcd09ff30de6b7495d9d90cb26ac1f4589fbf0f1897f9fe9e611448cf3dd912f604e225e0538c", - "java\/jdk-21.0.2+13-jre\/lib\/libjsvml.so": "ad0c7a0f7191e6dea75c87f309da66905207b35de71914444f0ab8b34136a699f43798c8c9c5c430ff6a9194027557d0bd5e68d2cb90ef5df4df9bb27255cffb", - "java\/jdk-21.0.2+13-jre\/lib\/liblcms.so": "092fbc7cf3bc5c8b762b0960966e1e46160240e5757af9e1980822f6d717ab20ded782bbb8e9c3424d2164471cc8b6fb32612b798aae2c7b9842aa0d6c933903", - "java\/jdk-21.0.2+13-jre\/lib\/libmanagement.so": "2b02ac889aabd460f638f735349b9ecdf95a3df4471a35ded7313405e59c91973f67567a165fe915059b575a72880d6be28eed20ad08e20814a385a87c3d4d43", - "java\/jdk-21.0.2+13-jre\/lib\/libmanagement_agent.so": "6b98e9e505ee98bcf6901c39c27b53fbc1f60121d2d194edc7893c5b17186761fc3d66de5543f047746d88fed55f4ce8e3fa7f7ae1881f1f9f895825e9374a95", - "java\/jdk-21.0.2+13-jre\/lib\/libmanagement_ext.so": "55fc6bddefc826a8cd3f66624625900cfa5de7c7ea0e14f7106ba509d935a26904193ba7d0be4149b17dcb87c8729a235175137cb7f0847c07a4c3e5c9cea824", - "java\/jdk-21.0.2+13-jre\/lib\/libmlib_image.so": "f4617bec60984379f6cbe81eb1d4be9fdc4277fddd8c1d381c9cf3121ddec27a9d50bca1e70c9146cc6f314f3e38d42fd7835b79a919abb4484a49f6d27938f9", - "java\/jdk-21.0.2+13-jre\/lib\/libnet.so": "fe0023af3c3b183c13b091fb8608ce09e47d6fb209d5cd0334d6811ede4f41806e2077a43578d26a82acbdf2459dd7ef8596ebb0950b7e94542a6146d2163149", - "java\/jdk-21.0.2+13-jre\/lib\/libnio.so": "26539ed73e685977c4cc4b97da4edd346501019f8180daeafd894f835778777f67eeb52fde45f9d303436359678b0a04b07dfd7402c0f664a0f6fa6c5095823a", - "java\/jdk-21.0.2+13-jre\/lib\/libprefs.so": "4d31f33b5e905a0d2655dd1bb572ec0788181c9a4cf6f28482acaaa89f0959786b8c603a1a4b2e343b4d97d108f2a2041294798b07e209a242e11392f14387e9", - "java\/jdk-21.0.2+13-jre\/lib\/librmi.so": "11f106bbf97d7b8dafc10da95acfa8878131fd557c8c438efa6ca77defca7ba7e821c28d3b77089593a130ca5eeb99babb0cba5b2fa7d34825ba015dcae18930", - "java\/jdk-21.0.2+13-jre\/lib\/libsctp.so": "27ed970b13bcb535fb423e37d7826af640c7be833b730de00c9d759972b41650616c7f9c9251295c2a072a78c3456a3aa92e818f0d0b1402053313262aece324", - "java\/jdk-21.0.2+13-jre\/lib\/libsplashscreen.so": "a999eb715e9beeefa6e6844a93c595a9374e2194ebcbf384626c5cb002c36bc4f4eced091bf5db520f7f9ff225471ff08b8e2aed1cc2a2b8357a2f7fecf4d0e5", - "java\/jdk-21.0.2+13-jre\/lib\/libsyslookup.so": "7cee79233d7f997bb804c72766ed54def3e0e74769f8938858e65bfba584984d8b24ef15b5e6f6eb4ff87ed0d63682a0b4e444d03491c45e1351538597ed795d", - "java\/jdk-21.0.2+13-jre\/lib\/libverify.so": "22372ab221cb4b26b439abdd704d9828501ef2876e08152c46279bc9203e23ca93ec05dfe07c3eec24ae2ca4a4b22e1258b55af823aa3d7fe90159d6ecfeae1f", - "java\/jdk-21.0.2+13-jre\/lib\/libzip.so": "4f9502ec0d51b43dd2d37aea06df0fe86bf2fcc76f41b5dabb1ed78da286aebe5ec198c7bcf03e220cd1923d2d010408c01a8a95bcc64633bb9af69146a987cc", - "java\/jdk-21.0.2+13-jre\/lib\/modules": "f3bd47f9feaecdcb4797d332b7b3886722dced66790ca7bedd54f073113844499457e9ff66ba6f3c5c88e2bc604ad67a1a2aab5e937c183be7fd26c278d06ff7", - "java\/jdk-21.0.2+13-jre\/lib\/psfont.properties.ja": "8124b25decfa64a65433ff2ce1f0f7bdf304abe2997568abc35264a705f07152aa993b543da37c4132b4b1b606743c825c90a0eb17b268518d478f5cf0889062", - "java\/jdk-21.0.2+13-jre\/lib\/psfontj2d.properties": "e4ee92d4598385cb2f6f3a4db91ddabd7e615dc105ed26cdc5b5598d01c526cea7726ff93f92a308350229f2e5a5dd64cc0c38865dd97666368a330b410d4892", - "java\/jdk-21.0.2+13-jre\/lib\/security\/blocked.certs": "c6d8d4ee0eb7eeb14532512ff4310dff9dd4f31d112716fc67a1052d37eef18d4bd6eb58301c76167ad35d31e73f5b28993f4da8c5de2dbe3836a5ef7e9c8b7e", - "java\/jdk-21.0.2+13-jre\/lib\/security\/cacerts": "a01185b26d6921ba639790904a7a7f37bcc39f931d4c959d489580fc4e0d38ae33033c1afe5fb926e27c526225b634cf2817e73e539875f91491fb04e01c0465", - "java\/jdk-21.0.2+13-jre\/lib\/security\/default.policy": "ba7ca64aee530cc36aa7bb556c44f976cc636750d31d8d8fa3d8c3d0070dfa83cb85f56be9ddc0e8418852b3a70c2716343f832973a753d4debe30042f4bc1ed", - "java\/jdk-21.0.2+13-jre\/lib\/security\/public_suffix_list.dat": "6caaa3c2a53782fd286ab8db4a6a2470cd0150608c33b27aa506735d37185d26eedd27ef95fe0ade83d8301fdb8ac1c4b972a87b3714c303181f5cd67bc64815", - "java\/jdk-21.0.2+13-jre\/lib\/server\/classes.jsa": "23df528e05459e6cd96cd3e2977e750e64693b5e75cc766eee6f262e7e8abb8635b166ef3b7f57f0a8b2a352a12ce8c9d59092d1abecd4457e4f16c1e2f60e36", - "java\/jdk-21.0.2+13-jre\/lib\/server\/classes_nocoops.jsa": "9c6a4f9dea7d78cf399b64012196bced503001047f232d151e68eebf9765718f497d3a11f39cf6f58f2b8e4dd33d8ee621b7e1e9de13b269251a06807b973a9f", - "java\/jdk-21.0.2+13-jre\/lib\/server\/libjsig.so": "659cd0b0ed9426d26224373f85d0addd80349e2a76ad69df725dbaf3b613c11dd24260744051fcbf89116a1cae193d80708d70a4a468071ecf5b5ca80a76274f", - "java\/jdk-21.0.2+13-jre\/lib\/server\/libjvm.so": "8df080e567f3a2017395f6e542fdccd57515dbfcd5047bf8696855408670b2f0faa2ffc3b0651ca5306d507a77d737092fd450a87f0e9afbdb8c8e06b585fc59", - "java\/jdk-21.0.2+13-jre\/lib\/tzdb.dat": "958f835407e4a10a268bf76bc2ef0196ecd5fa92e139de4c3760544dbdf76f95e67865bac22406aef8ac5ae7508fe63cd1a688c8328e46b73a5867efa4f18d47", - "java\/jdk-21.0.2+13-jre\/release": "9424659912a18e1e6368d62240542b4e821672ec4c3fa557665b1fbf3060d763c9de4edf525e80cea1ae2fb259821b98b3854f65f1beab080beeb0802ad43f98", - "jsignpdf-2.2.2.zip": "dac3fc83ea6ffede68f53e9db33161075db7b9b4028b5216522501b5cdf5f9815adb966c1af7a80d42ba09edad6efbf71d4b7ec4236cd5d7236d3868178022a5", - "jsignpdf-2.2.2\/InstallCert.jar": "748afcd66d2cb10d996ee83df4b7354f3cde9d73e8f5388b89107bd82a046cebd7982f38745c61b8dd1a5ca2099eb0e290281ea699dd6f2ebd32bc13a2794569", - "jsignpdf-2.2.2\/JSignPdf.jar": "dbc0bb7af34cc1c034cae7f5c0e05702260a26684a56ab6254025fe7a0afbf01e68f8664d73bab4b71b97142373143d1159068181ae6e137740485c38c475572", - "jsignpdf-2.2.2\/conf\/conf.properties": "9867ca50e21f620a85aeb77b1eeada52998ff5bed05c98e34365d78d38b5df9716e1e1cb0c316f26fbbac799faad7e73c6ccb8e8ecb3422f085da5b33b89862d", - "jsignpdf-2.2.2\/conf\/pkcs11.cfg": "7755a14ea0a9486948d25799134bdaa34a2bc9807b7470dbfd88fadd7eb1a3cb2d40dba830320ed864598b70f5fa4c7f426a3d992f9ce80298471b5346a890ca", - "jsignpdf-2.2.2\/docs\/JSignPdf.pdf": "fcf4cc584f7aaf039cf458bad5cf8165de586bb124088945ad0f293efca7c2803457e40ced4e20ed050d3fb98625f038e65533a8d3adb84d73a8a42f07b1a592", - "jsignpdf-2.2.2\/jsignpdf.sh": "6f7e547d846b8f74abff2f6a85fe30ce6be98779565f2eed1714ad2363ccf4bd6bb999a4de08d201e55d2c6ab21475b9afba259716e99c3cb673fe175c59c4e5", - "jsignpdf-2.2.2\/licenses\/MPL-2.0.txt": "7479c0cc9df5359cfffcb421e108dfbb4a5493589bbb3ff998f4c0c0499be3d974e608939f07c9644ae3936f008d299f0da80d4b181367284299f4ac3841eb73", - "jsignpdf-2.2.2\/licenses\/ThirdPartyLicenses\/DejaVu-font.license": "eb1b3f39d42d7a9a00c31ed6e97608b693fd9e519d5775ad83dd10f5af1172aa450eda6a1ec301e7dc348cfeb4c279067388ad88e76fbf2073fb100b648209e0", - "jsignpdf-2.2.2\/licenses\/ThirdPartyLicenses\/InstallCert.license": "ded0e324601bf2826998bfaf5c0aeb854cdb2fcad3b5046e901612372dafcf45e41b59a0c43d341d98edeec4ef7a078797f91abba104d3193d996677f2307a00", - "jsignpdf-2.2.2\/licenses\/ThirdPartyLicenses\/PdfRenderer.license": "c929152d51e8db633124dc8ec3272b8f76172c4820a587ebba0fcdb0c2ffa5eb90bc795696a2a8a863521b347822856b0e44d576649a3e85af21c17f28a7e437", - "jsignpdf-2.2.2\/licenses\/ThirdPartyLicenses\/apache-commons.license": "d43a0e998d3e817e71501086f4d6a46f1f18b46791c491932887ee15efd51426c606f92620766ba2688276406be970b32dbd18b4a54483a8466e05a6cd81d1c1", - "jsignpdf-2.2.2\/licenses\/ThirdPartyLicenses\/bouncycastle.license": "806473fdb2d8ea53e4f812a50ecd450bdb187e2fbd469e75ccd71142830d544417300bfed99967db39eea0e950978b012b9a48b5f73f4fe732759234ae05016d", - "jsignpdf-2.2.2\/licenses\/ThirdPartyLicenses\/icu4j.license": "085545902048420cddc84a6474238075ecb0839c158683256b939292f9067a49593714ac58eec4c445e36ea5a511e254f63fb97b4f9fa100d3f61437b5d2ef7b", - "jsignpdf-2.2.2\/licenses\/ThirdPartyLicenses\/pdfbox.license": "d43a0e998d3e817e71501086f4d6a46f1f18b46791c491932887ee15efd51426c606f92620766ba2688276406be970b32dbd18b4a54483a8466e05a6cd81d1c1", - "jsignpdf-2.2.2\/licenses\/ThirdPartyLicenses\/pokrytie_font.license": "ead14823e799bb46e4aa5ab0a2fb3efdc5d6bf73ccb4fdce892445d1852c0e6599c9e2fd2f83a953878eb34af3750920642275d83798364f134b78340582948c", - "jsignpdf-2.2.2\/licenses\/ThirdPartyLicenses\/splashscreen.info": "2be843531ec9d89bb953e03f26d550d9e3e6b567f63d0abbe9ed81f61e8967e53e096b63cacc681561a2006dbf498ef8eaa0ffbd1f60bcc14907c8222bf6db1c", - "jsignpdf-2.2.2\/licenses\/lgpl-2.1.txt": "c929152d51e8db633124dc8ec3272b8f76172c4820a587ebba0fcdb0c2ffa5eb90bc795696a2a8a863521b347822856b0e44d576649a3e85af21c17f28a7e437", - "pdftk.jar": "9ac70daf30c98209892895c05782bf08f69251e321887d3e30b3a8b0868d0e749da5a8f35584d46441c8b83090d0c4228bfe2185862c58231dc929b25b9d6b57" - }, - "signature": "ZcGk0YXYabX\/mjUJqBbAKYmzjXkTxvOEBpbx4\/QWih1XfXLBhbplttW7n+Pszjz2rWU9tNCt7guwHP2xdcev3ZWFx\/iCHp7rUc67zF+9Nw8LGYiVbeG+7M0zqwiqUtlyNpuNG8dyL5ePzqkcxK91W8AzWoth4ceShKwZNORAAJh5T4SAgzc+ThCbB0jDk+F957s0ZGfdPxxXc9Pd\/xqk1kvfQ3YMSkpC6bceulosZQUJFIREkQKTdLN\/FKAkLFcuURCKWuDMqBZ7qKF7uxFba3KIwDf+Bjd4zQL9DEoixQNuo2XXpg3dBAU6aqkN0BYvdgDkT7G7i0C2UdgSsQbTgNisq5oaUpf3ZAhu2iXo+5orUCv4fa1kWnJojmi4Gqlih4IY65oBYPQVBzgxJms\/VFpgFqnwms2moAGmXjxe+DyJ6O0reJHC8PlZBuIudvdIk5vMVB1fBuHFY4m5WP572oUOsrCtvRMMnc2xR1VPmeieVmatAQNr3Uj9vLnYfVmQyNDv1D9vXCq0oda2W4PYOd8vLI04O1YRoiM5lEyZJanVPQZKCOFb8nV6mApD1Zn0Hida3n3cVi\/O6E456DjAk3rj1wxQJEB8d6HoZ6myKpiBVoncdkQbnQX6KhItLIe5rr5VdBZ6mOENeLw7rLY+ORwznbVuXm\/gWCcT\/tjiupo=", - "certificate": "-----BEGIN CERTIFICATE-----\r\nMIIEBDCCAuwCAhF4MA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD\r\nVQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI\r\nMTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB\r\ndXRob3JpdHkwHhcNMjEwMzA0MTk1NzQ1WhcNMzEwNjEwMTk1NzQ1WjAUMRIwEAYD\r\nVQQDDAlsaWJyZXNpZ24wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDq\r\nNU7W4kX445A4yMlADzxuNCouzzIYJBDRZXrKuz5OtbApKY5mPqfXGEpc8N04+eAJ\r\n5EJz5f9r0WxVcWGtyFN1sPObAsoMGyhOzNvAGaveL40xBsc7LdQgCR2JraInHH\/e\r\nMNtkgHQcWL5nihqYIEWvMeVt3uMTiI05F3SjW4+u\/NaRRw\/5y5l5W4Fy6VPzPW0P\r\n22Wmllkb3BFG16C6hHG\/+qE8pf12AcxQZ3B21MbPkHjOjxSz6NS74jGIVRtcn6dO\r\ny26XZ1XoeNUPZDyLFluYCBw5fgTIIU+721mkkA7EjP9RighygVGk4WII7l9Pc+Sf\r\nNwcxQykNdEnZ67ETSr4v1CpArAeXZ2dEZ\/b9QqI\/MCGw0Aa\/Pv2vDc8McFFBBTrt\r\nPDvn0TG0RdfuFAkYdOpFjH3urGUEvcJ\/+lFvRVUu203PHLfx72zNI3XVXui\/slf3\r\noK4LsQrbvj+heYnNXyr5UQAzgXW9JDiXE0sBxfzUz2XKlbuuNpLLE9EkFFQ5LyZJ\r\nG3l1f\/yO3CvGLancbhCvRjo6Lts38GjmkWQT+0BNBpwYhoAd4wopnMYphI9qldbp\r\n1XPWBqb+0w1p6bkIHmci8D\/whC0\/BEHoCs+DpRciRZM0FqW7frZcEGeO6YOoDWJ2\r\nCAhwXGodT4iV8RtVUC6\/arGGUal\/YqBk2M\/9zK6eMwIDAQABMA0GCSqGSIb3DQEB\r\nCwUAA4IBAQBWMFEq++xjRqFsWNPpoTtkfuj0PUajfRHBGzSUXccz0hw8kdR4C2xx\r\nhkYlJ9kqyWNxO1h4urQL5cM1sbl4xf5CI9xf7iuOcB06\/kn3umLmruRec32WG2bS\r\nqAWnnljGCX4sVY8oSbdaUopXE9o9pl966XQ5858c+w9ydkjMDnfOmzrCpgHrJefN\r\n94hIttjJsV8te15VcKoNUxsrZBlPIrpueUQRc13Z9CWp8eRXl4J4CZfVFSY7T4ho\r\nBlNtdPas2R9HJJDYEGS+fg5dfLLvTL4qPSxLjm753pJprfrDxfE9qQl0xtIe8aaw\r\nKFJ\/AK3JTRBkBwsgAE5OYEXTUV9oNS2j\r\n-----END CERTIFICATE-----" -} \ No newline at end of file From 3fa1e9fb4e77f1dedd47f60a13e12151cbc4629d Mon Sep 17 00:00:00 2001 From: Vitor Mattos Date: Fri, 31 May 2024 14:09:14 -0300 Subject: [PATCH 04/50] chore: remove DIRECTORY_SEPARATOR Nextcloud is not compatible with Windows Signed-off-by: Vitor Mattos --- lib/Service/Install/InstallService.php | 32 +++++++++++++------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/lib/Service/Install/InstallService.php b/lib/Service/Install/InstallService.php index 7979e2f9fa..e29ef67209 100644 --- a/lib/Service/Install/InstallService.php +++ b/lib/Service/Install/InstallService.php @@ -136,7 +136,7 @@ private function getInternalPathOfFile(ISimpleFile $node): string { $reflectionProperty = $reflection->getProperty('parentFolder'); $reflectionProperty->setAccessible(true); $folder = $reflectionProperty->getValue($node); - $path = $folder->getInternalPath() . DIRECTORY_SEPARATOR . $node->getName(); + $path = $folder->getInternalPath() . '/' . $node->getName(); } elseif ($reflection->hasProperty('file')) { $reflectionProperty = $reflection->getProperty('file'); $reflectionProperty->setAccessible(true); @@ -332,8 +332,8 @@ public function installJava(?bool $async = false): void { $this->runAsync(); return; } - $extractDir = $this->getFullPath() . DIRECTORY_SEPARATOR . 'java'; - $javaFolder = $this->getFolder('java'); + $extractDir = $this->getFullPath() . '/java'; + $javaFolder = $this->getFolder('/java'); /** * Steps to update: @@ -365,7 +365,7 @@ public function installJava(?bool $async = false): void { } catch (NotFoundException $th) { $compressedFile = $javaFolder->newFile($compressedFileName); } - $comporessedInternalFileName = $this->getDataDir() . DIRECTORY_SEPARATOR . $this->getInternalPathOfFile($compressedFile); + $comporessedInternalFileName = $this->getDataDir() . '/' . $this->getInternalPathOfFile($compressedFile); $this->download($url, 'java', $comporessedInternalFileName, $hash, 'sha256'); @@ -426,17 +426,17 @@ public function installJSignPdf(?bool $async = false): void { } catch (\Throwable $th) { $compressedFile = $this->getFolder()->newFile($compressedFileName); } - $comporessedInternalFileName = $this->getDataDir() . DIRECTORY_SEPARATOR . $this->getInternalPathOfFile($compressedFile); + $comporessedInternalFileName = $this->getDataDir() . '/' . $this->getInternalPathOfFile($compressedFile); $url = 'https://github.com/intoolswetrust/jsignpdf/releases/download/JSignPdf_' . str_replace('.', '_', JSignPdfHandler::VERSION) . '/jsignpdf-' . JSignPdfHandler::VERSION . '.zip'; /** WHEN UPDATE version: generate this hash handmade and update here */ $hash = '7c66f5a9f5e7e35b601725414491a867'; $this->download($url, 'JSignPdf', $comporessedInternalFileName, $hash); - $zip = new ZIP($extractDir . DIRECTORY_SEPARATOR . $compressedFileName); + $zip = new ZIP($extractDir . '/' . $compressedFileName); $zip->extract($extractDir); - $fullPath = $extractDir . DIRECTORY_SEPARATOR . 'jsignpdf-' . JSignPdfHandler::VERSION . DIRECTORY_SEPARATOR . 'JSignPdf.jar'; + $fullPath = $extractDir . '/jsignpdf-' . JSignPdfHandler::VERSION . '/JSignPdf.jar'; $this->appConfig->setAppValue('jsignpdf_jar_path', $fullPath); $this->removeDownloadProgress(); } @@ -451,7 +451,7 @@ public function uninstallJSignPdf(): void { // Remove prefix $path = explode($name, $jsignpdJarPath)[1]; // Remove sufix - $path = trim($path, DIRECTORY_SEPARATOR . 'JSignPdf.jar'); + $path = trim($path, '/JSignPdf.jar'); try { $folder = $appFolder->getFolder($path); $folder->delete(); @@ -472,7 +472,7 @@ public function installPdftk(?bool $async = false): void { } catch (\Throwable $th) { $file = $this->getFolder()->newFile('pdftk.jar'); } - $fullPath = $this->getDataDir() . DIRECTORY_SEPARATOR . $this->getInternalPathOfFile($file); + $fullPath = $this->getDataDir() . '/' . $this->getInternalPathOfFile($file); $url = 'https://gitlab.com/api/v4/projects/5024297/packages/generic/pdftk-java/v' . self::PDFTK_VERSION . '/pdftk-all.jar'; /** WHEN UPDATE version: generate this hash handmade and update here */ $hash = '59a28bed53b428595d165d52988bf4cf'; @@ -543,15 +543,15 @@ private function installCfssl64(): void { $hash = $this->getHash($folder, 'cfssl', $download['file'], self::CFSSL_VERSION, $checksumUrl); $file = $folder->newFile($download['destination']); - $fullPath = $this->getDataDir() . DIRECTORY_SEPARATOR . $this->getInternalPathOfFile($file); + $fullPath = $this->getDataDir() . '/' . $this->getInternalPathOfFile($file); $this->download($baseUrl . $download['file'], $download['destination'], $fullPath, $hash, 'sha256'); chmod($fullPath, 0700); } - $cfsslBinPath = $this->getDataDir() . DIRECTORY_SEPARATOR . - $this->getInternalPathOfFolder($this->getFolder()) . DIRECTORY_SEPARATOR . + $cfsslBinPath = $this->getDataDir() . '/' . + $this->getInternalPathOfFolder($this->getFolder()) . '/' . $downloads[0]['destination']; $this->appConfig->setAppValue('cfssl_bin', $cfsslBinPath); } @@ -573,20 +573,20 @@ private function installCfsslArm(): void { $compressedFile = $cfsslFolder->newFile($compressedFileName); } - $comporessedInternalFileName = $this->getDataDir() . DIRECTORY_SEPARATOR . $this->getInternalPathOfFile($compressedFile); + $comporessedInternalFileName = $this->getDataDir() . '/' . $this->getInternalPathOfFile($compressedFile); $this->download($url, 'cfssl', $comporessedInternalFileName, $hash, 'sha256'); $this->appConfig->deleteAppValue('cfssl_bin'); $extractor = new TAR($comporessedInternalFileName); - $extractDir = $this->getFullPath() . DIRECTORY_SEPARATOR . 'cfssl'; + $extractDir = $this->getFullPath() . '/cfssl'; $result = $extractor->extract($extractDir); if (!$result) { throw new \RuntimeException('Error to extract xz file. Install xz. Read more: https://github.com/codemasher/php-ext-xz'); } - $cfsslBinPath = $this->getDataDir() . DIRECTORY_SEPARATOR . - $this->getInternalPathOfFolder($this->getFolder()) . DIRECTORY_SEPARATOR . + $cfsslBinPath = $this->getDataDir() . '/' . + $this->getInternalPathOfFolder($this->getFolder()) . '/' . 'cfssl/usr/bin/cfssl'; $this->appConfig->setAppValue('cfssl_bin', $cfsslBinPath); } From 8c98c6f13e979fd435a6878d3fb01c4c24576968 Mon Sep 17 00:00:00 2001 From: Vitor Mattos Date: Fri, 31 May 2024 14:10:03 -0300 Subject: [PATCH 05/50] chore: consider architecture to signature files Signed-off-by: Vitor Mattos --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 2c66f643ae..ccdf67ab22 100644 --- a/.gitignore +++ b/.gitignore @@ -12,4 +12,4 @@ node_modules/ .phpunit.result.cache *.phar /src/__test__/coverage -/appinfo/install-signature.json +/appinfo/install-*.json From fae55ddf01ecbc89b911df5dc23a13bb0f228454 Mon Sep 17 00:00:00 2001 From: Vitor Mattos Date: Fri, 31 May 2024 14:13:00 -0300 Subject: [PATCH 06/50] chore: make method private Isn't used at other places Signed-off-by: Vitor Mattos --- lib/Service/Install/InstallService.php | 2 +- tests/Unit/TestCase.php | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/Service/Install/InstallService.php b/lib/Service/Install/InstallService.php index e29ef67209..9c8c05da9a 100644 --- a/lib/Service/Install/InstallService.php +++ b/lib/Service/Install/InstallService.php @@ -151,7 +151,7 @@ private function getDataDir(): string { return $dataDir; } - public function getFullPath(): string { + private function getFullPath(): string { $folder = $this->getFolder(); return $this->getDataDir() . '/' . $this->getInternalPathOfFolder($folder); } diff --git a/tests/Unit/TestCase.php b/tests/Unit/TestCase.php index 219101e219..97fa1f4731 100644 --- a/tests/Unit/TestCase.php +++ b/tests/Unit/TestCase.php @@ -190,7 +190,7 @@ public function deleteUserIfExists($username): void { private function getBinariesFromCache(): void { /** @var \OCA\Libresign\Service\Install\InstallService */ $install = \OCP\Server::get(\OCA\Libresign\Service\Install\InstallService::class); - $appPath = $install->getFullPath(); + $appPath = self::invokePrivate($install, 'getFullPath'); $cachePath = preg_replace('/\/.*\/appdata_[a-z0-9]*/', \OC::$server->getTempManager()->getTempBaseDir(), $appPath); if (!file_exists($cachePath)) { return; @@ -204,7 +204,7 @@ private function getBinariesFromCache(): void { private function backupBinaries(): void { /** @var \OCA\Libresign\Service\Install\InstallService */ $install = \OCP\Server::get(\OCA\Libresign\Service\Install\InstallService::class); - $appPath = $install->getFullPath(); + $appPath = self::invokePrivate($install, 'getFullPath'); if (!is_readable($appPath)) { return; } From 46adbdf0abfc156318439e42789c45f0c8658759 Mon Sep 17 00:00:00 2001 From: Vitor Mattos Date: Fri, 31 May 2024 14:16:16 -0300 Subject: [PATCH 07/50] chore: get architecture when construct class Signed-off-by: Vitor Mattos --- lib/Service/Install/InstallService.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/Service/Install/InstallService.php b/lib/Service/Install/InstallService.php index 9c8c05da9a..a75266b263 100644 --- a/lib/Service/Install/InstallService.php +++ b/lib/Service/Install/InstallService.php @@ -75,6 +75,7 @@ class InstallService { 'pdftk', 'cfssl' ]; + private string $architecture; public function __construct( ICacheFactory $cacheFactory, @@ -88,6 +89,7 @@ public function __construct( ) { $this->cache = $cacheFactory->createDistributed('libresign-setup'); $this->appData = $appDataFactory->get('libresign'); + $this->architecture = php_uname('m'); } public function setOutput(OutputInterface $output): void { @@ -345,11 +347,10 @@ public function installJava(?bool $async = false): void { */ if (PHP_OS_FAMILY === 'Linux') { $linuxDistribution = $this->getLinuxDistributionToDownloadJava(); - $architecture = php_uname('m'); - if ($architecture === 'x86_64') { + if ($this->architecture === 'x86_64') { $compressedFileName = 'OpenJDK21U-jre_x64_' . $linuxDistribution . '_hotspot_' . self::JAVA_PARTIAL_VERSION . '.tar.gz'; $url = 'https://github.com/adoptium/temurin21-binaries/releases/download/jdk-21.0.2+13/' . $compressedFileName; - } elseif ($architecture === 'aarch64') { + } elseif ($this->architecture === 'aarch64') { $compressedFileName = 'OpenJDK21U-jre_aarch64_' . $linuxDistribution . '_hotspot_' . self::JAVA_PARTIAL_VERSION . '.tar.gz'; $url = 'https://github.com/adoptium/temurin21-binaries/releases/download/jdk-21.0.2+13/' . $compressedFileName; } @@ -359,7 +360,7 @@ public function installJava(?bool $async = false): void { } $folder = $this->getFolder(); $checksumUrl = $url . '.sha256.txt'; - $hash = $this->getHash($folder, 'java_' . $linuxDistribution . '_' . $architecture, $compressedFileName, self::JAVA_PARTIAL_VERSION, $checksumUrl); + $hash = $this->getHash($folder, 'java_' . $linuxDistribution . '_' . $this->architecture, $compressedFileName, self::JAVA_PARTIAL_VERSION, $checksumUrl); try { $compressedFile = $javaFolder->getFile($compressedFileName); } catch (NotFoundException $th) { @@ -515,10 +516,9 @@ public function installCfssl(?bool $async = false): void { if (PHP_OS_FAMILY !== 'Linux') { throw new RuntimeException(sprintf('OS_FAMILY %s is incompatible with LibreSign.', PHP_OS_FAMILY)); } - $architecture = php_uname('m'); - if ($architecture === 'x86_64') { + if ($this->architecture === 'x86_64') { $this->installCfssl64(); - } elseif ($architecture === 'aarch64') { + } elseif ($this->architecture === 'aarch64') { $this->installCfsslArm(); } $this->removeDownloadProgress(); From 6e264ca1e3146b37c1695272fbfc2ab453d01d1e Mon Sep 17 00:00:00 2001 From: Vitor Mattos Date: Fri, 31 May 2024 18:12:25 -0300 Subject: [PATCH 08/50] chore: store install files inside specific processor architecture folder Necessary to be possible sign the setup files and download all files to sign. Signed-off-by: Vitor Mattos --- lib/Service/Install/InstallService.php | 48 +++++++++++++++-------- lib/Service/Install/SignFiles.php | 6 ++- tests/Unit/Service/InstallServiceTest.php | 20 ++++++++++ 3 files changed, 55 insertions(+), 19 deletions(-) diff --git a/lib/Service/Install/InstallService.php b/lib/Service/Install/InstallService.php index a75266b263..87d04ac6f3 100644 --- a/lib/Service/Install/InstallService.php +++ b/lib/Service/Install/InstallService.php @@ -89,29 +89,43 @@ public function __construct( ) { $this->cache = $cacheFactory->createDistributed('libresign-setup'); $this->appData = $appDataFactory->get('libresign'); - $this->architecture = php_uname('m'); + $this->setArchitecture(php_uname('m')); } public function setOutput(OutputInterface $output): void { $this->output = $output; } - private function getFolder(string $path = ''): ISimpleFolder { - $folder = $this->appData->getFolder('/'); - if ($path) { + public function setArchitecture(string $architecture): void { + $this->architecture = $architecture; + } + + private function getFolder(string $path = '', ?ISimpleFolder $folder = null): ISimpleFolder { + if (!$folder) { + $folder = $this->appData->getFolder('/'); + if (!$path) { + $path = $this->architecture; + } else { + $path = $this->architecture . '/' . $path; + } + $path = explode('/', $path); + foreach ($path as $snippet) { + $folder = $this->getFolder($snippet, $folder); + } + return $folder; + } + try { + $folder = $folder->getFolder($path, $folder); + } catch (\Throwable $th) { try { - $folder = $folder->getFolder($path); - } catch (\Throwable $th) { - try { - $folder = $folder->newFolder($path); - } catch (NotPermittedException $e) { - $user = posix_getpwuid(posix_getuid()); - throw new LibresignException( - $e->getMessage() . '. ' . - 'Permission problems. ' . - 'Maybe this could fix: chown -R ' . $user['name'] . ' ' . $this->getDataDir() - ); - } + $folder = $folder->newFolder($path); + } catch (NotPermittedException $e) { + $user = posix_getpwuid(posix_getuid()); + throw new LibresignException( + $e->getMessage() . '. ' . + 'Permission problems. ' . + 'Maybe this could fix: chown -R ' . $user['name'] . ' ' . $this->getDataDir() + ); } } return $folder; @@ -360,7 +374,7 @@ public function installJava(?bool $async = false): void { } $folder = $this->getFolder(); $checksumUrl = $url . '.sha256.txt'; - $hash = $this->getHash($folder, 'java_' . $linuxDistribution . '_' . $this->architecture, $compressedFileName, self::JAVA_PARTIAL_VERSION, $checksumUrl); + $hash = $this->getHash($folder, 'java_' . $linuxDistribution, $compressedFileName, self::JAVA_PARTIAL_VERSION, $checksumUrl); try { $compressedFile = $javaFolder->getFile($compressedFileName); } catch (NotFoundException $th) { diff --git a/lib/Service/Install/SignFiles.php b/lib/Service/Install/SignFiles.php index 2813ccf0a4..1442cc2261 100644 --- a/lib/Service/Install/SignFiles.php +++ b/lib/Service/Install/SignFiles.php @@ -42,6 +42,7 @@ class SignFiles { 'cfssl_config', 'unauthetnicated', ]; + private string $architecture; public function __construct( private FileAccessHelper $fileAccessHelper, private IConfig $config, @@ -72,6 +73,7 @@ public function writeAppSignature( RSA $privateKey, string $architecture, ) { + $this->architecture = $architecture; $appInfoDir = __DIR__ . '/../../../appinfo'; try { $this->fileAccessHelper->assertDirectoryExists($appInfoDir); @@ -80,7 +82,7 @@ public function writeAppSignature( $hashes = $this->generateHashes($iterator); $signature = $this->createSignatureData($hashes, $certificate, $privateKey); $this->fileAccessHelper->file_put_contents( - $appInfoDir . '/install-' . $architecture . '.json', + $appInfoDir . '/install-' . $this->architecture . '.json', json_encode($signature, JSON_PRETTY_PRINT) ); } catch (\Exception $e) { @@ -110,7 +112,7 @@ private function getInternalPathOfFolder(ISimpleFolder $node): string { private function getInstallPath(): string { $folder = $this->getDataDir() . '/' . - $this->getInternalPathOfFolder($this->appData->getFolder('/')); + $this->getInternalPathOfFolder($this->appData->getFolder($this->architecture)); return $folder; } diff --git a/tests/Unit/Service/InstallServiceTest.php b/tests/Unit/Service/InstallServiceTest.php index 4bf06e4883..cdad8b8ebb 100644 --- a/tests/Unit/Service/InstallServiceTest.php +++ b/tests/Unit/Service/InstallServiceTest.php @@ -151,4 +151,24 @@ public function providerDownloadCli(): array { ], ]; } + + /** + * @dataProvider providerGetFolder + */ + public function testGetFolder(string $path): void { + $install = \OCP\Server::get(\OCA\Libresign\Service\Install\InstallService::class); + + $appPath = self::invokePrivate($install, 'getFullPath'); + + self::invokePrivate($install, 'getFolder', [$path]); + + $this->assertDirectoryExists($appPath . '/' . $path); + } + + public static function providerGetFolder(): array { + return [ + [''], + ['test'], + ]; + } } From fa6460097029d75ee525c048fd4b3b69cbd80ed8 Mon Sep 17 00:00:00 2001 From: Vitor Mattos Date: Fri, 31 May 2024 18:40:41 -0300 Subject: [PATCH 09/50] feat: make possible choose architecture when install binaries Signed-off-by: Vitor Mattos --- lib/Command/Install.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/Command/Install.php b/lib/Command/Install.php index 00901807be..0a8cc47f54 100644 --- a/lib/Command/Install.php +++ b/lib/Command/Install.php @@ -62,6 +62,12 @@ protected function configure(): void { shortcut: null, mode: InputOption::VALUE_NONE, description: 'Java' + ) + ->addOption( + name: 'architecture', + shortcut: null, + mode: InputOption::VALUE_REQUIRED, + description: 'x86_64 or aarch64' ); } @@ -70,6 +76,10 @@ protected function execute(InputInterface $input, OutputInterface $output): int $this->installService->setOutput($output); try { + $architecture = (string) $input->getOption('architecture'); + if (in_array($architecture, ['x86_64', 'aarch64'])) { + $this->installService->setArchitecture($architecture); + } $all = $input->getOption('all'); if ($input->getOption('java') || $all) { $this->installService->installJava(); From 8afcf994431e8ea0d6f20b26afc08296650fbe49 Mon Sep 17 00:00:00 2001 From: Vitor Mattos Date: Sat, 1 Jun 2024 11:00:47 -0300 Subject: [PATCH 10/50] fix: prevent to use Nextcloud internal classes The Nextcloud classes have database dependencies that broke the tests Signed-off-by: Vitor Mattos --- tests/Unit/TestCase.php | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/tests/Unit/TestCase.php b/tests/Unit/TestCase.php index 97fa1f4731..23672b1744 100644 --- a/tests/Unit/TestCase.php +++ b/tests/Unit/TestCase.php @@ -188,9 +188,7 @@ public function deleteUserIfExists($username): void { } private function getBinariesFromCache(): void { - /** @var \OCA\Libresign\Service\Install\InstallService */ - $install = \OCP\Server::get(\OCA\Libresign\Service\Install\InstallService::class); - $appPath = self::invokePrivate($install, 'getFullPath'); + $appPath = $this->getFullLiresignAppFolder(); $cachePath = preg_replace('/\/.*\/appdata_[a-z0-9]*/', \OC::$server->getTempManager()->getTempBaseDir(), $appPath); if (!file_exists($cachePath)) { return; @@ -201,10 +199,16 @@ private function getBinariesFromCache(): void { $this->recursiveCopy($cachePath, $appPath); } + private function getFullLiresignAppFolder(): string { + $libresignPath = glob('../../data/appdata_*/libresign'); + if (empty($libresignPath)) { + return ''; + } + return realpath(current($libresignPath)); + } + private function backupBinaries(): void { - /** @var \OCA\Libresign\Service\Install\InstallService */ - $install = \OCP\Server::get(\OCA\Libresign\Service\Install\InstallService::class); - $appPath = self::invokePrivate($install, 'getFullPath'); + $appPath = $this->getFullLiresignAppFolder(); if (!is_readable($appPath)) { return; } From 617d85be04a2b1abd57981752b26b69894526ce4 Mon Sep 17 00:00:00 2001 From: Vitor Mattos Date: Sat, 1 Jun 2024 12:40:33 -0300 Subject: [PATCH 11/50] chore: performance optimization Prevent to execute method when haven't the necessary data. Signed-off-by: Vitor Mattos --- tests/Unit/TestCase.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/Unit/TestCase.php b/tests/Unit/TestCase.php index 23672b1744..31957f6709 100644 --- a/tests/Unit/TestCase.php +++ b/tests/Unit/TestCase.php @@ -189,6 +189,9 @@ public function deleteUserIfExists($username): void { private function getBinariesFromCache(): void { $appPath = $this->getFullLiresignAppFolder(); + if (!$appPath) { + return; + } $cachePath = preg_replace('/\/.*\/appdata_[a-z0-9]*/', \OC::$server->getTempManager()->getTempBaseDir(), $appPath); if (!file_exists($cachePath)) { return; From 4b072dc6898996d5f7ebd40c4b1ef6b7c37dae5a Mon Sep 17 00:00:00 2001 From: Vitor Mattos Date: Sat, 1 Jun 2024 12:41:15 -0300 Subject: [PATCH 12/50] fix: check if don't throw exception This test will fail when isn't possible to fetch a folder Signed-off-by: Vitor Mattos --- tests/Unit/Service/InstallServiceTest.php | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/tests/Unit/Service/InstallServiceTest.php b/tests/Unit/Service/InstallServiceTest.php index cdad8b8ebb..6f8fe889d3 100644 --- a/tests/Unit/Service/InstallServiceTest.php +++ b/tests/Unit/Service/InstallServiceTest.php @@ -157,12 +157,8 @@ public function providerDownloadCli(): array { */ public function testGetFolder(string $path): void { $install = \OCP\Server::get(\OCA\Libresign\Service\Install\InstallService::class); - - $appPath = self::invokePrivate($install, 'getFullPath'); - self::invokePrivate($install, 'getFolder', [$path]); - - $this->assertDirectoryExists($appPath . '/' . $path); + $this->expectNotToPerformAssertions(); } public static function providerGetFolder(): array { From 95ff5967ed7f3da601277754510456d7da459015 Mon Sep 17 00:00:00 2001 From: Vitor Mattos Date: Sat, 1 Jun 2024 12:43:42 -0300 Subject: [PATCH 13/50] chore: add more scenarios Signed-off-by: Vitor Mattos --- tests/Unit/Service/InstallServiceTest.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/Unit/Service/InstallServiceTest.php b/tests/Unit/Service/InstallServiceTest.php index 6f8fe889d3..c6da9ed674 100644 --- a/tests/Unit/Service/InstallServiceTest.php +++ b/tests/Unit/Service/InstallServiceTest.php @@ -165,6 +165,8 @@ public static function providerGetFolder(): array { return [ [''], ['test'], + ['test/folder1'], + ['test/folder1/folder2'], ]; } } From acd9b1155b23de13b41df6620ade27c053355066 Mon Sep 17 00:00:00 2001 From: Vitor Mattos Date: Sat, 1 Jun 2024 12:55:50 -0300 Subject: [PATCH 14/50] fix: get binary path from database Signed-off-by: Vitor Mattos --- lib/Handler/CertificateEngine/CfsslHandler.php | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/lib/Handler/CertificateEngine/CfsslHandler.php b/lib/Handler/CertificateEngine/CfsslHandler.php index 21bdfbdaf8..eb71bdfd34 100644 --- a/lib/Handler/CertificateEngine/CfsslHandler.php +++ b/lib/Handler/CertificateEngine/CfsslHandler.php @@ -374,8 +374,8 @@ private function checkBinaries(): array { ->setResource('cfssl'), ]; } - $cfsslInstalled = $this->appConfig->getAppValue('cfssl_bin'); - if (!$cfsslInstalled) { + $binary = $this->appConfig->getAppValue('cfssl_bin'); + if (!$binary) { return [ (new ConfigureCheckHelper()) ->setErrorMessage('CFSSL not installed.') @@ -384,11 +384,6 @@ private function checkBinaries(): array { ]; } - $instanceId = $this->systemConfig->getValue('instanceid', null); - $binary = $this->systemConfig->getValue('datadirectory', \OC::$SERVERROOT . '/data/') . DIRECTORY_SEPARATOR . - 'appdata_' . $instanceId . DIRECTORY_SEPARATOR . - Application::APP_ID . DIRECTORY_SEPARATOR . - 'cfssl'; if (!file_exists($binary)) { return [ (new ConfigureCheckHelper()) From 2b3059d698f693c9b0a008194764e698dfbf3b01 Mon Sep 17 00:00:00 2001 From: Vitor Mattos Date: Sat, 1 Jun 2024 12:59:30 -0300 Subject: [PATCH 15/50] fix: cs Signed-off-by: Vitor Mattos --- lib/Handler/CertificateEngine/CfsslHandler.php | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/Handler/CertificateEngine/CfsslHandler.php b/lib/Handler/CertificateEngine/CfsslHandler.php index eb71bdfd34..627f1328c6 100644 --- a/lib/Handler/CertificateEngine/CfsslHandler.php +++ b/lib/Handler/CertificateEngine/CfsslHandler.php @@ -28,7 +28,6 @@ use GuzzleHttp\Exception\ConnectException; use GuzzleHttp\Exception\RequestException; use OC\SystemConfig; -use OCA\Libresign\AppInfo\Application; use OCA\Libresign\Exception\LibresignException; use OCA\Libresign\Handler\CfsslServerHandler; use OCA\Libresign\Helper\ConfigureCheckHelper; From d0ac5bc5caa3b610ef04c938d2bf2ff9011359c9 Mon Sep 17 00:00:00 2001 From: Vitor Mattos Date: Sat, 1 Jun 2024 13:08:53 -0300 Subject: [PATCH 16/50] chore: feedback improvement Signed-off-by: Vitor Mattos --- lib/Service/Install/SignFiles.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/Service/Install/SignFiles.php b/lib/Service/Install/SignFiles.php index 1442cc2261..555b06ebdb 100644 --- a/lib/Service/Install/SignFiles.php +++ b/lib/Service/Install/SignFiles.php @@ -30,6 +30,7 @@ use OCP\App\IAppManager; use OCP\Files\AppData\IAppDataFactory; use OCP\Files\IAppData; +use OCP\Files\NotFoundException; use OCP\Files\SimpleFS\ISimpleFolder; use OCP\IConfig; use phpseclib\Crypt\RSA; @@ -85,6 +86,8 @@ public function writeAppSignature( $appInfoDir . '/install-' . $this->architecture . '.json', json_encode($signature, JSON_PRETTY_PRINT) ); + } catch (NotFoundException $e) { + throw new \Exception(sprintf("Folder %s not found.\nIs necessary to run this command first: occ libresign:install --all --architecture %s", $e->getMessage(), $this->architecture)); } catch (\Exception $e) { if (!$this->fileAccessHelper->is_writable($appInfoDir)) { throw new \Exception($appInfoDir . ' is not writable'); From cb47c4838ae6a1d92b8d501acf3570d9a7fc205c Mon Sep 17 00:00:00 2001 From: Vitor Mattos Date: Sat, 1 Jun 2024 14:02:09 -0300 Subject: [PATCH 17/50] chore: move java version to constant To be more easy to update java version Signed-off-by: Vitor Mattos --- lib/Service/Install/InstallService.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/Service/Install/InstallService.php b/lib/Service/Install/InstallService.php index 87d04ac6f3..9dbe4ce3d2 100644 --- a/lib/Service/Install/InstallService.php +++ b/lib/Service/Install/InstallService.php @@ -57,6 +57,7 @@ class InstallService { public const JAVA_VERSION = 'openjdk version "21.0.2" 2024-01-16 LTS'; private const JAVA_PARTIAL_VERSION = '21.0.2_13'; + private const JAVA_URL_PATH_NAME = '21.0.2+13'; public const PDFTK_VERSION = '3.3.3'; /** * When update, verify the hash of all architectures @@ -363,10 +364,10 @@ public function installJava(?bool $async = false): void { $linuxDistribution = $this->getLinuxDistributionToDownloadJava(); if ($this->architecture === 'x86_64') { $compressedFileName = 'OpenJDK21U-jre_x64_' . $linuxDistribution . '_hotspot_' . self::JAVA_PARTIAL_VERSION . '.tar.gz'; - $url = 'https://github.com/adoptium/temurin21-binaries/releases/download/jdk-21.0.2+13/' . $compressedFileName; + $url = 'https://github.com/adoptium/temurin21-binaries/releases/download/jdk-' . self::JAVA_URL_PATH_NAME . '/' . $compressedFileName; } elseif ($this->architecture === 'aarch64') { $compressedFileName = 'OpenJDK21U-jre_aarch64_' . $linuxDistribution . '_hotspot_' . self::JAVA_PARTIAL_VERSION . '.tar.gz'; - $url = 'https://github.com/adoptium/temurin21-binaries/releases/download/jdk-21.0.2+13/' . $compressedFileName; + $url = 'https://github.com/adoptium/temurin21-binaries/releases/download/jdk-' . self::JAVA_URL_PATH_NAME . '/' . $compressedFileName; } $class = TAR::class; } else { @@ -387,7 +388,7 @@ public function installJava(?bool $async = false): void { $extractor = new $class($comporessedInternalFileName); $extractor->extract($extractDir); - $this->appConfig->setAppValue('java_path', $extractDir . '/jdk-21.0.2+13-jre/bin/java'); + $this->appConfig->setAppValue('java_path', $extractDir . '/jdk-' . self::JAVA_URL_PATH_NAME . '-jre/bin/java'); $this->removeDownloadProgress(); } From 1852ba42981f4dbcf2fb9f10f37dfbabf9222bd6 Mon Sep 17 00:00:00 2001 From: Vitor Mattos Date: Sat, 1 Jun 2024 14:03:01 -0300 Subject: [PATCH 18/50] fix: setup cfssl arm The previous repository haven't the right release to ARM Signed-off-by: Vitor Mattos --- lib/Service/Install/InstallService.php | 33 ++++++-------------------- 1 file changed, 7 insertions(+), 26 deletions(-) diff --git a/lib/Service/Install/InstallService.php b/lib/Service/Install/InstallService.php index 9dbe4ce3d2..d8eb9d9b7e 100644 --- a/lib/Service/Install/InstallService.php +++ b/lib/Service/Install/InstallService.php @@ -572,34 +572,15 @@ private function installCfssl64(): void { } private function installCfsslArm(): void { - $appFolder = $this->getFolder(); - try { - $cfsslFolder = $appFolder->getFolder('cfssl'); - } catch (NotFoundException $th) { - $cfsslFolder = $appFolder->newFolder('cfssl'); - } - $compressedFileName = 'cfssl-' . self::CFSSL_VERSION . '-1-aarch64.pkg.tar.xz'; - $url = 'http://mirror.archlinuxarm.org/aarch64/community/' . $compressedFileName; - // Generated handmade with command sha256sum - $hash = '944a6c54e53b0e2ef04c9b22477eb5f637715271c74ccea9bb91d7ac0473b855'; - try { - $compressedFile = $cfsslFolder->getFile($compressedFileName); - } catch (NotFoundException $th) { - $compressedFile = $cfsslFolder->newFile($compressedFileName); - } + $url = sprintf('https://github.com/cloudflare/cfssl/releases/download/v%s/cfssl-bundle_%s_linux_arm64', self::CFSSL_VERSION, self::CFSSL_VERSION); - $comporessedInternalFileName = $this->getDataDir() . '/' . $this->getInternalPathOfFile($compressedFile); - - $this->download($url, 'cfssl', $comporessedInternalFileName, $hash, 'sha256'); - - $this->appConfig->deleteAppValue('cfssl_bin'); - $extractor = new TAR($comporessedInternalFileName); + $folder = $this->getFolder(); + $file = $folder->newFile('cfssl'); + $fullPath = $this->getDataDir() . '/' . $this->getInternalPathOfFile($file); + $checksumUrl = sprintf('https://github.com/cloudflare/cfssl/releases/download/v%s/cfssl_%s_checksums.txt', self::CFSSL_VERSION, self::CFSSL_VERSION); + $hash = $this->getHash($folder, 'cfssl', 'cfssl-bundle_' . self::CFSSL_VERSION . '_linux_arm64', self::CFSSL_VERSION, $checksumUrl); + $this->download($url, 'cfssl', $fullPath, $hash, 'sha256'); - $extractDir = $this->getFullPath() . '/cfssl'; - $result = $extractor->extract($extractDir); - if (!$result) { - throw new \RuntimeException('Error to extract xz file. Install xz. Read more: https://github.com/codemasher/php-ext-xz'); - } $cfsslBinPath = $this->getDataDir() . '/' . $this->getInternalPathOfFolder($this->getFolder()) . '/' . 'cfssl/usr/bin/cfssl'; From b7cf152a00d3925457eb88832e06250c5a3b7e11 Mon Sep 17 00:00:00 2001 From: Vitor Mattos Date: Sat, 1 Jun 2024 14:20:06 -0300 Subject: [PATCH 19/50] chore: remove cache files Signed-off-by: Vitor Mattos --- lib/Service/Install/InstallService.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/Service/Install/InstallService.php b/lib/Service/Install/InstallService.php index d8eb9d9b7e..67d71d34e7 100644 --- a/lib/Service/Install/InstallService.php +++ b/lib/Service/Install/InstallService.php @@ -387,6 +387,7 @@ public function installJava(?bool $async = false): void { $extractor = new $class($comporessedInternalFileName); $extractor->extract($extractDir); + unlink($comporessedInternalFileName); $this->appConfig->setAppValue('java_path', $extractDir . '/jdk-' . self::JAVA_URL_PATH_NAME . '-jre/bin/java'); $this->removeDownloadProgress(); @@ -451,6 +452,7 @@ public function installJSignPdf(?bool $async = false): void { $zip = new ZIP($extractDir . '/' . $compressedFileName); $zip->extract($extractDir); + unlink($extractDir . '/' . $compressedFileName); $fullPath = $extractDir . '/jsignpdf-' . JSignPdfHandler::VERSION . '/JSignPdf.jar'; $this->appConfig->setAppValue('jsignpdf_jar_path', $fullPath); From 42958dff7634cb5397da221fa391e991e7d5eae2 Mon Sep 17 00:00:00 2001 From: Vitor Mattos Date: Sat, 1 Jun 2024 14:20:19 -0300 Subject: [PATCH 20/50] chore: simplify hash function Isn't more necessary to have the cache file. Signed-off-by: Vitor Mattos --- lib/Service/Install/InstallService.php | 29 +++----------------------- 1 file changed, 3 insertions(+), 26 deletions(-) diff --git a/lib/Service/Install/InstallService.php b/lib/Service/Install/InstallService.php index 67d71d34e7..e94c44531c 100644 --- a/lib/Service/Install/InstallService.php +++ b/lib/Service/Install/InstallService.php @@ -676,32 +676,9 @@ protected function downloadCli(string $url, string $filename, string $path, ?str } private function getHash(ISimpleFolder $folder, string $type, string $file, string $version, string $checksumUrl): string { - $hashFileName = 'checksums_' . $type . '_' . $version . '.txt'; - try { - $fileObject = $folder->getFile($hashFileName); - } catch (NotFoundException $th) { - $hashes = file_get_contents($checksumUrl); - if (!$hashes) { - throw new LibresignException('Failute to download hash file. URL: ' . $checksumUrl); - } - try { - $fileObject = $folder->newFile($hashFileName, $hashes); - } catch (\Throwable $th) { - throw new LibresignException( - 'Failute to create hash file: ' . $hashFileName . '. ' . - 'File corrupted or not found. Run "occ files:scan-app-data libresign".' - ); - } - } - try { - $hashes = $fileObject->getContent(); - } catch (\Throwable $th) { - } - if (empty($hashes)) { - throw new LibresignException( - 'Failute to load content of hash file: ' . $hashFileName . '. ' . - 'File corrupted or not found. Run "occ files:scan-app-data libresign".' - ); + $hashes = file_get_contents($checksumUrl); + if (!$hashes) { + throw new LibresignException('Failute to download hash file. URL: ' . $checksumUrl); } preg_match('/(?\w*) +' . $file . '/', $hashes, $matches); return $matches['hash']; From ff13ce1a2404bc46e58a499749788a78e94be284 Mon Sep 17 00:00:00 2001 From: Vitor Mattos Date: Sat, 1 Jun 2024 14:23:06 -0300 Subject: [PATCH 21/50] chore: remove duplicated call to finish progress bar Signed-off-by: Vitor Mattos --- lib/Service/Install/InstallService.php | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/Service/Install/InstallService.php b/lib/Service/Install/InstallService.php index e94c44531c..3ac0466c7f 100644 --- a/lib/Service/Install/InstallService.php +++ b/lib/Service/Install/InstallService.php @@ -663,7 +663,6 @@ protected function downloadCli(string $url, string $filename, string $path, ?str } $progressBar->finish(); $this->output->writeln(''); - $progressBar->finish(); if ($hash && file_exists($path) && hash_file($hash_algo, $path) !== $hash) { $this->output->writeln('Failure on download ' . $filename . ' try again'); $this->output->writeln('Invalid ' . $hash_algo . ''); From c3d2cae013fbff4046df735ccd845b2bc47c69bf Mon Sep 17 00:00:00 2001 From: Vitor Mattos Date: Sat, 1 Jun 2024 14:29:00 -0300 Subject: [PATCH 22/50] chore: psalm update baseline Signed-off-by: Vitor Mattos --- tests/psalm-baseline.xml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/psalm-baseline.xml b/tests/psalm-baseline.xml index affdcd1d51..b72213bf96 100644 --- a/tests/psalm-baseline.xml +++ b/tests/psalm-baseline.xml @@ -127,11 +127,11 @@ - - RSA - RSA - X509 - X509 + + + + + From 73cbd95575d5b740802f79e1580a312a8f7ed4ef Mon Sep 17 00:00:00 2001 From: Vitor Mattos Date: Sat, 1 Jun 2024 15:05:08 -0300 Subject: [PATCH 23/50] chore: increase test coverage Signed-off-by: Vitor Mattos --- lib/Service/Install/SignFiles.php | 2 +- tests/Unit/Service/Install/SignFilesTest.php | 64 ++++++++++++++++++++ 2 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 tests/Unit/Service/Install/SignFilesTest.php diff --git a/lib/Service/Install/SignFiles.php b/lib/Service/Install/SignFiles.php index 555b06ebdb..eeb36a3acc 100644 --- a/lib/Service/Install/SignFiles.php +++ b/lib/Service/Install/SignFiles.php @@ -55,7 +55,7 @@ public function __construct( public function getArchitectures(): array { $appInfo = $this->appManager->getAppInfo(Application::APP_ID); - if (!isset($appInfo['dependencies']['architecture'])) { + if (empty($appInfo['dependencies']['architecture'])) { throw new \Exception('dependencies>architecture not found at info.xml'); } return $appInfo['dependencies']['architecture']; diff --git a/tests/Unit/Service/Install/SignFilesTest.php b/tests/Unit/Service/Install/SignFilesTest.php new file mode 100644 index 0000000000..847f04ad7e --- /dev/null +++ b/tests/Unit/Service/Install/SignFilesTest.php @@ -0,0 +1,64 @@ +fileAccessHelper = $this->createMock(FileAccessHelper::class); + $this->config = $this->createMock(IConfig::class); + $this->appDataFactory = $this->createMock(IAppDataFactory::class); + $this->appManager = $this->createMock(IAppManager::class); + } + + private function getService(): SignFiles{ + return new SignFiles( + $this->fileAccessHelper, + $this->config, + $this->appDataFactory, + $this->appManager + ); + } + + /** + * @dataProvider dataGetArchitectures + */ + public function testGetArchitectures(array $appInfo, bool $throwException, $expected):void { + $this->appManager->method('getAppInfo') + ->willReturn($appInfo); + if ($throwException) { + $this->expectExceptionMessage('dependencies>architecture not found at info.xml'); + } + $actual = $this->getService()->getArchitectures(); + if ($throwException) { + return; + } + $this->assertEquals($expected, $actual); + } + + public static function dataGetArchitectures(): array { + return [ + [[], true, []], + [['dependencies' => ['architecture' => []]], true, []], + [['dependencies' => ['architecture' => ['x86_64']]], false, ['x86_64']], + [['dependencies' => ['architecture' => ['x86_64', 'aarch64']]], false, ['x86_64', 'aarch64']], + ]; + } +} From d05a917ec6c6401ed582d542b8fbc8ab371815c9 Mon Sep 17 00:00:00 2001 From: Vitor Mattos Date: Sat, 1 Jun 2024 15:19:11 -0300 Subject: [PATCH 24/50] fix: prevent wrong error when got a failure on test The TestCase class of Nextcloud try to access database and sometimes we haven't this instance generating a false error. To prevent this, I used a try catch to hide parent errors. Signed-off-by: Vitor Mattos --- tests/Unit/TestCase.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/Unit/TestCase.php b/tests/Unit/TestCase.php index 31957f6709..4d7be2b6b9 100644 --- a/tests/Unit/TestCase.php +++ b/tests/Unit/TestCase.php @@ -119,6 +119,13 @@ public function tearDown(): void { $this->cleanDatabase(); } + public static function tearDownAfterClass(): void { + try { + parent::tearDownAfterClass(); + } catch (\Throwable $th) { + } + } + private function cleanDatabase(): void { $db = \OCP\Server::get(\OCP\IDBConnection::class); if (!$db) { From fa7a1b3e9d3ae788300cc011e0b893bdaabc5b07 Mon Sep 17 00:00:00 2001 From: Vitor Mattos Date: Sat, 1 Jun 2024 16:34:23 -0300 Subject: [PATCH 25/50] chore: make protected to be possible mock this method Signed-off-by: Vitor Mattos --- lib/Service/Install/SignFiles.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Service/Install/SignFiles.php b/lib/Service/Install/SignFiles.php index eeb36a3acc..85541e4095 100644 --- a/lib/Service/Install/SignFiles.php +++ b/lib/Service/Install/SignFiles.php @@ -104,7 +104,7 @@ private function getDataDir(): string { /** * @todo check a best solution to don't use reflection */ - private function getInternalPathOfFolder(ISimpleFolder $node): string { + protected function getInternalPathOfFolder(ISimpleFolder $node): string { $reflection = new \ReflectionClass($node); $reflectionProperty = $reflection->getProperty('folder'); $reflectionProperty->setAccessible(true); From 64c717a6184b56301e58bd8510337b660ec52234 Mon Sep 17 00:00:00 2001 From: Vitor Mattos Date: Sat, 1 Jun 2024 16:36:23 -0300 Subject: [PATCH 26/50] chore: use mockbuilder to be possible mock methods of class Signed-off-by: Vitor Mattos --- tests/Unit/Service/Install/SignFilesTest.php | 24 +++++++++++++------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/tests/Unit/Service/Install/SignFilesTest.php b/tests/Unit/Service/Install/SignFilesTest.php index 847f04ad7e..d6eb08f927 100644 --- a/tests/Unit/Service/Install/SignFilesTest.php +++ b/tests/Unit/Service/Install/SignFilesTest.php @@ -28,13 +28,21 @@ public function setUp(): void { $this->appManager = $this->createMock(IAppManager::class); } - private function getService(): SignFiles{ - return new SignFiles( - $this->fileAccessHelper, - $this->config, - $this->appDataFactory, - $this->appManager - ); + /** + * @return SignFiles|MockObject + */ + private function getInstance(array $methods = []) { + return $this->getMockBuilder(SignFiles::class) + ->setConstructorArgs([ + $this->fileAccessHelper, + $this->config, + $this->appDataFactory, + $this->appManager, + ]) + ->onlyMethods($methods) + ->getMock(); + } + } /** @@ -46,7 +54,7 @@ public function testGetArchitectures(array $appInfo, bool $throwException, $expe if ($throwException) { $this->expectExceptionMessage('dependencies>architecture not found at info.xml'); } - $actual = $this->getService()->getArchitectures(); + $actual = $this->getInstance()->getArchitectures(); if ($throwException) { return; } From 2047b0f6816f5015ab01c2c5d5318697aa501f8e Mon Sep 17 00:00:00 2001 From: Vitor Mattos Date: Sat, 1 Jun 2024 16:37:52 -0300 Subject: [PATCH 27/50] chore: start to implement unit tests Signed-off-by: Vitor Mattos --- tests/Unit/Service/Install/SignFilesTest.php | 59 ++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/tests/Unit/Service/Install/SignFilesTest.php b/tests/Unit/Service/Install/SignFilesTest.php index d6eb08f927..210bc2c76c 100644 --- a/tests/Unit/Service/Install/SignFilesTest.php +++ b/tests/Unit/Service/Install/SignFilesTest.php @@ -8,11 +8,14 @@ namespace OCA\Libresign\Tests\Unit\Service; +use bovigo\vfs\vfsStream; use OC\IntegrityCheck\Helpers\FileAccessHelper; use OCA\Libresign\Service\Install\SignFiles; use OCP\App\IAppManager; use OCP\Files\AppData\IAppDataFactory; use OCP\IConfig; +use phpseclib\Crypt\RSA; +use phpseclib\File\X509; use PHPUnit\Framework\MockObject\MockObject; final class SignFilesTest extends \OCA\Libresign\Tests\Unit\TestCase { @@ -43,6 +46,28 @@ private function getInstance(array $methods = []) { ->getMock(); } + private function getNewCert(): array { + $privateKey = openssl_pkey_new([ + 'private_key_bits' => 2048, + 'private_key_type' => OPENSSL_KEYTYPE_RSA, + ]); + + $csrNames = ['commonName' => 'Jhon Doe']; + + $csr = openssl_csr_new($csrNames, $privateKey, ['digest_alg' => 'sha256']); + $x509 = openssl_csr_sign($csr, null, $privateKey, $days = 365, ['digest_alg' => 'sha256']); + + openssl_x509_export($x509, $rootCertificate); + openssl_pkey_export($privateKey, $rootPrivateKey); + + $privateKey = openssl_pkey_new([ + 'private_key_bits' => 2048, + 'private_key_type' => OPENSSL_KEYTYPE_RSA, + ]); + return [ + 'privateKey' => $privateKey, + 'certificate' => $rootCertificate, + ]; } /** @@ -69,4 +94,38 @@ public static function dataGetArchitectures(): array { [['dependencies' => ['architecture' => ['x86_64', 'aarch64']]], false, ['x86_64', 'aarch64']], ]; } + + /** + * @dataProvider dataWriteAppSignature + */ + public function testWriteAppSignature(string $architecture): void { + $this->appManager->method('getAppInfo') + ->willReturn(['dependencies' => ['architecture' => [$architecture]]]); + + $certificate = $this->getNewCert('123456'); + $rsa = new RSA(); + $rsa->loadKey($certificate['privateKey']); + $x509 = new X509(); + $x509->loadX509($certificate['certificate']); + $x509->setPrivateKey($rsa); + + + vfsStream::setup('home'); + + $this->config->method('getSystemValue') + ->willReturn(vfsStream::url('home/data')); + + $signFiles = $this->getInstance(['getInternalPathOfFolder']); + $signFiles->expects($this->any()) + ->method('getInternalPathOfFolder') + ->willReturn('libresign'); + mkdir('vfs://home/data/libresign', 0755, true); + $signFiles->writeAppSignature($x509, $rsa, $architecture); + } + + public static function dataWriteAppSignature(): array { + return [ + ['x86_64'], + ]; + } } From eaee1b9fd6a16af9779c7a887fb04ddbb569cd3d Mon Sep 17 00:00:00 2001 From: Vitor Mattos Date: Sat, 1 Jun 2024 16:38:18 -0300 Subject: [PATCH 28/50] chore: start to implement validate method Signed-off-by: Vitor Mattos --- lib/Service/Install/InstallService.php | 17 +++++++++++++++++ lib/Service/Install/SignFiles.php | 4 ++++ tests/Unit/Service/InstallServiceTest.php | 3 +++ 3 files changed, 24 insertions(+) diff --git a/lib/Service/Install/InstallService.php b/lib/Service/Install/InstallService.php index 3ac0466c7f..708153a76c 100644 --- a/lib/Service/Install/InstallService.php +++ b/lib/Service/Install/InstallService.php @@ -86,6 +86,7 @@ public function __construct( private IAppConfig $appConfig, private IRootFolder $rootFolder, private LoggerInterface $logger, + private SignFiles $signFiles, protected IAppDataFactory $appDataFactory, ) { $this->cache = $cacheFactory->createDistributed('libresign-setup'); @@ -343,8 +344,15 @@ public function setResource(string $resource): self { return $this; } + private function isDownloadedFilesOk(): bool { + return $this->signFiles->verify($this->architecture); + } + public function installJava(?bool $async = false): void { $this->setResource('java'); + if ($this->isDownloadedFilesOk()) { + return; + } if ($async) { $this->runAsync(); return; @@ -431,6 +439,9 @@ public function installJSignPdf(?bool $async = false): void { throw new RuntimeException('Zip extension is not available'); } $this->setResource('jsignpdf'); + if ($this->isDownloadedFilesOk()) { + return; + } if ($async) { $this->runAsync(); return; @@ -480,6 +491,9 @@ public function uninstallJSignPdf(): void { public function installPdftk(?bool $async = false): void { $this->setResource('pdftk'); + if ($this->isDownloadedFilesOk()) { + return; + } if ($async) { $this->runAsync(); return; @@ -526,6 +540,9 @@ public function installCfssl(?bool $async = false): void { return; } $this->setResource('cfssl'); + if ($this->isDownloadedFilesOk()) { + return; + } if ($async) { $this->runAsync(); return; diff --git a/lib/Service/Install/SignFiles.php b/lib/Service/Install/SignFiles.php index 85541e4095..526255d18f 100644 --- a/lib/Service/Install/SignFiles.php +++ b/lib/Service/Install/SignFiles.php @@ -96,6 +96,10 @@ public function writeAppSignature( } } + public function verify(string $architecture): bool { + return true; + } + private function getDataDir(): string { $dataDir = $this->config->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data/'); return $dataDir; diff --git a/tests/Unit/Service/InstallServiceTest.php b/tests/Unit/Service/InstallServiceTest.php index c6da9ed674..0ed9fe9097 100644 --- a/tests/Unit/Service/InstallServiceTest.php +++ b/tests/Unit/Service/InstallServiceTest.php @@ -27,6 +27,7 @@ use OCA\Libresign\Handler\CertificateEngine\Handler as CertificateEngineHandler; use OCA\Libresign\Service\Install\InstallService; +use OCA\Libresign\Service\Install\SignFiles; use OCP\AppFramework\Services\IAppConfig; use OCP\Files\AppData\IAppDataFactory; use OCP\Files\IRootFolder; @@ -60,6 +61,7 @@ protected function getInstallService(): InstallService { $this->appConfig = $this->createMock(IAppConfig::class); $this->rootFolder = $this->createMock(IRootFolder::class); $this->logger = $this->createMock(LoggerInterface::class); + $this->signFiles = $this->createMock(SignFiles::class); $this->appDataFactory = $this->createMock(IAppDataFactory::class); return new InstallService( $this->cacheFactory, @@ -69,6 +71,7 @@ protected function getInstallService(): InstallService { $this->appConfig, $this->rootFolder, $this->logger, + $this->signFiles, $this->appDataFactory ); } From ba99aae6e4c427b6f910c1159781c508c81dfa0f Mon Sep 17 00:00:00 2001 From: Vitor Mattos Date: Mon, 3 Jun 2024 16:07:43 -0300 Subject: [PATCH 29/50] fix: unit test Signed-off-by: Vitor Mattos --- lib/Service/Install/SignFiles.php | 8 +++++- tests/Unit/Service/Install/SignFilesTest.php | 30 +++++++++++++++----- 2 files changed, 30 insertions(+), 8 deletions(-) diff --git a/lib/Service/Install/SignFiles.php b/lib/Service/Install/SignFiles.php index 526255d18f..f5a7b801c8 100644 --- a/lib/Service/Install/SignFiles.php +++ b/lib/Service/Install/SignFiles.php @@ -44,6 +44,7 @@ class SignFiles { 'unauthetnicated', ]; private string $architecture; + private string $appInfoDir; public function __construct( private FileAccessHelper $fileAccessHelper, private IConfig $config, @@ -73,9 +74,14 @@ public function writeAppSignature( X509 $certificate, RSA $privateKey, string $architecture, + string $appInfoDir = '', ) { $this->architecture = $architecture; - $appInfoDir = __DIR__ . '/../../../appinfo'; + if (is_dir($appInfoDir)) { + $this->appInfoDir = $appInfoDir; + } else { + $appInfoDir = realpath(__DIR__ . '/../../../appinfo'); + } try { $this->fileAccessHelper->assertDirectoryExists($appInfoDir); diff --git a/tests/Unit/Service/Install/SignFilesTest.php b/tests/Unit/Service/Install/SignFilesTest.php index 210bc2c76c..ec725a2e2a 100644 --- a/tests/Unit/Service/Install/SignFilesTest.php +++ b/tests/Unit/Service/Install/SignFilesTest.php @@ -19,13 +19,13 @@ use PHPUnit\Framework\MockObject\MockObject; final class SignFilesTest extends \OCA\Libresign\Tests\Unit\TestCase { - private FileAccessHelper&MockObject $fileAccessHelper; + private FileAccessHelper $fileAccessHelper; private IConfig&MockObject $config; private IAppDataFactory&MockObject $appDataFactory; private IAppManager&MockObject $appManager; public function setUp(): void { - $this->fileAccessHelper = $this->createMock(FileAccessHelper::class); + $this->fileAccessHelper = new FileAccessHelper(); $this->config = $this->createMock(IConfig::class); $this->appDataFactory = $this->createMock(IAppDataFactory::class); $this->appManager = $this->createMock(IAppManager::class); @@ -58,7 +58,7 @@ private function getNewCert(): array { $x509 = openssl_csr_sign($csr, null, $privateKey, $days = 365, ['digest_alg' => 'sha256']); openssl_x509_export($x509, $rootCertificate); - openssl_pkey_export($privateKey, $rootPrivateKey); + openssl_pkey_export($privateKey, $publicKey); $privateKey = openssl_pkey_new([ 'private_key_bits' => 2048, @@ -67,6 +67,7 @@ private function getNewCert(): array { return [ 'privateKey' => $privateKey, 'certificate' => $rootCertificate, + 'publicKey' => $publicKey, ]; } @@ -105,12 +106,20 @@ public function testWriteAppSignature(string $architecture): void { $certificate = $this->getNewCert('123456'); $rsa = new RSA(); $rsa->loadKey($certificate['privateKey']); + $rsa->loadKey($certificate['publicKey']); $x509 = new X509(); $x509->loadX509($certificate['certificate']); $x509->setPrivateKey($rsa); - - vfsStream::setup('home'); + $structure = [ + 'data' => [ + 'libresign' => [ + 'fakeFile' => 'content', + ], + ], + 'appinfo' => [], + ]; + $root = vfsStream::setup('home', 0755, $structure); $this->config->method('getSystemValue') ->willReturn(vfsStream::url('home/data')); @@ -119,8 +128,15 @@ public function testWriteAppSignature(string $architecture): void { $signFiles->expects($this->any()) ->method('getInternalPathOfFolder') ->willReturn('libresign'); - mkdir('vfs://home/data/libresign', 0755, true); - $signFiles->writeAppSignature($x509, $rsa, $architecture); + $signFiles->writeAppSignature($x509, $rsa, $architecture, 'vfs://home/appinfo'); + $this->assertFileExists('vfs://home/appinfo/install-' . $architecture . '.json'); + $json = file_get_contents('vfs://home/appinfo/install-' . $architecture . '.json'); + $signatureContent = json_decode($json, true); + $this->assertArrayHasKey('hashes', $signatureContent); + $this->assertCount(1, $signatureContent['hashes']); + $expected = hash('sha512', $structure['data']['libresign']['fakeFile']); + $actual = $signatureContent['hashes']['fakeFile']; + $this->assertEquals($expected, $actual); } public static function dataWriteAppSignature(): array { From 32085644ee54bb4ddcdc3af79f30c0d7a7499733 Mon Sep 17 00:00:00 2001 From: Vitor Mattos Date: Mon, 3 Jun 2024 16:17:25 -0300 Subject: [PATCH 30/50] chore: use default permission Signed-off-by: Vitor Mattos [skip ci] --- tests/Unit/Service/Install/SignFilesTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Unit/Service/Install/SignFilesTest.php b/tests/Unit/Service/Install/SignFilesTest.php index ec725a2e2a..d7cb78c661 100644 --- a/tests/Unit/Service/Install/SignFilesTest.php +++ b/tests/Unit/Service/Install/SignFilesTest.php @@ -119,7 +119,7 @@ public function testWriteAppSignature(string $architecture): void { ], 'appinfo' => [], ]; - $root = vfsStream::setup('home', 0755, $structure); + $root = vfsStream::setup('home', null, $structure); $this->config->method('getSystemValue') ->willReturn(vfsStream::url('home/data')); @@ -141,7 +141,7 @@ public function testWriteAppSignature(string $architecture): void { public static function dataWriteAppSignature(): array { return [ - ['x86_64'], + ['x86_64', 'aarch64'], ]; } } From 943bec620c3732531dab9a710d245eaaedf8d309 Mon Sep 17 00:00:00 2001 From: Vitor Mattos Date: Mon, 3 Jun 2024 17:59:40 -0300 Subject: [PATCH 31/50] feat: implement verify method Signed-off-by: Vitor Mattos --- lib/Exception/InvalidSignatureException.php | 12 ++ lib/Service/Install/InstallService.php | 2 +- lib/Service/Install/SignFiles.php | 115 +++++++++++++++++-- tests/Unit/Service/Install/SignFilesTest.php | 73 ++++++++++-- 4 files changed, 182 insertions(+), 20 deletions(-) create mode 100644 lib/Exception/InvalidSignatureException.php diff --git a/lib/Exception/InvalidSignatureException.php b/lib/Exception/InvalidSignatureException.php new file mode 100644 index 0000000000..f012120f39 --- /dev/null +++ b/lib/Exception/InvalidSignatureException.php @@ -0,0 +1,12 @@ +signFiles->verify($this->architecture); + return count($this->signFiles->verify($this->architecture)) === 0; } public function installJava(?bool $async = false): void { diff --git a/lib/Service/Install/SignFiles.php b/lib/Service/Install/SignFiles.php index f5a7b801c8..be8a44f2c2 100644 --- a/lib/Service/Install/SignFiles.php +++ b/lib/Service/Install/SignFiles.php @@ -25,8 +25,10 @@ namespace OCA\Libresign\Service\Install; +use OC\IntegrityCheck\Helpers\EnvironmentHelper; use OC\IntegrityCheck\Helpers\FileAccessHelper; use OCA\Libresign\AppInfo\Application; +use OCA\Libresign\Exception\InvalidSignatureException; use OCP\App\IAppManager; use OCP\Files\AppData\IAppDataFactory; use OCP\Files\IAppData; @@ -44,8 +46,8 @@ class SignFiles { 'unauthetnicated', ]; private string $architecture; - private string $appInfoDir; public function __construct( + private EnvironmentHelper $environmentHelper, private FileAccessHelper $fileAccessHelper, private IConfig $config, private IAppDataFactory $appDataFactory, @@ -77,11 +79,7 @@ public function writeAppSignature( string $appInfoDir = '', ) { $this->architecture = $architecture; - if (is_dir($appInfoDir)) { - $this->appInfoDir = $appInfoDir; - } else { - $appInfoDir = realpath(__DIR__ . '/../../../appinfo'); - } + $appInfoDir = $this->getAppInfoDirectory($appInfoDir); try { $this->fileAccessHelper->assertDirectoryExists($appInfoDir); @@ -102,8 +100,109 @@ public function writeAppSignature( } } - public function verify(string $architecture): bool { - return true; + private function getAppInfoDirectory(string $appInfoDir): string { + if (is_dir($appInfoDir)) { + return $appInfoDir; + } + return realpath(__DIR__ . '/../../../appinfo'); + } + + /** + * Split the certificate file in individual certs + * + * @param string $cert + * @return string[] + */ + private function splitCerts(string $cert): array { + preg_match_all('([\-]{3,}[\S\ ]+?[\-]{3,}[\S\s]+?[\-]{3,}[\S\ ]+?[\-]{3,})', $cert, $matches); + + return $matches[0]; + } + + public function verify(string $architecture, string $appInfoDir = '', string $certificateCN = Application::APP_ID): array { + $this->architecture = $architecture; + $appInfoDir = $this->getAppInfoDirectory($appInfoDir); + + $signaturePath = $appInfoDir . '/install-' . $this->architecture . '.json'; + $content = $this->fileAccessHelper->file_get_contents($signaturePath); + $signatureData = null; + + if (\is_string($content)) { + $signatureData = json_decode($content, true); + } + if (!\is_array($signatureData)) { + throw new InvalidSignatureException('Signature data not found.'); + } + + $expectedHashes = $signatureData['hashes']; + ksort($expectedHashes); + $signature = base64_decode($signatureData['signature']); + $certificate = $signatureData['certificate']; + + // Check if certificate is signed by Nextcloud Root Authority + $x509 = new \phpseclib\File\X509(); + $rootCertificatePublicKey = $this->fileAccessHelper->file_get_contents($this->environmentHelper->getServerRoot().'/resources/codesigning/root.crt'); + + $rootCerts = $this->splitCerts($rootCertificatePublicKey); + foreach ($rootCerts as $rootCert) { + $x509->loadCA($rootCert); + } + $x509->loadX509($certificate); + if (!$x509->validateSignature()) { + throw new InvalidSignatureException('Certificate is not valid.'); + } + // Verify if certificate has proper CN. "core" CN is always trusted. + if ($x509->getDN(X509::DN_OPENSSL)['CN'] !== $certificateCN && $x509->getDN(X509::DN_OPENSSL)['CN'] !== 'core') { + throw new InvalidSignatureException( + sprintf('Certificate is not valid for required scope. (Requested: %s, current: CN=%s)', $certificateCN, $x509->getDN(true)['CN']) + ); + } + + // Check if the signature of the files is valid + $rsa = new \phpseclib\Crypt\RSA(); + $rsa->loadKey($x509->currentCert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey']); + $rsa->setSignatureMode(RSA::SIGNATURE_PSS); + $rsa->setMGFHash('sha512'); + // See https://tools.ietf.org/html/rfc3447#page-38 + $rsa->setSaltLength(0); + if (!$rsa->verify(json_encode($expectedHashes), $signature)) { + throw new InvalidSignatureException('Signature could not get verified.'); + } + + // Compare the list of files which are not identical + $installPath = $this->getInstallPath(); + $currentInstanceHashes = $this->generateHashes($this->getFolderIterator(), $installPath); + $differencesA = array_diff($expectedHashes, $currentInstanceHashes); + $differencesB = array_diff($currentInstanceHashes, $expectedHashes); + $differences = array_merge($differencesA, $differencesB); + $differenceArray = []; + foreach ($differences as $filename => $hash) { + // Check if file should not exist in the new signature table + if (!array_key_exists($filename, $expectedHashes)) { + $differenceArray['EXTRA_FILE'][$filename]['expected'] = ''; + $differenceArray['EXTRA_FILE'][$filename]['current'] = $hash; + continue; + } + + // Check if file is missing + if (!array_key_exists($filename, $currentInstanceHashes)) { + $differenceArray['FILE_MISSING'][$filename]['expected'] = $expectedHashes[$filename]; + $differenceArray['FILE_MISSING'][$filename]['current'] = ''; + continue; + } + + // Check if hash does mismatch + if ($expectedHashes[$filename] !== $currentInstanceHashes[$filename]) { + $differenceArray['INVALID_HASH'][$filename]['expected'] = $expectedHashes[$filename]; + $differenceArray['INVALID_HASH'][$filename]['current'] = $currentInstanceHashes[$filename]; + continue; + } + + // Should never happen. + throw new \Exception('Invalid behaviour in file hash comparison experienced. Please report this error to the developers.'); + } + + return $differenceArray; } private function getDataDir(): string { diff --git a/tests/Unit/Service/Install/SignFilesTest.php b/tests/Unit/Service/Install/SignFilesTest.php index d7cb78c661..85f51673b4 100644 --- a/tests/Unit/Service/Install/SignFilesTest.php +++ b/tests/Unit/Service/Install/SignFilesTest.php @@ -9,6 +9,7 @@ namespace OCA\Libresign\Tests\Unit\Service; use bovigo\vfs\vfsStream; +use OC\IntegrityCheck\Helpers\EnvironmentHelper; use OC\IntegrityCheck\Helpers\FileAccessHelper; use OCA\Libresign\Service\Install\SignFiles; use OCP\App\IAppManager; @@ -19,12 +20,14 @@ use PHPUnit\Framework\MockObject\MockObject; final class SignFilesTest extends \OCA\Libresign\Tests\Unit\TestCase { + private EnvironmentHelper&MockObject $environmentHelper; private FileAccessHelper $fileAccessHelper; private IConfig&MockObject $config; private IAppDataFactory&MockObject $appDataFactory; private IAppManager&MockObject $appManager; public function setUp(): void { + $this->environmentHelper = $this->createMock(EnvironmentHelper::class); $this->fileAccessHelper = new FileAccessHelper(); $this->config = $this->createMock(IConfig::class); $this->appDataFactory = $this->createMock(IAppDataFactory::class); @@ -37,6 +40,7 @@ public function setUp(): void { private function getInstance(array $methods = []) { return $this->getMockBuilder(SignFiles::class) ->setConstructorArgs([ + $this->environmentHelper, $this->fileAccessHelper, $this->config, $this->appDataFactory, @@ -52,7 +56,7 @@ private function getNewCert(): array { 'private_key_type' => OPENSSL_KEYTYPE_RSA, ]); - $csrNames = ['commonName' => 'Jhon Doe']; + $csrNames = ['commonName' => 'LibreSign']; $csr = openssl_csr_new($csrNames, $privateKey, ['digest_alg' => 'sha256']); $x509 = openssl_csr_sign($csr, null, $privateKey, $days = 365, ['digest_alg' => 'sha256']); @@ -66,7 +70,7 @@ private function getNewCert(): array { ]); return [ 'privateKey' => $privateKey, - 'certificate' => $rootCertificate, + 'rootCertificate' => $rootCertificate, 'publicKey' => $publicKey, ]; } @@ -96,10 +100,7 @@ public static function dataGetArchitectures(): array { ]; } - /** - * @dataProvider dataWriteAppSignature - */ - public function testWriteAppSignature(string $architecture): void { + private function writeAppSignature(string $architecture): SignFiles { $this->appManager->method('getAppInfo') ->willReturn(['dependencies' => ['architecture' => [$architecture]]]); @@ -108,13 +109,19 @@ public function testWriteAppSignature(string $architecture): void { $rsa->loadKey($certificate['privateKey']); $rsa->loadKey($certificate['publicKey']); $x509 = new X509(); - $x509->loadX509($certificate['certificate']); + $x509->loadX509($certificate['rootCertificate']); $x509->setPrivateKey($rsa); $structure = [ 'data' => [ 'libresign' => [ - 'fakeFile' => 'content', + 'fakeFile01' => 'content', + 'fakeFile02' => 'content', + ], + ], + 'resources' => [ + 'codesigning' => [ + 'root.crt' => $certificate['rootCertificate'], ], ], 'appinfo' => [], @@ -124,6 +131,9 @@ public function testWriteAppSignature(string $architecture): void { $this->config->method('getSystemValue') ->willReturn(vfsStream::url('home/data')); + $this->environmentHelper->method('getServerRoot') + ->willReturn('vfs://home'); + $signFiles = $this->getInstance(['getInternalPathOfFolder']); $signFiles->expects($this->any()) ->method('getInternalPathOfFolder') @@ -133,10 +143,20 @@ public function testWriteAppSignature(string $architecture): void { $json = file_get_contents('vfs://home/appinfo/install-' . $architecture . '.json'); $signatureContent = json_decode($json, true); $this->assertArrayHasKey('hashes', $signatureContent); - $this->assertCount(1, $signatureContent['hashes']); - $expected = hash('sha512', $structure['data']['libresign']['fakeFile']); - $actual = $signatureContent['hashes']['fakeFile']; + $this->assertCount(2, $signatureContent['hashes']); + $expected = hash('sha512', $structure['data']['libresign']['fakeFile01']); + $actual = $signatureContent['hashes']['fakeFile01']; $this->assertEquals($expected, $actual); + return $signFiles; + } + + /** + * @dataProvider dataWriteAppSignature + */ + public function testWriteAppSignature(string $architecture): void { + $signFiles = $this->writeAppSignature($architecture); + $actual = $signFiles->verify($architecture, 'vfs://home/appinfo', 'LibreSign'); + $this->assertCount(0, $actual); } public static function dataWriteAppSignature(): array { @@ -144,4 +164,35 @@ public static function dataWriteAppSignature(): array { ['x86_64', 'aarch64'], ]; } + + public function testVerify(): void { + $architecture = 'x86_64'; + $signFiles = $this->writeAppSignature($architecture); + unlink('vfs://home/data/libresign/fakeFile01'); + file_put_contents('vfs://home/data/libresign/fakeFile02', 'invalidContent'); + file_put_contents('vfs://home/data/libresign/fakeFile03', 'invalidContent'); + $expected = json_encode([ + 'FILE_MISSING' => [ + 'fakeFile01' => [ + 'expected' => 'b2d1d285b5199c85f988d03649c37e44fd3dde01e5d69c50fef90651962f48110e9340b60d49a479c4c0b53f5f07d690686dd87d2481937a512e8b85ee7c617f', + 'current' => '', + ], + ], + 'INVALID_HASH' => [ + 'fakeFile02' => [ + 'expected' => 'b2d1d285b5199c85f988d03649c37e44fd3dde01e5d69c50fef90651962f48110e9340b60d49a479c4c0b53f5f07d690686dd87d2481937a512e8b85ee7c617f', + 'current' => '827a4e298c978e1eeffebdf09f0fa5a1e1d8b608c8071144f3fffb31f9ed21f6d27f88a63f7409583df7438105f713ff58d55e68e61e01a285125d763045c726', + ], + ], + 'EXTRA_FILE' => [ + 'fakeFile03' => [ + 'expected' => '', + 'current' => '827a4e298c978e1eeffebdf09f0fa5a1e1d8b608c8071144f3fffb31f9ed21f6d27f88a63f7409583df7438105f713ff58d55e68e61e01a285125d763045c726', + ], + ], + ]); + $actual = $signFiles->verify($architecture, 'vfs://home/appinfo', 'LibreSign'); + $actual = json_encode($actual); + $this->assertJsonStringEqualsJsonString($expected, $actual); + } } From 3b9ce22bb9cb5f03a2c73691ea0719650cf4ef7a Mon Sep 17 00:00:00 2001 From: Vitor Mattos Date: Mon, 3 Jun 2024 19:02:58 -0300 Subject: [PATCH 32/50] feat: Check hash of binaries when validate setup Signed-off-by: Vitor Mattos --- lib/Service/Install/ConfigureCheckService.php | 57 +++++++++++++------ lib/Service/Install/InstallService.php | 9 ++- lib/Service/Install/SignFiles.php | 8 ++- tests/psalm-baseline.xml | 5 ++ 4 files changed, 57 insertions(+), 22 deletions(-) diff --git a/lib/Service/Install/ConfigureCheckService.php b/lib/Service/Install/ConfigureCheckService.php index 7c26f0f081..49b0d6d4bf 100644 --- a/lib/Service/Install/ConfigureCheckService.php +++ b/lib/Service/Install/ConfigureCheckService.php @@ -35,7 +35,8 @@ public function __construct( private IAppConfig $appConfig, private SystemConfig $systemConfig, private JSignPdfHandler $jSignPdfHandler, - private CertificateEngine $certificateEngine + private CertificateEngine $certificateEngine, + private InstallService $installService, ) { } @@ -58,12 +59,27 @@ public function checkAll(): array { */ public function checkSign(): array { $return = []; + $return = array_merge($return, $this->checkHash()); $return = array_merge($return, $this->checkJava()); $return = array_merge($return, $this->checkPdftk()); $return = array_merge($return, $this->checkJSignPdf()); return $return; } + public function checkHash(): array { + if (!$this->installService->isDownloadedFilesOk()) { + return [ + (new ConfigureCheckHelper()) + ->setErrorMessage( + 'Invalid hash of binaries files.' + ) + ->setResource('java') + ->setTip('Run occ libresign:install --all'), + ]; + } + return []; + } + /** * Check all requirements to use JSignPdf * @@ -133,17 +149,25 @@ public function checkPdftk(): array { $pdftkPath = $this->appConfig->getAppValue('pdftk_path'); if ($pdftkPath) { if (file_exists($pdftkPath)) { - $javaPath = $this->appConfig->getAppValue('java_path'); - if (empty($javaPath)) { + if (!$this->isJavaOk()) { return [ (new ConfigureCheckHelper()) - ->setErrorMessage('Java is necessary to run pdftk') - ->setResource('pdftk') + ->setErrorMessage('Necessary Java to run PDFtk') + ->setResource('jsignpdf') ->setTip('Run occ libresign:install --java'), ]; } + $javaPath = $this->appConfig->getAppValue('java_path'); $version = []; - \exec($javaPath . ' -jar ' . $pdftkPath . " --version 2>&1", $version); + \exec($javaPath . ' -jar ' . $pdftkPath . " --version 2>&1", $version, $resultCode); + if ($resultCode !== 0) { + return [ + (new ConfigureCheckHelper()) + ->setErrorMessage('Failure to check PDFtk version.') + ->setResource('java') + ->setTip('Run occ libresign:install --pdftk'), + ]; + } if (isset($version[0])) { preg_match('/pdftk port to java (?.*) a Handy Tool/', $version[0], $matches); if (isset($matches['version'])) { @@ -194,7 +218,7 @@ private function checkJava(): array { $javaPath = $this->appConfig->getAppValue('java_path'); if ($javaPath) { if (file_exists($javaPath)) { - \exec($javaPath . " -version 2>&1", $javaVersion); + \exec($javaPath . " -version 2>&1", $javaVersion, $resultCode); if (empty($javaVersion)) { return [ (new ConfigureCheckHelper()) @@ -205,6 +229,14 @@ private function checkJava(): array { ->setTip('https://github.com/LibreSign/libresign/issues/2327#issuecomment-1961988790'), ]; } + if ($resultCode !== 0) { + return [ + (new ConfigureCheckHelper()) + ->setErrorMessage('Failure to check Java version.') + ->setResource('java') + ->setTip('Run occ libresign:install --java'), + ]; + } $javaVersion = current($javaVersion); if ($javaVersion !== InstallService::JAVA_VERSION) { return [ @@ -236,17 +268,6 @@ private function checkJava(): array { ->setTip('Run occ libresign:install --java'), ]; } - \exec("java -version 2>&1", $javaVersion); - $javaVersion = current($javaVersion); - $hasJavaVersion = strpos($javaVersion, 'not found') === false; - if ($hasJavaVersion) { - return [ - (new ConfigureCheckHelper()) - ->setSuccessMessage('Using java from operational system. Version: ' . $javaVersion) - ->setResource('java') - ->setTip('Run occ libresign:install --java'), - ]; - } return [ (new ConfigureCheckHelper()) ->setErrorMessage('Java not installed') diff --git a/lib/Service/Install/InstallService.php b/lib/Service/Install/InstallService.php index 7f1065f181..a8b11fbd94 100644 --- a/lib/Service/Install/InstallService.php +++ b/lib/Service/Install/InstallService.php @@ -30,6 +30,7 @@ use OC\Archive\ZIP; use OC\Memcache\NullCache; use OCA\Libresign\AppInfo\Application; +use OCA\Libresign\Exception\InvalidSignatureException; use OCA\Libresign\Exception\LibresignException; use OCA\Libresign\Handler\CertificateEngine\AEngineHandler; use OCA\Libresign\Handler\CertificateEngine\CfsslHandler; @@ -344,8 +345,12 @@ public function setResource(string $resource): self { return $this; } - private function isDownloadedFilesOk(): bool { - return count($this->signFiles->verify($this->architecture)) === 0; + public function isDownloadedFilesOk(): bool { + try { + return count($this->signFiles->verify($this->architecture)) === 0; + } catch (InvalidSignatureException $e) { + return false; + } } public function installJava(?bool $async = false): void { diff --git a/lib/Service/Install/SignFiles.php b/lib/Service/Install/SignFiles.php index be8a44f2c2..b8b9f93eb0 100644 --- a/lib/Service/Install/SignFiles.php +++ b/lib/Service/Install/SignFiles.php @@ -223,8 +223,12 @@ protected function getInternalPathOfFolder(ISimpleFolder $node): string { } private function getInstallPath(): string { - $folder = $this->getDataDir() . '/' . - $this->getInternalPathOfFolder($this->appData->getFolder($this->architecture)); + try { + $folder = $this->getDataDir() . '/' . + $this->getInternalPathOfFolder($this->appData->getFolder($this->architecture)); + } catch (NotFoundException $e) { + throw new InvalidSignatureException('Invalid architecture ' . $this->architecture); + } return $folder; } diff --git a/tests/psalm-baseline.xml b/tests/psalm-baseline.xml index b72213bf96..1145f2da49 100644 --- a/tests/psalm-baseline.xml +++ b/tests/psalm-baseline.xml @@ -130,8 +130,13 @@ + + + + + From 9ff37fb6c50d4857d31fff8387a6fa7db131629e Mon Sep 17 00:00:00 2001 From: Vitor Mattos Date: Mon, 3 Jun 2024 19:06:55 -0300 Subject: [PATCH 33/50] chore: update header to new pattern Signed-off-by: Vitor Mattos --- lib/Command/Developer/SignSetup.php | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/lib/Command/Developer/SignSetup.php b/lib/Command/Developer/SignSetup.php index 2b8e7746d9..bdc51aa6d0 100644 --- a/lib/Command/Developer/SignSetup.php +++ b/lib/Command/Developer/SignSetup.php @@ -2,24 +2,8 @@ declare(strict_types=1); /** - * @copyright Copyright (c) 2024 Vitor Mattos - * - * @author Vitor Mattos - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . + * SPDX-FileCopyrightText: 2020-2024 LibreCode coop and contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCA\Libresign\Command\Developer; From f39a4717f3720bda8ddab186a7996e029b01e817 Mon Sep 17 00:00:00 2001 From: Vitor Mattos Date: Mon, 3 Jun 2024 19:11:51 -0300 Subject: [PATCH 34/50] chore: signature files Signed-off-by: Vitor Mattos --- lib/Service/Install/SignFiles.php | 21 ++------------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/lib/Service/Install/SignFiles.php b/lib/Service/Install/SignFiles.php index b8b9f93eb0..9e5c9dbf80 100644 --- a/lib/Service/Install/SignFiles.php +++ b/lib/Service/Install/SignFiles.php @@ -1,26 +1,9 @@ - * - * @author Vitor Mattos - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . + * SPDX-FileCopyrightText: 2020-2024 LibreCode coop and contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCA\Libresign\Service\Install; From 716a704b605834f957df35e5eb6022a7d750fd60 Mon Sep 17 00:00:00 2001 From: Vitor Mattos Date: Tue, 4 Jun 2024 08:50:52 -0300 Subject: [PATCH 35/50] chore: rename class Signed-off-by: Vitor Mattos --- lib/Command/Developer/SignSetup.php | 8 +++--- lib/Service/Install/InstallService.php | 4 +-- .../{SignFiles.php => SignSetupService.php} | 2 +- ...FilesTest.php => SignSetupServiceTest.php} | 26 +++++++++---------- tests/Unit/Service/InstallServiceTest.php | 7 ++--- 5 files changed, 24 insertions(+), 23 deletions(-) rename lib/Service/Install/{SignFiles.php => SignSetupService.php} (99%) rename tests/Unit/Service/Install/{SignFilesTest.php => SignSetupServiceTest.php} (87%) diff --git a/lib/Command/Developer/SignSetup.php b/lib/Command/Developer/SignSetup.php index bdc51aa6d0..31606b870e 100644 --- a/lib/Command/Developer/SignSetup.php +++ b/lib/Command/Developer/SignSetup.php @@ -10,7 +10,7 @@ use OC\Core\Command\Base; use OC\IntegrityCheck\Helpers\FileAccessHelper; -use OCA\Libresign\Service\Install\SignFiles; +use OCA\Libresign\Service\Install\SignSetupService; use OCP\IConfig; use phpseclib\Crypt\RSA; use phpseclib\File\X509; @@ -22,7 +22,7 @@ class SignSetup extends Base { public function __construct( private IConfig $config, private FileAccessHelper $fileAccessHelper, - private SignFiles $signFiles, + private SignSetupService $signSetupService, ) { parent::__construct(); } @@ -67,8 +67,8 @@ protected function execute(InputInterface $input, OutputInterface $output): int $x509->loadX509($keyBundle); $x509->setPrivateKey($rsa); try { - foreach ($this->signFiles->getArchitectures() as $architecture) { - $this->signFiles->writeAppSignature($x509, $rsa, $architecture); + foreach ($this->signSetupService->getArchitectures() as $architecture) { + $this->signSetupService->writeAppSignature($x509, $rsa, $architecture); } $output->writeln('Successfully signed'); } catch (\Exception $e) { diff --git a/lib/Service/Install/InstallService.php b/lib/Service/Install/InstallService.php index a8b11fbd94..5b8e8e15cf 100644 --- a/lib/Service/Install/InstallService.php +++ b/lib/Service/Install/InstallService.php @@ -87,7 +87,7 @@ public function __construct( private IAppConfig $appConfig, private IRootFolder $rootFolder, private LoggerInterface $logger, - private SignFiles $signFiles, + private SignSetupService $signSetupService, protected IAppDataFactory $appDataFactory, ) { $this->cache = $cacheFactory->createDistributed('libresign-setup'); @@ -347,7 +347,7 @@ public function setResource(string $resource): self { public function isDownloadedFilesOk(): bool { try { - return count($this->signFiles->verify($this->architecture)) === 0; + return count($this->signSetupService->verify($this->architecture)) === 0; } catch (InvalidSignatureException $e) { return false; } diff --git a/lib/Service/Install/SignFiles.php b/lib/Service/Install/SignSetupService.php similarity index 99% rename from lib/Service/Install/SignFiles.php rename to lib/Service/Install/SignSetupService.php index 9e5c9dbf80..b36ffbd2af 100644 --- a/lib/Service/Install/SignFiles.php +++ b/lib/Service/Install/SignSetupService.php @@ -21,7 +21,7 @@ use phpseclib\Crypt\RSA; use phpseclib\File\X509; -class SignFiles { +class SignSetupService { private IAppData $appData; private array $exclude = [ 'openssl_config', diff --git a/tests/Unit/Service/Install/SignFilesTest.php b/tests/Unit/Service/Install/SignSetupServiceTest.php similarity index 87% rename from tests/Unit/Service/Install/SignFilesTest.php rename to tests/Unit/Service/Install/SignSetupServiceTest.php index 85f51673b4..5d268f0554 100644 --- a/tests/Unit/Service/Install/SignFilesTest.php +++ b/tests/Unit/Service/Install/SignSetupServiceTest.php @@ -11,7 +11,7 @@ use bovigo\vfs\vfsStream; use OC\IntegrityCheck\Helpers\EnvironmentHelper; use OC\IntegrityCheck\Helpers\FileAccessHelper; -use OCA\Libresign\Service\Install\SignFiles; +use OCA\Libresign\Service\Install\SignSetupService; use OCP\App\IAppManager; use OCP\Files\AppData\IAppDataFactory; use OCP\IConfig; @@ -19,7 +19,7 @@ use phpseclib\File\X509; use PHPUnit\Framework\MockObject\MockObject; -final class SignFilesTest extends \OCA\Libresign\Tests\Unit\TestCase { +final class SignSetupServiceTest extends \OCA\Libresign\Tests\Unit\TestCase { private EnvironmentHelper&MockObject $environmentHelper; private FileAccessHelper $fileAccessHelper; private IConfig&MockObject $config; @@ -35,10 +35,10 @@ public function setUp(): void { } /** - * @return SignFiles|MockObject + * @return SignSetupService|MockObject */ private function getInstance(array $methods = []) { - return $this->getMockBuilder(SignFiles::class) + return $this->getMockBuilder(SignSetupService::class) ->setConstructorArgs([ $this->environmentHelper, $this->fileAccessHelper, @@ -100,7 +100,7 @@ public static function dataGetArchitectures(): array { ]; } - private function writeAppSignature(string $architecture): SignFiles { + private function writeAppSignature(string $architecture): SignSetupService { $this->appManager->method('getAppInfo') ->willReturn(['dependencies' => ['architecture' => [$architecture]]]); @@ -134,11 +134,11 @@ private function writeAppSignature(string $architecture): SignFiles { $this->environmentHelper->method('getServerRoot') ->willReturn('vfs://home'); - $signFiles = $this->getInstance(['getInternalPathOfFolder']); - $signFiles->expects($this->any()) + $signSetupService = $this->getInstance(['getInternalPathOfFolder']); + $signSetupService->expects($this->any()) ->method('getInternalPathOfFolder') ->willReturn('libresign'); - $signFiles->writeAppSignature($x509, $rsa, $architecture, 'vfs://home/appinfo'); + $signSetupService->writeAppSignature($x509, $rsa, $architecture, 'vfs://home/appinfo'); $this->assertFileExists('vfs://home/appinfo/install-' . $architecture . '.json'); $json = file_get_contents('vfs://home/appinfo/install-' . $architecture . '.json'); $signatureContent = json_decode($json, true); @@ -147,15 +147,15 @@ private function writeAppSignature(string $architecture): SignFiles { $expected = hash('sha512', $structure['data']['libresign']['fakeFile01']); $actual = $signatureContent['hashes']['fakeFile01']; $this->assertEquals($expected, $actual); - return $signFiles; + return $signSetupService; } /** * @dataProvider dataWriteAppSignature */ public function testWriteAppSignature(string $architecture): void { - $signFiles = $this->writeAppSignature($architecture); - $actual = $signFiles->verify($architecture, 'vfs://home/appinfo', 'LibreSign'); + $signSetupService = $this->writeAppSignature($architecture); + $actual = $signSetupService->verify($architecture, 'vfs://home/appinfo', 'LibreSign'); $this->assertCount(0, $actual); } @@ -167,7 +167,7 @@ public static function dataWriteAppSignature(): array { public function testVerify(): void { $architecture = 'x86_64'; - $signFiles = $this->writeAppSignature($architecture); + $signSetupService = $this->writeAppSignature($architecture); unlink('vfs://home/data/libresign/fakeFile01'); file_put_contents('vfs://home/data/libresign/fakeFile02', 'invalidContent'); file_put_contents('vfs://home/data/libresign/fakeFile03', 'invalidContent'); @@ -191,7 +191,7 @@ public function testVerify(): void { ], ], ]); - $actual = $signFiles->verify($architecture, 'vfs://home/appinfo', 'LibreSign'); + $actual = $signSetupService->verify($architecture, 'vfs://home/appinfo', 'LibreSign'); $actual = json_encode($actual); $this->assertJsonStringEqualsJsonString($expected, $actual); } diff --git a/tests/Unit/Service/InstallServiceTest.php b/tests/Unit/Service/InstallServiceTest.php index 0ed9fe9097..c198d4a166 100644 --- a/tests/Unit/Service/InstallServiceTest.php +++ b/tests/Unit/Service/InstallServiceTest.php @@ -27,7 +27,7 @@ use OCA\Libresign\Handler\CertificateEngine\Handler as CertificateEngineHandler; use OCA\Libresign\Service\Install\InstallService; -use OCA\Libresign\Service\Install\SignFiles; +use OCA\Libresign\Service\Install\SignSetupService; use OCP\AppFramework\Services\IAppConfig; use OCP\Files\AppData\IAppDataFactory; use OCP\Files\IRootFolder; @@ -47,6 +47,7 @@ final class InstallServiceTest extends \OCA\Libresign\Tests\Unit\TestCase { private IAppConfig|MockObject $appConfig; private IRootFolder|MockObject $rootFolder; private LoggerInterface|MockObject $logger; + private SignSetupService|MockObject $ignSetupService; private IAppDataFactory|MockObject $appDataFactory; public function setUp(): void { @@ -61,7 +62,7 @@ protected function getInstallService(): InstallService { $this->appConfig = $this->createMock(IAppConfig::class); $this->rootFolder = $this->createMock(IRootFolder::class); $this->logger = $this->createMock(LoggerInterface::class); - $this->signFiles = $this->createMock(SignFiles::class); + $this->ignSetupService = $this->createMock(SignSetupService::class); $this->appDataFactory = $this->createMock(IAppDataFactory::class); return new InstallService( $this->cacheFactory, @@ -71,7 +72,7 @@ protected function getInstallService(): InstallService { $this->appConfig, $this->rootFolder, $this->logger, - $this->signFiles, + $this->ignSetupService, $this->appDataFactory ); } From 525180ad69e169b80612a9f18cf327e08d634504 Mon Sep 17 00:00:00 2001 From: Vitor Mattos Date: Tue, 4 Jun 2024 09:29:08 -0300 Subject: [PATCH 36/50] chore: psalm update baseline Signed-off-by: Vitor Mattos --- tests/psalm-baseline.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/psalm-baseline.xml b/tests/psalm-baseline.xml index 1145f2da49..b703fe0f1d 100644 --- a/tests/psalm-baseline.xml +++ b/tests/psalm-baseline.xml @@ -126,7 +126,7 @@ - + From f210069eb86cf9d59b7b452680483e87cd251ff5 Mon Sep 17 00:00:00 2001 From: Vitor Mattos Date: Tue, 4 Jun 2024 15:46:25 -0300 Subject: [PATCH 37/50] chore: use architecture to uninstall dependencies Signed-off-by: Vitor Mattos --- lib/Command/Uninstall.php | 10 ++++++++++ lib/Service/Install/InstallService.php | 25 +++++++------------------ 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/lib/Command/Uninstall.php b/lib/Command/Uninstall.php index e3368db651..e4a6330a68 100644 --- a/lib/Command/Uninstall.php +++ b/lib/Command/Uninstall.php @@ -62,6 +62,12 @@ protected function configure(): void { shortcut: null, mode: InputOption::VALUE_NONE, description: 'Java' + ) + ->addOption( + name: 'architecture', + shortcut: null, + mode: InputOption::VALUE_REQUIRED, + description: 'x86_64 or aarch64' ); } @@ -69,6 +75,10 @@ protected function execute(InputInterface $input, OutputInterface $output): int $ok = false; try { + $architecture = (string) $input->getOption('architecture'); + if (in_array($architecture, ['x86_64', 'aarch64'])) { + $this->installService->setArchitecture($architecture); + } $all = $input->getOption('all'); if ($input->getOption('java') || $all) { $this->installService->uninstallJava(); diff --git a/lib/Service/Install/InstallService.php b/lib/Service/Install/InstallService.php index 5b8e8e15cf..e2fde636a9 100644 --- a/lib/Service/Install/InstallService.php +++ b/lib/Service/Install/InstallService.php @@ -480,14 +480,9 @@ public function uninstallJSignPdf(): void { if (!$jsignpdJarPath) { return; } - $appFolder = $this->appData->getFolder('/'); - $name = $appFolder->getName(); - // Remove prefix - $path = explode($name, $jsignpdJarPath)[1]; - // Remove sufix - $path = trim($path, '/JSignPdf.jar'); + $this->setResource('jsignpdf'); + $folder = $this->getFolder($this->resource); try { - $folder = $appFolder->getFolder($path); $folder->delete(); } catch (NotFoundException $e) { } @@ -525,13 +520,10 @@ public function uninstallPdftk(): void { if (!$jsignpdJarPath) { return; } - $appFolder = $this->appData->getFolder('/'); - $name = $appFolder->getName(); - // Remove prefix - $path = explode($name, $jsignpdJarPath)[1]; + $this->setResource('pdftk'); + $folder = $this->getFolder($this->resource); try { - $file = $appFolder->getFile($path); - $file->delete(); + $folder->delete(); } catch (NotFoundException $e) { } $this->appConfig->deleteAppValue('pdftk_path'); @@ -616,12 +608,9 @@ public function uninstallCfssl(): void { if (!$cfsslPath) { return; } - $appFolder = $this->appData->getFolder('/'); - $name = $appFolder->getName(); - // Remove prefix - $path = explode($name, $cfsslPath)[1]; + $this->setResource('cfssl'); + $folder = $this->getFolder($this->resource); try { - $folder = $appFolder->getFolder($path); $folder->delete(); } catch (NotFoundException $e) { } From dd4402e7ac09503e56dd897baf8e054f055db81e Mon Sep 17 00:00:00 2001 From: Vitor Mattos Date: Tue, 4 Jun 2024 15:47:45 -0300 Subject: [PATCH 38/50] chore: clean getHash function Signed-off-by: Vitor Mattos --- lib/Service/Install/InstallService.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/Service/Install/InstallService.php b/lib/Service/Install/InstallService.php index e2fde636a9..1df9fdb422 100644 --- a/lib/Service/Install/InstallService.php +++ b/lib/Service/Install/InstallService.php @@ -388,7 +388,7 @@ public function installJava(?bool $async = false): void { } $folder = $this->getFolder(); $checksumUrl = $url . '.sha256.txt'; - $hash = $this->getHash($folder, 'java_' . $linuxDistribution, $compressedFileName, self::JAVA_PARTIAL_VERSION, $checksumUrl); + $hash = $this->getHash($compressedFileName, $checksumUrl); try { $compressedFile = $javaFolder->getFile($compressedFileName); } catch (NotFoundException $th) { @@ -571,7 +571,7 @@ private function installCfssl64(): void { $baseUrl = 'https://github.com/cloudflare/cfssl/releases/download/v' . self::CFSSL_VERSION . '/'; $checksumUrl = 'https://github.com/cloudflare/cfssl/releases/download/v' . self::CFSSL_VERSION . '/cfssl_' . self::CFSSL_VERSION . '_checksums.txt'; foreach ($downloads as $download) { - $hash = $this->getHash($folder, 'cfssl', $download['file'], self::CFSSL_VERSION, $checksumUrl); + $hash = $this->getHash($download['file'], $checksumUrl); $file = $folder->newFile($download['destination']); $fullPath = $this->getDataDir() . '/' . $this->getInternalPathOfFile($file); @@ -685,7 +685,7 @@ protected function downloadCli(string $url, string $filename, string $path, ?str } } - private function getHash(ISimpleFolder $folder, string $type, string $file, string $version, string $checksumUrl): string { + private function getHash(string $file, string $checksumUrl): string { $hashes = file_get_contents($checksumUrl); if (!$hashes) { throw new LibresignException('Failute to download hash file. URL: ' . $checksumUrl); From e212f1e06885b757c1ec805483530a60fb890e38 Mon Sep 17 00:00:00 2001 From: Vitor Mattos Date: Tue, 4 Jun 2024 15:49:26 -0300 Subject: [PATCH 39/50] chore: unify cfssl setup methods Signed-off-by: Vitor Mattos --- lib/Service/Install/InstallService.php | 32 ++++++++------------------ 1 file changed, 9 insertions(+), 23 deletions(-) diff --git a/lib/Service/Install/InstallService.php b/lib/Service/Install/InstallService.php index 1df9fdb422..897e85ff90 100644 --- a/lib/Service/Install/InstallService.php +++ b/lib/Service/Install/InstallService.php @@ -548,23 +548,25 @@ public function installCfssl(?bool $async = false): void { throw new RuntimeException(sprintf('OS_FAMILY %s is incompatible with LibreSign.', PHP_OS_FAMILY)); } if ($this->architecture === 'x86_64') { - $this->installCfssl64(); + $this->installCfsslByArchitecture('amd64'); } elseif ($this->architecture === 'aarch64') { - $this->installCfsslArm(); + $this->installCfsslByArchitecture('arm64'); + } else { + throw new InvalidArgumentException('Invalid architecture to download cfssl'); } $this->removeDownloadProgress(); } - private function installCfssl64(): void { - $folder = $this->getFolder(); + private function installCfsslByArchitecture(string $arcitecture): void { + $folder = $this->getFolder($this->resource); $downloads = [ [ - 'file' => 'cfssl_' . self::CFSSL_VERSION . '_linux_amd64', + 'file' => 'cfssl_' . self::CFSSL_VERSION . '_linux_' . $arcitecture, 'destination' => 'cfssl', ], [ - 'file' => 'cfssljson_' . self::CFSSL_VERSION . '_linux_amd64', + 'file' => 'cfssljson_' . self::CFSSL_VERSION . '_linux_' . $arcitecture, 'destination' => 'cfssljson', ], ]; @@ -582,27 +584,11 @@ private function installCfssl64(): void { } $cfsslBinPath = $this->getDataDir() . '/' . - $this->getInternalPathOfFolder($this->getFolder()) . '/' . + $this->getInternalPathOfFolder($folder) . '/' . $downloads[0]['destination']; $this->appConfig->setAppValue('cfssl_bin', $cfsslBinPath); } - private function installCfsslArm(): void { - $url = sprintf('https://github.com/cloudflare/cfssl/releases/download/v%s/cfssl-bundle_%s_linux_arm64', self::CFSSL_VERSION, self::CFSSL_VERSION); - - $folder = $this->getFolder(); - $file = $folder->newFile('cfssl'); - $fullPath = $this->getDataDir() . '/' . $this->getInternalPathOfFile($file); - $checksumUrl = sprintf('https://github.com/cloudflare/cfssl/releases/download/v%s/cfssl_%s_checksums.txt', self::CFSSL_VERSION, self::CFSSL_VERSION); - $hash = $this->getHash($folder, 'cfssl', 'cfssl-bundle_' . self::CFSSL_VERSION . '_linux_arm64', self::CFSSL_VERSION, $checksumUrl); - $this->download($url, 'cfssl', $fullPath, $hash, 'sha256'); - - $cfsslBinPath = $this->getDataDir() . '/' . - $this->getInternalPathOfFolder($this->getFolder()) . '/' . - 'cfssl/usr/bin/cfssl'; - $this->appConfig->setAppValue('cfssl_bin', $cfsslBinPath); - } - public function uninstallCfssl(): void { $cfsslPath = $this->appConfig->getAppValue('cfssl_bin'); if (!$cfsslPath) { From 8bbcb496b6cbb22d3b17f56c6e6e098e0be9a759 Mon Sep 17 00:00:00 2001 From: Vitor Mattos Date: Tue, 4 Jun 2024 15:50:01 -0300 Subject: [PATCH 40/50] chore: store downloaded files at resource folder By this way will be possible simplify the uninstall method Signed-off-by: Vitor Mattos --- lib/Service/Install/InstallService.php | 27 ++++++++++---------------- 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/lib/Service/Install/InstallService.php b/lib/Service/Install/InstallService.php index 897e85ff90..4a29e252f0 100644 --- a/lib/Service/Install/InstallService.php +++ b/lib/Service/Install/InstallService.php @@ -362,8 +362,8 @@ public function installJava(?bool $async = false): void { $this->runAsync(); return; } - $extractDir = $this->getFullPath() . '/java'; - $javaFolder = $this->getFolder('/java'); + $extractDir = $this->getFullPath() . '/' . $this->resource; + $javaFolder = $this->getFolder($this->resource); /** * Steps to update: @@ -423,17 +423,10 @@ public function uninstallJava(): void { if (!$javaPath) { return; } - $appFolder = $this->getFolder('/'); - $name = $appFolder->getName(); - if (!strpos($javaPath, $name)) { - return; - } - if (PHP_OS_FAMILY !== 'Windows') { - exec('rm -rf ' . $this->getDataDir() . '/' . $this->getInternalPathOfFolder($this->getFolder()) . '/java'); - } + $this->setResource('java'); + $folder = $this->getFolder($this->resource); try { - $javaFolder = $appFolder->getFolder('/libresign/java'); - $javaFolder->delete(); + $folder->delete(); } catch (NotFoundException $th) { } $this->appConfig->deleteAppValue('java_path'); @@ -451,13 +444,13 @@ public function installJSignPdf(?bool $async = false): void { $this->runAsync(); return; } - $extractDir = $this->getFullPath(); + $extractDir = $this->getFullPath() . '/' . $this->resource; $compressedFileName = 'jsignpdf-' . JSignPdfHandler::VERSION . '.zip'; try { - $compressedFile = $this->getFolder()->getFile($compressedFileName); + $compressedFile = $this->getFolder($this->resource)->getFile($compressedFileName); } catch (\Throwable $th) { - $compressedFile = $this->getFolder()->newFile($compressedFileName); + $compressedFile = $this->getFolder($this->resource)->newFile($compressedFileName); } $comporessedInternalFileName = $this->getDataDir() . '/' . $this->getInternalPathOfFile($compressedFile); $url = 'https://github.com/intoolswetrust/jsignpdf/releases/download/JSignPdf_' . str_replace('.', '_', JSignPdfHandler::VERSION) . '/jsignpdf-' . JSignPdfHandler::VERSION . '.zip'; @@ -500,9 +493,9 @@ public function installPdftk(?bool $async = false): void { } try { - $file = $this->getFolder()->getFile('pdftk.jar'); + $file = $this->getFolder($this->resource)->getFile('pdftk.jar'); } catch (\Throwable $th) { - $file = $this->getFolder()->newFile('pdftk.jar'); + $file = $this->getFolder($this->resource)->newFile('pdftk.jar'); } $fullPath = $this->getDataDir() . '/' . $this->getInternalPathOfFile($file); $url = 'https://gitlab.com/api/v4/projects/5024297/packages/generic/pdftk-java/v' . self::PDFTK_VERSION . '/pdftk-all.jar'; From 7817d019be1ead7a566d4c3892a041557a35f969 Mon Sep 17 00:00:00 2001 From: Vitor Mattos Date: Tue, 4 Jun 2024 16:54:18 -0300 Subject: [PATCH 41/50] chore: validate signature by resource Signed-off-by: Vitor Mattos --- lib/Service/Install/ConfigureCheckService.php | 49 ++++++---- lib/Service/Install/InstallService.php | 2 +- lib/Service/Install/SignSetupService.php | 89 +++++++++++++------ .../Service/Install/SignSetupServiceTest.php | 39 +++++--- tests/psalm-baseline.xml | 3 +- 5 files changed, 124 insertions(+), 58 deletions(-) diff --git a/lib/Service/Install/ConfigureCheckService.php b/lib/Service/Install/ConfigureCheckService.php index 49b0d6d4bf..d8b0452204 100644 --- a/lib/Service/Install/ConfigureCheckService.php +++ b/lib/Service/Install/ConfigureCheckService.php @@ -31,13 +31,15 @@ use OCP\AppFramework\Services\IAppConfig; class ConfigureCheckService { + private string $architecture; public function __construct( private IAppConfig $appConfig, private SystemConfig $systemConfig, private JSignPdfHandler $jSignPdfHandler, private CertificateEngine $certificateEngine, - private InstallService $installService, + private SignSetupService $signSetupService, ) { + $this->architecture = php_uname('m'); } /** @@ -59,27 +61,12 @@ public function checkAll(): array { */ public function checkSign(): array { $return = []; - $return = array_merge($return, $this->checkHash()); $return = array_merge($return, $this->checkJava()); $return = array_merge($return, $this->checkPdftk()); $return = array_merge($return, $this->checkJSignPdf()); return $return; } - public function checkHash(): array { - if (!$this->installService->isDownloadedFilesOk()) { - return [ - (new ConfigureCheckHelper()) - ->setErrorMessage( - 'Invalid hash of binaries files.' - ) - ->setResource('java') - ->setTip('Run occ libresign:install --all'), - ]; - } - return []; - } - /** * Check all requirements to use JSignPdf * @@ -88,6 +75,16 @@ public function checkHash(): array { public function checkJSignPdf(): array { $jsignpdJarPath = $this->appConfig->getAppValue('jsignpdf_jar_path'); if ($jsignpdJarPath) { + if (count($this->signSetupService->verify($this->architecture, 'jsignpdf'))) { + return [ + (new ConfigureCheckHelper()) + ->setErrorMessage( + 'Invalid hash of binaries files.' + ) + ->setResource('jsignpdf') + ->setTip('Run occ libresign:install --all'), + ]; + } if (file_exists($jsignpdJarPath)) { if (!$this->isJavaOk()) { return [ @@ -148,6 +145,16 @@ public function checkJSignPdf(): array { public function checkPdftk(): array { $pdftkPath = $this->appConfig->getAppValue('pdftk_path'); if ($pdftkPath) { + if (count($this->signSetupService->verify($this->architecture, 'pdftk'))) { + return [ + (new ConfigureCheckHelper()) + ->setErrorMessage( + 'Invalid hash of binaries files.' + ) + ->setResource('pdftk') + ->setTip('Run occ libresign:install --all'), + ]; + } if (file_exists($pdftkPath)) { if (!$this->isJavaOk()) { return [ @@ -217,6 +224,16 @@ public function checkPdftk(): array { private function checkJava(): array { $javaPath = $this->appConfig->getAppValue('java_path'); if ($javaPath) { + if (count($this->signSetupService->verify($this->architecture, 'java'))) { + return [ + (new ConfigureCheckHelper()) + ->setErrorMessage( + 'Invalid hash of binaries files.' + ) + ->setResource('java') + ->setTip('Run occ libresign:install --all'), + ]; + } if (file_exists($javaPath)) { \exec($javaPath . " -version 2>&1", $javaVersion, $resultCode); if (empty($javaVersion)) { diff --git a/lib/Service/Install/InstallService.php b/lib/Service/Install/InstallService.php index 4a29e252f0..de9da28362 100644 --- a/lib/Service/Install/InstallService.php +++ b/lib/Service/Install/InstallService.php @@ -347,7 +347,7 @@ public function setResource(string $resource): self { public function isDownloadedFilesOk(): bool { try { - return count($this->signSetupService->verify($this->architecture)) === 0; + return count($this->signSetupService->verify($this->architecture, $this->resource)) === 0; } catch (InvalidSignatureException $e) { return false; } diff --git a/lib/Service/Install/SignSetupService.php b/lib/Service/Install/SignSetupService.php index b36ffbd2af..4d208859b7 100644 --- a/lib/Service/Install/SignSetupService.php +++ b/lib/Service/Install/SignSetupService.php @@ -29,6 +29,9 @@ class SignSetupService { 'unauthetnicated', ]; private string $architecture; + private string $resource; + private array $signatureData = []; + private ?x509 $x509 = null; public function __construct( private EnvironmentHelper $environmentHelper, private FileAccessHelper $fileAccessHelper, @@ -59,14 +62,11 @@ public function writeAppSignature( X509 $certificate, RSA $privateKey, string $architecture, - string $appInfoDir = '', ) { $this->architecture = $architecture; - $appInfoDir = $this->getAppInfoDirectory($appInfoDir); + $appInfoDir = $this->getAppInfoDirectory(); try { - $this->fileAccessHelper->assertDirectoryExists($appInfoDir); - - $iterator = $this->getFolderIterator(); + $iterator = $this->getFolderIterator($this->getInstallPath()); $hashes = $this->generateHashes($iterator); $signature = $this->createSignatureData($hashes, $certificate, $privateKey); $this->fileAccessHelper->file_put_contents( @@ -83,11 +83,10 @@ public function writeAppSignature( } } - private function getAppInfoDirectory(string $appInfoDir): string { - if (is_dir($appInfoDir)) { - return $appInfoDir; - } - return realpath(__DIR__ . '/../../../appinfo'); + protected function getAppInfoDirectory(): string { + $appInfoDir = realpath(__DIR__ . '/../../../appinfo'); + $this->fileAccessHelper->assertDirectoryExists($appInfoDir); + return $appInfoDir; } /** @@ -102,10 +101,11 @@ private function splitCerts(string $cert): array { return $matches[0]; } - public function verify(string $architecture, string $appInfoDir = '', string $certificateCN = Application::APP_ID): array { - $this->architecture = $architecture; - $appInfoDir = $this->getAppInfoDirectory($appInfoDir); - + private function getSignatureData(): array { + if (!empty($this->signatureData)) { + return $this->signatureData; + } + $appInfoDir = $this->getAppInfoDirectory(); $signaturePath = $appInfoDir . '/install-' . $this->architecture . '.json'; $content = $this->fileAccessHelper->file_get_contents($signaturePath); $signatureData = null; @@ -116,31 +116,58 @@ public function verify(string $architecture, string $appInfoDir = '', string $ce if (!\is_array($signatureData)) { throw new InvalidSignatureException('Signature data not found.'); } + $this->signatureData = $signatureData; + + $this->validateIfIssignedByLibresignAppCertificate($signatureData['hashes']); + return $this->signatureData; + } + + private function getHashesOfResource(): array { + $signatureData = $this->getSignatureData(); $expectedHashes = $signatureData['hashes']; - ksort($expectedHashes); - $signature = base64_decode($signatureData['signature']); + $filtered = array_filter($expectedHashes, function (string $key) { + return str_starts_with($key, $this->resource); + }, ARRAY_FILTER_USE_KEY); + if (!$filtered) { + throw new InvalidSignatureException('No signature files to ' . $this->resource); + } + return $filtered; + } + + private function getLibresignAppCertificate(): X509 { + if ($this->x509 instanceof X509) { + return $this->x509; + } + $signatureData = $this->getSignatureData(); $certificate = $signatureData['certificate']; // Check if certificate is signed by Nextcloud Root Authority - $x509 = new \phpseclib\File\X509(); + $this->x509 = new X509(); $rootCertificatePublicKey = $this->fileAccessHelper->file_get_contents($this->environmentHelper->getServerRoot().'/resources/codesigning/root.crt'); $rootCerts = $this->splitCerts($rootCertificatePublicKey); foreach ($rootCerts as $rootCert) { - $x509->loadCA($rootCert); + $this->x509->loadCA($rootCert); } - $x509->loadX509($certificate); - if (!$x509->validateSignature()) { + $this->x509->loadX509($certificate); + if (!$this->x509->validateSignature()) { throw new InvalidSignatureException('Certificate is not valid.'); } + // Verify if certificate has proper CN. "core" CN is always trusted. - if ($x509->getDN(X509::DN_OPENSSL)['CN'] !== $certificateCN && $x509->getDN(X509::DN_OPENSSL)['CN'] !== 'core') { + if ($this->x509->getDN(X509::DN_OPENSSL)['CN'] !== Application::APP_ID && $this->x509->getDN(X509::DN_OPENSSL)['CN'] !== 'core') { throw new InvalidSignatureException( - sprintf('Certificate is not valid for required scope. (Requested: %s, current: CN=%s)', $certificateCN, $x509->getDN(true)['CN']) + sprintf('Certificate is not valid for required scope. (Requested: %s, current: CN=%s)', Application::APP_ID, $this->x509->getDN(true)['CN']) ); } + return $this->x509; + } + + private function validateIfIssignedByLibresignAppCertificate(array $expectedHashes): void { + $x509 = $this->getLibresignAppCertificate(); + // Check if the signature of the files is valid $rsa = new \phpseclib\Crypt\RSA(); $rsa->loadKey($x509->currentCert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey']); @@ -148,13 +175,23 @@ public function verify(string $architecture, string $appInfoDir = '', string $ce $rsa->setMGFHash('sha512'); // See https://tools.ietf.org/html/rfc3447#page-38 $rsa->setSaltLength(0); + + $signatureData = $this->getSignatureData(); + $signature = base64_decode($signatureData['signature']); if (!$rsa->verify(json_encode($expectedHashes), $signature)) { throw new InvalidSignatureException('Signature could not get verified.'); } + } + + public function verify(string $architecture, $resource): array { + $this->architecture = $architecture; + $this->resource = $resource; + + $expectedHashes = $this->getHashesOfResource(); // Compare the list of files which are not identical - $installPath = $this->getInstallPath(); - $currentInstanceHashes = $this->generateHashes($this->getFolderIterator(), $installPath); + $installPath = $this->getInstallPath() . '/' . $this->resource; + $currentInstanceHashes = $this->generateHashes($this->getFolderIterator($installPath), $installPath); $differencesA = array_diff($expectedHashes, $currentInstanceHashes); $differencesB = array_diff($currentInstanceHashes, $expectedHashes); $differences = array_merge($differencesA, $differencesB); @@ -224,9 +261,9 @@ private function getInstallPath(): string { * @return \RecursiveIteratorIterator * @throws \Exception */ - private function getFolderIterator(): \RecursiveIteratorIterator { + private function getFolderIterator(string $folderToIterate): \RecursiveIteratorIterator { $dirItr = new \RecursiveDirectoryIterator( - $this->getInstallPath(), + $folderToIterate, \RecursiveDirectoryIterator::SKIP_DOTS ); diff --git a/tests/Unit/Service/Install/SignSetupServiceTest.php b/tests/Unit/Service/Install/SignSetupServiceTest.php index 5d268f0554..103d7d841c 100644 --- a/tests/Unit/Service/Install/SignSetupServiceTest.php +++ b/tests/Unit/Service/Install/SignSetupServiceTest.php @@ -56,7 +56,7 @@ private function getNewCert(): array { 'private_key_type' => OPENSSL_KEYTYPE_RSA, ]); - $csrNames = ['commonName' => 'LibreSign']; + $csrNames = ['commonName' => 'libresign']; $csr = openssl_csr_new($csrNames, $privateKey, ['digest_alg' => 'sha256']); $x509 = openssl_csr_sign($csr, null, $privateKey, $days = 365, ['digest_alg' => 'sha256']); @@ -115,8 +115,10 @@ private function writeAppSignature(string $architecture): SignSetupService { $structure = [ 'data' => [ 'libresign' => [ - 'fakeFile01' => 'content', - 'fakeFile02' => 'content', + 'java' => [ + 'fakeFile01' => 'content', + 'fakeFile02' => 'content', + ], ], ], 'resources' => [ @@ -134,18 +136,25 @@ private function writeAppSignature(string $architecture): SignSetupService { $this->environmentHelper->method('getServerRoot') ->willReturn('vfs://home'); - $signSetupService = $this->getInstance(['getInternalPathOfFolder']); + $signSetupService = $this->getInstance([ + 'getInternalPathOfFolder', + 'getAppInfoDirectory', + ]); $signSetupService->expects($this->any()) ->method('getInternalPathOfFolder') ->willReturn('libresign'); + $signSetupService->expects($this->any()) + ->method('getAppInfoDirectory') + ->willReturn('vfs://home/appinfo'); + $signSetupService->writeAppSignature($x509, $rsa, $architecture, 'vfs://home/appinfo'); $this->assertFileExists('vfs://home/appinfo/install-' . $architecture . '.json'); $json = file_get_contents('vfs://home/appinfo/install-' . $architecture . '.json'); $signatureContent = json_decode($json, true); $this->assertArrayHasKey('hashes', $signatureContent); $this->assertCount(2, $signatureContent['hashes']); - $expected = hash('sha512', $structure['data']['libresign']['fakeFile01']); - $actual = $signatureContent['hashes']['fakeFile01']; + $expected = hash('sha512', $structure['data']['libresign']['java']['fakeFile01']); + $actual = $signatureContent['hashes']['java/fakeFile01']; $this->assertEquals($expected, $actual); return $signSetupService; } @@ -155,7 +164,9 @@ private function writeAppSignature(string $architecture): SignSetupService { */ public function testWriteAppSignature(string $architecture): void { $signSetupService = $this->writeAppSignature($architecture); - $actual = $signSetupService->verify($architecture, 'vfs://home/appinfo', 'LibreSign'); + $architecture = 'x86_64'; + $resource = 'java'; + $actual = $signSetupService->verify($architecture, $resource); $this->assertCount(0, $actual); } @@ -168,30 +179,30 @@ public static function dataWriteAppSignature(): array { public function testVerify(): void { $architecture = 'x86_64'; $signSetupService = $this->writeAppSignature($architecture); - unlink('vfs://home/data/libresign/fakeFile01'); - file_put_contents('vfs://home/data/libresign/fakeFile02', 'invalidContent'); - file_put_contents('vfs://home/data/libresign/fakeFile03', 'invalidContent'); + unlink('vfs://home/data/libresign/java/fakeFile01'); + file_put_contents('vfs://home/data/libresign/java/fakeFile02', 'invalidContent'); + file_put_contents('vfs://home/data/libresign/java/fakeFile03', 'invalidContent'); $expected = json_encode([ 'FILE_MISSING' => [ - 'fakeFile01' => [ + 'java/fakeFile01' => [ 'expected' => 'b2d1d285b5199c85f988d03649c37e44fd3dde01e5d69c50fef90651962f48110e9340b60d49a479c4c0b53f5f07d690686dd87d2481937a512e8b85ee7c617f', 'current' => '', ], ], 'INVALID_HASH' => [ - 'fakeFile02' => [ + 'java/fakeFile02' => [ 'expected' => 'b2d1d285b5199c85f988d03649c37e44fd3dde01e5d69c50fef90651962f48110e9340b60d49a479c4c0b53f5f07d690686dd87d2481937a512e8b85ee7c617f', 'current' => '827a4e298c978e1eeffebdf09f0fa5a1e1d8b608c8071144f3fffb31f9ed21f6d27f88a63f7409583df7438105f713ff58d55e68e61e01a285125d763045c726', ], ], 'EXTRA_FILE' => [ - 'fakeFile03' => [ + 'java/fakeFile03' => [ 'expected' => '', 'current' => '827a4e298c978e1eeffebdf09f0fa5a1e1d8b608c8071144f3fffb31f9ed21f6d27f88a63f7409583df7438105f713ff58d55e68e61e01a285125d763045c726', ], ], ]); - $actual = $signSetupService->verify($architecture, 'vfs://home/appinfo', 'LibreSign'); + $actual = $signSetupService->verify($architecture, 'java'); $actual = json_encode($actual); $this->assertJsonStringEqualsJsonString($expected, $actual); } diff --git a/tests/psalm-baseline.xml b/tests/psalm-baseline.xml index b703fe0f1d..26059fd874 100644 --- a/tests/psalm-baseline.xml +++ b/tests/psalm-baseline.xml @@ -128,6 +128,8 @@ + currentCert]]> + @@ -136,7 +138,6 @@ - From 845f2afb579b9fcadda7670002254a686f36b9fd Mon Sep 17 00:00:00 2001 From: Vitor Mattos Date: Tue, 4 Jun 2024 17:05:06 -0300 Subject: [PATCH 42/50] fix: shrink package Signed-off-by: Vitor Mattos --- Makefile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Makefile b/Makefile index ef39f31655..cd3f2d620c 100644 --- a/Makefile +++ b/Makefile @@ -99,6 +99,9 @@ appstore: $(appstore_sign_dir)/$(app_name) rm $(appstore_sign_dir)/$(app_name)/vendor/endroid/qr-code/assets/* + find $(appstore_sign_dir)/$(app_name)/vendor/mpdf/mpdf/ttfonts -type f -not -name 'DejaVuSerifCondensed.ttf' -delete + find $(appstore_sign_dir)/$(app_name)/vendor/mpdf/mpdf/data/ -type f -delete + rm -rf $(appstore_sign_dir)/$(app_name)/img/screenshot/ mkdir -p $(appstore_sign_dir)/$(app_name)/tests/fixtures cp tests/fixtures/small_valid.pdf $(appstore_sign_dir)/$(app_name)/tests/fixtures From 3891a960ee1e413a844d85b98e70c9c1f0b54ee1 Mon Sep 17 00:00:00 2001 From: Vitor Mattos Date: Tue, 4 Jun 2024 18:21:48 -0300 Subject: [PATCH 43/50] chore: sign dependencies when build app Signed-off-by: Vitor Mattos --- Makefile | 74 +++++++++++++++----------------------------------------- 1 file changed, 20 insertions(+), 54 deletions(-) diff --git a/Makefile b/Makefile index cd3f2d620c..51bd8998a4 100644 --- a/Makefile +++ b/Makefile @@ -16,6 +16,11 @@ appstore_sign_dir=$(appstore_build_directory)/sign cert_dir=$(build_tools_directory)/certificates npm=$(shell which npm 2> /dev/null) composer=$(shell which composer 2> /dev/null) +ifeq (,$(shell type occ)) + occ="php ../../occ" +else + occ="occ" +endif all: dev-setup build-js-production serve: dev-setup watch-js @@ -82,52 +87,7 @@ updateocp: # Builds the source package for the app store, ignores php and js tests .PHONY: appstore -appstore: - rm -rf $(appstore_build_directory) - mkdir -p $(appstore_sign_dir)/$(app_name) - cp -r \ - appinfo \ - composer \ - img \ - js \ - l10n \ - lib \ - templates \ - vendor \ - CHANGELOG.md \ - LICENSE \ - $(appstore_sign_dir)/$(app_name) - - rm $(appstore_sign_dir)/$(app_name)/vendor/endroid/qr-code/assets/* - find $(appstore_sign_dir)/$(app_name)/vendor/mpdf/mpdf/ttfonts -type f -not -name 'DejaVuSerifCondensed.ttf' -delete - find $(appstore_sign_dir)/$(app_name)/vendor/mpdf/mpdf/data/ -type f -delete - rm -rf $(appstore_sign_dir)/$(app_name)/img/screenshot/ - mkdir -p $(appstore_sign_dir)/$(app_name)/tests/fixtures - cp tests/fixtures/small_valid.pdf $(appstore_sign_dir)/$(app_name)/tests/fixtures - - # Remove stray .htaccess files since they are filtered by Nextcloud - find $(appstore_sign_dir) -name .htaccess -exec rm {} \; - - @if [ -f $(cert_dir)/$(app_name).key ]; then \ - echo "Signing app files…"; \ - php ../../occ integrity:sign-app \ - --privateKey=$(cert_dir)/$(app_name).key\ - --certificate=$(cert_dir)/$(app_name).crt\ - --path=$(appstore_sign_dir)/$(app_name); \ - fi - tar -czf $(appstore_package_name).tar.gz \ - -C $(appstore_sign_dir) $(app_name) - - @if [ -f $(cert_dir)/$(app_name).key ]; then \ - echo "Signing package…"; \ - openssl dgst -sha512 -sign $(cert_dir)/$(app_name).key $(build_dir)/$(app_name).tar.gz | openssl base64; \ - fi - -# Earlier version of appstore command that builds the app and has some custom -# support for local signing. Left here in case it's needed by some developer -# used to it. -.PHONY: appstore-local -appstore-local: clean +appstore: clean mkdir -p $(appstore_sign_dir)/$(app_name) composer install --no-dev npm ci @@ -144,12 +104,19 @@ appstore-local: clean CHANGELOG.md \ LICENSE \ $(appstore_sign_dir)/$(app_name) + rm $(appstore_sign_dir)/$(app_name)/vendor/endroid/qr-code/assets/* find $(appstore_sign_dir)/$(app_name)/vendor/mpdf/mpdf/ttfonts -type f -not -name 'DejaVuSerifCondensed.ttf' -delete find $(appstore_sign_dir)/$(app_name)/vendor/mpdf/mpdf/data/ -type f -delete rm -rf $(appstore_sign_dir)/$(app_name)/img/screenshot/ mkdir -p $(appstore_sign_dir)/$(app_name)/tests/fixtures - cp tests/fixtures/small_valid.pdf $(appstore_sign_dir)/$(app_name)/tests/fixtures \ + cp tests/fixtures/small_valid.pdf $(appstore_sign_dir)/$(app_name)/tests/fixtures + + $(occ) config:app:set libresign certificate_engine --value cfssl + $(occ) libresign:install --all + $(occ) libresign:install --all --architecture aarch64 + $(occ) libresign:developer:sign-setup --privateKey=$(cert_dir)/$(app_name).key \ + --certificate=$(cert_dir)/$(app_name).crt @if [ -z "$$GITHUB_ACTION" ]; then \ chown -R www-data:www-data $(appstore_sign_dir)/$(app_name) ; \ @@ -160,18 +127,17 @@ appstore-local: clean curl -o $(cert_dir)/$(app_name).crt \ "https://github.com/nextcloud/app-certificate-requests/raw/master/$(app_name)/$(app_name).crt"; \ fi - @if [ -n "$$APP_PRIVATE_KEY" ]; then \ - echo "$$APP_PRIVATE_KEY" > $(cert_dir)/$(app_name).key; \ + @if [ -f $(cert_dir)/$(app_name).key ]; then \ echo "Signing app files…"; \ - runuser -u www-data -- \ - php ../../occ integrity:sign-app \ + $(occ) integrity:sign-app \ --privateKey=$(cert_dir)/$(app_name).key\ --certificate=$(cert_dir)/$(app_name).crt\ --path=$(appstore_sign_dir)/$(app_name); \ - echo "Signing app files ... done"; \ fi - tar -czf $(appstore_package_name).tar.gz -C $(appstore_sign_dir) $(app_name) - @if [ -n "$$APP_PRIVATE_KEY" ]; then \ + tar -czf $(appstore_package_name).tar.gz \ + -C $(appstore_sign_dir) $(app_name) + + @if [ -f $(cert_dir)/$(app_name).key ]; then \ echo "Signing package…"; \ openssl dgst -sha512 -sign $(cert_dir)/$(app_name).key $(appstore_package_name).tar.gz | openssl base64; \ fi From beb930d33455bbe492309ac47b7a1fba95b81945 Mon Sep 17 00:00:00 2001 From: Vitor Mattos Date: Tue, 4 Jun 2024 18:33:14 -0300 Subject: [PATCH 44/50] chore: remove unused var Signed-off-by: Vitor Mattos --- lib/Service/Install/InstallService.php | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/Service/Install/InstallService.php b/lib/Service/Install/InstallService.php index de9da28362..5f655514d1 100644 --- a/lib/Service/Install/InstallService.php +++ b/lib/Service/Install/InstallService.php @@ -386,7 +386,6 @@ public function installJava(?bool $async = false): void { } else { throw new RuntimeException(sprintf('OS_FAMILY %s is incompatible with LibreSign.', PHP_OS_FAMILY)); } - $folder = $this->getFolder(); $checksumUrl = $url . '.sha256.txt'; $hash = $this->getHash($compressedFileName, $checksumUrl); try { From 970de2979503eda8d2f79ed73806d6431f983d4c Mon Sep 17 00:00:00 2001 From: Vitor Mattos Date: Wed, 5 Jun 2024 16:31:22 -0300 Subject: [PATCH 45/50] chore: clean folder before download binaries Signed-off-by: Vitor Mattos --- lib/Service/Install/InstallService.php | 29 ++++++++++++++++-------- lib/Service/Install/SignSetupService.php | 3 +++ 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/lib/Service/Install/InstallService.php b/lib/Service/Install/InstallService.php index 5f655514d1..35e621a4bc 100644 --- a/lib/Service/Install/InstallService.php +++ b/lib/Service/Install/InstallService.php @@ -103,7 +103,7 @@ public function setArchitecture(string $architecture): void { $this->architecture = $architecture; } - private function getFolder(string $path = '', ?ISimpleFolder $folder = null): ISimpleFolder { + private function getFolder(string $path = '', ?ISimpleFolder $folder = null, $needToBeEmpty = false): ISimpleFolder { if (!$folder) { $folder = $this->appData->getFolder('/'); if (!$path) { @@ -119,6 +119,10 @@ private function getFolder(string $path = '', ?ISimpleFolder $folder = null): IS } try { $folder = $folder->getFolder($path, $folder); + if ($needToBeEmpty) { + $folder->delete(); + throw new \Exception('Need to be empty'); + } } catch (\Throwable $th) { try { $folder = $folder->newFolder($path); @@ -134,6 +138,10 @@ private function getFolder(string $path = '', ?ISimpleFolder $folder = null): IS return $folder; } + private function getEmptyFolder(string $path): ISimpleFolder { + return $this->getFolder($path, null, true); + } + /** * @todo check a best solution to don't use reflection */ @@ -362,8 +370,8 @@ public function installJava(?bool $async = false): void { $this->runAsync(); return; } + $folder = $this->getEmptyFolder($this->resource); $extractDir = $this->getFullPath() . '/' . $this->resource; - $javaFolder = $this->getFolder($this->resource); /** * Steps to update: @@ -389,9 +397,9 @@ public function installJava(?bool $async = false): void { $checksumUrl = $url . '.sha256.txt'; $hash = $this->getHash($compressedFileName, $checksumUrl); try { - $compressedFile = $javaFolder->getFile($compressedFileName); + $compressedFile = $folder->getFile($compressedFileName); } catch (NotFoundException $th) { - $compressedFile = $javaFolder->newFile($compressedFileName); + $compressedFile = $folder->newFile($compressedFileName); } $comporessedInternalFileName = $this->getDataDir() . '/' . $this->getInternalPathOfFile($compressedFile); @@ -443,13 +451,14 @@ public function installJSignPdf(?bool $async = false): void { $this->runAsync(); return; } + $folder = $this->getEmptyFolder($this->resource); $extractDir = $this->getFullPath() . '/' . $this->resource; $compressedFileName = 'jsignpdf-' . JSignPdfHandler::VERSION . '.zip'; try { - $compressedFile = $this->getFolder($this->resource)->getFile($compressedFileName); + $compressedFile = $folder->getFile($compressedFileName); } catch (\Throwable $th) { - $compressedFile = $this->getFolder($this->resource)->newFile($compressedFileName); + $compressedFile = $folder->newFile($compressedFileName); } $comporessedInternalFileName = $this->getDataDir() . '/' . $this->getInternalPathOfFile($compressedFile); $url = 'https://github.com/intoolswetrust/jsignpdf/releases/download/JSignPdf_' . str_replace('.', '_', JSignPdfHandler::VERSION) . '/jsignpdf-' . JSignPdfHandler::VERSION . '.zip'; @@ -490,11 +499,11 @@ public function installPdftk(?bool $async = false): void { $this->runAsync(); return; } - + $folder = $this->getEmptyFolder($this->resource); try { - $file = $this->getFolder($this->resource)->getFile('pdftk.jar'); + $file = $folder->getFile('pdftk.jar'); } catch (\Throwable $th) { - $file = $this->getFolder($this->resource)->newFile('pdftk.jar'); + $file = $folder->newFile('pdftk.jar'); } $fullPath = $this->getDataDir() . '/' . $this->getInternalPathOfFile($file); $url = 'https://gitlab.com/api/v4/projects/5024297/packages/generic/pdftk-java/v' . self::PDFTK_VERSION . '/pdftk-all.jar'; @@ -550,7 +559,7 @@ public function installCfssl(?bool $async = false): void { } private function installCfsslByArchitecture(string $arcitecture): void { - $folder = $this->getFolder($this->resource); + $folder = $this->getEmptyFolder($this->resource); $downloads = [ [ diff --git a/lib/Service/Install/SignSetupService.php b/lib/Service/Install/SignSetupService.php index 4d208859b7..9c09ee3a99 100644 --- a/lib/Service/Install/SignSetupService.php +++ b/lib/Service/Install/SignSetupService.php @@ -262,6 +262,9 @@ private function getInstallPath(): string { * @throws \Exception */ private function getFolderIterator(string $folderToIterate): \RecursiveIteratorIterator { + if (!is_dir($folderToIterate)) { + throw new InvalidSignatureException('No such directory ' . $folderToIterate); + } $dirItr = new \RecursiveDirectoryIterator( $folderToIterate, \RecursiveDirectoryIterator::SKIP_DOTS From 86643a4f814d058d7fecfd42e55fe778a6104b67 Mon Sep 17 00:00:00 2001 From: Vitor Mattos Date: Wed, 5 Jun 2024 16:42:35 -0300 Subject: [PATCH 46/50] chore: remove namespase that already was declared at this file Signed-off-by: Vitor Mattos --- lib/Service/Install/SignSetupService.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Service/Install/SignSetupService.php b/lib/Service/Install/SignSetupService.php index 9c09ee3a99..cab069e617 100644 --- a/lib/Service/Install/SignSetupService.php +++ b/lib/Service/Install/SignSetupService.php @@ -169,7 +169,7 @@ private function validateIfIssignedByLibresignAppCertificate(array $expectedHash $x509 = $this->getLibresignAppCertificate(); // Check if the signature of the files is valid - $rsa = new \phpseclib\Crypt\RSA(); + $rsa = new RSA(); $rsa->loadKey($x509->currentCert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey']); $rsa->setSignatureMode(RSA::SIGNATURE_PSS); $rsa->setMGFHash('sha512'); From 2799715241d3d4db5f4fa1bcd85f9dcef82101d3 Mon Sep 17 00:00:00 2001 From: Vitor Mattos Date: Wed, 5 Jun 2024 17:05:42 -0300 Subject: [PATCH 47/50] fix: SPDX Signed-off-by: Vitor Mattos --- lib/Exception/InvalidSignatureException.php | 2 +- lib/Service/Install/SignSetupService.php | 2 +- tests/Unit/Service/Install/SignSetupServiceTest.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/Exception/InvalidSignatureException.php b/lib/Exception/InvalidSignatureException.php index f012120f39..cb51f6ada2 100644 --- a/lib/Exception/InvalidSignatureException.php +++ b/lib/Exception/InvalidSignatureException.php @@ -2,7 +2,7 @@ declare(strict_types=1); /** - * SPDX-FileCopyrightText: 2020-2024 LibreCode coop and contributors + * SPDX-FileCopyrightText: 2024 LibreCode coop and contributors * SPDX-License-Identifier: AGPL-3.0-or-later */ diff --git a/lib/Service/Install/SignSetupService.php b/lib/Service/Install/SignSetupService.php index cab069e617..228c3529cd 100644 --- a/lib/Service/Install/SignSetupService.php +++ b/lib/Service/Install/SignSetupService.php @@ -2,7 +2,7 @@ declare(strict_types=1); /** - * SPDX-FileCopyrightText: 2020-2024 LibreCode coop and contributors + * SPDX-FileCopyrightText: 2024 LibreCode coop and contributors * SPDX-License-Identifier: AGPL-3.0-or-later */ diff --git a/tests/Unit/Service/Install/SignSetupServiceTest.php b/tests/Unit/Service/Install/SignSetupServiceTest.php index 103d7d841c..ff933e2001 100644 --- a/tests/Unit/Service/Install/SignSetupServiceTest.php +++ b/tests/Unit/Service/Install/SignSetupServiceTest.php @@ -2,7 +2,7 @@ declare(strict_types=1); /** - * SPDX-FileCopyrightText: 2020-2024 LibreCode coop and contributors + * SPDX-FileCopyrightText: 2024 LibreCode coop and contributors * SPDX-License-Identifier: AGPL-3.0-or-later */ From 2c82256224b7d14f51fa4a8081ad818495d72fe7 Mon Sep 17 00:00:00 2001 From: Vitor Mattos Date: Wed, 5 Jun 2024 17:06:26 -0300 Subject: [PATCH 48/50] chore: Update baseline Signed-off-by: Vitor Mattos --- tests/psalm-baseline.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/psalm-baseline.xml b/tests/psalm-baseline.xml index 26059fd874..ce5b4bf9d1 100644 --- a/tests/psalm-baseline.xml +++ b/tests/psalm-baseline.xml @@ -133,11 +133,11 @@ + - From b01ef79969e541976a93943b0ab8990614f1b580 Mon Sep 17 00:00:00 2001 From: Vitor Mattos Date: Wed, 5 Jun 2024 18:11:17 -0300 Subject: [PATCH 49/50] feat: implement repair step to delete previous setup files Will be necessary run the follow occ command first: files:scan-app-data libresign Signed-off-by: Vitor Mattos --- appinfo/info.xml | 5 +++ lib/Migration/DeleteOldBinaries.php | 58 +++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+) create mode 100644 lib/Migration/DeleteOldBinaries.php diff --git a/appinfo/info.xml b/appinfo/info.xml index 552625f8f5..82bf0796a8 100644 --- a/appinfo/info.xml +++ b/appinfo/info.xml @@ -47,6 +47,11 @@ Developed with ❤️ by [LibreCode](https://librecode.coop). Help us transform x86_64 aarch64 + + + OCA\Libresign\Migration\DeleteOldBinaries + + OCA\Libresign\Command\Configure\Check OCA\Libresign\Command\Configure\Cfssl diff --git a/lib/Migration/DeleteOldBinaries.php b/lib/Migration/DeleteOldBinaries.php new file mode 100644 index 0000000000..4d1ec668a1 --- /dev/null +++ b/lib/Migration/DeleteOldBinaries.php @@ -0,0 +1,58 @@ +appData = $appDataFactory->get('libresign'); + } + + public function getName(): string { + return 'Delete old binaries.'; + } + + public function run(IOutput $output): void { + $output->warning('Run the follow command first: files:scan-app-data libresign'); + $this->output = $output; + $folder = $this->appData->getFolder('/'); + + $list = $this->getDirectoryListing($folder); + foreach ($list as $file) { + if (!in_array($file->getName(), $this->allowedFiles)) { + $file->delete(); + } + } + } + + private function getDirectoryListing(ISimpleFolder $node): array { + $reflection = new \ReflectionClass($node); + $reflectionProperty = $reflection->getProperty('folder'); + $reflectionProperty->setAccessible(true); + $folder = $reflectionProperty->getValue($node); + $list = $folder->getDirectoryListing(); + return $list; + } +} From 798b36e0eddcc83b0d4f439bc1644efad6092a74 Mon Sep 17 00:00:00 2001 From: Vitor Mattos Date: Wed, 5 Jun 2024 18:59:45 -0300 Subject: [PATCH 50/50] fix: backport Signed-off-by: Vitor Mattos --- tests/Unit/Service/Install/SignSetupServiceTest.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/Unit/Service/Install/SignSetupServiceTest.php b/tests/Unit/Service/Install/SignSetupServiceTest.php index ff933e2001..c34f0e16dc 100644 --- a/tests/Unit/Service/Install/SignSetupServiceTest.php +++ b/tests/Unit/Service/Install/SignSetupServiceTest.php @@ -20,11 +20,11 @@ use PHPUnit\Framework\MockObject\MockObject; final class SignSetupServiceTest extends \OCA\Libresign\Tests\Unit\TestCase { - private EnvironmentHelper&MockObject $environmentHelper; + private EnvironmentHelper|MockObject $environmentHelper; private FileAccessHelper $fileAccessHelper; - private IConfig&MockObject $config; - private IAppDataFactory&MockObject $appDataFactory; - private IAppManager&MockObject $appManager; + private IConfig|MockObject $config; + private IAppDataFactory|MockObject $appDataFactory; + private IAppManager|MockObject $appManager; public function setUp(): void { $this->environmentHelper = $this->createMock(EnvironmentHelper::class);