From 1d0268c501c7e2c571a472b0f171f9abab38560a Mon Sep 17 00:00:00 2001
From: Awiteb
Date: Sat, 27 Jul 2024 02:09:21 +0300
Subject: [PATCH] chore: Imple openAPI traits for `PublicKey` and `Signature`
Signed-off-by: Awiteb
---
crates/oxidetalis_core/src/types/cipher.rs | 29 ----
.../oxidetalis_core/src/types/impl_openapi.rs | 162 ++++++++++++++++++
crates/oxidetalis_core/src/types/mod.rs | 2 +
3 files changed, 164 insertions(+), 29 deletions(-)
create mode 100644 crates/oxidetalis_core/src/types/impl_openapi.rs
diff --git a/crates/oxidetalis_core/src/types/cipher.rs b/crates/oxidetalis_core/src/types/cipher.rs
index 8aa8aa5..b2f50d8 100644
--- a/crates/oxidetalis_core/src/types/cipher.rs
+++ b/crates/oxidetalis_core/src/types/cipher.rs
@@ -24,15 +24,6 @@
use std::{fmt, str::FromStr};
use base58::{FromBase58, ToBase58};
-#[cfg(feature = "openapi")]
-use salvo_oapi::{
- schema::{
- Schema as OapiSchema,
- SchemaFormat as OapiSchemaFormat,
- SchemaType as OapiSchemaType,
- },
- ToSchema,
-};
use crate::cipher::{hmac_sha256, CipherError};
@@ -206,23 +197,3 @@ impl From<[u8; 56]> for Signature {
}
}
}
-
-#[cfg(feature = "openapi")]
-impl ToSchema for PublicKey {
- fn to_schema(_components: &mut salvo_oapi::Components) -> salvo_oapi::RefOr {
- salvo_oapi::Object::new()
- .schema_type(OapiSchemaType::String)
- .format(OapiSchemaFormat::Custom("base58".to_owned()))
- .into()
- }
-}
-
-#[cfg(feature = "openapi")]
-impl ToSchema for Signature {
- fn to_schema(_components: &mut salvo_oapi::Components) -> salvo_oapi::RefOr {
- salvo_oapi::Object::new()
- .schema_type(OapiSchemaType::String)
- .format(OapiSchemaFormat::Custom("hex".to_owned()))
- .into()
- }
-}
diff --git a/crates/oxidetalis_core/src/types/impl_openapi.rs b/crates/oxidetalis_core/src/types/impl_openapi.rs
new file mode 100644
index 0000000..b22fbfe
--- /dev/null
+++ b/crates/oxidetalis_core/src/types/impl_openapi.rs
@@ -0,0 +1,162 @@
+// OxideTalis Messaging Protocol homeserver core implementation
+// Copyright (C) 2024 Awiteb , OxideTalis Contributors
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+//! OpenAPI schema for some core types.
+
+use std::str::FromStr;
+
+use salvo_core::{extract::Metadata as ExtractMetadata, http::StatusError, Extractible, Request};
+use salvo_oapi::{
+ schema::{
+ Schema as OapiSchema,
+ SchemaFormat as OapiSchemaFormat,
+ SchemaType as OapiSchemaType,
+ },
+ Components as OapiComponents,
+ EndpointArgRegister,
+ Parameter,
+ ParameterIn,
+ Parameters,
+ ToParameters,
+ ToSchema,
+};
+
+use super::{PublicKey as CorePublicKey, Signature};
+
+impl ToSchema for CorePublicKey {
+ fn to_schema(_components: &mut salvo_oapi::Components) -> salvo_oapi::RefOr {
+ salvo_oapi::Object::new()
+ .name(crate::PUBLIC_KEY_HEADER)
+ .description("User's public key")
+ .schema_type(OapiSchemaType::String)
+ .format(OapiSchemaFormat::Custom("base58".to_owned()))
+ .required(crate::PUBLIC_KEY_HEADER)
+ // A 33-byte base58 string can be either 44 or 45 characters long
+ .example("rW8FMG5D75NVNJV3Wd498dEh65BgUuhwY1Yk5zYJPpRe".into())
+ .max_length(45)
+ .min_length(44)
+ .into()
+ }
+}
+
+impl ToSchema for Signature {
+ fn to_schema(_components: &mut salvo_oapi::Components) -> salvo_oapi::RefOr {
+ salvo_oapi::Object::new()
+ .name(crate::SIGNATURE_HEADER)
+ .description("Signature of the request")
+ .schema_type(OapiSchemaType::String)
+ .format(OapiSchemaFormat::Custom("hex".to_owned()))
+ .required(crate::SIGNATURE_HEADER)
+ // 56 bytes in hex (valid signature)
+ .example("0".repeat(112).into())
+ .max_length(112)
+ .min_length(112)
+ .into()
+ }
+}
+
+impl<'ex> Extractible<'ex> for CorePublicKey {
+ fn metadata() -> &'ex ExtractMetadata {
+ static METADATA: ExtractMetadata = ExtractMetadata::new("");
+ &METADATA
+ }
+
+ #[allow(refining_impl_trait)]
+ async fn extract(req: &'ex mut Request) -> Result {
+ extract_header(req, crate::PUBLIC_KEY_HEADER).and_then(|public_key| {
+ CorePublicKey::from_str(public_key).map_err(|err| {
+ StatusError::bad_request()
+ .brief("Invalid public key")
+ .cause(err.to_string())
+ })
+ })
+ }
+
+ #[allow(refining_impl_trait)]
+ async fn extract_with_arg(req: &'ex mut Request, _: &str) -> Result {
+ Self::extract(req).await
+ }
+}
+
+impl EndpointArgRegister for CorePublicKey {
+ fn register(components: &mut OapiComponents, operation: &mut salvo_oapi::Operation, _: &str) {
+ operation.parameters.insert(
+ Parameter::new(crate::PUBLIC_KEY_HEADER)
+ .parameter_in(ParameterIn::Header)
+ .required(true)
+ .description("User's public key")
+ .example("2BiUSWkJUy5bcdJB8qszq9K6a5EXVHvK41vQWZVkUBUM8".into())
+ .schema(CorePublicKey::to_schema(components)),
+ )
+ }
+}
+
+impl<'ex> Extractible<'ex> for Signature {
+ fn metadata() -> &'ex ExtractMetadata {
+ unreachable!(
+ "
+ `Extractible` is required to implement `ToParameters` for `Signature`, but \
+ Salvo does not need it actually, see https://github.com/salvo-rs/salvo/issues/838"
+ )
+ }
+
+ #[allow(refining_impl_trait)]
+ async fn extract(_: &'ex mut Request) -> Result {
+ unreachable!(
+ "
+ `Extractible` is required to implement `ToParameters` for `Signature`, but \
+ Salvo does not need it actually, see https://github.com/salvo-rs/salvo/issues/838"
+ )
+ }
+}
+
+impl ToParameters<'_> for Signature {
+ fn to_parameters(components: &mut OapiComponents) -> Parameters {
+ Parameters::new().parameter(
+ Parameter::new(crate::SIGNATURE_HEADER)
+ .parameter_in(ParameterIn::Header)
+ .required(true)
+ .description("Signature of the request")
+ .example("0".repeat(112).into())
+ .schema(Self::to_schema(components)),
+ )
+ }
+}
+
+fn extract_header<'req>(req: &'req Request, name: &str) -> Result<&'req str, StatusError> {
+ req.headers()
+ .get(name)
+ .map(|v| {
+ v.to_str().map_err(|_| {
+ StatusError::bad_request()
+ .brief("Invalid header value")
+ .cause("Header value must be a valid ascii string")
+ })
+ })
+ .transpose()?
+ .ok_or_else(|| {
+ StatusError::bad_request()
+ .brief(format!("Could not find {name} in headers"))
+ .cause(format!(
+ "{name} is required to authenication and authorization"
+ ))
+ })
+}
diff --git a/crates/oxidetalis_core/src/types/mod.rs b/crates/oxidetalis_core/src/types/mod.rs
index 7635eb3..a2257f1 100644
--- a/crates/oxidetalis_core/src/types/mod.rs
+++ b/crates/oxidetalis_core/src/types/mod.rs
@@ -22,6 +22,8 @@
//! Oxidetalis server types
mod cipher;
+#[cfg(feature = "openapi")]
+mod impl_openapi;
#[cfg(feature = "sea-orm")]
mod impl_sea_orm;
#[cfg(feature = "serde")]