Script 'mail_helper' called by obssrc
Hello community,
here is the log from the commit of package python-proton-vpn-local-agent for
openSUSE:Factory checked in at 2026-07-31 15:29:23
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-proton-vpn-local-agent (Old)
and /work/SRC/openSUSE:Factory/.python-proton-vpn-local-agent.new.2004
(New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-proton-vpn-local-agent"
Fri Jul 31 15:29:23 2026 rev:6 rq:1368436 version:1.6.3
Changes:
--------
---
/work/SRC/openSUSE:Factory/python-proton-vpn-local-agent/python-proton-vpn-local-agent.changes
2025-12-24 13:18:18.479407813 +0100
+++
/work/SRC/openSUSE:Factory/.python-proton-vpn-local-agent.new.2004/python-proton-vpn-local-agent.changes
2026-07-31 16:10:06.410272256 +0200
@@ -1,0 +2,10 @@
+Thu Jul 30 04:11:04 UTC 2026 - Richard Rahl <[email protected]>
+
+- Update to version 1.6.3:
+ + fix: add error handling for certificate not yet valid
+- Update to version 1.6.2:
+ + chore: Update Root CA and add legacy intermediate CA
+- Update to version 1.6.1:
+ + Fix lint
+
+-------------------------------------------------------------------
Old:
----
1.6.0.tar.gz
New:
----
1.6.3.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-proton-vpn-local-agent.spec ++++++
--- /var/tmp/diff_new_pack.n1UEo8/_old 2026-07-31 16:10:07.258301756 +0200
+++ /var/tmp/diff_new_pack.n1UEo8/_new 2026-07-31 16:10:07.258301756 +0200
@@ -1,7 +1,7 @@
#
# spec file for package python-proton-vpn-local-agent
#
-# Copyright (c) 2025 SUSE LLC
+# Copyright (c) 2026 SUSE LLC and contributors
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
@@ -19,7 +19,7 @@
%{?sle15_python_module_pythons}
%define _name python-proton-vpn-local-agent
Name: python-proton-vpn-local-agent
-Version: 1.6.0
+Version: 1.6.3
Release: 0
Summary: Proton VPN local agent written in Rust
License: GPL-3.0-only
@@ -55,7 +55,7 @@
popd
%install
-%if 0%{?suse_version} == 1600
+%if 0%{?suse_version} >= 1600 && 0%{?suse_version} < 1650
pushd %{_name}
%endif
for p in $(echo "%{pythons}" | sed s/python31/python3.1/g); do
++++++ 1.6.0.tar.gz -> 1.6.3.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/local-agent-rs-1.6.0/local_agent_rs/Cargo.lock
new/local-agent-rs-1.6.3/local_agent_rs/Cargo.lock
--- old/local-agent-rs-1.6.0/local_agent_rs/Cargo.lock 2025-09-30
10:14:00.000000000 +0200
+++ new/local-agent-rs-1.6.3/local_agent_rs/Cargo.lock 2026-05-26
13:02:36.000000000 +0200
@@ -424,9 +424,9 @@
[[package]]
name = "deranged"
-version = "0.3.11"
+version = "0.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4"
+checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c"
dependencies = [
"powerfmt",
]
@@ -670,7 +670,8 @@
"socket2",
"static_assertions",
"test-log",
- "thiserror 1.0.63",
+ "thiserror 2.0.12",
+ "time",
"tokio",
"tokio-rustls",
"uniffi",
@@ -775,9 +776,9 @@
[[package]]
name = "num-conv"
-version = "0.1.0"
+version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
+checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441"
[[package]]
name = "num-integer"
@@ -1102,18 +1103,28 @@
[[package]]
name = "serde"
-version = "1.0.204"
+version = "1.0.228"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
+dependencies = [
+ "serde_core",
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_core"
+version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12"
+checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
-version = "1.0.204"
+version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222"
+checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
dependencies = [
"proc-macro2",
"quote",
@@ -1325,30 +1336,30 @@
[[package]]
name = "time"
-version = "0.3.36"
+version = "0.3.47"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885"
+checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c"
dependencies = [
"deranged",
"itoa",
"num-conv",
"powerfmt",
- "serde",
+ "serde_core",
"time-core",
"time-macros",
]
[[package]]
name = "time-core"
-version = "0.1.2"
+version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"
+checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca"
[[package]]
name = "time-macros"
-version = "0.2.18"
+version = "0.2.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf"
+checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215"
dependencies = [
"num-conv",
"time-core",
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/local-agent-rs-1.6.0/local_agent_rs/Cargo.toml
new/local-agent-rs-1.6.3/local_agent_rs/Cargo.toml
--- old/local-agent-rs-1.6.0/local_agent_rs/Cargo.toml 2025-09-30
10:14:00.000000000 +0200
+++ new/local-agent-rs-1.6.3/local_agent_rs/Cargo.toml 2026-05-26
13:02:36.000000000 +0200
@@ -25,6 +25,9 @@
uniffi = { version = "0.29.3", features = ["cli"], optional = true }
x509-parser = "0.16.0"
+[dev-dependencies]
+time = { version = "0.3.47", features = ["macros"] }
+
[build-dependencies]
uniffi = { version = "0.29.3", features = ["build"], optional = true }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/local-agent-rs-1.6.0/local_agent_rs/src/agent_connector.rs
new/local-agent-rs-1.6.3/local_agent_rs/src/agent_connector.rs
--- old/local-agent-rs-1.6.0/local_agent_rs/src/agent_connector.rs
2025-09-30 10:14:00.000000000 +0200
+++ new/local-agent-rs-1.6.3/local_agent_rs/src/agent_connector.rs
2026-05-26 13:02:36.000000000 +0200
@@ -11,6 +11,7 @@
use tokio::net::TcpStream;
use tokio_rustls::rustls::{ClientConfig, RootCertStore};
use tokio_rustls::TlsConnector;
+use x509_parser::time::ASN1Time;
//
-----------------------------------------------------------------------------
/// The address of the local agent server, this ip is always the same
@@ -19,38 +20,71 @@
/// The root certificate of the local agent server, this may expire in the
future
/// we have a test in the gtk python application unit tests which will fail
/// when this expires.
-const PROTON_VPN_ROOT_CA: &str = r#"-----BEGIN CERTIFICATE-----
-MIIFozCCA4ugAwIBAgIBATANBgkqhkiG9w0BAQ0FADBAMQswCQYDVQQGEwJDSDEV
-MBMGA1UEChMMUHJvdG9uVlBOIEFHMRowGAYDVQQDExFQcm90b25WUE4gUm9vdCBD
-QTAeFw0xNzAyMTUxNDM4MDBaFw0yNzAyMTUxNDM4MDBaMEAxCzAJBgNVBAYTAkNI
-MRUwEwYDVQQKEwxQcm90b25WUE4gQUcxGjAYBgNVBAMTEVByb3RvblZQTiBSb290
-IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAt+BsSsZg7+AuqTq7
-vDbPzfygtl9f8fLJqO4amsyOXlI7pquL5IsEZhpWyJIIvYybqS4s1/T7BbvHPLVE
-wlrq8A5DBIXcfuXrBbKoYkmpICGc2u1KYVGOZ9A+PH9z4Tr6OXFfXRnsbZToie8t
-2Xjv/dZDdUDAqeW89I/mXg3k5x08m2nfGCQDm4gCanN1r5MT7ge56z0MkY3FFGCO
-qRwspIEUzu1ZqGSTkG1eQiOYIrdOF5cc7n2APyvBIcfvp/W3cpTOEmEBJ7/14RnX
-nHo0fcx61Inx/6ZxzKkW8BMdGGQF3tF6u2M0FjVN0lLH9S0ul1TgoOS56yEJ34hr
-JSRTqHuar3t/xdCbKFZjyXFZFNsXVvgJu34CNLrHHTGJj9jiUfFnxWQYMo9UNUd4
-a3PPG1HnbG7LAjlvj5JlJ5aqO5gshdnqb9uIQeR2CdzcCJgklwRGCyDT1pm7eoiv
-WV19YBd81vKulLzgPavu3kRRe83yl29It2hwQ9FMs5w6ZV/X6ciTKo3etkX9nBD9
-ZzJPsGQsBUy7CzO1jK4W01+u3ItmQS+1s4xtcFxdFY8o/q1zoqBlxpe5MQIWN6Qa
-lryiET74gMHE/S5WrPlsq/gehxsdgc6GDUXG4dk8vn6OUMa6wb5wRO3VXGEc67IY
-m4mDFTYiPvLaFOxtndlUWuCruKcCAwEAAaOBpzCBpDAMBgNVHRMEBTADAQH/MB0G
-A1UdDgQWBBSDkIaYhLVZTwyLNTetNB2qV0gkVDBoBgNVHSMEYTBfgBSDkIaYhLVZ
-TwyLNTetNB2qV0gkVKFEpEIwQDELMAkGA1UEBhMCQ0gxFTATBgNVBAoTDFByb3Rv
-blZQTiBBRzEaMBgGA1UEAxMRUHJvdG9uVlBOIFJvb3QgQ0GCAQEwCwYDVR0PBAQD
-AgEGMA0GCSqGSIb3DQEBDQUAA4ICAQCYr7LpvnfZXBCxVIVc2ea1fjxQ6vkTj0zM
-htFs3qfeXpMRf+g1NAh4vv1UIwLsczilMt87SjpJ25pZPyS3O+/VlI9ceZMvtGXd
-MGfXhTDp//zRoL1cbzSHee9tQlmEm1tKFxB0wfWd/inGRjZxpJCTQh8oc7CTziHZ
-ufS+Jkfpc4Rasr31fl7mHhJahF1j/ka/OOWmFbiHBNjzmNWPQInJm+0ygFqij5qs
-51OEvubR8yh5Mdq4TNuWhFuTxpqoJ87VKaSOx/Aefca44Etwcj4gHb7LThidw/ky
-zysZiWjyrbfX/31RX7QanKiMk2RDtgZaWi/lMfsl5O+6E2lJ1vo4xv9pW8225B5X
-eAeXHCfjV/vrrCFqeCprNF6a3Tn/LX6VNy3jbeC+167QagBOaoDA01XPOx7Odhsb
-Gd7cJ5VkgyycZgLnT9zrChgwjx59JQosFEG1DsaAgHfpEl/N3YPJh68N7fwN41Cj
-zsk39v6iZdfuet/sP7oiP5/gLmA/CIPNhdIYxaojbLjFPkftVjVPn49RqwqzJJPR
-N8BOyb94yhQ7KO4F3IcLT/y/dsWitY0ZH4lCnAVV/v2YjWAWS3OWyC8BFx/Jmc3W
-DK/yPwECUcPgHIeXiRjHnJt0Zcm23O2Q3RphpU+1SO3XixsXpOVOYP6rJIXW9bMZ
-A1gTTlpi7A==
+const PROTON_VPN_ROOT_FOLLOWED_BY_INTERMEDIATE_LEGACY_CA: &str = r#"
+-----BEGIN CERTIFICATE-----
+MIIFnTCCA4WgAwIBAgIUCI574SM3Lyh47GyNl0WAOYrqb5QwDQYJKoZIhvcNAQEL
+BQAwXjELMAkGA1UEBhMCQ0gxHzAdBgNVBAoMFlByb3RvbiBUZWNobm9sb2dpZXMg
+QUcxEjAQBgNVBAsMCVByb3RvblZQTjEaMBgGA1UEAwwRUHJvdG9uVlBOIFJvb3Qg
+Q0EwHhcNMTkxMDE3MDgwNjQxWhcNMzkxMDEyMDgwNjQxWjBeMQswCQYDVQQGEwJD
+SDEfMB0GA1UECgwWUHJvdG9uIFRlY2hub2xvZ2llcyBBRzESMBAGA1UECwwJUHJv
+dG9uVlBOMRowGAYDVQQDDBFQcm90b25WUE4gUm9vdCBDQTCCAiIwDQYJKoZIhvcN
+AQEBBQADggIPADCCAgoCggIBAMkUT7zMUS5C+NjQ7YoGpVFlfbN9HFgG4JiKfHB8
+QxnPPRgyTi0zVOAj1ImsRilauY8Ddm5dQtd8qcApoz6oCx5cFiiSQG2uyhS/59Zl
+5wqIkw1o+CgwZgeWkq04lcrxhhfPgJZRFjrYVezy/Z2Ssd18s3/FFNQ+2iV1KC2K
+z8eSPr50u+l9vEKsKiNGkJTdlWjoDKZM2C15i/h8Smi+PdJlx7WMTtYoVC1Fzq0r
+aCPDQl18kspu11b6d8ECPWghKcDIIKuA0r0nGqF1GvH1AmbC/xUaNrKgz9AfioZL
+MP/l22tVG3KKM1ku0eYHX7NzNHgkM2JKnBBannImQQBGTAcvvUlnfF3AHx4vzx7H
+ahpBz8ebThx2uv+vzu8lCVEcKjQObGwLbAONJN2enug8hwSSZQv7tz7onDQWlYh0
+El5fnkrEQGbukNnSyOqTwfobvBllIPzBqdO38eZFA0YTlH9plYjIjPjGl931lFAA
+3G9t0x7nxAauLXN5QVp1yoF1tzXc5kN0SFAasM9VtVEOSMaGHLKhF+IMyVX8h5Iu
+IRC8u5O672r7cHS+Dtx87LjxypqNhmbf1TWyLJSoh0qYhMr+BbO7+N6zKRIZPI5b
+MXc8Be2pQwbSA4ZrDvSjFC9yDXmSuZTyVo6Bqi/KCUZeaXKof68oNxVYeGowNeQd
+g/znAgMBAAGjUzBRMB0GA1UdDgQWBBR44WtTuEKCaPPUltYEHZoyhJo+4TAfBgNV
+HSMEGDAWgBR44WtTuEKCaPPUltYEHZoyhJo+4TAPBgNVHRMBAf8EBTADAQH/MA0G
+CSqGSIb3DQEBCwUAA4ICAQBBmzCQlHxOJ6izys3TVpaze+rUkA9GejgsB2DZXIcm
+4Lj/SNzQsPlZRu4S0IZV253dbE1DoWlHanw5lnXwx8iU82X7jdm/5uZOwj2NqSqT
+bTn0WLAC6khEKKe5bPTf18UOcwN82Le3AnkwcNAaBO5/TzFQVgnVedXr2g6rmpp9
+gdedeEl9acB7xqfYfkrmijqYMm+xeG2rXaanch3HjweMDuZdT/Ub5G6oir0Kowft
+lA1ytjXRg+X+yWymTpF/zGLYfSodWWjMKhpzZtRJZ+9B0pWXUyY7SuCj5T5SMIAu
+x3NQQ46wSbHRolIlwh7zD7kBgkyLe7ByLvGFKa2Vw4PuWjqYwrRbFjb2+EKAwPu6
+VTWz/QQTU8oJewGFipw94Bi61zuaPvF1qZCHgYhVojRy6KcqncX2Hx9hjfVxspBZ
+DrVH6uofCmd99GmVu+qizybWQTrPaubfc/a2jJIbXc2bRQjYj/qmjE3hTlmO3k7V
+EP6i8CLhEl+dX75aZw9StkqjdpIApYwX6XNDqVuGzfeTXXclk4N4aDPwPFM/Yo/e
+KnvlNlKbljWdMYkfx8r37aOHpchH34cv0Jb5Im+1H07ywnshXNfUhRazOpubJRHn
+bjDuBwWS1/Vwp5AJ+QHsPXhJdl3qHc1szJZVJb3VyAWvG/bWApKfFuZX18tiI4N0
+EA==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIFjDCCA3SgAwIBAgIBBDANBgkqhkiG9w0BAQsFADBeMQswCQYDVQQGEwJDSDEf
+MB0GA1UECgwWUHJvdG9uIFRlY2hub2xvZ2llcyBBRzESMBAGA1UECwwJUHJvdG9u
+VlBOMRowGAYDVQQDDBFQcm90b25WUE4gUm9vdCBDQTAeFw0yMjAxMTQxNjQ4MTBa
+Fw0zMjAxMTIxNjQ4NDBaMEoxCzAJBgNVBAYTAkNIMRUwEwYDVQQKEwxQcm90b25W
+UE4gQUcxJDAiBgNVBAMTG1Byb3RvblZQTiBJbnRlcm1lZGlhdGUgQ0EgMTCCAiIw
+DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANv3uwQMFjYOx74taxadhczLbjCT
+uT73jMz09EqFNv7O7UesXfYJ6kQgYV9YyE86znP4xbsswNUZYh+XdZUpOoP6Zu3t
+R/iiYiuzi6jVYrJ66G89nPqS2mm5dn8Fbb8CRWkJygm8AdlYkDwYNldhDUrERlQd
+CRDGsYYg/98dded+5pXnSG8Y/+iuLM6/YYhkUVQeCfq1L6XguSwu8CuvJjIjjE1P
+ptUHa3Hc3tGziVydltKynxWlqb1dJqinGKiBZvYnoiV4motpFYwhc3Wd09JLPzeo
+bhD2IAZ2evSatikMWDingEv1EJXpI+V/E2AK3xHKSkhw+YZx99tNxCiOu3U5BFAr
+eZR3j2YnZzX1nEv9p02IGaWzzYJPNED0zSO2w07uthSmKcxA39VTvs91lptbcV7V
+TxoJY0SErHIeVS3Scrnr7WvoOTuu3M3SCRqe6oI9oJZMOdfNsceBdvG+qlpOFICo
+BjO53W4BK8KahzTd/PWlBRiVJ3UVv8xXwUDA+o9834DXVAobaAHXQtM9jNobqT98
+FXhZktjOQEA2UORL581ZPxfKeHLRcgWJ5dmPsDBGy/L6/qW/yrm6DUDAdN5+q41+
+gSNEjNBjLBJQFUmDk3l6Qxiu0uEDQ98oFvGHk5US2Kbj0OAq1RpiDjHci/536yua
+9rTC+cxekTM2asdXAgMBAAGjaTBnMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8E
+CDAGAQH/AgEAMB8GA1UdIwQYMBaAFHjha1O4QoJo89SW1gQdmjKEmj7hMCAGA1Ud
+JQEB/wQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATANBgkqhkiG9w0BAQsFAAOCAgEA
+fFMtLGksBmCWBbLu5SJW+6/8EtOoGD+QbCRc7kCpsKZOqgwKuVeEQHsTCJgeSyWM
+XXnD5mqtEKcgaJ8bjgE2YkPPajiqnqAYPxJ4xCUXELY+Tm6LMifAuxtGIC9M04Cy
+IIe44OtblEQDP+JB++TLKbwnj/+TAC7537eGxZa3Jesc4YUD2qUTp2Zqqo2Tzqib
+iyuGCeVfc+OiG0xcZls9lvYOIAcEIqxvWEwgSCJUul1567b3/mKe5S2SkpY6du29
+I3k3qhvSvrA1WtBlqAAeggLiQ5DE47LIMdJU+roYmk4TAJmibI2nKoonf1+OBF/S
+Zg04xEd18dtAoX1CjgTHlIeNQzeGV6O0/jhn3BfNWB2a2A8u5mVxDyOG3ZJEjdKC
+eiv6r/iEGI7BwOe3WSdvcmNpsa+UehbupN9azRyhEykXmG+LGF5DEylLxK128tdD
+0rl3p1qEWcRYIdzE8iS7rp0y0wD0pz0ye80OyGXJYc3Y8WSxPVQL/t35x7gaKnIW
+8S0Goqe7Or/F3bxYXh+kk1ARZyF0bmH/yOlkstV7ETsL7OB8aDEvlc/BG80bU68m
+cQDquPP1RszuksYu6pGZPtwra23Wuo8alsxVg4aJhhIKP/iocJdWKnodMMAIF23N
++WPATcqIu3YrtUFWnNHGAa/z3xBx3VwPMGIOcmfVl4E=
-----END CERTIFICATE-----
"#;
@@ -72,9 +106,11 @@
pub timeout_in_seconds: u64,
}
-/// Builds the root certificate store, fom the constant PROTON_VPN_ROOT_CA.
+/// Builds the root certificate store, from the constant
PROTON_VPN_ROOT_FOLLOWED_BY_INTERMEDIATE_LEGACY_CA.
fn build_root_cert_store() -> Result<RootCertStore> {
- let mut cursor = std::io::Cursor::new(PROTON_VPN_ROOT_CA);
+ let mut cursor = std::io::Cursor::new(
+ PROTON_VPN_ROOT_FOLLOWED_BY_INTERMEDIATE_LEGACY_CA
+ );
let ca = rustls_pemfile::certs(&mut cursor);
let mut root_cert_store = RootCertStore::empty();
for i in ca {
@@ -99,8 +135,10 @@
}
fn ensure_certificates_are_current(
- certificates: &[CertificateDer<'_>]
+ certificates: &[CertificateDer<'_>],
+ now: Option<ASN1Time>, // Optional time for testing
) -> Result<()> {
+ let now = now.unwrap_or_else(ASN1Time::now);
for cert_d in certificates {
@@ -109,11 +147,20 @@
)?;
let validity = &cert.tbs_certificate.validity;
- if !validity.is_valid() {
+
+ // Check if current time is before the certificate's start time
+ if now < validity.not_before {
+ return Err(Error::NotYetValidCertificate(format!(
+ "Now {:?}, Start: {}, End: {}",
+ now, &validity.not_before, &validity.not_after
+ )));
+ }
+
+ // Check if current time is after the certificate's end time
+ if now > validity.not_after {
return Err(Error::ExpiredCertificate(format!(
"Now {:?}, Start: {}, End: {}",
- std::time::SystemTime::now(),
- &validity.not_before, &validity.not_after
+ now, &validity.not_before, &validity.not_after
)));
}
}
@@ -147,7 +194,7 @@
// This does a time validation of the certificates
// and will return an error if any of them are expired.
- ensure_certificates_are_current(&certs)?;
+ ensure_certificates_are_current(&certs, None)?;
// Key is in pks8 format
let key = rustls_pemfile::private_key(&mut
std::io::Cursor::new(¶ms.key))?
@@ -206,9 +253,10 @@
#[cfg(test)]
mod tests {
use super::*;
+ use time::macros::datetime;
#[test]
- fn test_proton_vpn_root_certificate_is_not_close_to_expiration() {
+ fn
test_proton_vpn_root_and_intermediate_legacy_certificates_are_not_close_to_expiration()
{
// Ensure that the certificate still has 90 days before it expires.
let ninety_days = 90_f64;
@@ -217,7 +265,9 @@
// We need an in-memory reader for the certificate as we are reading
// an in-memory hard coded certificate.
- let mut reader = std::io::Cursor::new(PROTON_VPN_ROOT_CA);
+ let mut reader = std::io::Cursor::new(
+ PROTON_VPN_ROOT_FOLLOWED_BY_INTERMEDIATE_LEGACY_CA
+ );
// Find the certificate in the pem file
for cert_der in rustls_pemfile::certs(&mut reader) {
@@ -241,4 +291,49 @@
assert!(expires_in > seconds);
}
}
+
+ // Testing certificate validity errors with the embedded root/intermediate
certificates
+
+ // Root CA: Valid 2019-01-17 - 2039-01-12
+ // Intermediate: Valid 2022-01-14 - 2032-01-12
+
+ fn parse_embedded_certificates() -> Vec<CertificateDer<'static>> {
+ let mut cursor = std::io::Cursor::new(
+ PROTON_VPN_ROOT_FOLLOWED_BY_INTERMEDIATE_LEGACY_CA
+ );
+ rustls_pemfile::certs(&mut cursor)
+ .filter_map(|x| x.ok())
+ .collect()
+ }
+
+ #[test]
+ fn test_valid_certificate_with_current_time() {
+ let certs = parse_embedded_certificates();
+
+ // Use current time
+ let result = ensure_certificates_are_current(&certs, None);
+ assert!(result.is_ok(), "Embedded certificates should be currently
valid");
+ }
+
+ #[test]
+ fn test_expired_certificate_error() {
+ let certs = parse_embedded_certificates();
+ // Time after both certificates end
+ let expired_time = ASN1Time::new(datetime!(2040-01-15 00:00:00 UTC));
+ let result = ensure_certificates_are_current(&certs,
Some(expired_time));
+ assert!(matches!(result, Err(Error::ExpiredCertificate(_))),
+ "Should return ExpiredCertificate error when time is past
certificate end date");
+ }
+
+ #[test]
+ fn test_not_yet_valid_certificate_error() {
+ let certs = parse_embedded_certificates();
+
+ // Time before the root cert starts (with buffer)
+ let not_yet_valid_time = ASN1Time::new(datetime!(2019-01-01 00:00:00
UTC));
+
+ let result = ensure_certificates_are_current(&certs,
Some(not_yet_valid_time));
+ assert!(matches!(result, Err(Error::NotYetValidCertificate(_))),
+ "Should return NotYetValidCertificate error when time is
before certificate start date");
+ }
}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/local-agent-rs-1.6.0/local_agent_rs/src/error.rs
new/local-agent-rs-1.6.3/local_agent_rs/src/error.rs
--- old/local-agent-rs-1.6.0/local_agent_rs/src/error.rs 2025-09-30
10:14:00.000000000 +0200
+++ new/local-agent-rs-1.6.3/local_agent_rs/src/error.rs 2026-05-26
13:02:36.000000000 +0200
@@ -41,6 +41,8 @@
BincodeError(#[from] bincode::Error),
#[error("Expired certificate: {0}")]
ExpiredCertificate(String),
+ #[error("Certificate not yet valid: {0}")]
+ NotYetValidCertificate(String),
#[error("Unable to parse certificate")]
UnableToParseCertificate,
}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/local-agent-rs-1.6.0/local_agent_rs/src/port_forwarding.rs
new/local-agent-rs-1.6.3/local_agent_rs/src/port_forwarding.rs
--- old/local-agent-rs-1.6.0/local_agent_rs/src/port_forwarding.rs
2025-09-30 10:14:00.000000000 +0200
+++ new/local-agent-rs-1.6.3/local_agent_rs/src/port_forwarding.rs
2026-05-26 13:02:36.000000000 +0200
@@ -158,8 +158,7 @@
if bytes_read != BYTE_SIZE {
return Err(Error::PortForwarding(format!(
"Protocol error incorrect number of bytes returned in \
- nat-pmp response {}",
- bytes_read
+ nat-pmp response {bytes_read}"
)));
}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/local-agent-rs-1.6.0/local_agent_rs/src/reason_code.rs
new/local-agent-rs-1.6.3/local_agent_rs/src/reason_code.rs
--- old/local-agent-rs-1.6.0/local_agent_rs/src/reason_code.rs 2025-09-30
10:14:00.000000000 +0200
+++ new/local-agent-rs-1.6.3/local_agent_rs/src/reason_code.rs 2026-05-26
13:02:36.000000000 +0200
@@ -1,9 +1,9 @@
//
-----------------------------------------------------------------------------
// Copyright (c) 2024 Proton AG
//
-----------------------------------------------------------------------------
-/// Represents the reason for a status message.
+//! Represents the reason for a status message.
+//! The reason code is used to indicate why a connection is jailed.
-/// The reason code is used to indicate why a connection is jailed.
pub const REASON_CODE_UNKNOWN: i32 = 0;
pub const REASON_CODE_GUEST_SESSION: i32 = 86100;
pub const REASON_CODE_RESTRICTED_SERVER: i32 = 86104;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/local-agent-rs-1.6.0/python-proton-vpn-local-agent/Cargo.lock
new/local-agent-rs-1.6.3/python-proton-vpn-local-agent/Cargo.lock
--- old/local-agent-rs-1.6.0/python-proton-vpn-local-agent/Cargo.lock
2025-09-30 10:14:00.000000000 +0200
+++ new/local-agent-rs-1.6.3/python-proton-vpn-local-agent/Cargo.lock
2026-05-26 13:02:36.000000000 +0200
@@ -702,9 +702,9 @@
[[package]]
name = "num-conv"
-version = "0.1.0"
+version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
+checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441"
[[package]]
name = "num-integer"
@@ -916,7 +916,7 @@
[[package]]
name = "python-proton-vpn-local-agent"
-version = "1.6.0"
+version = "1.6.3"
dependencies = [
"local-agent-rs",
"log",
@@ -1094,18 +1094,28 @@
[[package]]
name = "serde"
-version = "1.0.204"
+version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12"
+checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
+dependencies = [
+ "serde_core",
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_core"
+version = "1.0.228"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
-version = "1.0.204"
+version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222"
+checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
dependencies = [
"proc-macro2",
"quote",
@@ -1273,29 +1283,30 @@
[[package]]
name = "time"
-version = "0.3.43"
+version = "0.3.47"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "83bde6f1ec10e72d583d91623c939f623002284ef622b87de38cfd546cbf2031"
+checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c"
dependencies = [
"deranged",
+ "itoa",
"num-conv",
"powerfmt",
- "serde",
+ "serde_core",
"time-core",
"time-macros",
]
[[package]]
name = "time-core"
-version = "0.1.6"
+version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b"
+checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca"
[[package]]
name = "time-macros"
-version = "0.2.24"
+version = "0.2.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "30cfb0125f12d9c277f35663a0a33f8c30190f4e4574868a330595412d34ebf3"
+checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215"
dependencies = [
"num-conv",
"time-core",
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/local-agent-rs-1.6.0/python-proton-vpn-local-agent/Cargo.toml
new/local-agent-rs-1.6.3/python-proton-vpn-local-agent/Cargo.toml
--- old/local-agent-rs-1.6.0/python-proton-vpn-local-agent/Cargo.toml
2025-09-30 10:14:00.000000000 +0200
+++ new/local-agent-rs-1.6.3/python-proton-vpn-local-agent/Cargo.toml
2026-05-26 13:02:36.000000000 +0200
@@ -1,6 +1,6 @@
[package]
name = "python-proton-vpn-local-agent"
-version = "1.6.0"
+version = "1.6.3"
edition = "2021"
# See more keys and their definitions at
https://doc.rust-lang.org/cargo/reference/manifest.html
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/local-agent-rs-1.6.0/python-proton-vpn-local-agent/src/connection_details.rs
new/local-agent-rs-1.6.3/python-proton-vpn-local-agent/src/connection_details.rs
---
old/local-agent-rs-1.6.0/python-proton-vpn-local-agent/src/connection_details.rs
2025-09-30 10:14:00.000000000 +0200
+++
new/local-agent-rs-1.6.3/python-proton-vpn-local-agent/src/connection_details.rs
2026-05-26 13:02:36.000000000 +0200
@@ -36,7 +36,7 @@
/// This method is used to convert the object to a string for easier
/// debugging in Python.
fn __str__(&self) -> PyResult<String> {
- Ok(format!("{:?}", self))
+ Ok(format!("{self:?}"))
}
}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/local-agent-rs-1.6.0/python-proton-vpn-local-agent/src/error.rs
new/local-agent-rs-1.6.3/python-proton-vpn-local-agent/src/error.rs
--- old/local-agent-rs-1.6.0/python-proton-vpn-local-agent/src/error.rs
2025-09-30 10:14:00.000000000 +0200
+++ new/local-agent-rs-1.6.3/python-proton-vpn-local-agent/src/error.rs
2026-05-26 13:02:36.000000000 +0200
@@ -4,7 +4,7 @@
use local_agent_rs as la;
use crate::{
- APIError, ExpiredCertificateError, LocalAgentError, PolicyAPIError,
+ APIError, ExpiredCertificateError, NotYetValidCertificateError,
LocalAgentError, PolicyAPIError,
SyntaxAPIError,
};
use pyo3::exceptions::PyTimeoutError;
@@ -45,6 +45,8 @@
match err {
Error::LocalAgent(la::Error::ExpiredCertificate(e)) =>
ExpiredCertificateError::new_err(e.to_string()),
+ Error::LocalAgent(la::Error::NotYetValidCertificate(e)) =>
+ NotYetValidCertificateError::new_err(e.to_string()),
Error::LocalAgent(la::Error::Tokio(e))
if e.kind() == ErrorKind::TimedOut
|| e.kind() == ErrorKind::BrokenPipe =>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/local-agent-rs-1.6.0/python-proton-vpn-local-agent/src/exception.rs
new/local-agent-rs-1.6.3/python-proton-vpn-local-agent/src/exception.rs
--- old/local-agent-rs-1.6.0/python-proton-vpn-local-agent/src/exception.rs
2025-09-30 10:14:00.000000000 +0200
+++ new/local-agent-rs-1.6.3/python-proton-vpn-local-agent/src/exception.rs
2026-05-26 13:02:36.000000000 +0200
@@ -14,6 +14,13 @@
create_exception!(
local_agent,
+ NotYetValidCertificateError,
+ LocalAgentError,
+ "Raised when the passed certificate is not yet valid during read from
socket."
+);
+
+create_exception!(
+ local_agent,
ExpiredCertificateError,
LocalAgentError,
"Raised when the passed certificate is expired during read from socket."
@@ -46,6 +53,10 @@
"ExpiredCertificateError",
m.py().get_type::<ExpiredCertificateError>(),
)?;
+ m.add(
+ "NotYetValidCertificateError",
+ m.py().get_type::<NotYetValidCertificateError>(),
+ )?;
m.add("APIError", m.py().get_type::<APIError>())?;
m.add("SyntaxAPIError", m.py().get_type::<SyntaxAPIError>())?;
m.add("PolicyAPIError", m.py().get_type::<PolicyAPIError>())?;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/local-agent-rs-1.6.0/python-proton-vpn-local-agent/src/logger.rs
new/local-agent-rs-1.6.3/python-proton-vpn-local-agent/src/logger.rs
--- old/local-agent-rs-1.6.0/python-proton-vpn-local-agent/src/logger.rs
2025-09-30 10:14:00.000000000 +0200
+++ new/local-agent-rs-1.6.3/python-proton-vpn-local-agent/src/logger.rs
2026-05-26 13:02:36.000000000 +0200
@@ -122,7 +122,7 @@
let filename = filename.to_string();
rust_info.set_item(
"name",
- format!("{LOG_NAME}/{}", filename),
+ format!("{LOG_NAME}/{filename}"),
)?;
}
}
@@ -153,7 +153,7 @@
match result {
Ok(_) => (),
- Err(error) => eprintln!("Failure in logger: {}", error),
+ Err(error) => eprintln!("Failure in logger: {error}"),
}
}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/local-agent-rs-1.6.0/python-proton-vpn-local-agent/src/reason.rs
new/local-agent-rs-1.6.3/python-proton-vpn-local-agent/src/reason.rs
--- old/local-agent-rs-1.6.0/python-proton-vpn-local-agent/src/reason.rs
2025-09-30 10:14:00.000000000 +0200
+++ new/local-agent-rs-1.6.3/python-proton-vpn-local-agent/src/reason.rs
2026-05-26 13:02:36.000000000 +0200
@@ -101,7 +101,7 @@
/// This method is used to convert the object to a string for easier
/// debugging in Python.
fn __str__(&self) -> PyResult<String> {
- Ok(format!("{:?}", self))
+ Ok(format!("{self:?}"))
}
}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/local-agent-rs-1.6.0/python-proton-vpn-local-agent/src/state.rs
new/local-agent-rs-1.6.3/python-proton-vpn-local-agent/src/state.rs
--- old/local-agent-rs-1.6.0/python-proton-vpn-local-agent/src/state.rs
2025-09-30 10:14:00.000000000 +0200
+++ new/local-agent-rs-1.6.3/python-proton-vpn-local-agent/src/state.rs
2026-05-26 13:02:36.000000000 +0200
@@ -17,7 +17,7 @@
// This method is used to convert the object to a string for easier
/// debugging in Python.
fn __str__(&self) -> PyResult<String> {
- Ok(format!("{:?}", self))
+ Ok(format!("{self:?}"))
}
}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/local-agent-rs-1.6.0/python-proton-vpn-local-agent/src/status.rs
new/local-agent-rs-1.6.3/python-proton-vpn-local-agent/src/status.rs
--- old/local-agent-rs-1.6.0/python-proton-vpn-local-agent/src/status.rs
2025-09-30 10:14:00.000000000 +0200
+++ new/local-agent-rs-1.6.3/python-proton-vpn-local-agent/src/status.rs
2026-05-26 13:02:36.000000000 +0200
@@ -26,7 +26,7 @@
/// This method is used to convert the Status object to a string for easier
/// debugging in Python.
fn __str__(&self) -> PyResult<String> {
- Ok(format!("{:?}", self))
+ Ok(format!("{self:?}"))
}
}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/local-agent-rs-1.6.0/python-proton-vpn-local-agent/versions.yml
new/local-agent-rs-1.6.3/python-proton-vpn-local-agent/versions.yml
--- old/local-agent-rs-1.6.0/python-proton-vpn-local-agent/versions.yml
2025-09-30 10:14:00.000000000 +0200
+++ new/local-agent-rs-1.6.3/python-proton-vpn-local-agent/versions.yml
2026-05-26 13:02:36.000000000 +0200
@@ -1,3 +1,30 @@
+version: 1.6.3
+time: 2026/05/14 13:55
+author: Elena Švilpė
+email: [email protected]
+urgency: low
+stability: unstable
+description:
+- "fix: add error when certificate is not yet valid"
+---
+version: 1.6.2
+time: 2026/04/13 15:27
+author: Richard Paterson
+email: [email protected]
+urgency: low
+stability: unstable
+description:
+- "chore: Update Root CA and add legacy intermediate CA"
+---
+version: 1.6.1
+time: 2026/03/12 13:07
+author: Luke Titley
+email: [email protected]
+urgency: low
+stability: unstable
+description:
+- "fix: Linting errors"
+---
version: 1.6.0
time: 2025/09/29 14:38
author: Luke Titley
++++++ vendor.tar.zst ++++++
/work/SRC/openSUSE:Factory/python-proton-vpn-local-agent/vendor.tar.zst
/work/SRC/openSUSE:Factory/.python-proton-vpn-local-agent.new.2004/vendor.tar.zst
differ: char 7, line 1