feat: added capes table and fetch upon registration

Co-authored-by: zaaarf <zaaarf@proton.me>
This commit is contained in:
dev@ftbsc 2023-01-23 01:33:22 +01:00
parent 98446959bc
commit a090e6f1aa
8 changed files with 212 additions and 5 deletions

View file

@ -1,12 +1,16 @@
pub use sea_orm_migration::prelude::*;
mod m20220101_000001_create_table;
mod m20230123_000947_skin_table;
pub struct Migrator;
#[async_trait::async_trait]
impl MigratorTrait for Migrator {
fn migrations() -> Vec<Box<dyn MigrationTrait>> {
vec![Box::new(m20220101_000001_create_table::Migration)]
vec![
Box::new(m20220101_000001_create_table::Migration),
Box::new(m20230123_000947_skin_table::Migration),
]
}
}

View file

@ -0,0 +1,61 @@
use sea_orm_migration::prelude::*;
#[derive(DeriveMigrationName)]
pub struct Migration;
#[async_trait::async_trait]
impl MigrationTrait for Migration {
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager
.create_table(
Table::create()
.table(Property::Table)
.if_not_exists()
.col(
ColumnDef::new(Property::Id)
.integer()
.not_null()
.auto_increment()
.primary_key(),
)
.col(ColumnDef::new(Property::UserId).integer().not_null()) // TODO
.foreign_key(
ForeignKey::create()
.name("fk-property-user")
.from(Property::Table, Property::UserId)
.to(User::Table, User::Id)
)
.col(ColumnDef::new(Property::Name).string().not_null())
.col(ColumnDef::new(Property::Value).string().not_null())
.col(ColumnDef::new(Property::Signature).string().null())
.to_owned(),
)
.await?;
Ok(())
}
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager
.drop_table(Table::drop().table(Property::Table).to_owned())
.await?;
Ok(())
}
}
#[derive(Iden)]
enum User {
Table,
Id,
}
#[derive(Iden)]
enum Property {
Table,
Id,
UserId,
Name,
Value,
Signature,
}

View file

@ -2,5 +2,6 @@
pub mod prelude;
pub mod property;
pub mod token;
pub mod user;

View file

@ -1,4 +1,5 @@
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.10.7
pub use super::property::Entity as Property;
pub use super::token::Entity as Token;
pub use super::user::Entity as User;

34
src/entities/property.rs Normal file
View file

@ -0,0 +1,34 @@
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.10.7
use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[sea_orm(table_name = "property")]
pub struct Model {
#[sea_orm(primary_key)]
pub id: i32,
pub user_id: i32,
pub name: String,
pub value: String,
pub signature: Option<String>,
}
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {
#[sea_orm(
belongs_to = "super::user::Entity",
from = "Column::UserId",
to = "super::user::Column::Id",
on_update = "NoAction",
on_delete = "NoAction"
)]
User,
}
impl Related<super::user::Entity> for Entity {
fn to() -> RelationDef {
Relation::User.def()
}
}
impl ActiveModelBehavior for ActiveModel {}

View file

@ -17,13 +17,19 @@ pub struct Model {
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {
#[sea_orm(
belongs_to = "Entity",
belongs_to = "super::user::Entity",
from = "Column::UserId",
to = "Column::Id",
to = "super::user::Column::Id",
on_update = "NoAction",
on_delete = "NoAction"
)]
SelfRef,
User,
}
impl Related<super::user::Entity> for Entity {
fn to() -> RelationDef {
Relation::User.def()
}
}
impl ActiveModelBehavior for ActiveModel {}

View file

@ -13,6 +13,23 @@ pub struct Model {
}
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {}
pub enum Relation {
#[sea_orm(has_many = "super::property::Entity")]
Property,
#[sea_orm(has_many = "super::token::Entity")]
Token,
}
impl Related<super::property::Entity> for Entity {
fn to() -> RelationDef {
Relation::Property.def()
}
}
impl Related<super::token::Entity> for Entity {
fn to() -> RelationDef {
Relation::Token.def()
}
}
impl ActiveModelBehavior for ActiveModel {}

83
src/routes/register.rs Normal file
View file

@ -0,0 +1,83 @@
use axum::{extract::State, Json};
use reqwest::StatusCode;
use sea_orm::{EntityTrait, QueryFilter, ColumnTrait, Set, ActiveValue::NotSet};
use tracing::info;
use crate::{AppState, proto::{self, Response}, entities};
//TODO: replace format! with axum's own
pub async fn register_unmigrated(State(state): State<AppState>, Json(payload): Json<proto::RegisterRequest>) -> Response<proto::RegisterResponse> {
info!(target: "REGISTER", "[UNMIGRATED] called with {:?}", payload);
let form = proto::RefreshRequest {
accessToken: payload.token.accessToken,
clientToken: payload.token.clientToken,
selectedProfile: None,
requestUser: Some(true),
};
let c = reqwest::Client::new();
let response = c.post("https://authserver.mojang.com/refresh")
.json(&form)
.send().await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, Json(proto::Error::simple(format!("mojang error : {:?}", e)))))?
.text().await.expect("invalid body on response");
info!(target:"REGISTER", "Mojang response to refresh request: {}", &response);
let doc = serde_json::from_str::<proto::RefreshResponse>(&response)
.map_err(|_| (StatusCode::UNAUTHORIZED, Json(proto::Error::simple("invalid token"))))?;
let user = doc.user.expect("user not found in response, even though we requested it!");
entities::user::Entity::insert(
entities::user::ActiveModel {
id: NotSet,
name: Set(user.username.clone()),
password: Set(payload.password),
uuid: Set(user.id),
}
).exec(&state.db).await
.map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, Json(proto::Error::simple("db error"))))?;
let u = entities::user::Entity::find().filter(
entities::user::Column::Uuid.eq(user.id)
).one(&state.db).await
.map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, Json(proto::Error::simple("db error"))))?
.ok_or((StatusCode::INTERNAL_SERVER_ERROR, Json(proto::Error::simple("failed creating user"))))?;
let response = c.get(format!("https://sessionserver.mojang.com/session/minecraft/profile/{}", user.id)) //TODO: needs trimmed uuid, is it trimmed by default?
.send().await
.map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, Json(proto::Error::simple("internal server error"))))?
.text().await.expect("invalid body on response");
info!(target:"REGISTER", "Mojang response to texture fetch: {}", &response);
let doc = serde_json::from_str::<proto::SessionUser>(&response)
.map_err(|_| (StatusCode::UNAUTHORIZED, Json(proto::Error::simple("invalid texture response"))))?;
let mut skin = proto::Property::default_skin();
for s in doc.properties.expect("missing properties field") {
if s.name == "textures" {
skin = s;
break;
}
}
entities::property::Entity::insert(
entities::property::ActiveModel {
id: NotSet,
name: Set("textures".into()),
user_id: Set(u.id),
value: Set(skin.value),
signature: Set(skin.signature),
}
).exec(&state.db).await
.map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, Json(proto::Error::simple("db error"))))?;
Ok(Json(proto::RegisterResponse {
user: proto::Profile {
name: user.username,
id: user.id,
}
}))
}