57个版本

0.11.1 2024年4月15日
0.11.0 2023年11月26日
0.10.4 2023年9月9日
0.10.0 2023年7月27日
0.1.0 2019年9月21日

#817 in 加密学

Download history 55/week @ 2024-04-22 13/week @ 2024-04-29 10/week @ 2024-05-06 8/week @ 2024-05-13 25/week @ 2024-05-20 11/week @ 2024-05-27 40/week @ 2024-06-03 50/week @ 2024-06-10 13/week @ 2024-06-17 30/week @ 2024-06-24 29/week @ 2024-07-01 20/week @ 2024-07-08 9/week @ 2024-07-15 1/week @ 2024-07-22 450/week @ 2024-07-29 7/week @ 2024-08-05

每月469次下载
用于 7 个crate(4 直接)

AGPL-3.0

115KB
2.5K SLoC

HTTP Signature Normalization Actix

一个将签名留给您的HTTP签名库

Http Signature Normalization是一个使用用户提供的签名和验证来生成HTTP签名的最小依赖crate。API很简单;有一系列用于创建和验证的步骤,类型确保合理使用。

使用方法

此crate为Actix Web的ClientRequest类型提供扩展,并提供用于验证HTTP签名的中间件,以及可选的Digest头。

首先,将此crate添加到您的依赖项中

actix-rt = "2.6.0"
actix-web = "4.0.0"
thiserror = "0.1"
http-signature-normalization-actix = { version = "0.8.0", default-features = false, features = ["sha-2"] }
sha2 = "0.9"

然后,在您的客户端中使用它

async fn request(config: Config) -> Result<(), Box<dyn std::error::Error>> {
    let digest = Sha256::new();

    let mut response = Client::default()
        .post("http://127.0.0.1:8010/")
        .append_header(("User-Agent", "Actix Web"))
        .append_header(("Accept", "text/plain"))
        .insert_header(actix_web::http::header::Date(SystemTime::now().into()))
        .signature_with_digest(config, "my-key-id", digest, "Hewwo-owo", |s| {
            info!("Signing String\n{}", s);
            Ok(base64::encode(s)) as Result<_, MyError>
        })
        .await?
        .send()
        .await
        .map_err(|e| {
            error!("Error, {}", e);
            MyError::SendRequest
        })?;

    let body = response.body().await.map_err(|e| {
        error!("Error, {}", e);
        MyError::Body
    })?;

    info!("{:?}", body);
    Ok(())
}

或者,在您的服务器中使用它

#[derive(Clone, Debug)]
struct MyVerify;

impl SignatureVerify for MyVerify {
    type Error = MyError;
    type Future = Ready<Result<bool, Self::Error>>;

    fn signature_verify(
        &mut self,
        algorithm: Option<Algorithm>,
        key_id: String,
        signature: String,
        signing_string: String,
    ) -> Self::Future {
        match algorithm {
            Some(Algorithm::Hs2019) => (),
            _ => return ready(Err(MyError::Algorithm)),
        };

        if key_id != "my-key-id" {
            return ready(Err(MyError::Key));
        }

        let decoded = match base64::decode(&signature) {
            Ok(decoded) => decoded,
            Err(_) => return ready(Err(MyError::Decode)),
        };

        info!("Signing String\n{}", signing_string);

        ready(Ok(decoded == signing_string.as_bytes()))
    }
}

async fn index(
    _: DigestVerified,
    sig_verified: SignatureVerified,
    req: HttpRequest,
    _body: web::Bytes,
) -> &'static str {
    info!("Verified request for {}", sig_verified.key_id());
    info!("{:?}", req);
    "Eyyyyup"
}

#[actix_rt::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let env_filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info"));

    let subscriber = tracing_subscriber::Registry::default()
        .with(env_filter)
        .with(ErrorLayer::default())
        .with(tracing_subscriber::fmt::layer());

    tracing::subscriber::set_global_default(subscriber)?;

    let config = Config::default().require_header("accept").require_digest();

    HttpServer::new(move || {
        App::new()
            .wrap(VerifyDigest::new(Sha256::new()).optional())
            .wrap(VerifySignature::new(MyVerify, config.clone()))
            .wrap(TracingLogger::default())
            .route("/", web::post().to(index))
    })
    .bind("127.0.0.1:8010")?
    .run()
    .await?;

    Ok(())
}

#[derive(Debug, thiserror::Error)]
enum MyError {
    #[error("Failed to verify, {0}")]
    Verify(#[from] PrepareVerifyError),

    #[error("Unsupported algorithm")]
    Algorithm,

    #[error("Couldn't decode signature")]
    Decode,

    #[error("Invalid key")]
    Key,
}

impl ResponseError for MyError {
    fn status_code(&self) -> StatusCode {
        StatusCode::BAD_REQUEST
    }

    fn error_response(&self) -> HttpResponse {
        HttpResponse::BadRequest().finish()
    }
}

贡献

请随意为任何您发现的问题打开问题。请注意,任何贡献的代码都将根据AGPLv3许可。

许可

版权所有 © 2022 Riley Trautman

HTTP Signature Normalization Actix是免费软件:您可以在自由软件基金会发布的GNU通用公共许可证的条款和条件下重新分发和/或修改它,许可证版本为3,或者(根据您的选择)任何较新版本。

HTTP Signature Normalization Actix的目的是希望它会有所帮助,但没有任何保证;甚至没有关于其商誉或适用于特定目的的暗示性保证。有关详细信息,请参阅GNU通用公共许可证。此文件是HTTP Signature Normalization Actix的一部分。

您应该已经收到了随HTTP Signature Normalization Actix一起提供的GNU通用公共许可证副本。如果没有,请参阅http://www.gnu.org/licenses/

依赖项

~10–24MB
~404K SLoC