Compare commits

...

2 commits

Author SHA1 Message Date
1d1bb962bb
refactor: Update public key column type from String to PublicKey
All checks were successful
Write changelog / write-changelog (push) Successful in 4s
Update Contributors / Update Contributors (push) Successful in 5s
Rust CI / Rust CI (push) Successful in 4m29s
Reviewed-on: #29
Reviewed-by: Amjad Alsharafi <me@amjad.alsharafi.dev>
Helped-by: Amjad Alsharafi <me@amjad.alsharafi.dev>
Signed-off-by: Awiteb <a@4rs.nl>
2024-07-24 01:19:34 +03:00
a01f4add0c
refactor: Change config private key type to K256Secret
Reviewed-on: #30
Reviewed-by: Amjad Alsharafi <me@amjad.alsharafi.dev>
Signed-off-by: Awiteb <a@4rs.nl>
2024-07-24 01:17:13 +03:00
26 changed files with 155 additions and 66 deletions

2
Cargo.lock generated
View file

@ -1954,6 +1954,7 @@ dependencies = [
"k256", "k256",
"rand", "rand",
"salvo-oapi", "salvo-oapi",
"sea-orm",
"serde", "serde",
"sha2", "sha2",
"thiserror", "thiserror",
@ -1964,6 +1965,7 @@ name = "oxidetalis_entities"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"chrono", "chrono",
"oxidetalis_core",
"sea-orm", "sea-orm",
] ]

View file

@ -42,7 +42,7 @@ impl InChatRequestsExt for DatabaseConnection {
) -> ServerResult<()> { ) -> ServerResult<()> {
InChatRequestsEntity::insert(InChatRequestsActiveModel { InChatRequestsEntity::insert(InChatRequestsActiveModel {
recipient_id: Set(recipient.id), recipient_id: Set(recipient.id),
sender: Set(sender.to_string()), sender: Set(*sender),
in_on: Set(Utc::now()), in_on: Set(Utc::now()),
..Default::default() ..Default::default()
}) })

View file

@ -57,7 +57,7 @@ impl OutChatRequestsExt for DatabaseConnection {
) -> ServerResult<Option<OutChatRequestsModel>> { ) -> ServerResult<Option<OutChatRequestsModel>> {
requester requester
.find_related(OutChatRequestsEntity) .find_related(OutChatRequestsEntity)
.filter(OutChatRequestsColumn::Recipient.eq(recipient.to_string())) .filter(OutChatRequestsColumn::Recipient.eq(recipient))
.one(self) .one(self)
.await .await
.map_err(Into::into) .map_err(Into::into)
@ -71,7 +71,7 @@ impl OutChatRequestsExt for DatabaseConnection {
) -> ServerResult<()> { ) -> ServerResult<()> {
if let Err(err) = (OutChatRequestsActiveModel { if let Err(err) = (OutChatRequestsActiveModel {
sender_id: Set(requester.id), sender_id: Set(requester.id),
recipient: Set(recipient.to_string()), recipient: Set(*recipient),
out_on: Set(Utc::now()), out_on: Set(Utc::now()),
..Default::default() ..Default::default()
} }

View file

@ -45,7 +45,7 @@ impl UserTableExt for DatabaseConnection {
#[logcall] #[logcall]
async fn register_user(&self, public_key: &PublicKey, is_admin: bool) -> ServerResult<()> { async fn register_user(&self, public_key: &PublicKey, is_admin: bool) -> ServerResult<()> {
if let Err(err) = (UserActiveModel { if let Err(err) = (UserActiveModel {
public_key: Set(public_key.to_string()), public_key: Set(*public_key),
is_admin: Set(is_admin), is_admin: Set(is_admin),
..Default::default() ..Default::default()
}) })
@ -63,7 +63,7 @@ impl UserTableExt for DatabaseConnection {
#[logcall] #[logcall]
async fn get_user_by_pubk(&self, public_key: &PublicKey) -> ServerResult<Option<UserModel>> { async fn get_user_by_pubk(&self, public_key: &PublicKey) -> ServerResult<Option<UserModel>> {
UserEntity::find() UserEntity::find()
.filter(UserColumn::PublicKey.eq(public_key.to_string())) .filter(UserColumn::PublicKey.eq(public_key))
.one(self) .one(self)
.await .await
.map_err(Into::into) .map_err(Into::into)

View file

@ -138,7 +138,7 @@ impl UsersStatusExt for DatabaseConnection {
whitelister: &UserModel, whitelister: &UserModel,
target_public_key: &PublicKey, target_public_key: &PublicKey,
) -> ServerResult<()> { ) -> ServerResult<()> {
if whitelister.public_key == target_public_key.to_string() { if &whitelister.public_key == target_public_key {
return Err(WsError::CannotAddSelfToWhitelist.into()); return Err(WsError::CannotAddSelfToWhitelist.into());
} }
@ -156,7 +156,7 @@ impl UsersStatusExt for DatabaseConnection {
user.update(self).await?; user.update(self).await?;
} else if let Err(err) = (UsersStatusActiveModel { } else if let Err(err) = (UsersStatusActiveModel {
user_id: Set(whitelister.id), user_id: Set(whitelister.id),
target: Set(target_public_key.to_string()), target: Set(*target_public_key),
status: Set(AccessStatus::Whitelisted), status: Set(AccessStatus::Whitelisted),
updated_at: Set(Utc::now()), updated_at: Set(Utc::now()),
..Default::default() ..Default::default()
@ -181,7 +181,7 @@ impl UsersStatusExt for DatabaseConnection {
blacklister: &UserModel, blacklister: &UserModel,
target_public_key: &PublicKey, target_public_key: &PublicKey,
) -> ServerResult<()> { ) -> ServerResult<()> {
if blacklister.public_key == target_public_key.to_string() { if &blacklister.public_key == target_public_key {
return Err(WsError::CannotAddSelfToBlacklist.into()); return Err(WsError::CannotAddSelfToBlacklist.into());
} }
@ -199,7 +199,7 @@ impl UsersStatusExt for DatabaseConnection {
user.update(self).await?; user.update(self).await?;
} else if let Err(err) = (UsersStatusActiveModel { } else if let Err(err) = (UsersStatusActiveModel {
user_id: Set(blacklister.id), user_id: Set(blacklister.id),
target: Set(target_public_key.to_string()), target: Set(*target_public_key),
status: Set(AccessStatus::Blacklisted), status: Set(AccessStatus::Blacklisted),
updated_at: Set(Utc::now()), updated_at: Set(Utc::now()),
..Default::default() ..Default::default()
@ -297,7 +297,7 @@ async fn get_user_status(
user.find_related(UsersStatusEntity) user.find_related(UsersStatusEntity)
.filter( .filter(
UsersStatusColumn::Target UsersStatusColumn::Target
.eq(target_public_key.to_string()) .eq(target_public_key)
.and(UsersStatusColumn::Status.eq(status)), .and(UsersStatusColumn::Status.eq(status)),
) )
.one(conn) .one(conn)

View file

@ -71,11 +71,10 @@ pub async fn signature_check(
}; };
if !utils::is_valid_nonce(&signature, &depot.nonce_cache()).await if !utils::is_valid_nonce(&signature, &depot.nonce_cache()).await
|| !utils::is_valid_signature( || !depot.config().server.private_key.verify(
&sender_public_key,
&depot.config().server.private_key,
&signature,
data.as_bytes(), data.as_bytes(),
&signature,
&sender_public_key,
) )
{ {
write_err("Invalid signature", UNAUTHORIZED); write_err("Invalid signature", UNAUTHORIZED);

View file

@ -54,7 +54,7 @@ impl Default for WhiteListedUser {
impl From<UsersStatusModel> for WhiteListedUser { impl From<UsersStatusModel> for WhiteListedUser {
fn from(user: UsersStatusModel) -> Self { fn from(user: UsersStatusModel) -> Self {
Self { Self {
public_key: PublicKey::from_str(&user.target).expect("Is valid public key"), public_key: user.target,
whitelisted_at: user.updated_at, whitelisted_at: user.updated_at,
} }
} }
@ -72,7 +72,7 @@ impl Default for BlackListedUser {
impl From<UsersStatusModel> for BlackListedUser { impl From<UsersStatusModel> for BlackListedUser {
fn from(user: UsersStatusModel) -> Self { fn from(user: UsersStatusModel) -> Self {
Self { Self {
public_key: PublicKey::from_str(&user.target).expect("Is valid public key"), public_key: user.target,
blacklisted_at: user.updated_at, blacklisted_at: user.updated_at,
} }
} }

View file

@ -22,8 +22,7 @@ use chrono::Utc;
use logcall::logcall; use logcall::logcall;
use oxidetalis_config::Postgres; use oxidetalis_config::Postgres;
use oxidetalis_core::{ use oxidetalis_core::{
cipher::K256Secret, types::{PublicKey, Signature},
types::{PrivateKey, PublicKey, Signature},
PUBLIC_KEY_HEADER, PUBLIC_KEY_HEADER,
SIGNATURE_HEADER, SIGNATURE_HEADER,
}; };
@ -50,16 +49,6 @@ pub(crate) async fn is_valid_nonce(signature: &Signature, nonce_cache: &NonceCac
new_timestamp && unused_nonce new_timestamp && unused_nonce
} }
/// Returns true if the given signature is valid.
pub(crate) fn is_valid_signature(
signer: &PublicKey,
private_key: &PrivateKey,
signature: &Signature,
data: &[u8],
) -> bool {
K256Secret::from_privkey(private_key).verify(data, signature, signer)
}
/// Extract the sender public key from the request /// Extract the sender public key from the request
/// ///
/// Returns the public key of the sender extracted from the request, or the /// Returns the public key of the sender extracted from the request, or the

View file

@ -16,8 +16,6 @@
//! Handler for incoming and outgoing chat requests. //! Handler for incoming and outgoing chat requests.
use std::str::FromStr;
use oxidetalis_core::types::PublicKey; use oxidetalis_core::types::PublicKey;
use oxidetalis_entities::prelude::*; use oxidetalis_entities::prelude::*;
use sea_orm::DatabaseConnection; use sea_orm::DatabaseConnection;
@ -47,14 +45,12 @@ pub async fn handle_chat_request(
if from_user.id == to_user.id { if from_user.id == to_user.id {
return Some(WsError::CannotSendChatRequestToSelf.into()); return Some(WsError::CannotSendChatRequestToSelf.into());
} }
// FIXME: When change the entity public key to a PublicKey type, change this
let from_public_key = PublicKey::from_str(&from_user.public_key).expect("Is valid public key");
if try_ws!(Some db.get_chat_request_to(from_user, to_public_key).await).is_some() { if try_ws!(Some db.get_chat_request_to(from_user, to_public_key).await).is_some() {
return Some(WsError::AlreadySendChatRequest.into()); return Some(WsError::AlreadySendChatRequest.into());
} }
if try_ws!(Some db.is_blacklisted(&to_user, &from_public_key).await) { if try_ws!(Some db.is_blacklisted(&to_user, &from_user.public_key).await) {
return Some(WsError::RecipientBlacklist.into()); return Some(WsError::RecipientBlacklist.into());
} }
@ -64,17 +60,17 @@ pub async fn handle_chat_request(
return Some(WsError::InternalServerError.into()); return Some(WsError::InternalServerError.into());
} }
if try_ws!(Some db.is_whitelisted(&to_user, &from_public_key).await) { if try_ws!(Some db.is_whitelisted(&to_user, &from_user.public_key).await) {
return Some(WsError::AlreadyInRecipientWhitelist.into()); return Some(WsError::AlreadyInRecipientWhitelist.into());
} }
try_ws!(Some db.save_out_chat_request(from_user, to_public_key).await); try_ws!(Some db.save_out_chat_request(from_user, to_public_key).await);
if let Some(conn_id) = ONLINE_USERS.is_online(to_public_key).await { if let Some(conn_id) = ONLINE_USERS.is_online(to_public_key).await {
ONLINE_USERS ONLINE_USERS
.send(&conn_id, ServerEvent::chat_request(&from_public_key)) .send(&conn_id, ServerEvent::chat_request(&from_user.public_key))
.await; .await;
} else { } else {
try_ws!(Some db.save_in_chat_request(&from_public_key, &to_user).await); try_ws!(Some db.save_in_chat_request(&from_user.public_key, &to_user).await);
} }
None None
} }
@ -96,12 +92,8 @@ pub async fn handle_chat_response(
return Some(WsError::CannotRespondToOwnChatRequest.into()); return Some(WsError::CannotRespondToOwnChatRequest.into());
} }
// FIXME: When change the entity public key to a PublicKey type, change this
let recipient_public_key =
PublicKey::from_str(&recipient_user.public_key).expect("Is valid public key");
if try_ws!(Some if try_ws!(Some
db.get_chat_request_to(&sender_user, &recipient_public_key) db.get_chat_request_to(&sender_user, &recipient_user.public_key)
.await .await
) )
.is_none() .is_none()
@ -118,7 +110,7 @@ pub async fn handle_chat_response(
}; };
try_ws!(Some try_ws!(Some
db.remove_out_chat_request(&sender_user, &recipient_public_key) db.remove_out_chat_request(&sender_user, &recipient_user.public_key)
.await .await
); );
@ -126,7 +118,7 @@ pub async fn handle_chat_response(
ONLINE_USERS ONLINE_USERS
.send( .send(
&conn_id, &conn_id,
ServerEvent::chat_request_response(recipient_public_key, accepted), ServerEvent::chat_request_response(recipient_user.public_key, accepted),
) )
.await; .await;
} else { } else {

View file

@ -23,7 +23,7 @@ use chrono::Utc;
use errors::{WsError, WsResult}; use errors::{WsError, WsResult};
use futures::{channel::mpsc, FutureExt, StreamExt, TryStreamExt}; use futures::{channel::mpsc, FutureExt, StreamExt, TryStreamExt};
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use oxidetalis_core::{cipher::K256Secret, types::PublicKey}; use oxidetalis_core::types::PublicKey;
use oxidetalis_entities::prelude::*; use oxidetalis_entities::prelude::*;
use salvo::{ use salvo::{
handler, handler,
@ -102,9 +102,7 @@ pub async fn user_connected(
let db_conn = depot.db_conn(); let db_conn = depot.db_conn();
let public_key = let public_key =
utils::extract_public_key(req).expect("The public key was checked in the middleware"); utils::extract_public_key(req).expect("The public key was checked in the middleware");
// FIXME: The config should hold `K256Secret` not `PrivateKey` let shared_secret = depot.config().server.private_key.shared_secret(&public_key);
let shared_secret =
K256Secret::from_privkey(&depot.config().server.private_key).shared_secret(&public_key);
WebSocketUpgrade::new() WebSocketUpgrade::new()
.upgrade(req, res, move |ws| { .upgrade(req, res, move |ws| {

View file

@ -25,10 +25,7 @@
pub(crate) mod server { pub(crate) mod server {
use std::net::{IpAddr, Ipv4Addr}; use std::net::{IpAddr, Ipv4Addr};
use oxidetalis_core::{ use oxidetalis_core::{cipher::K256Secret, types::Size};
cipher::K256Secret,
types::{PrivateKey, Size},
};
pub fn name() -> String { pub fn name() -> String {
"example.com".to_owned() "example.com".to_owned()
@ -39,8 +36,8 @@ pub(crate) mod server {
pub const fn port() -> u16 { pub const fn port() -> u16 {
7294 7294
} }
pub fn private_key() -> PrivateKey { pub fn private_key() -> K256Secret {
K256Secret::new().privkey() K256Secret::new()
} }
pub const fn nonce_cache_size() -> Size { pub const fn nonce_cache_size() -> Size {
Size::MB(1) Size::MB(1)

View file

@ -23,7 +23,7 @@
use std::{fs, io::Error as IoError, net::IpAddr, path::Path}; use std::{fs, io::Error as IoError, net::IpAddr, path::Path};
use derivative::Derivative; use derivative::Derivative;
use oxidetalis_core::types::{PrivateKey, Size}; use oxidetalis_core::{cipher::K256Secret, types::Size};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use toml::{de::Error as TomlDeError, ser::Error as TomlSerError}; use toml::{de::Error as TomlDeError, ser::Error as TomlSerError};
@ -66,7 +66,7 @@ pub struct Server {
pub port: u16, pub port: u16,
/// Server keypair /// Server keypair
#[derivative(Default(value = "defaults::server::private_key()"))] #[derivative(Default(value = "defaults::server::private_key()"))]
pub private_key: PrivateKey, pub private_key: K256Secret,
/// Nonce cache limit /// Nonce cache limit
#[derivative(Default(value = "defaults::server::nonce_cache_size()"))] #[derivative(Default(value = "defaults::server::nonce_cache_size()"))]
pub nonce_cache_size: Size, pub nonce_cache_size: Size,

View file

@ -15,6 +15,7 @@ base58 = { workspace = true }
thiserror = { workspace = true } thiserror = { workspace = true }
salvo-oapi = { workspace = true, optional = true } salvo-oapi = { workspace = true, optional = true }
serde = { workspace = true, optional = true } serde = { workspace = true, optional = true }
sea-orm = { workspace = true, optional = true }
cbc = { version = "0.1.2", features = ["alloc", "std"] } cbc = { version = "0.1.2", features = ["alloc", "std"] }
k256 = { version = "0.13.3", default-features = false, features = ["ecdh"] } k256 = { version = "0.13.3", default-features = false, features = ["ecdh"] }
rand = { version = "0.8.5", default-features = false, features = ["std_rng", "std"] } rand = { version = "0.8.5", default-features = false, features = ["std_rng", "std"] }
@ -26,6 +27,7 @@ sha2 = "0.10.8"
[features] [features]
openapi = ["dep:salvo-oapi"] openapi = ["dep:salvo-oapi"]
serde = ["dep:serde"] serde = ["dep:serde"]
sea-orm = ["dep:sea-orm"]
[lints.rust] [lints.rust]

View file

@ -72,6 +72,7 @@ type HmacSha256 = hmac::Hmac<sha2::Sha256>;
/// An wrapper around the k256 crate to provide a simple API for ecdh key /// An wrapper around the k256 crate to provide a simple API for ecdh key
/// exchange and keypair generation. /// exchange and keypair generation.
#[derive(Clone)]
pub struct K256Secret { pub struct K256Secret {
/// The private key scalar /// The private key scalar
scalar: NonZeroScalar, scalar: NonZeroScalar,

View file

@ -0,0 +1,84 @@
// OxideTalis Messaging Protocol homeserver core implementation
// Copyright (C) 2024 Awiteb <a@4rs.nl>, 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.
//! Implemented SeaORM support for core types, enabling the use of these types
//! as column types in SeaORM
use sea_orm::{
sea_query::{ArrayType, BlobSize, ValueType, ValueTypeErr},
ColumnType,
DbErr,
QueryResult,
TryGetError,
TryGetable,
Value,
};
use super::PublicKey;
impl From<PublicKey> for Value {
fn from(public_key: PublicKey) -> Self {
public_key.as_bytes().as_slice().into()
}
}
impl From<&PublicKey> for Value {
fn from(public_key: &PublicKey) -> Self {
public_key.as_bytes().as_slice().into()
}
}
impl TryGetable for PublicKey {
fn try_get_by<I: sea_orm::ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
let db_err = |err: &str| TryGetError::DbErr(DbErr::Type(err.to_owned()));
<Vec<u8> as TryGetable>::try_get_by(res, idx).and_then(|v| {
v.try_into()
.map_err(|_| db_err("Invalid binary length"))
.and_then(|bytes| {
<PublicKey as TryFrom<[u8; 33]>>::try_from(bytes)
.map_err(|_| db_err("Invalid Public Key"))
})
})
}
}
impl ValueType for PublicKey {
fn try_from(v: Value) -> Result<Self, ValueTypeErr> {
<Vec<u8> as ValueType>::try_from(v).and_then(|v| {
v.try_into().map_err(|_| ValueTypeErr).and_then(|bytes| {
<PublicKey as TryFrom<[u8; 33]>>::try_from(bytes).map_err(|_| ValueTypeErr)
})
})
}
fn type_name() -> String {
String::from("PublicKey")
}
fn array_type() -> ArrayType {
ArrayType::Bytes
}
fn column_type() -> ColumnType {
ColumnType::Binary(BlobSize::Blob(None))
}
}

View file

@ -25,6 +25,7 @@ use base58::FromBase58;
use serde::{de::Error as DeError, Deserialize, Serialize}; use serde::{de::Error as DeError, Deserialize, Serialize};
use super::{PrivateKey, PublicKey, Signature}; use super::{PrivateKey, PublicKey, Signature};
use crate::cipher::K256Secret;
impl<'de> Deserialize<'de> for PrivateKey { impl<'de> Deserialize<'de> for PrivateKey {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
@ -99,3 +100,21 @@ impl Serialize for Signature {
serializer.serialize_str(self.to_string().as_str()) serializer.serialize_str(self.to_string().as_str())
} }
} }
impl Serialize for K256Secret {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
PrivateKey::serialize(&self.privkey(), serializer)
}
}
impl<'de> Deserialize<'de> for K256Secret {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
Ok(Self::from_privkey(&PrivateKey::deserialize(deserializer)?))
}
}

View file

@ -22,6 +22,8 @@
//! Oxidetalis server types //! Oxidetalis server types
mod cipher; mod cipher;
#[cfg(feature = "sea-orm")]
mod impl_sea_orm;
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
mod impl_serde; mod impl_serde;
mod size; mod size;

View file

@ -11,8 +11,9 @@ rust-version.workspace = true
[dependencies] [dependencies]
sea-orm = { workspace = true } oxidetalis_core = { workspace = true, features = ["sea-orm"] }
chrono = { workspace = true } sea-orm = { workspace = true }
chrono = { workspace = true }
[lints.rust] [lints.rust]
unsafe_code = "deny" unsafe_code = "deny"

View file

@ -22,6 +22,7 @@
//! Entity for `in_chat_requests` table //! Entity for `in_chat_requests` table
use chrono::Utc; use chrono::Utc;
use oxidetalis_core::types::PublicKey;
use sea_orm::entity::prelude::*; use sea_orm::entity::prelude::*;
use crate::prelude::*; use crate::prelude::*;
@ -33,7 +34,7 @@ pub struct Model {
pub id: UserId, pub id: UserId,
pub recipient_id: UserId, pub recipient_id: UserId,
/// Public key of the sender /// Public key of the sender
pub sender: String, pub sender: PublicKey,
/// The timestamp of the request, when it was received /// The timestamp of the request, when it was received
pub in_on: chrono::DateTime<Utc>, pub in_on: chrono::DateTime<Utc>,
} }

View file

@ -22,6 +22,7 @@
//! Entity for `out_chat_requests` table //! Entity for `out_chat_requests` table
use chrono::Utc; use chrono::Utc;
use oxidetalis_core::types::PublicKey;
use sea_orm::entity::prelude::*; use sea_orm::entity::prelude::*;
use crate::prelude::*; use crate::prelude::*;
@ -33,7 +34,7 @@ pub struct Model {
pub id: UserId, pub id: UserId,
pub sender_id: UserId, pub sender_id: UserId,
/// Public key of the recipient /// Public key of the recipient
pub recipient: String, pub recipient: PublicKey,
/// The timestamp of the request, when it was sent /// The timestamp of the request, when it was sent
pub out_on: chrono::DateTime<Utc>, pub out_on: chrono::DateTime<Utc>,
} }

View file

@ -21,6 +21,7 @@
//! Entity for `users` table //! Entity for `users` table
use oxidetalis_core::types::PublicKey;
use sea_orm::entity::prelude::*; use sea_orm::entity::prelude::*;
use crate::prelude::*; use crate::prelude::*;
@ -30,7 +31,7 @@ use crate::prelude::*;
pub struct Model { pub struct Model {
#[sea_orm(primary_key)] #[sea_orm(primary_key)]
pub id: UserId, pub id: UserId,
pub public_key: String, pub public_key: PublicKey,
pub is_admin: bool, pub is_admin: bool,
} }

View file

@ -22,6 +22,7 @@
//! Entity for `users_status` table //! Entity for `users_status` table
use chrono::Utc; use chrono::Utc;
use oxidetalis_core::types::PublicKey;
use sea_orm::entity::prelude::*; use sea_orm::entity::prelude::*;
use crate::prelude::*; use crate::prelude::*;
@ -41,8 +42,7 @@ pub struct Model {
#[sea_orm(primary_key)] #[sea_orm(primary_key)]
pub id: UserId, pub id: UserId,
pub user_id: UserId, pub user_id: UserId,
/// Public key of the target pub target: PublicKey,
pub target: String,
pub status: AccessStatus, pub status: AccessStatus,
pub updated_at: chrono::DateTime<Utc>, pub updated_at: chrono::DateTime<Utc>,
} }

View file

@ -57,7 +57,7 @@ impl MigrationTrait for Migration {
.on_update(ForeignKeyAction::NoAction) .on_update(ForeignKeyAction::NoAction)
.on_delete(ForeignKeyAction::Cascade), .on_delete(ForeignKeyAction::Cascade),
) )
.col(ColumnDef::new(InChatRequests::Sender).string().not_null()) .col(ColumnDef::new(InChatRequests::Sender).binary().not_null())
.col( .col(
ColumnDef::new(InChatRequests::InOn) ColumnDef::new(InChatRequests::InOn)
.timestamp_with_time_zone() .timestamp_with_time_zone()

View file

@ -59,7 +59,7 @@ impl MigrationTrait for Migration {
) )
.col( .col(
ColumnDef::new(OutChatRequests::Recipient) ColumnDef::new(OutChatRequests::Recipient)
.string() .binary()
.not_null(), .not_null(),
) )
.col( .col(

View file

@ -65,7 +65,7 @@ impl MigrationTrait for Migration {
.on_update(ForeignKeyAction::NoAction) .on_update(ForeignKeyAction::NoAction)
.on_delete(ForeignKeyAction::Cascade), .on_delete(ForeignKeyAction::Cascade),
) )
.col(ColumnDef::new(UsersStatus::Target).string().not_null()) .col(ColumnDef::new(UsersStatus::Target).binary().not_null())
.col( .col(
ColumnDef::new(UsersStatus::Status) ColumnDef::new(UsersStatus::Status)
.enumeration( .enumeration(

View file

@ -43,7 +43,7 @@ impl MigrationTrait for Migration {
) )
.col( .col(
ColumnDef::new(Users::PublicKey) ColumnDef::new(Users::PublicKey)
.string() .binary()
.not_null() .not_null()
.unique_key(), .unique_key(),
) )