Skip to main content

Interceptor

Struct Interceptor 

Source
pub struct Interceptor {
    pub key_store: Arc<RwLock<KeyStore>>,
    pub handshake_store: HandshakeStore,
    pub replay_store: Option<ConnectionManager>,
    pub memory_replay_store: Option<Arc<MemoryReplayStore>>,
    pub max_body_bytes: usize,
    pub max_decompressed_bytes: usize,
    pub allow_encrypted_get: bool,
}
Expand description

Actix-web middleware that transparently decrypts incoming request bodies and encrypts outgoing response bodies using the X25519 ECDH + AES-256-GCM + HMAC-SHA256 pipeline.

§Usage

Prefer Interceptor::new_with_memory_replay for new deployments — it enables in-memory replay protection and sensible body/decompression size limits without requiring Redis:

use alterion_encrypt::interceptor::Interceptor;
use alterion_encrypt::{init_key_store, init_handshake_store, start_rotation};

let store = init_key_store(3600);
let hs    = init_handshake_store();
start_rotation(store.clone(), 3600, hs.clone());
// App::new().wrap(Interceptor::new_with_memory_replay(store, hs))

To tune size limits or add Redis replay protection after construction:

let mut interceptor = Interceptor::new_with_memory_replay(store, hs);
interceptor.max_body_bytes        = 5 * 1024 * 1024;  // 5 MiB raw body
interceptor.max_decompressed_bytes = 50 * 1024 * 1024; // 50 MiB decompressed
// interceptor.replay_store = Some(redis_connection_manager);

Request path (POST / PUT / PATCH, and GET when allow_encrypted_get is true):

  1. Collect raw body bytes up to max_body_bytes — reject 413 if exceeded.
  2. MessagePack-decode a Request and validate timestamp.
  3. Check the replay store (Redis → in-memory fallback). Fails closed on store error.
  4. ECDH → wrap key → AES-GCM unwrap enc_key → AES-256-GCM decrypt payload.
  5. Preflight decompress against max_decompressed_bytes — reject 413 if exceeded.
  6. Inject DecryptedBody and RequestSessionKeys into request extensions.

Requests whose body is not a valid encrypted Request are passed through unchanged.

Response path (only when RequestSessionKeys is present): JSON → deflate → msgpack → AES-256-GCM → HMAC-SHA256 → Response → msgpack.

Fields§

§key_store: Arc<RwLock<KeyStore>>§handshake_store: HandshakeStore§replay_store: Option<ConnectionManager>

Redis-backed replay store. Takes precedence over memory_replay_store when Some.

§memory_replay_store: Option<Arc<MemoryReplayStore>>

In-memory replay store used when replay_store is None. Initialized automatically by Interceptor::new_with_memory_replay.

§max_body_bytes: usize

Maximum raw (compressed + encrypted) request body in bytes. Requests exceeding this are rejected with 413 before any decryption occurs. Default: DEFAULT_MAX_BODY_BYTES (1 MiB).

§max_decompressed_bytes: usize

Maximum decompressed payload size in bytes. Requests whose payload would expand beyond this are rejected with 413 after decryption but before the handler sees the body. Set this to whatever your largest valid request body is — there is no upper bound imposed by the library. Default: MAX_DECOMPRESSED_SIZE (10 MiB).

§allow_encrypted_get: bool

When true, GET requests that carry a body are processed through the full encrypt/decrypt pipeline identically to POST/PUT/PATCH. The client sends the msgpack-encoded [Request] as the GET body using the same buildRequestPacket function. Default: false.

Implementations§

Source§

impl Interceptor

Source

pub fn new_with_memory_replay( key_store: Arc<RwLock<KeyStore>>, handshake_store: HandshakeStore, ) -> Self

Creates an Interceptor with in-memory replay protection and default size limits (1 MiB raw body, 10 MiB decompressed).

This is the recommended constructor for new deployments. Tune max_body_bytes and max_decompressed_bytes on the returned value for your workload, or assign replay_store to upgrade to Redis-backed replay detection for multi-instance deployments.

Trait Implementations§

Source§

impl<S, B> Transform<S, ServiceRequest> for Interceptor
where S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error> + 'static, B: MessageBody + 'static,

Source§

type Response = ServiceResponse<EitherBody<B>>

Responses produced by the service.
Source§

type Error = Error

Errors produced by the service.
Source§

type Transform = InterceptorService<S>

The TransformService value created by this factory
Source§

type InitError = ()

Errors produced while building a transform service.
Source§

type Future = Ready<Result<<Interceptor as Transform<S, ServiceRequest>>::Transform, <Interceptor as Transform<S, ServiceRequest>>::InitError>>

The future response value.
Source§

fn new_transform(&self, service: S) -> Self::Future

Creates and returns a new Transform component, asynchronously

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ManuallyDropMut for T

Source§

type Ret = ManuallyDrop<T>

Source§

fn manually_drop_mut<'__>(&'__ mut self) -> &'__ mut ManuallyDrop<T>

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more