photoncloud-monorepo/plasmavmc/crates/plasmavmc-server/src/prismnet_client.rs
centra d2149b6249 fix(lightningstor): Fix SigV4 canonicalization for AWS S3 auth
- Replace form_urlencoded with RFC 3986 compliant URI encoding
- Implement aws_uri_encode() matching AWS SigV4 spec exactly
- Unreserved chars (A-Z,a-z,0-9,-,_,.,~) not encoded
- All other chars percent-encoded with uppercase hex
- Preserve slashes in paths, encode in query params
- Normalize empty paths to '/' per AWS spec
- Fix test expectations (body hash, HMAC values)
- Add comprehensive SigV4 signature determinism test

This fixes the canonicalization mismatch that caused signature
validation failures in T047. Auth can now be enabled for production.

Refs: T058.S1
2025-12-12 06:23:46 +09:00

81 lines
2.5 KiB
Rust

//! PrismNET client for port management
use prismnet_api::proto::{
port_service_client::PortServiceClient, GetPortRequest, AttachDeviceRequest,
DetachDeviceRequest,
};
use tonic::transport::Channel;
/// PrismNET client wrapper
pub struct PrismNETClient {
port_client: PortServiceClient<Channel>,
}
impl PrismNETClient {
/// Create a new PrismNET client
pub async fn new(endpoint: String) -> Result<Self, Box<dyn std::error::Error>> {
let channel = Channel::from_shared(endpoint)?
.connect()
.await?;
let port_client = PortServiceClient::new(channel);
Ok(Self { port_client })
}
/// Get port details
pub async fn get_port(
&mut self,
org_id: &str,
project_id: &str,
subnet_id: &str,
port_id: &str,
) -> Result<prismnet_api::proto::Port, Box<dyn std::error::Error>> {
let request = tonic::Request::new(GetPortRequest {
org_id: org_id.to_string(),
project_id: project_id.to_string(),
subnet_id: subnet_id.to_string(),
id: port_id.to_string(),
});
let response = self.port_client.get_port(request).await?;
Ok(response.into_inner().port.ok_or("Port not found in response")?)
}
/// Attach a device to a port
pub async fn attach_device(
&mut self,
org_id: &str,
project_id: &str,
subnet_id: &str,
port_id: &str,
device_id: &str,
device_type: i32,
) -> Result<(), Box<dyn std::error::Error>> {
let request = tonic::Request::new(AttachDeviceRequest {
org_id: org_id.to_string(),
project_id: project_id.to_string(),
subnet_id: subnet_id.to_string(),
port_id: port_id.to_string(),
device_id: device_id.to_string(),
device_type,
});
self.port_client.attach_device(request).await?;
Ok(())
}
/// Detach a device from a port
pub async fn detach_device(
&mut self,
org_id: &str,
project_id: &str,
subnet_id: &str,
port_id: &str,
) -> Result<(), Box<dyn std::error::Error>> {
let request = tonic::Request::new(DetachDeviceRequest {
org_id: org_id.to_string(),
project_id: project_id.to_string(),
subnet_id: subnet_id.to_string(),
port_id: port_id.to_string(),
});
self.port_client.detach_device(request).await?;
Ok(())
}
}