From a1d92e3ad1320a80c4cb5730713380c5273401aa Mon Sep 17 00:00:00 2001 From: eason <30045503+Eason0729@users.noreply.github.com> Date: Mon, 11 Dec 2023 19:08:26 +0800 Subject: [PATCH] feat: :lock: sign pagination --- backend/Cargo.lock | 14 +++++ backend/Cargo.toml | 5 +- backend/src/controller/crypto.rs | 71 +++++++++++++++---------- backend/src/endpoint/contest.rs | 8 +-- backend/src/endpoint/education.rs | 7 ++- backend/src/endpoint/problem.rs | 18 ++++--- backend/src/endpoint/submit.rs | 14 +++-- backend/src/endpoint/testcase.rs | 14 +++-- backend/src/endpoint/user.rs | 8 +-- backend/src/endpoint/util/pagination.rs | 30 +++++------ 10 files changed, 120 insertions(+), 69 deletions(-) diff --git a/backend/Cargo.lock b/backend/Cargo.lock index cae2a721..8cc45891 100644 --- a/backend/Cargo.lock +++ b/backend/Cargo.lock @@ -899,6 +899,7 @@ dependencies = [ "digest", "elliptic-curve", "rfc6979", + "serdect", "signature", "spki", ] @@ -927,6 +928,7 @@ dependencies = [ "pkcs8", "rand_core", "sec1", + "serdect", "subtle", "zeroize", ] @@ -1641,6 +1643,7 @@ dependencies = [ "ecdsa", "elliptic-curve", "once_cell", + "serdect", "sha2", "signature", ] @@ -2937,6 +2940,7 @@ dependencies = [ "der", "generic-array", "pkcs8", + "serdect", "subtle", "zeroize", ] @@ -3004,6 +3008,16 @@ dependencies = [ "serde", ] +[[package]] +name = "serdect" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a84f14a19e9a014bb9f4512488d9829a68e04ecabffb0f9904cd1ace94598177" +dependencies = [ + "base16ct", + "serde", +] + [[package]] name = "sha1" version = "0.10.5" diff --git a/backend/Cargo.toml b/backend/Cargo.toml index 6713fa25..e1f95f56 100644 --- a/backend/Cargo.toml +++ b/backend/Cargo.toml @@ -32,7 +32,6 @@ tracing-opentelemetry = "0.22.0" rand = "0.8.5" rand_hc = "0.3.2" blake2 = "0.10.6" -k256 = "0.13.2" # a lot of opentelemetry dependencies opentelemetry = {version="0.21.0", features = ["metrics"]} opentelemetry_sdk = { version = "0.21.1", features = ["rt-tokio","metrics"] } @@ -40,6 +39,10 @@ opentelemetry-stdout = { version = "0.2.0", features = ["metrics"] } opentelemetry-semantic-conventions = "0.13.0" opentelemetry-otlp = { version = "0.14.0", features = ["metrics"] } +[dependencies.k256] +version = "0.13.2" +features = ["arithmetic","serde","sha256"] + [dependencies.tokio-stream] version = "0.1.14" features = ["sync"] diff --git a/backend/src/controller/crypto.rs b/backend/src/controller/crypto.rs index 5c11c39e..afac4f45 100644 --- a/backend/src/controller/crypto.rs +++ b/backend/src/controller/crypto.rs @@ -1,11 +1,14 @@ -use rand::SeedableRng; +use k256::ecdsa::{ + signature::{Signer, Verifier}, + Signature, SigningKey, VerifyingKey, +}; +use rand::{rngs::OsRng, SeedableRng}; use rand_hc::Hc128Rng; -use serde::{de::DeserializeOwned, Serialize}; +use serde::{de::DeserializeOwned, Deserialize, Serialize}; use spin::Mutex; use tracing::Span; -use k256::{SecretKey, Secp256k1, PublicKey}; -use crate::{init::config::GlobalConfig, report_internal}; +use crate::init::config::GlobalConfig; use blake2::{Blake2b512, Digest}; type Result = std::result::Result; @@ -16,30 +19,14 @@ pub enum Error { Bincode(#[from] bincode::Error), #[error("Invalid signature")] InvalidSignature, - #[error("Encode error")] - Encode, - #[error("Decode error")] - Decode, } impl From for tonic::Status { fn from(value: Error) -> Self { - match value { - Error::Bincode(_) => report_internal!(debug, "`{}`", value), - Error::InvalidSignature => report_internal!(trace, "`{}`", value), - Error::Encode => report_internal!(trace, "`{}`", value), - Error::Decode => tonic::Status::invalid_argument("signature is invalid"), - } + tonic::Status::invalid_argument("Invalid signature") } } -pub struct CryptoController { - salt: Vec, - rng: Mutex, - secret:SecretKey, - public:PublicKey, -} - #[derive(PartialEq, Eq)] pub struct HashValue(Vec); @@ -55,18 +42,30 @@ impl From for Vec { } } +#[derive(Serialize, Deserialize)] +struct Signed { + data: Vec, + signature: Signature, +} +pub struct CryptoController { + salt: Vec, + signing_key: SigningKey, + verifying_key: VerifyingKey, +} + impl CryptoController { #[tracing::instrument(parent=span,name="crypto_construct",level = "info",skip_all)] pub fn new(config: &GlobalConfig, span: &Span) -> Self { let salt = config.database.salt.as_bytes().to_vec(); - let mut rng = Hc128Rng::from_entropy(); - let secret=SecretKey::random(&mut rng); - let public=secret.public_key(); + let signing_key = SigningKey::random(&mut OsRng); + + let verifying_key = signing_key.verifying_key().clone(); + Self { salt, - rng: Mutex::new(rng), - secret,public + signing_key, + verifying_key, } } #[tracing::instrument(name = "crypto_hasheq_controller", level = "debug", skip_all)] @@ -90,13 +89,27 @@ impl CryptoController { } #[tracing::instrument(level = "trace", skip_all)] pub fn encode(&self, obj: M) -> Result> { - let mut raw = bincode::serialize(&obj)?; + let raw = bincode::serialize(&obj)?; - todo!() + let signature: Signature = self.signing_key.sign(&raw); + + let signed = Signed { + data: raw, + signature, + }; + Ok(bincode::serialize(&signed)?) } #[tracing::instrument(level = "trace", skip_all)] pub fn decode(&self, raw: Vec) -> Result { - todo!() + let raw: Signed = bincode::deserialize(&raw)?; + let signature = raw.signature; + + self.verifying_key + .verify(&raw.data, &signature) + .map_err(|_| Error::InvalidSignature)?; + + let obj = bincode::deserialize(&raw.data)?; + Ok(obj) } } diff --git a/backend/src/endpoint/contest.rs b/backend/src/endpoint/contest.rs index 4b381503..36553bd4 100644 --- a/backend/src/endpoint/contest.rs +++ b/backend/src/endpoint/contest.rs @@ -106,7 +106,7 @@ impl ContestSet for Arc { } list_request::Request::Pager(old) => { reverse = old.reverse; - as NoParentPager>::from_raw(old.session)? + as NoParentPager>::from_raw(old.session, &self)? } }; @@ -117,7 +117,7 @@ impl ContestSet for Arc { .map(|x| x.into()) .collect(); - let next_session = pager.into_raw(); + let next_session = pager.into_raw(&self); Ok(Response::new(ListContestResponse { list, next_session })) } @@ -133,7 +133,7 @@ impl ContestSet for Arc { text_search_request::Request::Text(create) => Pager::text_search(create), text_search_request::Request::Pager(old) => { reverse = old.reverse; - as NoParentPager>::from_raw(old.session)? + as NoParentPager>::from_raw(old.session, &self)? } }; @@ -144,7 +144,7 @@ impl ContestSet for Arc { .map(|x| x.into()) .collect(); - let next_session = pager.into_raw(); + let next_session = pager.into_raw(&self); Ok(Response::new(ListContestResponse { list, next_session })) } diff --git a/backend/src/endpoint/education.rs b/backend/src/endpoint/education.rs index ea370375..1f95a5ed 100644 --- a/backend/src/endpoint/education.rs +++ b/backend/src/endpoint/education.rs @@ -234,7 +234,10 @@ impl EducationSet for Arc { } list_by_request::Request::Pager(old) => { reverse = old.reverse; - as HasParentPager>::from_raw(old.session)? + as HasParentPager>::from_raw( + old.session, + &self, + )? } }; @@ -245,7 +248,7 @@ impl EducationSet for Arc { .map(|x| x.into()) .collect(); - let next_session = pager.into_raw(); + let next_session = pager.into_raw(&self); Ok(Response::new(ListEducationResponse { list, next_session })) } diff --git a/backend/src/endpoint/problem.rs b/backend/src/endpoint/problem.rs index 7d2b9dce..2cc716eb 100644 --- a/backend/src/endpoint/problem.rs +++ b/backend/src/endpoint/problem.rs @@ -112,7 +112,10 @@ impl ProblemSet for Arc { } list_request::Request::Pager(old) => { reverse = old.reverse; - as HasParentPager>::from_raw(old.session)? + as HasParentPager>::from_raw( + old.session, + &self, + )? } }; @@ -123,7 +126,7 @@ impl ProblemSet for Arc { .map(|x| x.into()) .collect(); - let next_session = pager.into_raw(); + let next_session = pager.into_raw(&self); Ok(Response::new(ListProblemResponse { list, next_session })) } @@ -142,7 +145,7 @@ impl ProblemSet for Arc { } text_search_request::Request::Pager(old) => { reverse = old.reverse; - as HasParentPager>::from_raw(old.session)? + as HasParentPager>::from_raw(old.session, &self)? } }; @@ -153,7 +156,7 @@ impl ProblemSet for Arc { .map(|x| x.into()) .collect(); - let next_session = pager.into_raw(); + let next_session = pager.into_raw(&self); Ok(Response::new(ListProblemResponse { list, next_session })) } @@ -409,7 +412,10 @@ impl ProblemSet for Arc { } list_by_request::Request::Pager(old) => { reverse = old.reverse; - as HasParentPager>::from_raw(old.session)? + as HasParentPager>::from_raw( + old.session, + &self, + )? } }; @@ -420,7 +426,7 @@ impl ProblemSet for Arc { .map(|x| x.into()) .collect(); - let next_session = pager.into_raw(); + let next_session = pager.into_raw(&self); Ok(Response::new(ListProblemResponse { list, next_session })) } diff --git a/backend/src/endpoint/submit.rs b/backend/src/endpoint/submit.rs index c57fb15a..2285c6ed 100644 --- a/backend/src/endpoint/submit.rs +++ b/backend/src/endpoint/submit.rs @@ -75,7 +75,10 @@ impl SubmitSet for Arc { } list_request::Request::Pager(old) => { reverse = old.reverse; - as HasParentPager>::from_raw(old.session)? + as HasParentPager>::from_raw( + old.session, + &self, + )? } }; @@ -86,7 +89,7 @@ impl SubmitSet for Arc { .map(|x| x.into()) .collect(); - let next_session = pager.into_raw(); + let next_session = pager.into_raw(&self); Ok(Response::new(ListSubmitResponse { list, next_session })) } @@ -106,7 +109,10 @@ impl SubmitSet for Arc { } list_by_request::Request::Pager(old) => { reverse = old.reverse; - as HasParentPager>::from_raw(old.session)? + as HasParentPager>::from_raw( + old.session, + &self, + )? } }; @@ -117,7 +123,7 @@ impl SubmitSet for Arc { .map(|x| x.into()) .collect(); - let next_session = pager.into_raw(); + let next_session = pager.into_raw(&self); Ok(Response::new(ListSubmitResponse { list, next_session })) } diff --git a/backend/src/endpoint/testcase.rs b/backend/src/endpoint/testcase.rs index 73a22f79..ebf59966 100644 --- a/backend/src/endpoint/testcase.rs +++ b/backend/src/endpoint/testcase.rs @@ -95,7 +95,10 @@ impl TestcaseSet for Arc { } list_request::Request::Pager(old) => { reverse = old.reverse; - as HasParentPager>::from_raw(old.session)? + as HasParentPager>::from_raw( + old.session, + &self, + )? } }; @@ -106,7 +109,7 @@ impl TestcaseSet for Arc { .map(|x| x.into()) .collect(); - let next_session = pager.into_raw(); + let next_session = pager.into_raw(&self); Ok(Response::new(ListTestcaseResponse { list, next_session })) } @@ -293,7 +296,10 @@ impl TestcaseSet for Arc { } list_by_request::Request::Pager(old) => { reverse = old.reverse; - as HasParentPager>::from_raw(old.session)? + as HasParentPager>::from_raw( + old.session, + &self, + )? } }; @@ -304,7 +310,7 @@ impl TestcaseSet for Arc { .map(|x| x.into()) .collect(); - let next_session = pager.into_raw(); + let next_session = pager.into_raw(&self); Ok(Response::new(ListTestcaseResponse { list, next_session })) } diff --git a/backend/src/endpoint/user.rs b/backend/src/endpoint/user.rs index d9201ea2..6bcd2088 100644 --- a/backend/src/endpoint/user.rs +++ b/backend/src/endpoint/user.rs @@ -105,7 +105,7 @@ impl UserSet for Arc { } list_request::Request::Pager(old) => { reverse = old.reverse; - as NoParentPager>::from_raw(old.session)? + as NoParentPager>::from_raw(old.session, &self)? } }; @@ -116,7 +116,7 @@ impl UserSet for Arc { .map(|x| x.into()) .collect(); - let next_session = pager.into_raw(); + let next_session = pager.into_raw(&self); Ok(Response::new(ListUserResponse { list, next_session })) } @@ -132,7 +132,7 @@ impl UserSet for Arc { text_search_request::Request::Text(create) => Pager::text_search(create), text_search_request::Request::Pager(old) => { reverse = old.reverse; - as NoParentPager>::from_raw(old.session)? + as NoParentPager>::from_raw(old.session, &self)? } }; @@ -143,7 +143,7 @@ impl UserSet for Arc { .map(|x| x.into()) .collect(); - let next_session = pager.into_raw(); + let next_session = pager.into_raw(&self); Ok(Response::new(ListUserResponse { list, next_session })) } diff --git a/backend/src/endpoint/util/pagination.rs b/backend/src/endpoint/util/pagination.rs index fd3ac249..0e47a509 100644 --- a/backend/src/endpoint/util/pagination.rs +++ b/backend/src/endpoint/util/pagination.rs @@ -5,7 +5,7 @@ use sea_orm::*; use serde::{Deserialize, Serialize}; use tracing::instrument; -use crate::{grpc::backend::SortBy, init::db::DB}; +use crate::{grpc::backend::SortBy, init::db::DB, server::Server}; use super::{auth::Auth, error::Error, filter::Filter}; @@ -83,8 +83,8 @@ where E: EntityTrait + PagerTrait>, { fn parent_search(ppk: i32) -> Self; - fn from_raw(s: String) -> Result, Error>; - fn into_raw(self) -> String; + fn from_raw(s: String, server: &Server) -> Result, Error>; + fn into_raw(self, server: &Server) -> String; async fn fetch( &mut self, limit: u64, @@ -99,8 +99,8 @@ pub trait NoParentPager where E: EntityTrait + PagerTrait, { - fn from_raw(s: String) -> Result, Error>; - fn into_raw(self) -> String; + fn from_raw(s: String, server: &Server) -> Result, Error>; + fn into_raw(self, server: &Server) -> String; async fn fetch( &mut self, limit: u64, @@ -125,8 +125,8 @@ where _entity: PhantomData, } } - #[instrument(name = "pagination_deserialize", level = "trace")] - fn into_raw(self) -> String { + #[instrument(name = "pagination_deserialize", level = "trace", skip(server))] + fn into_raw(self, server: &Server) -> String { let raw = RawPager { type_number: E::TYPE_NUMBER, ppk: self.ppk.unwrap_or(0), @@ -138,7 +138,7 @@ where SearchDep::Parent(x) => RawSearchDep::Parent(x), }, }; - let byte = bincode::serialize(&raw); + let byte = server.crypto.encode(&raw); base64::Engine::encode( &base64::engine::general_purpose::STANDARD_NO_PAD, @@ -146,13 +146,13 @@ where ) } #[instrument(skip_all, name = "pagination_deserialize", level = "trace")] - fn from_raw(s: String) -> Result, Error> { + fn from_raw(s: String, server: &Server) -> Result, Error> { let byte = base64::Engine::decode(&base64::engine::general_purpose::STANDARD_NO_PAD, s) .map_err(|e| { tracing::trace!(err=?e,"base64_deserialize"); Error::PaginationError("Not base64") })?; - let pager = bincode::deserialize::(&byte).map_err(|e| { + let pager = server.crypto.decode::(byte).map_err(|e| { tracing::debug!(err=?e,"bincode_deserialize"); Error::PaginationError("Malformated pager") })?; @@ -262,8 +262,8 @@ impl NoParentPager for Pager where E: PagerTrait, { - #[instrument(name = "pagination_deserialize", level = "trace")] - fn into_raw(self) -> String { + #[instrument(name = "pagination_deserialize", level = "trace", skip(server))] + fn into_raw(self, server: &Server) -> String { let raw = RawPager { type_number: E::TYPE_NUMBER, ppk: self.ppk.unwrap_or(0), @@ -275,7 +275,7 @@ where SearchDep::Parent(x) => RawSearchDep::Parent(x), }, }; - let byte = bincode::serialize(&raw); + let byte = server.crypto.encode(&raw); base64::Engine::encode( &base64::engine::general_purpose::STANDARD_NO_PAD, @@ -283,13 +283,13 @@ where ) } #[instrument(skip_all, name = "pagination_deserialize", level = "trace")] - fn from_raw(s: String) -> Result, Error> { + fn from_raw(s: String, server: &Server) -> Result, Error> { let byte = base64::Engine::decode(&base64::engine::general_purpose::STANDARD_NO_PAD, s) .map_err(|e| { tracing::trace!(err=?e,"base64_deserialize"); Error::PaginationError("Not base64") })?; - let pager = bincode::deserialize::(&byte).map_err(|e| { + let pager = server.crypto.decode::(byte).map_err(|e| { tracing::debug!(err=?e,"bincode_deserialize"); Error::PaginationError("Malformated pager") })?;