Compare commits

..

59 Commits

Author SHA1 Message Date
Jędrzej Stuczyński 8941c47f7d chore: remove duplicated code 2026-02-27 11:51:20 +00:00
Jędrzej Stuczyński dd31af50ff updated nym-node config template 2026-02-27 10:30:35 +00:00
Jędrzej Stuczyński ef5970c2f0 simple conversion method from semver to ciphersuite 2026-02-27 10:22:56 +00:00
Jędrzej Stuczyński 62146b1188 hopefully final wasm fixes 2026-02-27 09:09:01 +00:00
Jędrzej Stuczyński 1c8178a966 clippy 2026-02-27 08:12:58 +00:00
Georgio Nicolas 1ddbb970d0 Change receiver index to u32 and regorganize crates 2026-02-27 08:06:29 +00:00
Georgio Nicolas 3f500af7a7 Migrate receiver index 2026-02-26 18:40:16 +01:00
Georgio Nicolas e2c5b10c6b fix response size trait impl 2026-02-26 17:13:40 +01:00
Georgio Nicolas 737cd628ff integrate lpconfig payload 2026-02-26 16:43:30 +01:00
Jędrzej Stuczyński 96dbe583ce cargo fmt 2026-02-26 15:41:38 +00:00
Jędrzej Stuczyński 0f8598ad52 moved LP to nym-node crate 2026-02-26 15:41:01 +00:00
Georgio Nicolas 9c271d7344 make clippy happy 2026-02-26 16:02:01 +01:00
Georgio Nicolas 6339039500 add payload to kkt 2026-02-26 15:59:06 +01:00
Jędrzej Stuczyński 898c9dd11f additional fixes 2026-02-26 13:48:27 +00:00
Jędrzej Stuczyński ace3aff900 fixing wasm for real this time 2026-02-26 13:48:27 +00:00
Jędrzej Stuczyński 4d4e786d5e removed legacy nym-vpn-lib-wasm 2026-02-26 13:48:27 +00:00
Jędrzej Stuczyński 2b88c717c7 wasm fixes 2026-02-26 13:48:26 +00:00
Jędrzej Stuczyński 71b4e650d3 return error on mceliece within NestedSession 2026-02-26 13:48:26 +00:00
Jędrzej Stuczyński f9727ce0a0 clippy and formatting issues 2026-02-26 13:48:26 +00:00
Georgio Nicolas c93b056e36 better docs 2026-02-26 13:48:26 +00:00
Georgio Nicolas 4fc5139e29 add more tests and fix bug 2026-02-26 13:48:26 +00:00
Jędrzej Stuczyński 795c73f75c formatting 2026-02-26 13:48:25 +00:00
Georgio Nicolas 7dd0f6cfa1 add peer config happy path tests 2026-02-26 13:48:25 +00:00
Jędrzej Stuczyński 7042d155eb fixed tests compilation 2026-02-26 13:48:25 +00:00
Jędrzej Stuczyński c10d97372f re-expose LP information on the http API 2026-02-26 13:48:25 +00:00
Jędrzej Stuczyński f2be036009 removed dependency on pre-rand09 from nym-lp 2026-02-26 13:48:25 +00:00
Jędrzej Stuczyński 5e6bd80d45 nym-node startup cleanup 2026-02-26 13:48:25 +00:00
Georgio Nicolas ef5d503692 add lp peer config 2026-02-26 13:48:25 +00:00
Jędrzej Stuczyński 901557ad04 generate fresh x25519, mlkem768 and mceliece keys on config migration 2026-02-26 13:48:24 +00:00
Jędrzej Stuczyński f6a796fe71 feat: add kem key generation to nodes 2026-02-26 13:48:24 +00:00
Jędrzej Stuczyński 7c23cd2183 use derived receiver index 2026-02-26 13:48:24 +00:00
Georgio Nicolas 211f90692a Add receiver index derivation 2026-02-26 13:48:24 +00:00
Georgio Nicolas 9b44095b62 Add receiver index derivation 2026-02-26 13:48:24 +00:00
Jędrzej Stuczyński f347a4f349 update lp api model 2026-02-26 13:48:24 +00:00
Jędrzej Stuczyński 595d034f64 restoring nym-lp tests 2026-02-26 13:48:24 +00:00
Jędrzej Stuczyński 872ae85136 moved data encryption into the state machine 2026-02-26 13:48:23 +00:00
Jędrzej Stuczyński 25ef5f52b4 wip 2026-02-26 13:48:23 +00:00
Jędrzej Stuczyński 54d193caa9 removing dead code 2026-02-26 13:48:23 +00:00
Jędrzej Stuczyński 4f106c3d98 intial telescoping reg 2026-02-26 13:48:23 +00:00
Jędrzej Stuczyński ed9883fc16 reverted back to libcrux repo refs 2026-02-26 13:48:23 +00:00
Georgio Nicolas 6f0c447f88 Slightly reduce use of rand08 2026-02-26 13:48:23 +00:00
Georgio Nicolas bf88c0c9d4 Fix key conversion 2026-02-26 13:48:23 +00:00
Jędrzej Stuczyński 27b5bde7cf 'working' client-entry dvpn reg 2026-02-26 13:48:22 +00:00
Jędrzej Stuczyński 3da3c8396f compiling nym-crypto 2026-02-26 13:48:22 +00:00
Jędrzej Stuczyński 88f383dd29 revamp of the transport traits and initial work on client-side transport 2026-02-26 13:48:22 +00:00
Jędrzej Stuczyński d56ca5fa78 helpers for Transport 2026-02-26 13:48:22 +00:00
Jędrzej Stuczyński 63582dd4e1 LpSession cleanup 2026-02-26 13:48:22 +00:00
Jędrzej Stuczyński 39ee22e501 fixed unit-tests within nym-kkt 2026-02-26 13:48:22 +00:00
Jędrzej Stuczyński 26056909b7 responder side of the handshake and full e2e test 2026-02-26 13:48:22 +00:00
Jędrzej Stuczyński 4fcb8ed202 initiator side of the full handshake 2026-02-26 13:48:22 +00:00
Jędrzej Stuczyński 5536d49f65 Adding concrete types within KKT exchange 2026-02-26 13:48:22 +00:00
Jędrzej Stuczyński 5621c94c0a encapsulation key parsing 2026-02-26 13:48:21 +00:00
Jędrzej Stuczyński 0011975ae8 update KKTResponder 2026-02-26 13:48:21 +00:00
Jędrzej Stuczyński 8460270f62 moved principal generation 2026-02-26 13:48:21 +00:00
Jędrzej Stuczyński d313e4ef05 move key generation to peer 2026-02-26 13:48:21 +00:00
Jędrzej Stuczyński ad389c4fba moved the e2e test to nym-lp 2026-02-26 13:48:21 +00:00
Jędrzej Stuczyński 9d021481d0 nym-lp crate compiling 2026-02-26 13:48:21 +00:00
Georgio Nicolas afe4c7fb03 use authenicator on the responder's side 2026-02-26 13:48:21 +00:00
Georgio Nicolas 583edbc2ef merging georgio/lp-psqv2-integration 2026-02-26 13:48:21 +00:00
33 changed files with 721 additions and 424 deletions
Generated
+9 -9
View File
@@ -5346,7 +5346,7 @@ dependencies = [
[[package]]
name = "nym-api"
version = "1.1.75"
version = "1.1.74"
dependencies = [
"anyhow",
"async-trait",
@@ -5591,7 +5591,7 @@ dependencies = [
[[package]]
name = "nym-cli"
version = "1.1.72"
version = "1.1.71"
dependencies = [
"anyhow",
"base64 0.22.1",
@@ -5674,7 +5674,7 @@ dependencies = [
[[package]]
name = "nym-client"
version = "1.1.72"
version = "1.1.71"
dependencies = [
"bs58",
"clap",
@@ -7076,7 +7076,7 @@ dependencies = [
[[package]]
name = "nym-network-requester"
version = "1.1.73"
version = "1.1.72"
dependencies = [
"addr",
"anyhow",
@@ -7126,7 +7126,7 @@ dependencies = [
[[package]]
name = "nym-node"
version = "1.27.0"
version = "1.26.0"
dependencies = [
"anyhow",
"arc-swap",
@@ -7263,7 +7263,7 @@ dependencies = [
[[package]]
name = "nym-node-status-agent"
version = "1.1.2-test"
version = "1.1.2"
dependencies = [
"anyhow",
"clap",
@@ -7282,7 +7282,7 @@ dependencies = [
[[package]]
name = "nym-node-status-api"
version = "4.1.0-test"
version = "4.1.0"
dependencies = [
"ammonia",
"anyhow",
@@ -7672,7 +7672,7 @@ dependencies = [
[[package]]
name = "nym-socks5-client"
version = "1.1.72"
version = "1.1.71"
dependencies = [
"bs58",
"clap",
@@ -8469,7 +8469,7 @@ dependencies = [
[[package]]
name = "nymvisor"
version = "0.1.37"
version = "0.1.36"
dependencies = [
"anyhow",
"bytes",
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "nym-client"
version = "1.1.72"
version = "1.1.71"
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"]
description = "Implementation of the Nym Client"
edition = "2021"
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "nym-socks5-client"
version = "1.1.72"
version = "1.1.71"
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
description = "A SOCKS5 localhost proxy that converts incoming messages to Sphinx and sends them to a Nym address"
edition = "2021"
+6 -15
View File
@@ -48,7 +48,7 @@ pub(crate) fn encrypt_lp_packet(
) -> Result<EncryptedLpPacket, LpError> {
let mut plaintext = BytesMut::with_capacity(InnerHeader::SIZE + packet.message().len());
packet.header().inner.encode(&mut plaintext);
packet.message().encode(&mut plaintext);
packet.message().encode_content(&mut plaintext);
let ciphertext = encrypt_data(plaintext.as_ref(), transport)?;
@@ -67,7 +67,7 @@ pub(crate) fn decrypt_lp_packet(
let inner_header = InnerHeader::parse(&plaintext)?;
let payload = &plaintext[InnerHeader::SIZE..];
let message = LpMessage::decode(payload)?;
let message = LpMessage::decode_content(payload, inner_header.message_type)?;
Ok(LpPacket::new(
LpHeader {
@@ -82,7 +82,7 @@ pub(crate) fn decrypt_lp_packet(
mod tests {
use crate::LpError;
use crate::codec::{decrypt_data, decrypt_lp_packet, encrypt_data, encrypt_lp_packet};
use crate::packet::{EncryptedLpPacket, LpHeader, LpMessage, LpPacket};
use crate::packet::{EncryptedLpPacket, LpHeader, LpMessage, LpPacket, MessageType};
use crate::peer::mock_peers;
use crate::psq::initiator::{build_psq_ciphersuite, build_psq_principal};
use crate::psq::{PSQ_MSG2_SIZE, psq_msg1_size, responder};
@@ -259,10 +259,7 @@ mod tests {
let (mut init_transport, mut resp_transport) = mock_transport();
// happy path
let packet = LpPacket::new(
LpHeader::new(123, 0, 1),
LpMessage::new_opaque(b"foomp".to_vec()),
);
let packet = LpPacket::new(LpHeader::new(123, 0, 1, MessageType::Busy), LpMessage::Busy);
let ciphertext = encrypt_lp_packet(packet.clone(), &mut init_transport).unwrap();
assert_eq!(packet.header().outer, ciphertext.outer_header());
@@ -271,10 +268,7 @@ mod tests {
assert_eq!(packet, plaintext);
// incomplete ciphertext
let packet = LpPacket::new(
LpHeader::new(123, 1, 1),
LpMessage::new_opaque(b"foomp".to_vec()),
);
let packet = LpPacket::new(LpHeader::new(123, 1, 1, MessageType::Busy), LpMessage::Busy);
let ciphertext2 = encrypt_lp_packet(packet, &mut init_transport).unwrap();
let l = ciphertext2.ciphertext().len();
let malformed_content = ciphertext2.ciphertext()[..l - 1].to_vec();
@@ -283,10 +277,7 @@ mod tests {
assert!(matches!(dec_err, LpError::PSQSessionFailure { .. }));
// too small buffer
let packet = LpPacket::new(
LpHeader::new(123, 1, 1),
LpMessage::new_opaque(b"foomp".to_vec()),
);
let packet = LpPacket::new(LpHeader::new(123, 1, 1, MessageType::Busy), LpMessage::Busy);
let ciphertext3 = encrypt_lp_packet(packet, &mut resp_transport).unwrap();
let malformed = EncryptedLpPacket::new(ciphertext3.outer_header(), vec![]);
let dec_err = decrypt_lp_packet(malformed, &mut init_transport).unwrap_err();
+4 -4
View File
@@ -11,8 +11,8 @@ pub enum MalformedLpPacketError {
#[error("provided insufficient data to fully deserialise the struct")]
InsufficientData,
#[error("{0} is not a valid LpDataKind")]
InvalidLpDataKind(u16),
#[error("{0} is not a valid MessageType")]
InvalidMessageType(u32),
#[error("invalid payload size: expected {expected}, got {actual}")]
InvalidPayloadSize { expected: usize, actual: usize },
@@ -27,7 +27,7 @@ pub enum MalformedLpPacketError {
}
impl MalformedLpPacketError {
pub fn invalid_data_kind(message_type: u16) -> Self {
MalformedLpPacketError::InvalidLpDataKind(message_type)
pub fn invalid_message_type(message_type: u32) -> Self {
MalformedLpPacketError::InvalidMessageType(message_type)
}
}
+19 -2
View File
@@ -1,9 +1,11 @@
// Copyright 2026 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::packet::message::MessageType;
use crate::packet::version;
use crate::{packet::error::MalformedLpPacketError, peer_config::LpReceiverIndex};
use bytes::{BufMut, BytesMut};
// use nym_lp::peer_config::LpReceiverIndex;
use tracing::warn;
/// Outer header (12 bytes) - always cleartext, used for routing.
@@ -56,10 +58,11 @@ impl OuterHeader {
pub struct InnerHeader {
pub protocol_version: u8,
pub reserved: [u8; 3],
pub message_type: MessageType,
}
impl InnerHeader {
pub const SIZE: usize = 4; // protocol_version(1) + reserved(3)
pub const SIZE: usize = 8; // protocol_version(1) + reserved(3) + message_type(4)
pub fn encode(&self, dst: &mut BytesMut) {
// protocol version
@@ -67,6 +70,9 @@ impl InnerHeader {
// reserved
dst.put_slice(&self.reserved);
// message type
dst.put_slice(&(self.message_type as u32).to_le_bytes());
}
pub fn parse(src: &[u8]) -> Result<Self, MalformedLpPacketError> {
@@ -98,9 +104,14 @@ impl InnerHeader {
warn!("received non-zero reserved bytes. got: {reserved:?}");
}
let msg_type_raw = u32::from_le_bytes([src[4], src[5], src[6], src[7]]);
let message_type = MessageType::from_u32(msg_type_raw)
.ok_or_else(|| MalformedLpPacketError::invalid_message_type(msg_type_raw))?;
Ok(InnerHeader {
protocol_version,
reserved,
message_type,
})
}
}
@@ -118,7 +129,12 @@ pub struct LpHeader {
}
impl LpHeader {
pub fn new(receiver_idx: LpReceiverIndex, counter: u64, protocol_version: u8) -> Self {
pub fn new(
receiver_idx: LpReceiverIndex,
counter: u64,
protocol_version: u8,
message_type: MessageType,
) -> Self {
Self {
outer: OuterHeader {
receiver_idx,
@@ -127,6 +143,7 @@ impl LpHeader {
inner: InnerHeader {
protocol_version,
reserved: [0u8; 3],
message_type,
},
}
}
+344 -98
View File
@@ -2,121 +2,111 @@
// SPDX-License-Identifier: Apache-2.0
use crate::packet::error::MalformedLpPacketError;
use bytes::{BufMut, Bytes, BytesMut};
use bytes::{BufMut, BytesMut};
use num_enum::{IntoPrimitive, TryFromPrimitive};
use std::fmt;
use std::fmt::Display;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
#[derive(Debug, Clone, PartialEq)]
pub struct LpMessageHeader {
pub kind: LpMessageType,
pub message_attributes: [u8; 14],
#[derive(Debug, Copy, Clone, PartialEq, Eq, IntoPrimitive, TryFromPrimitive)]
#[repr(u32)]
pub enum MessageType {
/// The party is busy
Busy = 0x0000,
/// Encrypted payload
EncryptedData = 0x0001,
/// Receiver should forward this message via telescoping
ForwardPacket = 0x0002,
/// Receiver index collision - client should retry with new index
Collision = 0x0003,
/// Acknowledgment - gateway confirms receipt of message
Ack = 0x0004,
/// General error
Error = 0x00FF,
}
impl LpMessageHeader {
pub const SIZE: usize = 16; // message_kind(2) + message_attributes(14)
impl MessageType {
pub(crate) fn from_u32(value: u32) -> Option<Self> {
MessageType::try_from(value).ok()
}
pub fn new(kind: LpMessageType, message_attributes: [u8; 14]) -> Self {
Self {
kind,
message_attributes,
pub fn to_u32(&self) -> u32 {
u32::from(*self)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ApplicationData(pub Vec<u8>);
impl ApplicationData {
pub fn new(bytes: Vec<u8>) -> Self {
Self(bytes)
}
fn len(&self) -> usize {
self.0.len()
}
fn encode(&self, dst: &mut BytesMut) {
dst.put_slice(&self.0);
}
fn decode(bytes: &[u8]) -> Result<Self, MalformedLpPacketError> {
Ok(ApplicationData(bytes.to_vec()))
}
}
/// General human-readable error message
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ErrorPacketData {
pub message: String,
}
impl ErrorPacketData {
pub fn new(message: impl Into<String>) -> Self {
ErrorPacketData {
message: message.into(),
}
}
pub fn new_no_attributes(kind: LpMessageType) -> Self {
Self {
kind,
message_attributes: [0; 14],
fn len(&self) -> usize {
// length-encoding + message
4 + self.message.len()
}
fn encode(&self, dst: &mut BytesMut) {
dst.put_u32_le(self.message.len() as u32);
dst.put_slice(self.message.as_bytes());
}
fn decode(bytes: &[u8]) -> Result<Self, MalformedLpPacketError> {
if bytes.len() < 4 {
return Err(MalformedLpPacketError::DeserialisationFailure(format!(
"Too few bytes to deserialise ErrorPacketData. got {}",
bytes.len()
)));
}
}
/// Encode directly into a BytesMut buffer
pub fn encode(&self, dst: &mut BytesMut) {
dst.put_u16_le(self.kind as u16);
dst.put_slice(&self.message_attributes);
}
pub fn parse(src: &[u8]) -> Result<Self, MalformedLpPacketError> {
if src.len() < Self::SIZE {
return Err(MalformedLpPacketError::InsufficientData);
let message_len = u32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]) as usize;
if bytes[4..].len() != message_len {
return Err(MalformedLpPacketError::DeserialisationFailure(format!(
"Wrong number of bytes to deserialise ErrorPacketData. got {}. Expected {}",
bytes.len(),
4 + message_len
)));
}
let raw_kind = u16::from_le_bytes([src[0], src[1]]);
let kind = LpMessageType::try_from(raw_kind)
.map_err(|_| MalformedLpPacketError::invalid_data_kind(raw_kind))?;
let message = String::from_utf8_lossy(&bytes[4..]).to_string();
#[allow(clippy::unwrap_used)]
let message_attributes = src[2..16].try_into().unwrap();
Ok(Self {
kind,
message_attributes,
})
Ok(ErrorPacketData { message })
}
}
/// Represent application data being sent in Transport mode
#[derive(Debug, Clone, PartialEq)]
pub struct LpMessage {
pub header: LpMessageHeader,
pub content: Bytes,
}
impl AsRef<[u8]> for LpMessage {
fn as_ref(&self) -> &[u8] {
&self.content
}
}
impl LpMessage {
pub fn new(kind: LpMessageType, content: impl Into<Bytes>) -> Self {
Self {
header: LpMessageHeader::new_no_attributes(kind),
content: content.into(),
}
}
pub fn encode(&self, dst: &mut BytesMut) {
self.header.encode(dst);
dst.put_slice(&self.content);
}
pub fn decode(src: &[u8]) -> Result<Self, MalformedLpPacketError> {
let header = LpMessageHeader::parse(src)?;
let content = src[LpMessageHeader::SIZE..].to_vec().into();
Ok(Self { header, content })
}
pub fn kind(&self) -> LpMessageType {
self.header.kind
}
pub fn new_opaque(content: impl Into<Bytes>) -> Self {
Self::new(LpMessageType::Opaque, content)
}
pub fn new_registration(data: impl Into<Bytes>) -> Self {
Self::new(LpMessageType::Registration, data)
}
pub fn new_forward(data: impl Into<Bytes>) -> Self {
Self::new(LpMessageType::Forward, data)
}
pub(crate) fn len(&self) -> usize {
LpMessageHeader::SIZE + self.content.len()
}
}
/// Represent kind of application data being sent in Transport mode
#[derive(Clone, Copy, PartialEq, Eq, Debug, IntoPrimitive, TryFromPrimitive)]
#[repr(u16)]
pub enum LpMessageType {
Opaque = 0,
Registration = 1,
Forward = 2,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ExpectedResponseSize {
/// We've sent a handshake message and expect response of predefined size
@@ -173,6 +163,24 @@ impl ForwardPacketData {
}
}
fn len(&self) -> usize {
// 1 byte length of target lp address type
// +
// {4,16} target_lp_address IPv{4,6}
// +
// 2 bytes target_lp_address port
// +
// 4 bytes for expected response size
// +
// 4 bytes of length of inner packet bytes
// +
// inner_packet_bytes.len()
match self.target_lp_address {
SocketAddr::V4(_) => 1 + 4 + 2 + 4 + 4 + self.inner_packet_bytes.len(),
SocketAddr::V6(_) => 1 + 16 + 2 + 4 + 4 + self.inner_packet_bytes.len(),
}
}
// 0 || [4B ipv4] || [2B port] || [4B res size] || [4B plen] || payload
// 1 || [16B ipv6] || [2B port] || [4B res size] || [4B plen] || payload
fn encode(&self, dst: &mut BytesMut) {
@@ -253,3 +261,241 @@ impl ForwardPacketData {
})
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum LpMessage {
/// The party is busy
Busy,
/// Application payload is being sent
ApplicationData(ApplicationData),
/// Receiver should forward this message via telescoping
ForwardPacket(ForwardPacketData),
/// Receiver index collision - client should retry with new receiver_index
Collision,
/// Acknowledgment - gateway confirms receipt of message
Ack,
/// An error has occurred
Error(ErrorPacketData),
}
impl From<ApplicationData> for LpMessage {
fn from(value: ApplicationData) -> Self {
LpMessage::ApplicationData(value)
}
}
impl From<ForwardPacketData> for LpMessage {
fn from(value: ForwardPacketData) -> Self {
LpMessage::ForwardPacket(value)
}
}
impl Display for LpMessage {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
LpMessage::Busy => write!(f, "Busy"),
LpMessage::ApplicationData(_) => write!(f, "EncryptedData"),
LpMessage::ForwardPacket(_) => write!(f, "ForwardPacket"),
LpMessage::Collision => write!(f, "Collision"),
LpMessage::Ack => write!(f, "Ack"),
LpMessage::Error(_) => write!(f, "Error"),
}
}
}
impl LpMessage {
#[deprecated(note = "is it actually needed?")]
pub fn payload(&self) -> &[u8] {
match self {
LpMessage::Busy => &[],
LpMessage::ApplicationData(payload) => payload.0.as_slice(),
LpMessage::ForwardPacket(_) => &[], // Structured data, serialized in encode_content
LpMessage::Collision => &[],
LpMessage::Ack => &[],
LpMessage::Error(_) => &[], // Structured data, serialized in encode_content (?)
}
}
#[deprecated(note = "is it actually needed?")]
pub fn is_empty(&self) -> bool {
match self {
LpMessage::Busy => true,
LpMessage::ApplicationData(payload) => payload.0.is_empty(),
LpMessage::ForwardPacket(_) => false, // Always has data
LpMessage::Collision => true,
LpMessage::Ack => true,
LpMessage::Error(_) => false,
}
}
pub fn len(&self) -> usize {
match self {
LpMessage::Busy => 0,
LpMessage::ApplicationData(payload) => payload.len(),
LpMessage::ForwardPacket(payload) => payload.len(),
LpMessage::Collision => 0,
LpMessage::Ack => 0,
LpMessage::Error(payload) => payload.len(),
}
}
pub fn typ(&self) -> MessageType {
match self {
LpMessage::Busy => MessageType::Busy,
LpMessage::ApplicationData(_) => MessageType::EncryptedData,
LpMessage::ForwardPacket(_) => MessageType::ForwardPacket,
LpMessage::Collision => MessageType::Collision,
LpMessage::Ack => MessageType::Ack,
LpMessage::Error(_) => MessageType::Error,
}
}
pub fn encode_content(&self, dst: &mut BytesMut) {
match self {
LpMessage::Busy => { /* No content */ }
LpMessage::ApplicationData(payload) => payload.encode(dst),
LpMessage::ForwardPacket(data) => data.encode(dst),
LpMessage::Collision => { /* No content */ }
LpMessage::Ack => { /* No content */ }
LpMessage::Error(data) => data.encode(dst),
}
}
/// Parse message from its type and content bytes.
///
/// Used when decrypting outer-encrypted packets where the message type
/// was encrypted along with the content.
pub fn decode_content(
content: &[u8],
message_type: MessageType,
) -> Result<Self, MalformedLpPacketError> {
match message_type {
MessageType::Busy => {
content.ensure_empty()?;
Ok(LpMessage::Busy)
}
MessageType::EncryptedData => Ok(LpMessage::ApplicationData(ApplicationData::decode(
content,
)?)),
MessageType::ForwardPacket => Ok(LpMessage::ForwardPacket(ForwardPacketData::decode(
content,
)?)),
MessageType::Collision => {
content.ensure_empty()?;
Ok(LpMessage::Collision)
}
MessageType::Ack => {
content.ensure_empty()?;
Ok(LpMessage::Ack)
}
MessageType::Error => Ok(LpMessage::Error(ErrorPacketData::decode(content)?)),
}
}
}
/// Helper trait for improving readability to return error if bytes content is not empty
trait EnsureEmptyContent {
fn ensure_empty(&self) -> Result<(), MalformedLpPacketError>;
}
impl EnsureEmptyContent for &[u8] {
fn ensure_empty(&self) -> Result<(), MalformedLpPacketError> {
if !self.is_empty() {
return Err(MalformedLpPacketError::InvalidPayloadSize {
expected: 0,
actual: self.len(),
});
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::packet::{InnerHeader, LpHeader, LpPacket, OuterHeader};
#[test]
fn encoding() {
let message = LpMessage::ApplicationData(ApplicationData(vec![11u8; 124]));
let resp_header = LpHeader {
outer: OuterHeader {
receiver_idx: 456,
counter: 123,
},
inner: InnerHeader {
protocol_version: 1,
reserved: [0u8; 3],
message_type: MessageType::EncryptedData,
},
};
let packet = LpPacket {
header: resp_header,
message,
};
// Just print packet for debug, will be captured in test output
println!("{packet:?}");
// Verify message type
assert!(matches!(packet.message.typ(), MessageType::EncryptedData));
// Verify correct data in message
match &packet.message {
LpMessage::ApplicationData(data) => {
assert_eq!(*data, ApplicationData(vec![11u8; 124]));
}
_ => panic!("Wrong message type"),
}
}
#[test]
fn forward_message_encoding() {
let msg1 = ForwardPacketData {
target_lp_address: "1.2.3.4:5678".parse().unwrap(),
expected_response_size: ExpectedResponseSize::Transport,
inner_packet_bytes: vec![],
};
let msg2 = ForwardPacketData {
target_lp_address: "1.2.3.4:5678".parse().unwrap(),
expected_response_size: ExpectedResponseSize::Handshake(250),
inner_packet_bytes: vec![42u8; 64],
};
let msg3 = ForwardPacketData {
target_lp_address: "[2001:db8::1]:8080".parse().unwrap(),
expected_response_size: ExpectedResponseSize::Transport,
inner_packet_bytes: vec![],
};
let msg4 = ForwardPacketData {
target_lp_address: "[2001:db8::1]:8080".parse().unwrap(),
expected_response_size: ExpectedResponseSize::Handshake(250),
inner_packet_bytes: vec![42u8; 64],
};
let b = msg1.to_bytes();
let msg1_r = ForwardPacketData::decode(&b).unwrap();
assert_eq!(msg1_r, msg1);
let b = msg2.to_bytes();
let msg2_r = ForwardPacketData::decode(&b).unwrap();
assert_eq!(msg2_r, msg2);
let b = msg3.to_bytes();
let msg3_r = ForwardPacketData::decode(&b).unwrap();
assert_eq!(msg3_r, msg3);
let b = msg4.to_bytes();
let msg4_r = ForwardPacketData::decode(&b).unwrap();
assert_eq!(msg4_r, msg4);
}
}
+9 -3
View File
@@ -7,7 +7,7 @@ use std::fmt::{Debug, Formatter};
pub use error::MalformedLpPacketError;
pub use header::{InnerHeader, LpHeader, OuterHeader};
pub use message::{ForwardPacketData, LpMessage};
pub use message::{ApplicationData, ForwardPacketData, LpMessage, MessageType};
pub mod error;
pub mod header;
@@ -78,7 +78,7 @@ impl EncryptedLpPacket {
}
}
#[derive(Clone, PartialEq)]
#[derive(Clone, PartialEq, Eq)]
pub struct LpPacket {
pub(crate) header: LpHeader,
pub(crate) message: LpMessage,
@@ -95,6 +95,10 @@ impl LpPacket {
Self { header, message }
}
pub fn typ(&self) -> MessageType {
self.message.typ()
}
pub fn message(&self) -> &LpMessage {
&self.message
}
@@ -115,6 +119,8 @@ impl LpPacket {
pub(crate) fn dbg_encode(&self, dst: &mut BytesMut) {
self.header.dbg_encode(dst);
self.message.encode(dst)
dst.put_slice(&(self.message.typ() as u16).to_le_bytes());
self.message.encode_content(dst);
}
}
+9 -4
View File
@@ -6,7 +6,7 @@
//! This module implements session management functionality, including replay protection
use crate::codec::{decrypt_lp_packet, encrypt_lp_packet};
use crate::packet::{EncryptedLpPacket, LpHeader, LpMessage, LpPacket};
use crate::packet::{ApplicationData, EncryptedLpPacket, LpHeader, LpMessage, LpPacket};
use crate::peer::{LpLocalPeer, LpRemotePeer};
use crate::peer_config::LpReceiverIndex;
use crate::psq::{
@@ -174,7 +174,12 @@ impl LpSession {
pub fn next_packet(&mut self, message: LpMessage) -> Result<LpPacket, LpError> {
let counter = self.next_counter();
let header = LpHeader::new(self.receiver_index(), counter, self.protocol_version);
let header = LpHeader::new(
self.receiver_index(),
counter,
self.protocol_version,
message.typ(),
);
let packet = LpPacket::new(header, message);
Ok(packet)
}
@@ -250,9 +255,9 @@ impl LpSession {
/// * `Err(LpError)` if the session is not in transport mode or encryption fails.
pub(crate) fn encrypt_application_data(
&mut self,
data: LpMessage,
data: Vec<u8>,
) -> Result<EncryptedLpPacket, LpError> {
let packet = self.next_packet(data)?;
let packet = self.next_packet(LpMessage::ApplicationData(ApplicationData::new(data)))?;
encrypt_lp_packet(packet, &mut self.active_transport)
}
+12 -14
View File
@@ -1,7 +1,7 @@
#[cfg(test)]
mod tests {
use crate::packet::{EncryptedLpPacket, LpMessage};
use crate::state_machine::{LpAction, LpInput, LpStateBare};
use crate::packet::EncryptedLpPacket;
use crate::state_machine::{LpAction, LpData, LpInput, LpStateBare};
use crate::{LpError, SessionManager, SessionsMock};
use nym_kkt_ciphersuite::{IntoEnumIterator, KEM};
@@ -9,7 +9,7 @@ mod tests {
trait ActionExtract {
fn ciphertext(self) -> EncryptedLpPacket;
fn data(self) -> LpMessage;
fn data(self) -> LpData;
}
impl ActionExtract for LpAction {
@@ -21,7 +21,7 @@ mod tests {
}
}
fn data(self) -> LpMessage {
fn data(self) -> LpData {
if let LpAction::DeliverData(data) = self {
data
} else {
@@ -54,7 +54,7 @@ mod tests {
// --- A sends to B ---
let plaintext_a = format!("A->B Message {i}").into_bytes();
let ciphertext_a = session_manager_1
.send_data(peer_a_sm, LpMessage::new_opaque(plaintext_a.clone()))
.send_data(peer_a_sm, LpData::new_opaque(plaintext_a.clone()))
.unwrap()
.ciphertext();
@@ -69,7 +69,7 @@ mod tests {
// --- B sends to A ---
let plaintext_b = format!("B->A Message {i}").into_bytes();
let ciphertext_b = session_manager_2
.send_data(peer_b_sm, LpMessage::new_opaque(plaintext_b.clone()))
.send_data(peer_b_sm, LpData::new_opaque(plaintext_b.clone()))
.unwrap()
.ciphertext();
@@ -195,10 +195,8 @@ mod tests {
// --- 3. Simulate Data Transfer via process_input ---
println!("Starting data transfer simulation via process_input...");
let plaintext_a_to_b =
LpMessage::new_opaque(b"Hello from A via process_input!".to_vec());
let plaintext_b_to_a =
LpMessage::new_opaque(b"Hello from B via process_input!".to_vec());
let plaintext_a_to_b = LpData::new_opaque(b"Hello from A via process_input!".to_vec());
let plaintext_b_to_a = LpData::new_opaque(b"Hello from B via process_input!".to_vec());
// --- A sends to B ---
println!(" A sends to B");
@@ -274,8 +272,8 @@ mod tests {
println!("Testing out-of-order reception via process_input...");
// A prepares N+1 then N
let data_n_plus_1 = LpMessage::new_opaque(b"Message N+1".to_vec());
let data_n = LpMessage::new_opaque(b"Message N".to_vec());
let data_n_plus_1 = LpData::new_opaque(b"Message N+1".to_vec());
let data_n = LpData::new_opaque(b"Message N".to_vec());
let action_send_n1 = session_manager_1
.process_input(session_id, LpInput::SendData(data_n_plus_1.clone()))
@@ -346,7 +344,7 @@ mod tests {
// Further actions on A fail
let send_after_close_a = session_manager_1.process_input(
session_id,
LpInput::SendData(LpMessage::new_opaque(b"fail".to_vec())),
LpInput::SendData(LpData::new_opaque(b"fail".to_vec())),
);
assert!(send_after_close_a.is_err());
assert!(matches!(
@@ -368,7 +366,7 @@ mod tests {
// Further actions on B fail
let send_after_close_b = session_manager_2.process_input(
session_id,
LpInput::SendData(LpMessage::new_opaque(b"fail".to_vec())),
LpInput::SendData(LpData::new_opaque(b"fail".to_vec())),
);
assert!(send_after_close_b.is_err());
assert!(matches!(
+3 -7
View File
@@ -6,9 +6,9 @@
//! This module implements session lifecycle management functionality, handling
//! creation, retrieval, and storage of sessions.
use crate::packet::{EncryptedLpPacket, LpMessage};
use crate::packet::EncryptedLpPacket;
use crate::peer_config::LpReceiverIndex;
use crate::state_machine::{LpAction, LpInput, LpStateBare};
use crate::state_machine::{LpAction, LpData, LpInput, LpStateBare};
use crate::{LpError, LpSession, LpStateMachine};
use std::collections::HashMap;
@@ -44,11 +44,7 @@ impl SessionManager {
self.with_state_machine_mut(lp_id, |sm| sm.process_input(input).transpose())?
}
pub fn send_data(
&mut self,
lp_id: LpReceiverIndex,
data: LpMessage,
) -> Result<LpAction, LpError> {
pub fn send_data(&mut self, lp_id: LpReceiverIndex, data: LpData) -> Result<LpAction, LpError> {
self.process_input(lp_id, LpInput::SendData(data))?
.ok_or(LpError::NotInTransport)
}
+103 -12
View File
@@ -5,11 +5,12 @@
//! State machine ensures protocol steps execute in correct order. Invalid transitions
//! return LpError, preventing protocol violations.
use crate::packet::EncryptedLpPacket;
use crate::packet::message::LpMessage;
use crate::packet::{EncryptedLpPacket, LpMessage};
use crate::peer_config::LpReceiverIndex;
use crate::session::SessionId;
use crate::{LpError, session::LpSession};
use bytes::{Buf, Bytes};
use num_enum::{IntoPrimitive, TryFromPrimitive};
use std::mem;
#[derive(Debug)]
@@ -57,7 +58,7 @@ pub enum LpInput {
ReceivePacket(EncryptedLpPacket),
/// Application wants to send data (only valid in Transport state).
SendData(LpMessage),
SendData(LpData),
/// Close the connection.
Close,
@@ -70,12 +71,81 @@ pub enum LpAction {
SendPacket(EncryptedLpPacket),
/// Deliver decrypted application data received from the peer.
DeliverData(LpMessage),
DeliverData(LpData),
/// Inform the environment that the connection is closed.
ConnectionClosed,
}
/// Represent application data being sent in Transport mode
#[derive(Debug, Clone, PartialEq)]
pub struct LpData {
pub kind: LpDataKind,
pub content: Bytes,
}
impl AsRef<[u8]> for LpData {
fn as_ref(&self) -> &[u8] {
&self.content
}
}
impl LpData {
pub fn new(kind: LpDataKind, content: impl Into<Bytes>) -> Self {
Self {
kind,
content: content.into(),
}
}
pub fn new_opaque(content: impl Into<Bytes>) -> Self {
Self::new(LpDataKind::Opaque, content)
}
pub fn new_registration(data: impl Into<Bytes>) -> Self {
Self::new(LpDataKind::Registration, data)
}
pub fn new_forward(data: impl Into<Bytes>) -> Self {
Self::new(LpDataKind::Forward, data)
}
pub fn to_vec(self) -> Vec<u8> {
self.into()
}
}
impl From<LpData> for Vec<u8> {
fn from(data: LpData) -> Self {
let mut out = Vec::with_capacity(data.content.len() + 1);
out.push(data.kind as u8);
out.extend_from_slice(data.content.as_ref());
out
}
}
impl TryFrom<Vec<u8>> for LpData {
type Error = LpError;
fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
let kind = LpDataKind::try_from(value[0]).map_err(|_| {
LpError::DeserializationError(format!("unknown data type: {}", value[0]))
})?;
let mut content = Bytes::from(value);
content.advance(1);
Ok(LpData::new(kind, content))
}
}
/// Represent kind of application data being sent in Transport mode
#[derive(Clone, Copy, PartialEq, Eq, Debug, IntoPrimitive, TryFromPrimitive)]
#[repr(u8)]
pub enum LpDataKind {
Opaque = 0,
Registration = 1,
Forward = 2,
}
/// The Lewes Protocol State Machine.
pub struct LpStateMachine {
pub state: LpState,
@@ -164,10 +234,31 @@ impl LpStateMachine {
return (LpState::Transport(state), Some(Err(e)));
}
// 4. deliver the message
let message = packet.message;
let result_action = Some(Ok(LpAction::DeliverData(message)));
(LpState::Transport(state), result_action)
// Check message type
match packet.into_message() {
// Normal encrypted data
LpMessage::ApplicationData(payload) => {
// Deliver data
match payload.0.try_into() {
Ok(data) => {
let result_action = Some(Ok(LpAction::DeliverData(data)));
(LpState::Transport(state), result_action)
}
Err(e) => {
let reason = e.to_string();
(LpState::Closed { reason }, Some(Err(e)))
}
}
}
other => {
// Unexpected message type in Transport state
let err = LpError::InvalidStateTransition {
state: "Transport".to_string(),
input: format!("Unexpected message type: {other}"),
};
(LpState::Transport(state), Some(Err(err)))
}
}
}
LpInput::SendData(data) => {
// Encrypt and send application data
@@ -248,9 +339,9 @@ impl LpStateMachine {
fn prepare_data_packet(
&self,
session: &mut LpSession,
data: LpMessage,
data: LpData,
) -> Result<EncryptedLpPacket, LpError> {
session.encrypt_application_data(data)
session.encrypt_application_data(data.to_vec())
}
}
@@ -295,7 +386,7 @@ mod tests {
// --- Transport Phase ---
println!("--- Step 1: Initiator sends data ---");
let data_to_send_1 = LpMessage::new_opaque(b"hello responder".to_vec());
let data_to_send_1 = LpData::new_opaque(b"hello responder".to_vec());
let init_actions_4 = initiator.process_input(LpInput::SendData(data_to_send_1.clone()));
let data_packet_1 = if let Some(Ok(LpAction::SendPacket(packet))) = init_actions_4 {
packet.clone()
@@ -314,7 +405,7 @@ mod tests {
assert_eq!(resp_data_1, data_to_send_1);
println!("--- Step 3: Responder sends data ---");
let data_to_send_2 = LpMessage::new_opaque(b"hello initiator".to_vec());
let data_to_send_2 = LpData::new_opaque(b"hello initiator".to_vec());
let resp_actions_6 = responder.process_input(LpInput::SendData(data_to_send_2.clone()));
let data_packet_2 = if let Some(Ok(LpAction::SendPacket(packet))) = resp_actions_6 {
packet.clone()
@@ -57,37 +57,6 @@ This page displays a full list of all the changes during our release cycle from
<VarInfo />
## `v2026.4-quark`
- [Release Binaries](https://github.com/nymtech/nym/releases/tag/nym-binaries-v2026.4-quark)
- [`nym-node`](nodes/nym-node.mdx) version `1.26.0`
```sh
nym-node
Binary Name: nym-node
Build Timestamp: 2026-02-24T13:43:24.098285047Z
Build Version: 1.26.0
Commit SHA: a2081af6038ef3ef40b3d9368299d2676a2fbb6a
Commit Date: 2026-02-24T12:02:35.000000000+01:00
Commit Branch: HEAD
rustc Version: 1.91.1
rustc Channel: stable
cargo Profile: release
```
### Operator & Developer Updates
### Features
- [Stateless handshake improvements for LP Gateway](https://github.com/nymtech/nym/pull/6437)
- [HTTP & DNS improvements](https://github.com/nymtech/nym/pull/6423)
- [Endpoint support for exit gateway IPs](https://github.com/nymtech/nym/pull/6418)
### Tools
- **Diagnostic Tool** - a standalone binary for network diagnostics. It performs DNS, HTTP, and gateway connectivity tests, helping developers identify connectivity issues and monitor network performance. It can also be run via the daemon CLI. Read the full guide [here](https://nym.com/docs/developers/tools/diagnostic-tool).
- **Socks5 Score Calculation** - performed by the Gateway probe, which tests `nym-node --mode exit-gateway` instances over Socks5. The probe assigns a latency-based rating: high, medium, low, or offline. Full guide [here](https://nym.com/docs/operators/performance-and-testing#socks5-score-calculation-process).
## `v2026.3-parmigiano`
- [Release Binaries](https://github.com/nymtech/nym/releases/tag/nym-binaries-v2026.3-parmigiano)
- [`nym-node`](nodes/nym-node.mdx) version `1.25.0`
@@ -105,9 +74,9 @@ rustc Channel: stable
cargo Profile: release
```
### Operator & Developer Updates
### Key updates for operators include:
### Features
LP Gateway and Client fixes:
- [Registration client now properly supports fallback](https://github.com/nymtech/nym/pull/6419)
- [Exposed WireGuard PSK for vpn-client](https://github.com/nymtech/nym/pull/6411)
@@ -116,14 +85,28 @@ cargo Profile: release
Note: This code is currently deactivated and doesnt involve any changes for operators right now, but it will in the future.
### Bugfix
Mixnet & Networking Enhancements:
- [NS API Socks5 support](https://github.com/nymtech/nym/pull/6361)
- [Two-step dvpn registration flow](https://github.com/nymtech/nym/pull/6386)
- [DVPN PSK injection](https://github.com/nymtech/nym/pull/6378)
Security & Encoding Improvements:
- [Hex-encoding for LP key digests](https://github.com/nymtech/nym/pull/6394)
- [Encrypted KKT](https://github.com/nymtech/nym/pull/6331)
- [Reject packets with incompatible versions](https://github.com/nymtech/nym/pull/6326)
Bugfixes & Quality-of-Life:
- [Share IP allocation fixes](https://github.com/nymtech/nym/pull/6395)
- [Mixnet registration fixes](https://github.com/nymtech/nym/pull/6356)
- [Small QoL changes](https://github.com/nymtech/nym/pull/6340)
### Refactors & Maintenance
Chores & Maintenance:
- [Cleanup x25519/ed22519 usage](https://github.com/nymtech/nym/pull/6335)
- [Upgrade to def_guard_wireguard v0.8.0](https://github.com/nymtech/nym/pull/6315)
## `v2026.2-oscypek`
@@ -155,7 +138,7 @@ Secondly, the outcome of [NIP-7: Nym Exit Policy Update - Opening Ports for Stea
This release brings changes which would lead into a *foreign constraint bug* if operators just switched binaries and restarted the node. To prevent it we need to do a little `sqlite` tweak on the node database.
To simplify this, we made **a build in command, which operators must run after getting the new binary, but before restarting the node.**
To simplify this, we made **a build in command, which operators must run after getting the new binary, but beofre restarting the node.**
These are the steps to follow:
@@ -179,7 +162,7 @@ chmod +x nym-node
```sh
systemctl restart nym-node
```
- Additionally look for status or service journal
- Additionaly look for starus or serivice journal
```sh
service nym-node status
# or
@@ -1319,7 +1302,7 @@ cargo Profile: release
- [Listen for shutdown signals during nym-node startup](https://github.com/nymtech/nym/pull/5879): This is to avoid situation where the process can't be killed without 'kill -9' because the logic to listen to shutdown signals hasn't been hit yet
### Bugfix
### Bugfixes
- [Don't allow mixnode running in exit mode](https://github.com/nymtech/nym/pull/5898)
@@ -24,8 +24,8 @@ Yes, there are..
**Built by community**
* [SpectreDAO Explorer](https://explorer.nym.spectredao.net/dashboard)
* [Nymesis](https://nymesis.vercel.app)
* [ExploreNYM](https://explorenym.net/)
* [Mixplorer](https://mixplorer.xyz/)
### Which VPS providers would you recommend?
@@ -21,16 +21,17 @@ This documentation page provides a guide on how to set up and run a [NYM NODE](.
```sh
nym-node
Binary Name: nym-node
Build Timestamp: 2026-02-24T13:43:24.098285047Z
Build Version: 1.26.0
Commit SHA: a2081af6038ef3ef40b3d9368299d2676a2fbb6a
Commit Date: 2026-02-24T12:02:35.000000000+01:00
Build Timestamp: 2026-01-27T14:54:15.579821601Z
Build Version: 1.24.0
Commit SHA: 83bf9dc7cc2b01f65cab671733f2bf6c3abd471d
Commit Date: 2026-01-27T15:46:52.000000000+01:00
Commit Branch: HEAD
rustc Version: 1.91.1
rustc Channel: stable
cargo Profile: release
```
Detailed version archive and release notes is documented [here](../../changelog.mdx).
{/* COMMENTING THIS OUT ASS WE HAVE TO FIGURE OUT HOW TO SHOW THE LATEST VERSION FROM MASTER BRANCH
+1 -2
View File
@@ -393,11 +393,10 @@ mod tests {
#[tokio::test]
async fn test_basic_lp_entry_registration() -> anyhow::Result<()> {
// nym_test_utils::helpers::setup_test_logger();
for kem in KEM::iter() {
let ciphersuite = Ciphersuite::default().with_kem(kem);
// nym_test_utils::helpers::setup_test_logger();
// initialise random, but deterministic, keys, addresses, etc. for the parties
let mut client_rng = u64_seeded_rng_09(0);
let mut gateway_rng = u64_seeded_rng_09(1);
+1 -1
View File
@@ -4,7 +4,7 @@
[package]
name = "nym-api"
license = "GPL-3.0"
version = "1.1.75"
version = "1.1.74"
authors.workspace = true
edition = "2021"
rust-version.workspace = true
@@ -3,7 +3,7 @@
[package]
name = "nym-node-status-agent"
version = "1.1.2-test"
version = "1.1.2"
authors.workspace = true
repository.workspace = true
homepage.workspace = true
@@ -62,12 +62,6 @@ pub(crate) async fn run_probe(
let json_str = extract_json_from_log(&log);
if json_str.is_empty() {
tracing::error!("Failed to extract JSON from probe output");
let preview: String = log.chars().take(400).collect();
tracing::error!(
"Probe output preview (first {} chars): {}",
preview.len(),
preview
);
} else {
match serde_json::from_str::<serde_json::Value>(&json_str) {
Ok(json) => {
@@ -89,12 +83,6 @@ pub(crate) async fn run_probe(
}
Err(e) => {
tracing::error!("Failed to parse probe output as JSON: {e}");
let preview: String = json_str.chars().take(400).collect();
tracing::error!(
"Extracted JSON preview (first {} chars): {}",
preview.len(),
preview
);
}
}
}
@@ -104,13 +104,9 @@ impl GwProbe {
match command.spawn() {
Ok(child) => {
if let Ok(output) = child.wait_with_output() {
let err = String::from_utf8_lossy(&output.stderr);
if !err.trim().is_empty() {
tracing::info!("Probe stderr:\n{}", err);
}
if !output.status.success() {
let out = String::from_utf8_lossy(&output.stdout);
let err = String::from_utf8_lossy(&output.stderr);
tracing::error!("Probe exited with {:?}:\n{}\n{}", output.status, out, err);
}
@@ -3,7 +3,7 @@
[package]
name = "nym-node-status-api"
version = "4.1.0-test"
version = "4.1.0"
authors.workspace = true
repository.workspace = true
homepage.workspace = true
+1 -1
View File
@@ -3,7 +3,7 @@
[package]
name = "nym-node"
version = "1.27.0"
version = "1.26.0"
authors.workspace = true
repository.workspace = true
homepage.workspace = true
+2 -3
View File
@@ -2,8 +2,7 @@
// SPDX-License-Identifier: Apache-2.0
use crate::node::lp::LpReceiverIndex;
use nym_lp::packet::message::LpMessageType;
use nym_lp::state_machine::LpAction;
use nym_lp::state_machine::{LpAction, LpDataKind};
use nym_lp::transport::LpTransportError;
use nym_lp::{LpError, packet::MalformedLpPacketError};
use std::net::SocketAddr;
@@ -45,7 +44,7 @@ pub enum LpHandlerError {
MalformedLpPacket(#[from] MalformedLpPacketError),
#[error("received payload type of an unexpected type: {typ:?}")]
UnexpectedLpPayload { typ: LpMessageType },
UnexpectedLpPayload { typ: LpDataKind },
#[error("timed out while attempting to send to/receive from the connection")]
ConnectionTimeout,
+13 -15
View File
@@ -4,9 +4,8 @@
use super::{LpHandlerState, LpReceiverIndex, TimestampedState};
use crate::node::lp::error::LpHandlerError;
use dashmap::mapref::one::RefMut;
use nym_lp::packet::message::LpMessageType;
use nym_lp::packet::{EncryptedLpPacket, ForwardPacketData, LpMessage};
use nym_lp::state_machine::{LpAction, LpInput};
use nym_lp::packet::{EncryptedLpPacket, ForwardPacketData};
use nym_lp::state_machine::{LpAction, LpData, LpDataKind, LpInput};
use nym_lp::transport::LpHandshakeChannel;
use nym_lp::transport::traits::LpTransportChannel;
use nym_lp::{LpSession, LpStateMachine, packet::message::ExpectedResponseSize};
@@ -302,14 +301,13 @@ where
async fn handle_decrypted_payload(
&mut self,
receiver_idx: LpReceiverIndex,
decrypted_data: LpMessage,
decrypted_data: LpData,
) -> Result<(), LpHandlerError> {
let remote = self.remote_addr;
let header = decrypted_data.header;
let bytes = decrypted_data.content;
match header.kind {
LpMessageType::Registration => {
match decrypted_data.kind {
LpDataKind::Registration => {
let request = LpRegistrationRequest::try_deserialise(&bytes)
.map_err(|source| LpHandlerError::MalformedRegistrationRequest { source })?;
@@ -321,13 +319,13 @@ where
self.handle_registration_request(receiver_idx, request)
.await
}
LpMessageType::Forward => {
LpDataKind::Forward => {
let forward_data = ForwardPacketData::decode(&bytes)?;
self.handle_forwarding_request(receiver_idx, forward_data)
.await
}
typ @ LpMessageType::Opaque => {
typ @ LpDataKind::Opaque => {
// Neither registration nor forwarding - unknown payload type
warn!(
"Unknown transport payload type from {remote} (receiver_idx={receiver_idx}). dropping {} bytes",
@@ -343,14 +341,14 @@ where
async fn send_response_packet(
&mut self,
serialised_response: Vec<u8>,
response_kind: LpMessageType,
response_kind: LpDataKind,
) -> Result<(), LpHandlerError> {
let mut state_entry = self.state_entry_mut()?;
// Access session via state machine for subsession support
let state_machine = &mut state_entry.value_mut().state;
let wrapped_lp_data = LpMessage::new(response_kind, serialised_response);
let wrapped_lp_data = LpData::new(response_kind, serialised_response);
// Process packet through state machine
let action = state_machine
@@ -380,7 +378,7 @@ where
.serialise()
.map_err(|source| LpHandlerError::MalformedRegistrationRequest { source })?;
self.send_response_packet(response_bytes, LpMessageType::Registration)
self.send_response_packet(response_bytes, LpDataKind::Registration)
.await?;
match response.status {
@@ -417,7 +415,7 @@ where
// Forward the packet to the target gateway and retrieve its response
let response_bytes = self.handle_forward_packet(forward_data).await?;
self.send_response_packet(response_bytes, LpMessageType::Forward)
self.send_response_packet(response_bytes, LpDataKind::Forward)
.await?;
debug!(
@@ -752,7 +750,7 @@ mod tests {
// Send a valid packet from client side
let LpAction::SendPacket(packet) = init_sm
.send_data(id, LpMessage::new_opaque(b"foomp".to_vec()))
.send_data(id, LpData::new_opaque(b"foomp".to_vec()))
.unwrap()
else {
panic!("illegal state")
@@ -788,7 +786,7 @@ mod tests {
let (mut stream, _) = listener.accept().await.unwrap();
let LpAction::SendPacket(packet) = resp_sm
.send_data(id, LpMessage::new_opaque(b"foomp".to_vec()))
.send_data(id, LpData::new_opaque(b"foomp".to_vec()))
.unwrap()
else {
panic!("illegal state")
@@ -5,8 +5,7 @@
use nym_lp::LpError;
use nym_lp::packet::MalformedLpPacketError;
use nym_lp::packet::message::LpMessageType;
use nym_lp::state_machine::LpAction;
use nym_lp::state_machine::{LpAction, LpDataKind};
use nym_lp::transport::LpTransportError;
use thiserror::Error;
@@ -46,7 +45,7 @@ pub enum LpClientError {
MalformedLpPacket(#[from] MalformedLpPacketError),
#[error("received payload type of an unexpected type: {typ:?}")]
UnexpectedLpPayload { typ: LpMessageType },
UnexpectedLpPayload { typ: LpDataKind },
#[error("timed out while attempting to finish the KKT/PSQ handshake")]
HandshakeTimeout,
@@ -4,24 +4,23 @@
#![allow(dead_code)]
use crate::LpClientError;
use nym_lp::packet::message::LpMessageType;
use nym_lp::packet::{ForwardPacketData, LpMessage};
use nym_lp::packet::ForwardPacketData;
use nym_lp::peer::LpRemotePeer;
use nym_lp::state_machine::{LpAction, LpInput};
use nym_lp::state_machine::{LpAction, LpData, LpDataKind, LpInput};
use nym_registration_common::{
LpRegistrationRequest, LpRegistrationResponse, NymNodeLPInformation,
};
pub(crate) trait LpDataSendExt {
fn to_lp_data(&self) -> Result<LpMessage, LpClientError>;
fn to_lp_data(&self) -> Result<LpData, LpClientError>;
}
pub(crate) trait LpDataDeliverExt: Sized {
fn from_lp_data(data: LpMessage) -> Result<Self, LpClientError>;
fn from_lp_data(data: LpData) -> Result<Self, LpClientError>;
}
impl LpDataSendExt for LpRegistrationRequest {
fn to_lp_data(&self) -> Result<LpMessage, LpClientError> {
fn to_lp_data(&self) -> Result<LpData, LpClientError> {
let request_bytes = self.serialise().map_err(|e| {
LpClientError::SendRegistrationRequest(format!("Failed to serialize request: {e}"))
})?;
@@ -31,14 +30,14 @@ impl LpDataSendExt for LpRegistrationRequest {
request_bytes.len()
);
Ok(LpMessage::new_registration(request_bytes))
Ok(LpData::new_registration(request_bytes))
}
}
impl LpDataDeliverExt for LpRegistrationResponse {
fn from_lp_data(data: LpMessage) -> Result<Self, LpClientError> {
if data.kind() != LpMessageType::Registration {
return Err(LpClientError::UnexpectedLpPayload { typ: data.kind() });
fn from_lp_data(data: LpData) -> Result<Self, LpClientError> {
if data.kind != LpDataKind::Registration {
return Err(LpClientError::UnexpectedLpPayload { typ: data.kind });
}
let response = LpRegistrationResponse::try_deserialise(&data.content)
@@ -49,7 +48,7 @@ impl LpDataDeliverExt for LpRegistrationResponse {
}
impl LpDataSendExt for ForwardPacketData {
fn to_lp_data(&self) -> Result<LpMessage, LpClientError> {
fn to_lp_data(&self) -> Result<LpData, LpClientError> {
let request_bytes = self.to_bytes();
tracing::trace!(
@@ -57,7 +56,7 @@ impl LpDataSendExt for ForwardPacketData {
request_bytes.len()
);
Ok(LpMessage::new_forward(request_bytes))
Ok(LpData::new_forward(request_bytes))
}
}
@@ -71,9 +70,9 @@ pub(crate) fn try_convert_forward_response(action: LpAction) -> Result<Vec<u8>,
action => return Err(LpClientError::UnexpectedStateMachineAction { action }),
};
if response_data.kind() != LpMessageType::Forward {
if response_data.kind != LpDataKind::Forward {
return Err(LpClientError::UnexpectedLpPayload {
typ: response_data.kind(),
typ: response_data.kind,
});
}
@@ -25,10 +25,10 @@ use crate::lp_client::state_machine_helpers::{extract_forwarded_response, prepar
use nym_bandwidth_controller::{BandwidthTicketProvider, DEFAULT_TICKETS_TO_SPEND};
use nym_credentials_interface::TicketType;
use nym_crypto::asymmetric::{ed25519, x25519};
use nym_lp::packet::EncryptedLpPacket;
use nym_lp::packet::version;
use nym_lp::packet::{EncryptedLpPacket, LpMessage};
use nym_lp::peer::{DHKeyPair, LpLocalPeer, LpRemotePeer};
use nym_lp::state_machine::LpStateMachine;
use nym_lp::state_machine::{LpData, LpStateMachine};
use nym_lp::transport::LpHandshakeChannel;
use nym_lp::transport::traits::LpTransportChannel;
use nym_lp::{Ciphersuite, KEM, LpSession};
@@ -128,17 +128,14 @@ impl NestedLpSession {
/// Attempt to wrap the provided `LpData` into a `EncryptedLpPacket`
/// using the inner state machine.
fn prepare_transport_packet(&mut self, data: LpMessage) -> Result<EncryptedLpPacket> {
fn prepare_transport_packet(&mut self, data: LpData) -> Result<EncryptedLpPacket> {
let state_machine = self.state_machine_mut()?;
prepare_send_packet(data, state_machine)
}
/// Attempt to recover received `LpData` from the received `EncryptedLpPacket`
/// using the inner state machine.
fn extract_forwarded_response(
&mut self,
response_packet: EncryptedLpPacket,
) -> Result<LpMessage> {
fn extract_forwarded_response(&mut self, response_packet: EncryptedLpPacket) -> Result<LpData> {
let state_machine = self.state_machine_mut()?;
extract_forwarded_response(response_packet, state_machine)
}
@@ -2,14 +2,13 @@
// SPDX-License-Identifier: Apache-2.0
use crate::LpClientError;
use nym_lp::packet::LpMessage;
use nym_lp::state_machine::{LpAction, LpInput};
use nym_lp::state_machine::{LpAction, LpData, LpInput};
use nym_lp::{LpStateMachine, packet::EncryptedLpPacket};
/// Attempt to prepare the provided data for sending by wrapping it in appropriate `LpAction`,
/// and attempting to extract `EncryptedLpPacket` from the provided state machine.
pub(crate) fn prepare_send_packet(
data: LpMessage,
data: LpData,
state_machine: &mut LpStateMachine,
) -> Result<EncryptedLpPacket, LpClientError> {
let action = state_machine
@@ -27,7 +26,7 @@ pub(crate) fn prepare_send_packet(
pub(crate) fn extract_forwarded_response(
response_packet: EncryptedLpPacket,
state_machine: &mut LpStateMachine,
) -> Result<LpMessage, LpClientError> {
) -> Result<LpData, LpClientError> {
let action = state_machine
.process_input(LpInput::ReceivePacket(response_packet))
.ok_or(LpClientError::UnexpectedStateMachineHalt)??;
@@ -4,7 +4,7 @@
[package]
name = "nym-network-requester"
license = "GPL-3.0"
version = "1.1.73"
version = "1.1.72"
authors.workspace = true
edition.workspace = true
rust-version = "1.85"
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "nym-cli"
version = "1.1.72"
version = "1.1.71"
authors.workspace = true
edition = "2021"
license.workspace = true
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "nymvisor"
version = "0.1.37"
version = "0.1.36"
authors.workspace = true
repository.workspace = true
homepage.workspace = true
+16 -32
View File
@@ -1408,40 +1408,40 @@
}
},
"node_modules/express": {
"version": "4.22.1",
"resolved": "https://registry.npmjs.org/express/-/express-4.22.1.tgz",
"integrity": "sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==",
"version": "4.21.2",
"resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz",
"integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==",
"dev": true,
"license": "MIT",
"dependencies": {
"accepts": "~1.3.8",
"array-flatten": "1.1.1",
"body-parser": "~1.20.3",
"content-disposition": "~0.5.4",
"body-parser": "1.20.3",
"content-disposition": "0.5.4",
"content-type": "~1.0.4",
"cookie": "~0.7.1",
"cookie-signature": "~1.0.6",
"cookie": "0.7.1",
"cookie-signature": "1.0.6",
"debug": "2.6.9",
"depd": "2.0.0",
"encodeurl": "~2.0.0",
"escape-html": "~1.0.3",
"etag": "~1.8.1",
"finalhandler": "~1.3.1",
"fresh": "~0.5.2",
"http-errors": "~2.0.0",
"finalhandler": "1.3.1",
"fresh": "0.5.2",
"http-errors": "2.0.0",
"merge-descriptors": "1.0.3",
"methods": "~1.1.2",
"on-finished": "~2.4.1",
"on-finished": "2.4.1",
"parseurl": "~1.3.3",
"path-to-regexp": "~0.1.12",
"path-to-regexp": "0.1.12",
"proxy-addr": "~2.0.7",
"qs": "~6.14.0",
"qs": "6.13.0",
"range-parser": "~1.2.1",
"safe-buffer": "5.2.1",
"send": "~0.19.0",
"serve-static": "~1.16.2",
"send": "0.19.0",
"serve-static": "1.16.2",
"setprototypeof": "1.2.0",
"statuses": "~2.0.1",
"statuses": "2.0.1",
"type-is": "~1.6.18",
"utils-merge": "1.0.1",
"vary": "~1.1.2"
@@ -1461,22 +1461,6 @@
"dev": true,
"license": "MIT"
},
"node_modules/express/node_modules/qs": {
"version": "6.14.2",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.14.2.tgz",
"integrity": "sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==",
"dev": true,
"license": "BSD-3-Clause",
"dependencies": {
"side-channel": "^1.1.0"
},
"engines": {
"node": ">=0.6"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
+111 -106
View File
@@ -445,23 +445,23 @@ binary-extensions@^2.0.0:
resolved "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz"
integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==
body-parser@~1.20.3:
version "1.20.4"
resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.4.tgz#f8e20f4d06ca8a50a71ed329c15dccad1cdc547f"
integrity sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA==
body-parser@1.20.3:
version "1.20.3"
resolved "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz"
integrity sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==
dependencies:
bytes "~3.1.2"
bytes "3.1.2"
content-type "~1.0.5"
debug "2.6.9"
depd "2.0.0"
destroy "~1.2.0"
http-errors "~2.0.1"
iconv-lite "~0.4.24"
on-finished "~2.4.1"
qs "~6.14.0"
raw-body "~2.5.3"
destroy "1.2.0"
http-errors "2.0.0"
iconv-lite "0.4.24"
on-finished "2.4.1"
qs "6.13.0"
raw-body "2.5.2"
type-is "~1.6.18"
unpipe "~1.0.0"
unpipe "1.0.0"
bonjour-service@^1.0.11:
version "1.1.1"
@@ -509,9 +509,9 @@ bytes@3.0.0:
resolved "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz"
integrity sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==
bytes@~3.1.2:
bytes@3.1.2:
version "3.1.2"
resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5"
resolved "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz"
integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==
call-bind-apply-helpers@^1.0.1, call-bind-apply-helpers@^1.0.2:
@@ -609,9 +609,9 @@ connect-history-api-fallback@^2.0.0:
resolved "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz"
integrity sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==
content-disposition@~0.5.4:
content-disposition@0.5.4:
version "0.5.4"
resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe"
resolved "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz"
integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==
dependencies:
safe-buffer "5.2.1"
@@ -621,15 +621,15 @@ content-type@~1.0.4, content-type@~1.0.5:
resolved "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz"
integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==
cookie-signature@~1.0.6:
version "1.0.7"
resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.7.tgz#ab5dd7ab757c54e60f37ef6550f481c426d10454"
integrity sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==
cookie-signature@1.0.6:
version "1.0.6"
resolved "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz"
integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==
cookie@~0.7.1:
version "0.7.2"
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.7.2.tgz#556369c472a2ba910f2979891b526b3436237ed7"
integrity sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==
cookie@0.7.1:
version "0.7.1"
resolved "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz"
integrity sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==
copy-webpack-plugin@^11.0.0:
version "11.0.0"
@@ -683,7 +683,7 @@ define-lazy-prop@^2.0.0:
resolved "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz"
integrity sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==
depd@2.0.0, depd@~2.0.0:
depd@2.0.0:
version "2.0.0"
resolved "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz"
integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==
@@ -693,7 +693,7 @@ depd@~1.1.2:
resolved "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz"
integrity sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==
destroy@1.2.0, destroy@~1.2.0:
destroy@1.2.0:
version "1.2.0"
resolved "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz"
integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==
@@ -741,6 +741,11 @@ electron-to-chromium@^1.5.263:
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.286.tgz#142be1ab5e1cd5044954db0e5898f60a4960384e"
integrity sha512-9tfDXhJ4RKFNerfjdCcZfufu49vg620741MNs26a9+bhLThdB+plgMeou98CAaHu/WATj2iHOOHTp1hWtABj2A==
encodeurl@~1.0.2:
version "1.0.2"
resolved "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz"
integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==
encodeurl@~2.0.0:
version "2.0.0"
resolved "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz"
@@ -847,38 +852,38 @@ execa@^5.0.0:
strip-final-newline "^2.0.0"
express@^4.17.3:
version "4.22.1"
resolved "https://registry.yarnpkg.com/express/-/express-4.22.1.tgz#1de23a09745a4fffdb39247b344bb5eaff382069"
integrity sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==
version "4.21.2"
resolved "https://registry.npmjs.org/express/-/express-4.21.2.tgz"
integrity sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==
dependencies:
accepts "~1.3.8"
array-flatten "1.1.1"
body-parser "~1.20.3"
content-disposition "~0.5.4"
body-parser "1.20.3"
content-disposition "0.5.4"
content-type "~1.0.4"
cookie "~0.7.1"
cookie-signature "~1.0.6"
cookie "0.7.1"
cookie-signature "1.0.6"
debug "2.6.9"
depd "2.0.0"
encodeurl "~2.0.0"
escape-html "~1.0.3"
etag "~1.8.1"
finalhandler "~1.3.1"
fresh "~0.5.2"
http-errors "~2.0.0"
finalhandler "1.3.1"
fresh "0.5.2"
http-errors "2.0.0"
merge-descriptors "1.0.3"
methods "~1.1.2"
on-finished "~2.4.1"
on-finished "2.4.1"
parseurl "~1.3.3"
path-to-regexp "~0.1.12"
path-to-regexp "0.1.12"
proxy-addr "~2.0.7"
qs "~6.14.0"
qs "6.13.0"
range-parser "~1.2.1"
safe-buffer "5.2.1"
send "~0.19.0"
serve-static "~1.16.2"
send "0.19.0"
serve-static "1.16.2"
setprototypeof "1.2.0"
statuses "~2.0.1"
statuses "2.0.1"
type-is "~1.6.18"
utils-merge "1.0.1"
vary "~1.1.2"
@@ -925,17 +930,17 @@ fill-range@^7.0.1:
dependencies:
to-regex-range "^5.0.1"
finalhandler@~1.3.1:
version "1.3.2"
resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.3.2.tgz#1ebc2228fc7673aac4a472c310cc05b77d852b88"
integrity sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==
finalhandler@1.3.1:
version "1.3.1"
resolved "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz"
integrity sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==
dependencies:
debug "2.6.9"
encodeurl "~2.0.0"
escape-html "~1.0.3"
on-finished "~2.4.1"
on-finished "2.4.1"
parseurl "~1.3.3"
statuses "~2.0.2"
statuses "2.0.1"
unpipe "~1.0.0"
find-up@^4.0.0:
@@ -956,9 +961,9 @@ forwarded@0.2.0:
resolved "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz"
integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==
fresh@~0.5.2:
fresh@0.5.2:
version "0.5.2"
resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7"
resolved "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz"
integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==
fs-monkey@^1.0.3:
@@ -1116,6 +1121,17 @@ http-deceiver@^1.2.7:
resolved "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz"
integrity sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==
http-errors@2.0.0:
version "2.0.0"
resolved "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz"
integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==
dependencies:
depd "2.0.0"
inherits "2.0.4"
setprototypeof "1.2.0"
statuses "2.0.1"
toidentifier "1.0.1"
http-errors@~1.6.2:
version "1.6.3"
resolved "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz"
@@ -1126,17 +1142,6 @@ http-errors@~1.6.2:
setprototypeof "1.1.0"
statuses ">= 1.4.0 < 2"
http-errors@~2.0.0, http-errors@~2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.1.tgz#36d2f65bc909c8790018dd36fb4d93da6caae06b"
integrity sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==
dependencies:
depd "~2.0.0"
inherits "~2.0.4"
setprototypeof "~1.2.0"
statuses "~2.0.2"
toidentifier "~1.0.1"
http-parser-js@>=0.5.1:
version "0.5.8"
resolved "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz"
@@ -1167,9 +1172,9 @@ human-signals@^2.1.0:
resolved "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz"
integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==
iconv-lite@~0.4.24:
iconv-lite@0.4.24:
version "0.4.24"
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz"
integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==
dependencies:
safer-buffer ">= 2.1.2 < 3"
@@ -1195,7 +1200,7 @@ inflight@^1.0.4:
once "^1.3.0"
wrappy "1"
inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.3, inherits@~2.0.4:
inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.3:
version "2.0.4"
resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz"
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
@@ -1483,9 +1488,9 @@ obuf@^1.0.0, obuf@^1.1.2:
resolved "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz"
integrity sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==
on-finished@~2.4.1:
on-finished@2.4.1:
version "2.4.1"
resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f"
resolved "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz"
integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==
dependencies:
ee-first "1.1.1"
@@ -1570,9 +1575,9 @@ path-parse@^1.0.7:
resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz"
integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
path-to-regexp@~0.1.12:
path-to-regexp@0.1.12:
version "0.1.12"
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.12.tgz#d5e1a12e478a976d432ef3c58d534b9923164bb7"
resolved "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz"
integrity sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==
path-type@^4.0.0:
@@ -1615,12 +1620,12 @@ punycode@^2.1.0:
resolved "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz"
integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==
qs@~6.14.0:
version "6.14.2"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.14.2.tgz#b5634cf9d9ad9898e31fba3504e866e8efb6798c"
integrity sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==
qs@6.13.0:
version "6.13.0"
resolved "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz"
integrity sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==
dependencies:
side-channel "^1.1.0"
side-channel "^1.0.6"
queue-microtask@^1.2.2:
version "1.2.3"
@@ -1639,15 +1644,15 @@ range-parser@^1.2.1, range-parser@~1.2.1:
resolved "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz"
integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==
raw-body@~2.5.3:
version "2.5.3"
resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.3.tgz#11c6650ee770a7de1b494f197927de0c923822e2"
integrity sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==
raw-body@2.5.2:
version "2.5.2"
resolved "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz"
integrity sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==
dependencies:
bytes "~3.1.2"
http-errors "~2.0.1"
iconv-lite "~0.4.24"
unpipe "~1.0.0"
bytes "3.1.2"
http-errors "2.0.0"
iconv-lite "0.4.24"
unpipe "1.0.0"
readable-stream@^2.0.1:
version "2.3.8"
@@ -1777,24 +1782,24 @@ selfsigned@^2.1.1:
dependencies:
node-forge "^1"
send@~0.19.0, send@~0.19.1:
version "0.19.2"
resolved "https://registry.yarnpkg.com/send/-/send-0.19.2.tgz#59bc0da1b4ea7ad42736fd642b1c4294e114ff29"
integrity sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==
send@0.19.0:
version "0.19.0"
resolved "https://registry.npmjs.org/send/-/send-0.19.0.tgz"
integrity sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==
dependencies:
debug "2.6.9"
depd "2.0.0"
destroy "1.2.0"
encodeurl "~2.0.0"
encodeurl "~1.0.2"
escape-html "~1.0.3"
etag "~1.8.1"
fresh "~0.5.2"
http-errors "~2.0.1"
fresh "0.5.2"
http-errors "2.0.0"
mime "1.6.0"
ms "2.1.3"
on-finished "~2.4.1"
on-finished "2.4.1"
range-parser "~1.2.1"
statuses "~2.0.2"
statuses "2.0.1"
serialize-javascript@^6.0.0, serialize-javascript@^6.0.2:
version "6.0.2"
@@ -1816,22 +1821,22 @@ serve-index@^1.9.1:
mime-types "~2.1.17"
parseurl "~1.3.2"
serve-static@~1.16.2:
version "1.16.3"
resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.16.3.tgz#a97b74d955778583f3862a4f0b841eb4d5d78cf9"
integrity sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==
serve-static@1.16.2:
version "1.16.2"
resolved "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz"
integrity sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==
dependencies:
encodeurl "~2.0.0"
escape-html "~1.0.3"
parseurl "~1.3.3"
send "~0.19.1"
send "0.19.0"
setprototypeof@1.1.0:
version "1.1.0"
resolved "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz"
integrity sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==
setprototypeof@1.2.0, setprototypeof@~1.2.0:
setprototypeof@1.2.0:
version "1.2.0"
resolved "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz"
integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==
@@ -1889,9 +1894,9 @@ side-channel-weakmap@^1.0.2:
object-inspect "^1.13.3"
side-channel-map "^1.0.1"
side-channel@^1.1.0:
side-channel@^1.0.6:
version "1.1.0"
resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.1.0.tgz#c3fcff9c4da932784873335ec9765fa94ff66bc9"
resolved "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz"
integrity sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==
dependencies:
es-errors "^1.3.0"
@@ -1955,16 +1960,16 @@ spdy@^4.0.2:
select-hose "^2.0.0"
spdy-transport "^3.0.0"
statuses@2.0.1:
version "2.0.1"
resolved "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz"
integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==
"statuses@>= 1.4.0 < 2":
version "1.5.0"
resolved "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz"
integrity sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==
statuses@~2.0.1, statuses@~2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.2.tgz#8f75eecef765b5e1cfcdc080da59409ed424e382"
integrity sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==
string_decoder@^1.1.1:
version "1.3.0"
resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz"
@@ -2034,9 +2039,9 @@ to-regex-range@^5.0.1:
dependencies:
is-number "^7.0.0"
toidentifier@~1.0.1:
toidentifier@1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35"
resolved "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz"
integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==
type-is@~1.6.18:
@@ -2047,7 +2052,7 @@ type-is@~1.6.18:
media-typer "0.3.0"
mime-types "~2.1.24"
unpipe@~1.0.0:
unpipe@1.0.0, unpipe@~1.0.0:
version "1.0.0"
resolved "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz"
integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==