Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lack of Send and Sync on Box<dyn Primitive> makes library very difficult to use in async code #653

Open
edvardfagerholmsc opened this issue Feb 16, 2024 · 1 comment

Comments

@edvardfagerholmsc
Copy link

edvardfagerholmsc commented Feb 16, 2024

The lack of Send and Sync make the library almost unusable. I've had to resort to weird thread local tricks like the one below:

mod hello {
    tonic::include_proto!("hello");
}

use std::cell::Cell;

use hello::{HelloRequest,HelloResponse};
use hello::hello_service_server::{HelloService,HelloServiceServer};
use tonic::transport::Server;
use tonic::{Request, Response, Status};

// This would be passed through the environment to the container.
static KEY: &str = "my encryption key";

thread_local! {
    static DECRYPTER: Cell<Option<Box<dyn tink_core::Aead>>> = Cell::new(None)
}

fn parse_encryption_key(key: &str) -> Option<Box<dyn tink_core::Aead>> {
    if key != "" {
        let mut key_reader = tink_core::keyset::BinaryReader::new(key.as_bytes());
        match tink_core::keyset::insecure::read(&mut key_reader) {
            Ok(h) => Some(tink_aead::new(&h).unwrap()),
            Err(e) => None        }
    } else {
        None
    }
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let addr = "[::1]:50051";
    let service = MyServer { };

    Server::builder()
        .add_service(HelloServiceServer::new(service))
        .serve(addr.parse().unwrap())
        .await?;

    Ok(())
}

struct MyServer {
}

#[tonic::async_trait]
impl HelloService for MyServer {
    async fn hello(
        &self,
        req: Request<HelloRequest>,
    ) -> Result<Response<HelloResponse>, Status> {
        DECRYPTER.with(|c| {
            let decrypter = match c.take() {
                Some(d) => d,
                None => parse_encryption_key(KEY).unwrap()
            };
            c.set(Some(decrypter));
        });

        Ok(Response::new(HelloResponse::default()))
    }
}

What I'd like to be able to do is just:

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let decrypter = parse_encryption_key(KEY).unwrap();
    let addr = "[::1]:50051";
    let service = MyServer { decrypter };

    Server::builder()
        .add_service(HelloServiceServer::new(service))
        .serve(addr.parse().unwrap())
        .await?;

    Ok(())
}

struct MyServer {
    decrypter: ...
}

The types should be such that this is easily supported. Most DB client libraries etc. play well together with Tonic. Not having Send and Sync also makes it impossible to hold a reference across await points.

@realtimetodie
Copy link

This library well designed and perfect.

Just keep a pointer to tink_core::keyset::Manager and create a new handle for the managed keyset in every request. By doing so, the original key will remain in the keyset.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants