Compare commits

..

8 Commits

Author SHA1 Message Date
benedettadavico 1fa1b67c8d debug 2026-03-09 09:28:51 +01:00
Jędrzej Stuczyński 05b6f5e282 removed redundant LP states (#6509) 2026-03-03 13:58:47 +00:00
benedettadavico 5093450004 bump versions 2026-03-02 10:44:54 +01:00
Jędrzej Stuczyński f6bd511599 feat: Lewes Protocol with PSQv2 (#6491)
* merging georgio/lp-psqv2-integration

* use authenicator on the responder's side

* nym-lp crate compiling

* moved the e2e test to nym-lp

* move key generation to peer

* moved principal generation

* update KKTResponder

* encapsulation key parsing

* Adding concrete types within KKT exchange

* initiator side of the full handshake

* responder side of the handshake and full e2e test

* fixed unit-tests within nym-kkt

* LpSession cleanup

* helpers for Transport

* revamp of the transport traits and initial work on client-side transport

* compiling nym-crypto

* 'working' client-entry dvpn reg

* Fix key conversion

* Slightly reduce use of rand08

* reverted back to libcrux repo refs

* intial telescoping reg

* removing dead code

* wip

* moved data encryption into the state machine

* restoring nym-lp tests

* update lp api model

* Add receiver index derivation

* Add receiver index derivation

* use derived receiver index

* feat: add kem key generation to nodes

* generate fresh x25519, mlkem768 and mceliece keys on config migration

* add lp peer config

* nym-node startup cleanup

* removed dependency on pre-rand09 from nym-lp

* re-expose LP information on the http API

* fixed tests compilation

* add peer config happy path tests

* formatting

* add more tests and fix bug

* better docs

* clippy and formatting issues

* return error on mceliece within NestedSession

* wasm fixes

* removed legacy nym-vpn-lib-wasm

* fixing wasm for real this time

* additional fixes

* add payload to kkt

* make clippy happy

* moved LP to nym-node crate

* cargo fmt

* integrate lpconfig payload

* fix response size trait impl

* Migrate receiver index

* Change receiver index to u32 and regorganize crates

* clippy

* hopefully final wasm fixes

* simple conversion method from semver to ciphersuite

* updated nym-node config template

* chore: remove duplicated code

---------

Co-authored-by: Georgio Nicolas <me@georgio.xyz>
2026-02-27 13:49:08 +00:00
benedetta davico e5c3f39a57 Merge pull request #6498 from nymtech/master
Merge pull request #6481 from nymtech/release/2026.4-quark
2026-02-27 11:13:58 +01:00
Merve 76f999fc88 {DOCs/operators]: Platform release docs and changelog + docs cleanup (#6482)
* changelog-updates

* Update changelog.mdx

* Update changelog.mdx

* Edits per reviewer request

* fixes

* fixes

* typo fixed

* removed outdated info

* Update docs based on reviewer feedback

* Update changelog.mdx

---------

Co-authored-by: merve <e@E-MacBook-Air.local>
2026-02-27 10:10:16 +00:00
dependabot[bot] 2fce8c7ca3 build(deps): bump qs and express in /wasm/client/internal-dev (#6461)
Bumps [qs](https://github.com/ljharb/qs) and [express](https://github.com/expressjs/express). These dependencies needed to be updated together.

Updates `qs` from 6.13.0 to 6.14.2
- [Changelog](https://github.com/ljharb/qs/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ljharb/qs/compare/v6.13.0...v6.14.2)

Updates `express` from 4.21.2 to 4.22.1
- [Release notes](https://github.com/expressjs/express/releases)
- [Changelog](https://github.com/expressjs/express/blob/v4.22.1/History.md)
- [Commits](https://github.com/expressjs/express/compare/4.21.2...v4.22.1)

---
updated-dependencies:
- dependency-name: qs
  dependency-version: 6.14.2
  dependency-type: indirect
- dependency-name: express
  dependency-version: 4.22.1
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-26 14:20:59 +00:00
benedetta davico 4ed9d8fb7a Merge pull request #6481 from nymtech/release/2026.4-quark
Quark to master
2026-02-25 08:53:45 +01:00
33 changed files with 428 additions and 725 deletions
Generated
+9 -9
View File
@@ -5346,7 +5346,7 @@ dependencies = [
[[package]]
name = "nym-api"
version = "1.1.74"
version = "1.1.75"
dependencies = [
"anyhow",
"async-trait",
@@ -5591,7 +5591,7 @@ dependencies = [
[[package]]
name = "nym-cli"
version = "1.1.71"
version = "1.1.72"
dependencies = [
"anyhow",
"base64 0.22.1",
@@ -5674,7 +5674,7 @@ dependencies = [
[[package]]
name = "nym-client"
version = "1.1.71"
version = "1.1.72"
dependencies = [
"bs58",
"clap",
@@ -7076,7 +7076,7 @@ dependencies = [
[[package]]
name = "nym-network-requester"
version = "1.1.72"
version = "1.1.73"
dependencies = [
"addr",
"anyhow",
@@ -7126,7 +7126,7 @@ dependencies = [
[[package]]
name = "nym-node"
version = "1.26.0"
version = "1.27.0"
dependencies = [
"anyhow",
"arc-swap",
@@ -7263,7 +7263,7 @@ dependencies = [
[[package]]
name = "nym-node-status-agent"
version = "1.1.2"
version = "1.1.2-test"
dependencies = [
"anyhow",
"clap",
@@ -7282,7 +7282,7 @@ dependencies = [
[[package]]
name = "nym-node-status-api"
version = "4.1.0"
version = "4.1.0-test"
dependencies = [
"ammonia",
"anyhow",
@@ -7672,7 +7672,7 @@ dependencies = [
[[package]]
name = "nym-socks5-client"
version = "1.1.71"
version = "1.1.72"
dependencies = [
"bs58",
"clap",
@@ -8469,7 +8469,7 @@ dependencies = [
[[package]]
name = "nymvisor"
version = "0.1.36"
version = "0.1.37"
dependencies = [
"anyhow",
"bytes",
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "nym-client"
version = "1.1.71"
version = "1.1.72"
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.71"
version = "1.1.72"
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"
+15 -6
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_content(&mut plaintext);
packet.message().encode(&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_content(payload, inner_header.message_type)?;
let message = LpMessage::decode(payload)?;
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, MessageType};
use crate::packet::{EncryptedLpPacket, LpHeader, LpMessage, LpPacket};
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,7 +259,10 @@ mod tests {
let (mut init_transport, mut resp_transport) = mock_transport();
// happy path
let packet = LpPacket::new(LpHeader::new(123, 0, 1, MessageType::Busy), LpMessage::Busy);
let packet = LpPacket::new(
LpHeader::new(123, 0, 1),
LpMessage::new_opaque(b"foomp".to_vec()),
);
let ciphertext = encrypt_lp_packet(packet.clone(), &mut init_transport).unwrap();
assert_eq!(packet.header().outer, ciphertext.outer_header());
@@ -268,7 +271,10 @@ mod tests {
assert_eq!(packet, plaintext);
// incomplete ciphertext
let packet = LpPacket::new(LpHeader::new(123, 1, 1, MessageType::Busy), LpMessage::Busy);
let packet = LpPacket::new(
LpHeader::new(123, 1, 1),
LpMessage::new_opaque(b"foomp".to_vec()),
);
let ciphertext2 = encrypt_lp_packet(packet, &mut init_transport).unwrap();
let l = ciphertext2.ciphertext().len();
let malformed_content = ciphertext2.ciphertext()[..l - 1].to_vec();
@@ -277,7 +283,10 @@ mod tests {
assert!(matches!(dec_err, LpError::PSQSessionFailure { .. }));
// too small buffer
let packet = LpPacket::new(LpHeader::new(123, 1, 1, MessageType::Busy), LpMessage::Busy);
let packet = LpPacket::new(
LpHeader::new(123, 1, 1),
LpMessage::new_opaque(b"foomp".to_vec()),
);
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 MessageType")]
InvalidMessageType(u32),
#[error("{0} is not a valid LpDataKind")]
InvalidLpDataKind(u16),
#[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_message_type(message_type: u32) -> Self {
MalformedLpPacketError::InvalidMessageType(message_type)
pub fn invalid_data_kind(message_type: u16) -> Self {
MalformedLpPacketError::InvalidLpDataKind(message_type)
}
}
+2 -19
View File
@@ -1,11 +1,9 @@
// 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.
@@ -58,11 +56,10 @@ impl OuterHeader {
pub struct InnerHeader {
pub protocol_version: u8,
pub reserved: [u8; 3],
pub message_type: MessageType,
}
impl InnerHeader {
pub const SIZE: usize = 8; // protocol_version(1) + reserved(3) + message_type(4)
pub const SIZE: usize = 4; // protocol_version(1) + reserved(3)
pub fn encode(&self, dst: &mut BytesMut) {
// protocol version
@@ -70,9 +67,6 @@ 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> {
@@ -104,14 +98,9 @@ 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,
})
}
}
@@ -129,12 +118,7 @@ pub struct LpHeader {
}
impl LpHeader {
pub fn new(
receiver_idx: LpReceiverIndex,
counter: u64,
protocol_version: u8,
message_type: MessageType,
) -> Self {
pub fn new(receiver_idx: LpReceiverIndex, counter: u64, protocol_version: u8) -> Self {
Self {
outer: OuterHeader {
receiver_idx,
@@ -143,7 +127,6 @@ impl LpHeader {
inner: InnerHeader {
protocol_version,
reserved: [0u8; 3],
message_type,
},
}
}
+102 -348
View File
@@ -2,109 +2,119 @@
// SPDX-License-Identifier: Apache-2.0
use crate::packet::error::MalformedLpPacketError;
use bytes::{BufMut, BytesMut};
use bytes::{BufMut, Bytes, BytesMut};
use num_enum::{IntoPrimitive, TryFromPrimitive};
use std::fmt;
use std::fmt::Display;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
#[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,
#[derive(Debug, Clone, PartialEq)]
pub struct LpMessageHeader {
pub kind: LpMessageType,
pub message_attributes: [u8; 14],
}
impl MessageType {
pub(crate) fn from_u32(value: u32) -> Option<Self> {
MessageType::try_from(value).ok()
}
impl LpMessageHeader {
pub const SIZE: usize = 16; // message_kind(2) + message_attributes(14)
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(kind: LpMessageType, message_attributes: [u8; 14]) -> Self {
Self {
kind,
message_attributes,
}
}
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()
)));
pub fn new_no_attributes(kind: LpMessageType) -> Self {
Self {
kind,
message_attributes: [0; 14],
}
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 message = String::from_utf8_lossy(&bytes[4..]).to_string();
Ok(ErrorPacketData { message })
}
/// 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 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))?;
#[allow(clippy::unwrap_used)]
let message_attributes = src[2..16].try_into().unwrap();
Ok(Self {
kind,
message_attributes,
})
}
}
/// 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)]
@@ -163,24 +173,6 @@ 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) {
@@ -261,241 +253,3 @@ 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);
}
}
+3 -9
View File
@@ -7,7 +7,7 @@ use std::fmt::{Debug, Formatter};
pub use error::MalformedLpPacketError;
pub use header::{InnerHeader, LpHeader, OuterHeader};
pub use message::{ApplicationData, ForwardPacketData, LpMessage, MessageType};
pub use message::{ForwardPacketData, LpMessage};
pub mod error;
pub mod header;
@@ -78,7 +78,7 @@ impl EncryptedLpPacket {
}
}
#[derive(Clone, PartialEq, Eq)]
#[derive(Clone, PartialEq)]
pub struct LpPacket {
pub(crate) header: LpHeader,
pub(crate) message: LpMessage,
@@ -95,10 +95,6 @@ impl LpPacket {
Self { header, message }
}
pub fn typ(&self) -> MessageType {
self.message.typ()
}
pub fn message(&self) -> &LpMessage {
&self.message
}
@@ -119,8 +115,6 @@ impl LpPacket {
pub(crate) fn dbg_encode(&self, dst: &mut BytesMut) {
self.header.dbg_encode(dst);
dst.put_slice(&(self.message.typ() as u16).to_le_bytes());
self.message.encode_content(dst);
self.message.encode(dst)
}
}
+4 -9
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::{ApplicationData, EncryptedLpPacket, LpHeader, LpMessage, LpPacket};
use crate::packet::{EncryptedLpPacket, LpHeader, LpMessage, LpPacket};
use crate::peer::{LpLocalPeer, LpRemotePeer};
use crate::peer_config::LpReceiverIndex;
use crate::psq::{
@@ -174,12 +174,7 @@ 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,
message.typ(),
);
let header = LpHeader::new(self.receiver_index(), counter, self.protocol_version);
let packet = LpPacket::new(header, message);
Ok(packet)
}
@@ -255,9 +250,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: Vec<u8>,
data: LpMessage,
) -> Result<EncryptedLpPacket, LpError> {
let packet = self.next_packet(LpMessage::ApplicationData(ApplicationData::new(data)))?;
let packet = self.next_packet(data)?;
encrypt_lp_packet(packet, &mut self.active_transport)
}
+14 -12
View File
@@ -1,7 +1,7 @@
#[cfg(test)]
mod tests {
use crate::packet::EncryptedLpPacket;
use crate::state_machine::{LpAction, LpData, LpInput, LpStateBare};
use crate::packet::{EncryptedLpPacket, LpMessage};
use crate::state_machine::{LpAction, 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) -> LpData;
fn data(self) -> LpMessage;
}
impl ActionExtract for LpAction {
@@ -21,7 +21,7 @@ mod tests {
}
}
fn data(self) -> LpData {
fn data(self) -> LpMessage {
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, LpData::new_opaque(plaintext_a.clone()))
.send_data(peer_a_sm, LpMessage::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, LpData::new_opaque(plaintext_b.clone()))
.send_data(peer_b_sm, LpMessage::new_opaque(plaintext_b.clone()))
.unwrap()
.ciphertext();
@@ -195,8 +195,10 @@ mod tests {
// --- 3. Simulate Data Transfer via process_input ---
println!("Starting data transfer simulation via process_input...");
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());
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());
// --- A sends to B ---
println!(" A sends to B");
@@ -272,8 +274,8 @@ mod tests {
println!("Testing out-of-order reception via process_input...");
// A prepares N+1 then N
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 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 action_send_n1 = session_manager_1
.process_input(session_id, LpInput::SendData(data_n_plus_1.clone()))
@@ -344,7 +346,7 @@ mod tests {
// Further actions on A fail
let send_after_close_a = session_manager_1.process_input(
session_id,
LpInput::SendData(LpData::new_opaque(b"fail".to_vec())),
LpInput::SendData(LpMessage::new_opaque(b"fail".to_vec())),
);
assert!(send_after_close_a.is_err());
assert!(matches!(
@@ -366,7 +368,7 @@ mod tests {
// Further actions on B fail
let send_after_close_b = session_manager_2.process_input(
session_id,
LpInput::SendData(LpData::new_opaque(b"fail".to_vec())),
LpInput::SendData(LpMessage::new_opaque(b"fail".to_vec())),
);
assert!(send_after_close_b.is_err());
assert!(matches!(
+7 -3
View File
@@ -6,9 +6,9 @@
//! This module implements session lifecycle management functionality, handling
//! creation, retrieval, and storage of sessions.
use crate::packet::EncryptedLpPacket;
use crate::packet::{EncryptedLpPacket, LpMessage};
use crate::peer_config::LpReceiverIndex;
use crate::state_machine::{LpAction, LpData, LpInput, LpStateBare};
use crate::state_machine::{LpAction, LpInput, LpStateBare};
use crate::{LpError, LpSession, LpStateMachine};
use std::collections::HashMap;
@@ -44,7 +44,11 @@ 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: LpData) -> Result<LpAction, LpError> {
pub fn send_data(
&mut self,
lp_id: LpReceiverIndex,
data: LpMessage,
) -> Result<LpAction, LpError> {
self.process_input(lp_id, LpInput::SendData(data))?
.ok_or(LpError::NotInTransport)
}
+12 -103
View File
@@ -5,12 +5,11 @@
//! State machine ensures protocol steps execute in correct order. Invalid transitions
//! return LpError, preventing protocol violations.
use crate::packet::{EncryptedLpPacket, LpMessage};
use crate::packet::EncryptedLpPacket;
use crate::packet::message::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)]
@@ -58,7 +57,7 @@ pub enum LpInput {
ReceivePacket(EncryptedLpPacket),
/// Application wants to send data (only valid in Transport state).
SendData(LpData),
SendData(LpMessage),
/// Close the connection.
Close,
@@ -71,81 +70,12 @@ pub enum LpAction {
SendPacket(EncryptedLpPacket),
/// Deliver decrypted application data received from the peer.
DeliverData(LpData),
DeliverData(LpMessage),
/// 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,
@@ -234,31 +164,10 @@ impl LpStateMachine {
return (LpState::Transport(state), Some(Err(e)));
}
// 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)))
}
}
// 4. deliver the message
let message = packet.message;
let result_action = Some(Ok(LpAction::DeliverData(message)));
(LpState::Transport(state), result_action)
}
LpInput::SendData(data) => {
// Encrypt and send application data
@@ -339,9 +248,9 @@ impl LpStateMachine {
fn prepare_data_packet(
&self,
session: &mut LpSession,
data: LpData,
data: LpMessage,
) -> Result<EncryptedLpPacket, LpError> {
session.encrypt_application_data(data.to_vec())
session.encrypt_application_data(data)
}
}
@@ -386,7 +295,7 @@ mod tests {
// --- Transport Phase ---
println!("--- Step 1: Initiator sends data ---");
let data_to_send_1 = LpData::new_opaque(b"hello responder".to_vec());
let data_to_send_1 = LpMessage::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()
@@ -405,7 +314,7 @@ mod tests {
assert_eq!(resp_data_1, data_to_send_1);
println!("--- Step 3: Responder sends data ---");
let data_to_send_2 = LpData::new_opaque(b"hello initiator".to_vec());
let data_to_send_2 = LpMessage::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,6 +57,37 @@ 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`
@@ -74,9 +105,9 @@ rustc Channel: stable
cargo Profile: release
```
### Key updates for operators include:
### Operator & Developer Updates
LP Gateway and Client fixes:
### Features
- [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)
@@ -85,28 +116,14 @@ LP Gateway and Client fixes:
Note: This code is currently deactivated and doesnt involve any changes for operators right now, but it will in the future.
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:
### Bugfix
- [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)
Chores & Maintenance:
### Refactors & 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`
@@ -138,7 +155,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 beofre restarting the node.**
To simplify this, we made **a build in command, which operators must run after getting the new binary, but before restarting the node.**
These are the steps to follow:
@@ -162,7 +179,7 @@ chmod +x nym-node
```sh
systemctl restart nym-node
```
- Additionaly look for starus or serivice journal
- Additionally look for status or service journal
```sh
service nym-node status
# or
@@ -1302,7 +1319,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
### Bugfixes
### Bugfix
- [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**
* [ExploreNYM](https://explorenym.net/)
* [Mixplorer](https://mixplorer.xyz/)
* [SpectreDAO Explorer](https://explorer.nym.spectredao.net/dashboard)
* [Nymesis](https://nymesis.vercel.app)
### Which VPS providers would you recommend?
@@ -21,17 +21,16 @@ 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-01-27T14:54:15.579821601Z
Build Version: 1.24.0
Commit SHA: 83bf9dc7cc2b01f65cab671733f2bf6c3abd471d
Commit Date: 2026-01-27T15:46:52.000000000+01:00
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
```
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
+2 -1
View File
@@ -393,10 +393,11 @@ 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.74"
version = "1.1.75"
authors.workspace = true
edition = "2021"
rust-version.workspace = true
@@ -3,7 +3,7 @@
[package]
name = "nym-node-status-agent"
version = "1.1.2"
version = "1.1.2-test"
authors.workspace = true
repository.workspace = true
homepage.workspace = true
@@ -62,6 +62,12 @@ 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) => {
@@ -83,6 +89,12 @@ 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,9 +104,13 @@ 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"
version = "4.1.0-test"
authors.workspace = true
repository.workspace = true
homepage.workspace = true
+1 -1
View File
@@ -3,7 +3,7 @@
[package]
name = "nym-node"
version = "1.26.0"
version = "1.27.0"
authors.workspace = true
repository.workspace = true
homepage.workspace = true
+3 -2
View File
@@ -2,7 +2,8 @@
// SPDX-License-Identifier: Apache-2.0
use crate::node::lp::LpReceiverIndex;
use nym_lp::state_machine::{LpAction, LpDataKind};
use nym_lp::packet::message::LpMessageType;
use nym_lp::state_machine::LpAction;
use nym_lp::transport::LpTransportError;
use nym_lp::{LpError, packet::MalformedLpPacketError};
use std::net::SocketAddr;
@@ -44,7 +45,7 @@ pub enum LpHandlerError {
MalformedLpPacket(#[from] MalformedLpPacketError),
#[error("received payload type of an unexpected type: {typ:?}")]
UnexpectedLpPayload { typ: LpDataKind },
UnexpectedLpPayload { typ: LpMessageType },
#[error("timed out while attempting to send to/receive from the connection")]
ConnectionTimeout,
+15 -13
View File
@@ -4,8 +4,9 @@
use super::{LpHandlerState, LpReceiverIndex, TimestampedState};
use crate::node::lp::error::LpHandlerError;
use dashmap::mapref::one::RefMut;
use nym_lp::packet::{EncryptedLpPacket, ForwardPacketData};
use nym_lp::state_machine::{LpAction, LpData, LpDataKind, LpInput};
use nym_lp::packet::message::LpMessageType;
use nym_lp::packet::{EncryptedLpPacket, ForwardPacketData, LpMessage};
use nym_lp::state_machine::{LpAction, LpInput};
use nym_lp::transport::LpHandshakeChannel;
use nym_lp::transport::traits::LpTransportChannel;
use nym_lp::{LpSession, LpStateMachine, packet::message::ExpectedResponseSize};
@@ -301,13 +302,14 @@ where
async fn handle_decrypted_payload(
&mut self,
receiver_idx: LpReceiverIndex,
decrypted_data: LpData,
decrypted_data: LpMessage,
) -> Result<(), LpHandlerError> {
let remote = self.remote_addr;
let header = decrypted_data.header;
let bytes = decrypted_data.content;
match decrypted_data.kind {
LpDataKind::Registration => {
match header.kind {
LpMessageType::Registration => {
let request = LpRegistrationRequest::try_deserialise(&bytes)
.map_err(|source| LpHandlerError::MalformedRegistrationRequest { source })?;
@@ -319,13 +321,13 @@ where
self.handle_registration_request(receiver_idx, request)
.await
}
LpDataKind::Forward => {
LpMessageType::Forward => {
let forward_data = ForwardPacketData::decode(&bytes)?;
self.handle_forwarding_request(receiver_idx, forward_data)
.await
}
typ @ LpDataKind::Opaque => {
typ @ LpMessageType::Opaque => {
// Neither registration nor forwarding - unknown payload type
warn!(
"Unknown transport payload type from {remote} (receiver_idx={receiver_idx}). dropping {} bytes",
@@ -341,14 +343,14 @@ where
async fn send_response_packet(
&mut self,
serialised_response: Vec<u8>,
response_kind: LpDataKind,
response_kind: LpMessageType,
) -> 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 = LpData::new(response_kind, serialised_response);
let wrapped_lp_data = LpMessage::new(response_kind, serialised_response);
// Process packet through state machine
let action = state_machine
@@ -378,7 +380,7 @@ where
.serialise()
.map_err(|source| LpHandlerError::MalformedRegistrationRequest { source })?;
self.send_response_packet(response_bytes, LpDataKind::Registration)
self.send_response_packet(response_bytes, LpMessageType::Registration)
.await?;
match response.status {
@@ -415,7 +417,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, LpDataKind::Forward)
self.send_response_packet(response_bytes, LpMessageType::Forward)
.await?;
debug!(
@@ -750,7 +752,7 @@ mod tests {
// Send a valid packet from client side
let LpAction::SendPacket(packet) = init_sm
.send_data(id, LpData::new_opaque(b"foomp".to_vec()))
.send_data(id, LpMessage::new_opaque(b"foomp".to_vec()))
.unwrap()
else {
panic!("illegal state")
@@ -786,7 +788,7 @@ mod tests {
let (mut stream, _) = listener.accept().await.unwrap();
let LpAction::SendPacket(packet) = resp_sm
.send_data(id, LpData::new_opaque(b"foomp".to_vec()))
.send_data(id, LpMessage::new_opaque(b"foomp".to_vec()))
.unwrap()
else {
panic!("illegal state")
@@ -5,7 +5,8 @@
use nym_lp::LpError;
use nym_lp::packet::MalformedLpPacketError;
use nym_lp::state_machine::{LpAction, LpDataKind};
use nym_lp::packet::message::LpMessageType;
use nym_lp::state_machine::LpAction;
use nym_lp::transport::LpTransportError;
use thiserror::Error;
@@ -45,7 +46,7 @@ pub enum LpClientError {
MalformedLpPacket(#[from] MalformedLpPacketError),
#[error("received payload type of an unexpected type: {typ:?}")]
UnexpectedLpPayload { typ: LpDataKind },
UnexpectedLpPayload { typ: LpMessageType },
#[error("timed out while attempting to finish the KKT/PSQ handshake")]
HandshakeTimeout,
@@ -4,23 +4,24 @@
#![allow(dead_code)]
use crate::LpClientError;
use nym_lp::packet::ForwardPacketData;
use nym_lp::packet::message::LpMessageType;
use nym_lp::packet::{ForwardPacketData, LpMessage};
use nym_lp::peer::LpRemotePeer;
use nym_lp::state_machine::{LpAction, LpData, LpDataKind, LpInput};
use nym_lp::state_machine::{LpAction, LpInput};
use nym_registration_common::{
LpRegistrationRequest, LpRegistrationResponse, NymNodeLPInformation,
};
pub(crate) trait LpDataSendExt {
fn to_lp_data(&self) -> Result<LpData, LpClientError>;
fn to_lp_data(&self) -> Result<LpMessage, LpClientError>;
}
pub(crate) trait LpDataDeliverExt: Sized {
fn from_lp_data(data: LpData) -> Result<Self, LpClientError>;
fn from_lp_data(data: LpMessage) -> Result<Self, LpClientError>;
}
impl LpDataSendExt for LpRegistrationRequest {
fn to_lp_data(&self) -> Result<LpData, LpClientError> {
fn to_lp_data(&self) -> Result<LpMessage, LpClientError> {
let request_bytes = self.serialise().map_err(|e| {
LpClientError::SendRegistrationRequest(format!("Failed to serialize request: {e}"))
})?;
@@ -30,14 +31,14 @@ impl LpDataSendExt for LpRegistrationRequest {
request_bytes.len()
);
Ok(LpData::new_registration(request_bytes))
Ok(LpMessage::new_registration(request_bytes))
}
}
impl LpDataDeliverExt for LpRegistrationResponse {
fn from_lp_data(data: LpData) -> Result<Self, LpClientError> {
if data.kind != LpDataKind::Registration {
return Err(LpClientError::UnexpectedLpPayload { typ: data.kind });
fn from_lp_data(data: LpMessage) -> Result<Self, LpClientError> {
if data.kind() != LpMessageType::Registration {
return Err(LpClientError::UnexpectedLpPayload { typ: data.kind() });
}
let response = LpRegistrationResponse::try_deserialise(&data.content)
@@ -48,7 +49,7 @@ impl LpDataDeliverExt for LpRegistrationResponse {
}
impl LpDataSendExt for ForwardPacketData {
fn to_lp_data(&self) -> Result<LpData, LpClientError> {
fn to_lp_data(&self) -> Result<LpMessage, LpClientError> {
let request_bytes = self.to_bytes();
tracing::trace!(
@@ -56,7 +57,7 @@ impl LpDataSendExt for ForwardPacketData {
request_bytes.len()
);
Ok(LpData::new_forward(request_bytes))
Ok(LpMessage::new_forward(request_bytes))
}
}
@@ -70,9 +71,9 @@ pub(crate) fn try_convert_forward_response(action: LpAction) -> Result<Vec<u8>,
action => return Err(LpClientError::UnexpectedStateMachineAction { action }),
};
if response_data.kind != LpDataKind::Forward {
if response_data.kind() != LpMessageType::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::{LpData, LpStateMachine};
use nym_lp::state_machine::LpStateMachine;
use nym_lp::transport::LpHandshakeChannel;
use nym_lp::transport::traits::LpTransportChannel;
use nym_lp::{Ciphersuite, KEM, LpSession};
@@ -128,14 +128,17 @@ impl NestedLpSession {
/// Attempt to wrap the provided `LpData` into a `EncryptedLpPacket`
/// using the inner state machine.
fn prepare_transport_packet(&mut self, data: LpData) -> Result<EncryptedLpPacket> {
fn prepare_transport_packet(&mut self, data: LpMessage) -> 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<LpData> {
fn extract_forwarded_response(
&mut self,
response_packet: EncryptedLpPacket,
) -> Result<LpMessage> {
let state_machine = self.state_machine_mut()?;
extract_forwarded_response(response_packet, state_machine)
}
@@ -2,13 +2,14 @@
// SPDX-License-Identifier: Apache-2.0
use crate::LpClientError;
use nym_lp::state_machine::{LpAction, LpData, LpInput};
use nym_lp::packet::LpMessage;
use nym_lp::state_machine::{LpAction, 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: LpData,
data: LpMessage,
state_machine: &mut LpStateMachine,
) -> Result<EncryptedLpPacket, LpClientError> {
let action = state_machine
@@ -26,7 +27,7 @@ pub(crate) fn prepare_send_packet(
pub(crate) fn extract_forwarded_response(
response_packet: EncryptedLpPacket,
state_machine: &mut LpStateMachine,
) -> Result<LpData, LpClientError> {
) -> Result<LpMessage, 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.72"
version = "1.1.73"
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.71"
version = "1.1.72"
authors.workspace = true
edition = "2021"
license.workspace = true
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "nymvisor"
version = "0.1.36"
version = "0.1.37"
authors.workspace = true
repository.workspace = true
homepage.workspace = true
+32 -16
View File
@@ -1408,40 +1408,40 @@
}
},
"node_modules/express": {
"version": "4.21.2",
"resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz",
"integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==",
"version": "4.22.1",
"resolved": "https://registry.npmjs.org/express/-/express-4.22.1.tgz",
"integrity": "sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==",
"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.13.0",
"qs": "~6.14.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,6 +1461,22 @@
"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",
+106 -111
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.3"
resolved "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz"
integrity sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==
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==
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.0"
iconv-lite "0.4.24"
on-finished "2.4.1"
qs "6.13.0"
raw-body "2.5.2"
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"
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.npmjs.org/bytes/-/bytes-3.1.2.tgz"
resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5"
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.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz"
resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe"
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.6"
resolved "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz"
integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==
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@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==
cookie@~0.7.1:
version "0.7.2"
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.7.2.tgz#556369c472a2ba910f2979891b526b3436237ed7"
integrity sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==
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,11 +741,6 @@ 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"
@@ -852,38 +847,38 @@ execa@^5.0.0:
strip-final-newline "^2.0.0"
express@^4.17.3:
version "4.21.2"
resolved "https://registry.npmjs.org/express/-/express-4.21.2.tgz"
integrity sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==
version "4.22.1"
resolved "https://registry.yarnpkg.com/express/-/express-4.22.1.tgz#1de23a09745a4fffdb39247b344bb5eaff382069"
integrity sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==
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.13.0"
qs "~6.14.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"
@@ -930,17 +925,17 @@ fill-range@^7.0.1:
dependencies:
to-regex-range "^5.0.1"
finalhandler@1.3.1:
version "1.3.1"
resolved "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz"
integrity sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==
finalhandler@~1.3.1:
version "1.3.2"
resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.3.2.tgz#1ebc2228fc7673aac4a472c310cc05b77d852b88"
integrity sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==
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.1"
statuses "~2.0.2"
unpipe "~1.0.0"
find-up@^4.0.0:
@@ -961,9 +956,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.npmjs.org/fresh/-/fresh-0.5.2.tgz"
resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7"
integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==
fs-monkey@^1.0.3:
@@ -1121,17 +1116,6 @@ 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"
@@ -1142,6 +1126,17 @@ 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"
@@ -1172,9 +1167,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.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz"
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==
dependencies:
safer-buffer ">= 2.1.2 < 3"
@@ -1200,7 +1195,7 @@ inflight@^1.0.4:
once "^1.3.0"
wrappy "1"
inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.3:
inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.3, inherits@~2.0.4:
version "2.0.4"
resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz"
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
@@ -1488,9 +1483,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.npmjs.org/on-finished/-/on-finished-2.4.1.tgz"
resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f"
integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==
dependencies:
ee-first "1.1.1"
@@ -1575,9 +1570,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.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz"
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.12.tgz#d5e1a12e478a976d432ef3c58d534b9923164bb7"
integrity sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==
path-type@^4.0.0:
@@ -1620,12 +1615,12 @@ punycode@^2.1.0:
resolved "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz"
integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==
qs@6.13.0:
version "6.13.0"
resolved "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz"
integrity sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==
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==
dependencies:
side-channel "^1.0.6"
side-channel "^1.1.0"
queue-microtask@^1.2.2:
version "1.2.3"
@@ -1644,15 +1639,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.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==
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==
dependencies:
bytes "3.1.2"
http-errors "2.0.0"
iconv-lite "0.4.24"
unpipe "1.0.0"
bytes "~3.1.2"
http-errors "~2.0.1"
iconv-lite "~0.4.24"
unpipe "~1.0.0"
readable-stream@^2.0.1:
version "2.3.8"
@@ -1782,24 +1777,24 @@ selfsigned@^2.1.1:
dependencies:
node-forge "^1"
send@0.19.0:
version "0.19.0"
resolved "https://registry.npmjs.org/send/-/send-0.19.0.tgz"
integrity sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==
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==
dependencies:
debug "2.6.9"
depd "2.0.0"
destroy "1.2.0"
encodeurl "~1.0.2"
encodeurl "~2.0.0"
escape-html "~1.0.3"
etag "~1.8.1"
fresh "0.5.2"
http-errors "2.0.0"
fresh "~0.5.2"
http-errors "~2.0.1"
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.1"
statuses "~2.0.2"
serialize-javascript@^6.0.0, serialize-javascript@^6.0.2:
version "6.0.2"
@@ -1821,22 +1816,22 @@ serve-index@^1.9.1:
mime-types "~2.1.17"
parseurl "~1.3.2"
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==
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==
dependencies:
encodeurl "~2.0.0"
escape-html "~1.0.3"
parseurl "~1.3.3"
send "0.19.0"
send "~0.19.1"
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==
@@ -1894,9 +1889,9 @@ side-channel-weakmap@^1.0.2:
object-inspect "^1.13.3"
side-channel-map "^1.0.1"
side-channel@^1.0.6:
side-channel@^1.1.0:
version "1.1.0"
resolved "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz"
resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.1.0.tgz#c3fcff9c4da932784873335ec9765fa94ff66bc9"
integrity sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==
dependencies:
es-errors "^1.3.0"
@@ -1960,16 +1955,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"
@@ -2039,9 +2034,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.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz"
resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35"
integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==
type-is@~1.6.18:
@@ -2052,7 +2047,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==