mirror of
https://github.com/LemmyNet/lemmy.git
synced 2024-11-26 22:31:20 +00:00
move claims.rs back to utils
This commit is contained in:
parent
48918f362d
commit
43b0371775
13 changed files with 170 additions and 184 deletions
3
Cargo.lock
generated
3
Cargo.lock
generated
|
@ -1628,8 +1628,6 @@ dependencies = [
|
||||||
"actix-web",
|
"actix-web",
|
||||||
"chrono",
|
"chrono",
|
||||||
"diesel",
|
"diesel",
|
||||||
"jsonwebtoken",
|
|
||||||
"lazy_static",
|
|
||||||
"lemmy_db_queries",
|
"lemmy_db_queries",
|
||||||
"lemmy_db_schema",
|
"lemmy_db_schema",
|
||||||
"lemmy_db_views",
|
"lemmy_db_views",
|
||||||
|
@ -1909,6 +1907,7 @@ dependencies = [
|
||||||
"futures",
|
"futures",
|
||||||
"http",
|
"http",
|
||||||
"itertools",
|
"itertools",
|
||||||
|
"jsonwebtoken",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"lettre",
|
"lettre",
|
||||||
"log",
|
"log",
|
||||||
|
|
|
@ -187,30 +187,22 @@ pub(crate) fn captcha_as_wav_base64(captcha: &Captcha) -> String {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use diesel::{
|
use lemmy_api_common::check_validator_time;
|
||||||
r2d2::{ConnectionManager, Pool},
|
|
||||||
PgConnection,
|
|
||||||
};
|
|
||||||
use lemmy_api_common::{check_validator_time, claims::Claims};
|
|
||||||
use lemmy_db_queries::{
|
use lemmy_db_queries::{
|
||||||
establish_unpooled_connection,
|
establish_unpooled_connection,
|
||||||
get_database_url_from_env,
|
source::{local_user::LocalUser_, secrets::Secrets_},
|
||||||
source::local_user::LocalUser_,
|
|
||||||
Crud,
|
Crud,
|
||||||
};
|
};
|
||||||
use lemmy_db_schema::source::{
|
use lemmy_db_schema::source::{
|
||||||
local_user::{LocalUser, LocalUserForm},
|
local_user::{LocalUser, LocalUserForm},
|
||||||
person::{Person, PersonForm},
|
person::{Person, PersonForm},
|
||||||
|
secrets::Secrets,
|
||||||
};
|
};
|
||||||
use lemmy_utils::settings::structs::Settings;
|
use lemmy_utils::claims::Claims;
|
||||||
|
|
||||||
#[actix_rt::test]
|
#[test]
|
||||||
async fn test_should_not_validate_user_token_after_password_change() {
|
fn test_should_not_validate_user_token_after_password_change() {
|
||||||
let conn = establish_unpooled_connection();
|
let conn = establish_unpooled_connection();
|
||||||
let db_url = get_database_url_from_env().unwrap_or_else(|_| Settings::get().get_database_url());
|
|
||||||
let pool = Pool::builder()
|
|
||||||
.build(ConnectionManager::<PgConnection>::new(&db_url))
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let new_person = PersonForm {
|
let new_person = PersonForm {
|
||||||
name: "Gerry9812".into(),
|
name: "Gerry9812".into(),
|
||||||
|
@ -227,8 +219,9 @@ mod tests {
|
||||||
|
|
||||||
let inserted_local_user = LocalUser::create(&conn, &local_user_form).unwrap();
|
let inserted_local_user = LocalUser::create(&conn, &local_user_form).unwrap();
|
||||||
|
|
||||||
let jwt = Claims::jwt(inserted_local_user.id.0, &pool).await.unwrap();
|
let jwt_secret = Secrets::read_jwt_secret(&conn).unwrap();
|
||||||
let claims = Claims::decode(&jwt, &pool).await.unwrap().claims;
|
let jwt = Claims::jwt(inserted_local_user.id.0, jwt_secret.as_ref()).unwrap();
|
||||||
|
let claims = Claims::decode(&jwt, jwt_secret.as_ref()).unwrap().claims;
|
||||||
let check = check_validator_time(&inserted_local_user.validator_time, &claims);
|
let check = check_validator_time(&inserted_local_user.validator_time, &claims);
|
||||||
assert!(check.is_ok());
|
assert!(check.is_ok());
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,6 @@ use captcha::{gen, Difficulty};
|
||||||
use chrono::Duration;
|
use chrono::Duration;
|
||||||
use lemmy_api_common::{
|
use lemmy_api_common::{
|
||||||
blocking,
|
blocking,
|
||||||
claims::Claims,
|
|
||||||
collect_moderated_communities,
|
collect_moderated_communities,
|
||||||
get_local_user_view_from_jwt,
|
get_local_user_view_from_jwt,
|
||||||
is_admin,
|
is_admin,
|
||||||
|
@ -26,6 +25,7 @@ use lemmy_db_queries::{
|
||||||
person_mention::PersonMention_,
|
person_mention::PersonMention_,
|
||||||
post::Post_,
|
post::Post_,
|
||||||
private_message::PrivateMessage_,
|
private_message::PrivateMessage_,
|
||||||
|
secrets::Secrets_,
|
||||||
},
|
},
|
||||||
Blockable,
|
Blockable,
|
||||||
Crud,
|
Crud,
|
||||||
|
@ -44,6 +44,7 @@ use lemmy_db_schema::{
|
||||||
person_mention::*,
|
person_mention::*,
|
||||||
post::Post,
|
post::Post,
|
||||||
private_message::PrivateMessage,
|
private_message::PrivateMessage,
|
||||||
|
secrets::Secrets,
|
||||||
site::*,
|
site::*,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -59,6 +60,7 @@ use lemmy_db_views_actor::{
|
||||||
person_view::PersonViewSafe,
|
person_view::PersonViewSafe,
|
||||||
};
|
};
|
||||||
use lemmy_utils::{
|
use lemmy_utils::{
|
||||||
|
claims::Claims,
|
||||||
email::send_email,
|
email::send_email,
|
||||||
location_info,
|
location_info,
|
||||||
settings::structs::Settings,
|
settings::structs::Settings,
|
||||||
|
@ -103,8 +105,9 @@ impl Perform for Login {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the jwt
|
// Return the jwt
|
||||||
|
let jwt_secret = blocking(context.pool(), move |conn| Secrets::read_jwt_secret(conn)).await??;
|
||||||
Ok(LoginResponse {
|
Ok(LoginResponse {
|
||||||
jwt: Claims::jwt(local_user_view.local_user.id.0, context.pool()).await?,
|
jwt: Claims::jwt(local_user_view.local_user.id.0, jwt_secret.as_ref())?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -268,8 +271,9 @@ impl Perform for SaveUserSettings {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Return the jwt
|
// Return the jwt
|
||||||
|
let jwt_secret = blocking(context.pool(), move |conn| Secrets::read_jwt_secret(conn)).await??;
|
||||||
Ok(LoginResponse {
|
Ok(LoginResponse {
|
||||||
jwt: Claims::jwt(updated_local_user.id.0, context.pool()).await?,
|
jwt: Claims::jwt(updated_local_user.id.0, jwt_secret.as_ref())?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -311,8 +315,9 @@ impl Perform for ChangePassword {
|
||||||
.await??;
|
.await??;
|
||||||
|
|
||||||
// Return the jwt
|
// Return the jwt
|
||||||
|
let jwt_secret = blocking(context.pool(), move |conn| Secrets::read_jwt_secret(conn)).await??;
|
||||||
Ok(LoginResponse {
|
Ok(LoginResponse {
|
||||||
jwt: Claims::jwt(updated_local_user.id.0, context.pool()).await?,
|
jwt: Claims::jwt(updated_local_user.id.0, jwt_secret.as_ref())?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -770,8 +775,9 @@ impl Perform for PasswordChange {
|
||||||
.map_err(|_| ApiError::err("couldnt_update_user"))?;
|
.map_err(|_| ApiError::err("couldnt_update_user"))?;
|
||||||
|
|
||||||
// Return the jwt
|
// Return the jwt
|
||||||
|
let jwt_secret = blocking(context.pool(), move |conn| Secrets::read_jwt_secret(conn)).await??;
|
||||||
Ok(LoginResponse {
|
Ok(LoginResponse {
|
||||||
jwt: Claims::jwt(updated_local_user.id.0, context.pool()).await?,
|
jwt: Claims::jwt(updated_local_user.id.0, jwt_secret.as_ref())?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,5 +24,3 @@ actix-web = { version = "4.0.0-beta.8", default-features = false, features = ["c
|
||||||
chrono = { version = "0.4.19", features = ["serde"] }
|
chrono = { version = "0.4.19", features = ["serde"] }
|
||||||
serde_json = { version = "1.0.66", features = ["preserve_order"] }
|
serde_json = { version = "1.0.66", features = ["preserve_order"] }
|
||||||
url = "2.2.2"
|
url = "2.2.2"
|
||||||
jsonwebtoken = "7.2.0"
|
|
||||||
lazy_static = "1.4.0"
|
|
||||||
|
|
|
@ -1,63 +0,0 @@
|
||||||
use crate::blocking;
|
|
||||||
use chrono::Utc;
|
|
||||||
use diesel::PgConnection;
|
|
||||||
use jsonwebtoken::{decode, encode, DecodingKey, EncodingKey, Header, TokenData, Validation};
|
|
||||||
use lazy_static::lazy_static;
|
|
||||||
use lemmy_db_queries::{source::secrets::Secrets_, DbPool};
|
|
||||||
use lemmy_db_schema::source::secrets::Secrets;
|
|
||||||
use lemmy_utils::{settings::structs::Settings, LemmyError};
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use std::{ops::Deref, sync::RwLock};
|
|
||||||
|
|
||||||
type Jwt = String;
|
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
|
||||||
pub struct Claims {
|
|
||||||
/// local_user_id, standard claim by RFC 7519.
|
|
||||||
pub sub: i32,
|
|
||||||
pub iss: String,
|
|
||||||
/// Time when this token was issued as UNIX-timestamp in seconds
|
|
||||||
pub iat: i64,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Claims {
|
|
||||||
pub async fn decode(jwt: &str, pool: &DbPool) -> Result<TokenData<Claims>, LemmyError> {
|
|
||||||
let v = Validation {
|
|
||||||
validate_exp: false,
|
|
||||||
..Validation::default()
|
|
||||||
};
|
|
||||||
let secret = blocking(pool, move |conn| get_jwt_secret(conn)).await??;
|
|
||||||
let key = DecodingKey::from_secret(secret.as_ref());
|
|
||||||
Ok(decode::<Claims>(jwt, &key, &v)?)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn jwt(local_user_id: i32, pool: &DbPool) -> Result<Jwt, LemmyError> {
|
|
||||||
let my_claims = Claims {
|
|
||||||
sub: local_user_id,
|
|
||||||
iss: Settings::get().hostname,
|
|
||||||
iat: Utc::now().timestamp(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let secret = blocking(pool, move |conn| get_jwt_secret(conn)).await??;
|
|
||||||
let key = EncodingKey::from_secret(secret.as_ref());
|
|
||||||
Ok(encode(&Header::default(), &my_claims, &key)?)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
lazy_static! {
|
|
||||||
static ref JWT_SECRET: RwLock<Option<String>> = RwLock::new(None);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_jwt_secret(conn: &PgConnection) -> Result<String, LemmyError> {
|
|
||||||
let jwt_option: Option<String> = JWT_SECRET.read().unwrap().deref().clone();
|
|
||||||
match jwt_option {
|
|
||||||
Some(j) => Ok(j),
|
|
||||||
None => {
|
|
||||||
let jwt = Secrets::read(conn)?;
|
|
||||||
let jwt_static = JWT_SECRET.write();
|
|
||||||
let mut jwt_static = jwt_static.unwrap();
|
|
||||||
*jwt_static = Some(jwt.clone());
|
|
||||||
Ok(jwt)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,4 +1,3 @@
|
||||||
pub mod claims;
|
|
||||||
pub mod comment;
|
pub mod comment;
|
||||||
pub mod community;
|
pub mod community;
|
||||||
pub mod person;
|
pub mod person;
|
||||||
|
@ -6,12 +5,13 @@ pub mod post;
|
||||||
pub mod site;
|
pub mod site;
|
||||||
pub mod websocket;
|
pub mod websocket;
|
||||||
|
|
||||||
use crate::{claims::Claims, site::FederatedInstances};
|
use crate::site::FederatedInstances;
|
||||||
use diesel::PgConnection;
|
use diesel::PgConnection;
|
||||||
use lemmy_db_queries::{
|
use lemmy_db_queries::{
|
||||||
source::{
|
source::{
|
||||||
community::{CommunityModerator_, Community_},
|
community::{CommunityModerator_, Community_},
|
||||||
person_block::PersonBlock_,
|
person_block::PersonBlock_,
|
||||||
|
secrets::Secrets_,
|
||||||
site::Site_,
|
site::Site_,
|
||||||
},
|
},
|
||||||
Crud,
|
Crud,
|
||||||
|
@ -26,6 +26,7 @@ use lemmy_db_schema::{
|
||||||
person_block::PersonBlock,
|
person_block::PersonBlock,
|
||||||
person_mention::{PersonMention, PersonMentionForm},
|
person_mention::{PersonMention, PersonMentionForm},
|
||||||
post::{Post, PostRead, PostReadForm},
|
post::{Post, PostRead, PostReadForm},
|
||||||
|
secrets::Secrets,
|
||||||
site::Site,
|
site::Site,
|
||||||
},
|
},
|
||||||
CommunityId,
|
CommunityId,
|
||||||
|
@ -39,6 +40,7 @@ use lemmy_db_views_actor::{
|
||||||
community_view::CommunityView,
|
community_view::CommunityView,
|
||||||
};
|
};
|
||||||
use lemmy_utils::{
|
use lemmy_utils::{
|
||||||
|
claims::Claims,
|
||||||
email::send_email,
|
email::send_email,
|
||||||
settings::structs::Settings,
|
settings::structs::Settings,
|
||||||
utils::MentionData,
|
utils::MentionData,
|
||||||
|
@ -245,8 +247,8 @@ pub async fn get_local_user_view_from_jwt(
|
||||||
jwt: &str,
|
jwt: &str,
|
||||||
pool: &DbPool,
|
pool: &DbPool,
|
||||||
) -> Result<LocalUserView, LemmyError> {
|
) -> Result<LocalUserView, LemmyError> {
|
||||||
let claims = Claims::decode(jwt, pool)
|
let jwt_secret = blocking(pool, move |conn| Secrets::read_jwt_secret(conn)).await??;
|
||||||
.await
|
let claims = Claims::decode(jwt, jwt_secret.as_ref())
|
||||||
.map_err(|_| ApiError::err("not_logged_in"))?
|
.map_err(|_| ApiError::err("not_logged_in"))?
|
||||||
.claims;
|
.claims;
|
||||||
let local_user_id = LocalUserId(claims.sub);
|
let local_user_id = LocalUserId(claims.sub);
|
||||||
|
@ -294,8 +296,8 @@ pub async fn get_local_user_settings_view_from_jwt(
|
||||||
jwt: &str,
|
jwt: &str,
|
||||||
pool: &DbPool,
|
pool: &DbPool,
|
||||||
) -> Result<LocalUserSettingsView, LemmyError> {
|
) -> Result<LocalUserSettingsView, LemmyError> {
|
||||||
let claims = Claims::decode(jwt, pool)
|
let jwt_secret = blocking(pool, move |conn| Secrets::read_jwt_secret(conn)).await??;
|
||||||
.await
|
let claims = Claims::decode(jwt, jwt_secret.as_ref())
|
||||||
.map_err(|_| ApiError::err("not_logged_in"))?
|
.map_err(|_| ApiError::err("not_logged_in"))?
|
||||||
.claims;
|
.claims;
|
||||||
let local_user_id = LocalUserId(claims.sub);
|
let local_user_id = LocalUserId(claims.sub);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::PerformCrud;
|
use crate::PerformCrud;
|
||||||
use actix_web::web::Data;
|
use actix_web::web::Data;
|
||||||
use lemmy_api_common::{blocking, claims::Claims, password_length_check, person::*};
|
use lemmy_api_common::{blocking, password_length_check, person::*};
|
||||||
use lemmy_apub::{
|
use lemmy_apub::{
|
||||||
generate_apub_endpoint,
|
generate_apub_endpoint,
|
||||||
generate_followers_url,
|
generate_followers_url,
|
||||||
|
@ -9,7 +9,7 @@ use lemmy_apub::{
|
||||||
EndpointType,
|
EndpointType,
|
||||||
};
|
};
|
||||||
use lemmy_db_queries::{
|
use lemmy_db_queries::{
|
||||||
source::{local_user::LocalUser_, site::Site_},
|
source::{local_user::LocalUser_, secrets::Secrets_, site::Site_},
|
||||||
Crud,
|
Crud,
|
||||||
Followable,
|
Followable,
|
||||||
Joinable,
|
Joinable,
|
||||||
|
@ -21,6 +21,7 @@ use lemmy_db_schema::{
|
||||||
community::*,
|
community::*,
|
||||||
local_user::{LocalUser, LocalUserForm},
|
local_user::{LocalUser, LocalUserForm},
|
||||||
person::*,
|
person::*,
|
||||||
|
secrets::Secrets,
|
||||||
site::*,
|
site::*,
|
||||||
},
|
},
|
||||||
CommunityId,
|
CommunityId,
|
||||||
|
@ -28,6 +29,7 @@ use lemmy_db_schema::{
|
||||||
use lemmy_db_views_actor::person_view::PersonViewSafe;
|
use lemmy_db_views_actor::person_view::PersonViewSafe;
|
||||||
use lemmy_utils::{
|
use lemmy_utils::{
|
||||||
apub::generate_actor_keypair,
|
apub::generate_actor_keypair,
|
||||||
|
claims::Claims,
|
||||||
settings::structs::Settings,
|
settings::structs::Settings,
|
||||||
utils::{check_slurs, is_valid_actor_name},
|
utils::{check_slurs, is_valid_actor_name},
|
||||||
ApiError,
|
ApiError,
|
||||||
|
@ -217,8 +219,9 @@ impl PerformCrud for Register {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the jwt
|
// Return the jwt
|
||||||
|
let jwt_secret = blocking(context.pool(), move |conn| Secrets::read_jwt_secret(conn)).await??;
|
||||||
Ok(LoginResponse {
|
Ok(LoginResponse {
|
||||||
jwt: Claims::jwt(inserted_local_user.id.0, context.pool()).await?,
|
jwt: Claims::jwt(inserted_local_user.id.0, jwt_secret.as_ref())?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,31 @@
|
||||||
use diesel::{result::Error, *};
|
use crate::{diesel::RunQueryDsl, lazy_static::__Deref};
|
||||||
|
use diesel::PgConnection;
|
||||||
use lemmy_db_schema::source::secrets::Secrets;
|
use lemmy_db_schema::source::secrets::Secrets;
|
||||||
|
use lemmy_utils::LemmyError;
|
||||||
|
use std::sync::RwLock;
|
||||||
|
|
||||||
pub trait Secrets_ {
|
pub trait Secrets_ {
|
||||||
fn read(conn: &PgConnection) -> Result<String, Error>;
|
fn read_jwt_secret(conn: &PgConnection) -> Result<String, LemmyError>;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: thread_local! might be better in terms of performance, but i couldnt get it to work
|
||||||
|
lazy_static! {
|
||||||
|
static ref JWT_SECRET: RwLock<Option<String>> = RwLock::new(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Secrets_ for Secrets {
|
impl Secrets_ for Secrets {
|
||||||
fn read(conn: &PgConnection) -> Result<String, Error> {
|
fn read_jwt_secret(conn: &PgConnection) -> Result<String, LemmyError> {
|
||||||
use lemmy_db_schema::schema::secrets::dsl::*;
|
use lemmy_db_schema::schema::secrets::dsl::*;
|
||||||
secrets.first::<Self>(conn).map(|s| s.jwt_secret)
|
let jwt_option: Option<String> = JWT_SECRET.read().unwrap().deref().clone();
|
||||||
|
match jwt_option {
|
||||||
|
Some(j) => Ok(j),
|
||||||
|
None => {
|
||||||
|
let jwt = secrets.first::<Self>(conn).map(|s| s.jwt_secret)?;
|
||||||
|
let jwt_static = JWT_SECRET.write();
|
||||||
|
let mut jwt_static = jwt_static.unwrap();
|
||||||
|
*jwt_static = Some(jwt.clone());
|
||||||
|
Ok(jwt)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
use actix_web::{error::ErrorBadRequest, *};
|
use actix_web::{error::ErrorBadRequest, *};
|
||||||
use anyhow::anyhow;
|
use anyhow::anyhow;
|
||||||
use chrono::{DateTime, NaiveDateTime, Utc};
|
use chrono::{DateTime, NaiveDateTime, Utc};
|
||||||
use lemmy_api_common::{blocking, claims::Claims};
|
use diesel::PgConnection;
|
||||||
|
use lemmy_api_common::blocking;
|
||||||
use lemmy_db_queries::{
|
use lemmy_db_queries::{
|
||||||
source::{community::Community_, person::Person_},
|
source::{community::Community_, person::Person_, secrets::Secrets_},
|
||||||
Crud,
|
Crud,
|
||||||
DbPool,
|
|
||||||
ListingType,
|
ListingType,
|
||||||
SortType,
|
SortType,
|
||||||
};
|
};
|
||||||
use lemmy_db_schema::{
|
use lemmy_db_schema::{
|
||||||
source::{community::Community, local_user::LocalUser, person::Person},
|
source::{community::Community, local_user::LocalUser, person::Person, secrets::Secrets},
|
||||||
LocalUserId,
|
LocalUserId,
|
||||||
};
|
};
|
||||||
use lemmy_db_views::{
|
use lemmy_db_views::{
|
||||||
|
@ -19,7 +19,12 @@ use lemmy_db_views::{
|
||||||
site_view::SiteView,
|
site_view::SiteView,
|
||||||
};
|
};
|
||||||
use lemmy_db_views_actor::person_mention_view::{PersonMentionQueryBuilder, PersonMentionView};
|
use lemmy_db_views_actor::person_mention_view::{PersonMentionQueryBuilder, PersonMentionView};
|
||||||
use lemmy_utils::{settings::structs::Settings, utils::markdown_to_html, LemmyError};
|
use lemmy_utils::{
|
||||||
|
claims::Claims,
|
||||||
|
settings::structs::Settings,
|
||||||
|
utils::markdown_to_html,
|
||||||
|
LemmyError,
|
||||||
|
};
|
||||||
use lemmy_websocket::LemmyContext;
|
use lemmy_websocket::LemmyContext;
|
||||||
use rss::{
|
use rss::{
|
||||||
extension::dublincore::DublinCoreExtensionBuilder,
|
extension::dublincore::DublinCoreExtensionBuilder,
|
||||||
|
@ -136,12 +141,13 @@ async fn get_feed(
|
||||||
_ => return Err(ErrorBadRequest(LemmyError::from(anyhow!("wrong_type")))),
|
_ => return Err(ErrorBadRequest(LemmyError::from(anyhow!("wrong_type")))),
|
||||||
};
|
};
|
||||||
|
|
||||||
let builder = match request_type {
|
let builder = blocking(context.pool(), move |conn| match request_type {
|
||||||
RequestType::User => get_feed_user(context.pool(), sort_type, param).await,
|
RequestType::User => get_feed_user(conn, &sort_type, param),
|
||||||
RequestType::Community => get_feed_community(context.pool(), sort_type, param).await,
|
RequestType::Community => get_feed_community(conn, &sort_type, param),
|
||||||
RequestType::Front => get_feed_front(context.pool(), sort_type, param).await,
|
RequestType::Front => get_feed_front(conn, &sort_type, param),
|
||||||
RequestType::Inbox => get_feed_inbox(context.pool(), param).await,
|
RequestType::Inbox => get_feed_inbox(conn, param),
|
||||||
}
|
})
|
||||||
|
.await?
|
||||||
.map_err(ErrorBadRequest)?;
|
.map_err(ErrorBadRequest)?;
|
||||||
|
|
||||||
let rss = builder.build().map_err(ErrorBadRequest)?.to_string();
|
let rss = builder.build().map_err(ErrorBadRequest)?.to_string();
|
||||||
|
@ -161,23 +167,19 @@ fn get_sort_type(info: web::Query<Params>) -> Result<SortType, ParseError> {
|
||||||
SortType::from_str(&sort_query)
|
SortType::from_str(&sort_query)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_feed_user(
|
fn get_feed_user(
|
||||||
pool: &DbPool,
|
conn: &PgConnection,
|
||||||
sort_type: SortType,
|
sort_type: &SortType,
|
||||||
user_name: String,
|
user_name: String,
|
||||||
) -> Result<ChannelBuilder, LemmyError> {
|
) -> Result<ChannelBuilder, LemmyError> {
|
||||||
let site_view = blocking(pool, move |conn| SiteView::read(conn)).await??;
|
let site_view = SiteView::read(conn)?;
|
||||||
let person = blocking(pool, move |conn| Person::find_by_name(conn, &user_name)).await??;
|
let person = Person::find_by_name(conn, &user_name)?;
|
||||||
|
|
||||||
let person_id = person.id;
|
let posts = PostQueryBuilder::create(conn)
|
||||||
let posts = blocking(pool, move |conn| {
|
|
||||||
PostQueryBuilder::create(conn)
|
|
||||||
.listing_type(ListingType::All)
|
.listing_type(ListingType::All)
|
||||||
.sort(sort_type)
|
.sort(*sort_type)
|
||||||
.creator_id(person_id)
|
.creator_id(person.id)
|
||||||
.list()
|
.list()?;
|
||||||
})
|
|
||||||
.await??;
|
|
||||||
|
|
||||||
let items = create_post_items(posts)?;
|
let items = create_post_items(posts)?;
|
||||||
|
|
||||||
|
@ -191,26 +193,19 @@ async fn get_feed_user(
|
||||||
Ok(channel_builder)
|
Ok(channel_builder)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_feed_community(
|
fn get_feed_community(
|
||||||
pool: &DbPool,
|
conn: &PgConnection,
|
||||||
sort_type: SortType,
|
sort_type: &SortType,
|
||||||
community_name: String,
|
community_name: String,
|
||||||
) -> Result<ChannelBuilder, LemmyError> {
|
) -> Result<ChannelBuilder, LemmyError> {
|
||||||
let site_view = blocking(pool, move |conn| SiteView::read(conn)).await??;
|
let site_view = SiteView::read(conn)?;
|
||||||
let community = blocking(pool, move |conn| {
|
let community = Community::read_from_name(conn, &community_name)?;
|
||||||
Community::read_from_name(conn, &community_name)
|
|
||||||
})
|
|
||||||
.await??;
|
|
||||||
|
|
||||||
let community_id = community.id;
|
let posts = PostQueryBuilder::create(conn)
|
||||||
let posts = blocking(pool, move |conn| {
|
|
||||||
PostQueryBuilder::create(conn)
|
|
||||||
.listing_type(ListingType::All)
|
.listing_type(ListingType::All)
|
||||||
.sort(sort_type)
|
.sort(*sort_type)
|
||||||
.community_id(community_id)
|
.community_id(community.id)
|
||||||
.list()
|
.list()?;
|
||||||
})
|
|
||||||
.await??;
|
|
||||||
|
|
||||||
let items = create_post_items(posts)?;
|
let items = create_post_items(posts)?;
|
||||||
|
|
||||||
|
@ -228,25 +223,23 @@ async fn get_feed_community(
|
||||||
Ok(channel_builder)
|
Ok(channel_builder)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_feed_front(
|
fn get_feed_front(
|
||||||
pool: &DbPool,
|
conn: &PgConnection,
|
||||||
sort_type: SortType,
|
sort_type: &SortType,
|
||||||
jwt: String,
|
jwt: String,
|
||||||
) -> Result<ChannelBuilder, LemmyError> {
|
) -> Result<ChannelBuilder, LemmyError> {
|
||||||
let site_view = blocking(pool, move |conn| SiteView::read(conn)).await??;
|
let site_view = SiteView::read(conn)?;
|
||||||
let local_user_id = LocalUserId(Claims::decode(&jwt, pool).await?.claims.sub);
|
let jwt_secret = Secrets::read_jwt_secret(conn)?;
|
||||||
|
let local_user_id = LocalUserId(Claims::decode(&jwt, jwt_secret.as_ref())?.claims.sub);
|
||||||
let posts = blocking(pool, move |conn| {
|
|
||||||
let local_user = LocalUser::read(conn, local_user_id)?;
|
let local_user = LocalUser::read(conn, local_user_id)?;
|
||||||
PostQueryBuilder::create(conn)
|
|
||||||
|
let posts = PostQueryBuilder::create(conn)
|
||||||
.listing_type(ListingType::Subscribed)
|
.listing_type(ListingType::Subscribed)
|
||||||
.my_person_id(local_user.person_id)
|
.my_person_id(local_user.person_id)
|
||||||
.show_bot_accounts(local_user.show_bot_accounts)
|
.show_bot_accounts(local_user.show_bot_accounts)
|
||||||
.show_read_posts(local_user.show_read_posts)
|
.show_read_posts(local_user.show_read_posts)
|
||||||
.sort(sort_type)
|
.sort(*sort_type)
|
||||||
.list()
|
.list()?;
|
||||||
})
|
|
||||||
.await??;
|
|
||||||
|
|
||||||
let items = create_post_items(posts)?;
|
let items = create_post_items(posts)?;
|
||||||
|
|
||||||
|
@ -264,33 +257,28 @@ async fn get_feed_front(
|
||||||
Ok(channel_builder)
|
Ok(channel_builder)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_feed_inbox(pool: &DbPool, jwt: String) -> Result<ChannelBuilder, LemmyError> {
|
fn get_feed_inbox(conn: &PgConnection, jwt: String) -> Result<ChannelBuilder, LemmyError> {
|
||||||
let site_view = blocking(pool, move |conn| SiteView::read(conn)).await??;
|
let site_view = SiteView::read(conn)?;
|
||||||
let local_user_id = LocalUserId(Claims::decode(&jwt, pool).await?.claims.sub);
|
let jwt_secret = Secrets::read_jwt_secret(conn)?;
|
||||||
let local_user = blocking(pool, move |conn| LocalUser::read(conn, local_user_id)).await??;
|
let local_user_id = LocalUserId(Claims::decode(&jwt, jwt_secret.as_ref())?.claims.sub);
|
||||||
|
let local_user = LocalUser::read(conn, local_user_id)?;
|
||||||
let person_id = local_user.person_id;
|
let person_id = local_user.person_id;
|
||||||
let show_bot_accounts = local_user.show_bot_accounts;
|
let show_bot_accounts = local_user.show_bot_accounts;
|
||||||
|
|
||||||
let sort = SortType::New;
|
let sort = SortType::New;
|
||||||
|
|
||||||
let replies = blocking(pool, move |conn| {
|
let replies = CommentQueryBuilder::create(conn)
|
||||||
CommentQueryBuilder::create(conn)
|
|
||||||
.recipient_id(person_id)
|
.recipient_id(person_id)
|
||||||
.my_person_id(person_id)
|
.my_person_id(person_id)
|
||||||
.show_bot_accounts(show_bot_accounts)
|
.show_bot_accounts(show_bot_accounts)
|
||||||
.sort(sort)
|
.sort(sort)
|
||||||
.list()
|
.list()?;
|
||||||
})
|
|
||||||
.await??;
|
|
||||||
|
|
||||||
let mentions = blocking(pool, move |conn| {
|
let mentions = PersonMentionQueryBuilder::create(conn)
|
||||||
PersonMentionQueryBuilder::create(conn)
|
|
||||||
.recipient_id(person_id)
|
.recipient_id(person_id)
|
||||||
.my_person_id(person_id)
|
.my_person_id(person_id)
|
||||||
.sort(sort)
|
.sort(sort)
|
||||||
.list()
|
.list()?;
|
||||||
})
|
|
||||||
.await??;
|
|
||||||
|
|
||||||
let items = create_reply_and_mention_items(replies, mentions)?;
|
let items = create_reply_and_mention_items(replies, mentions)?;
|
||||||
|
|
||||||
|
|
|
@ -2,8 +2,10 @@ use actix_http::http::header::ACCEPT_ENCODING;
|
||||||
use actix_web::{body::BodyStream, http::StatusCode, web::Data, *};
|
use actix_web::{body::BodyStream, http::StatusCode, web::Data, *};
|
||||||
use anyhow::anyhow;
|
use anyhow::anyhow;
|
||||||
use awc::Client;
|
use awc::Client;
|
||||||
use lemmy_api_common::claims::Claims;
|
use lemmy_api_common::blocking;
|
||||||
use lemmy_utils::{rate_limit::RateLimit, settings::structs::Settings, LemmyError};
|
use lemmy_db_queries::source::secrets::Secrets_;
|
||||||
|
use lemmy_db_schema::source::secrets::Secrets;
|
||||||
|
use lemmy_utils::{claims::Claims, rate_limit::RateLimit, settings::structs::Settings, LemmyError};
|
||||||
use lemmy_websocket::LemmyContext;
|
use lemmy_websocket::LemmyContext;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
@ -47,15 +49,16 @@ struct PictrsParams {
|
||||||
async fn upload(
|
async fn upload(
|
||||||
req: HttpRequest,
|
req: HttpRequest,
|
||||||
body: web::Payload,
|
body: web::Payload,
|
||||||
client: web::Data<Client>,
|
|
||||||
context: web::Data<LemmyContext>,
|
context: web::Data<LemmyContext>,
|
||||||
|
client: web::Data<Client>,
|
||||||
) -> Result<HttpResponse, Error> {
|
) -> Result<HttpResponse, Error> {
|
||||||
// TODO: check rate limit here
|
// TODO: check rate limit here
|
||||||
let jwt = req
|
let jwt = req
|
||||||
.cookie("jwt")
|
.cookie("jwt")
|
||||||
.expect("No auth header for picture upload");
|
.expect("No auth header for picture upload");
|
||||||
|
|
||||||
if Claims::decode(jwt.value(), context.pool()).await.is_err() {
|
let jwt_secret = blocking(context.pool(), move |conn| Secrets::read_jwt_secret(conn)).await??;
|
||||||
|
if Claims::decode(jwt.value(), jwt_secret.as_ref()).is_err() {
|
||||||
return Ok(HttpResponse::Unauthorized().finish());
|
return Ok(HttpResponse::Unauthorized().finish());
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -38,3 +38,4 @@ http = "0.2.4"
|
||||||
deser-hjson = "1.0.2"
|
deser-hjson = "1.0.2"
|
||||||
smart-default = "0.6.0"
|
smart-default = "0.6.0"
|
||||||
webpage = { version = "1.3.0", default-features = false, features = ["serde"] }
|
webpage = { version = "1.3.0", default-features = false, features = ["serde"] }
|
||||||
|
jsonwebtoken = "7.2.0"
|
||||||
|
|
37
crates/utils/src/claims.rs
Normal file
37
crates/utils/src/claims.rs
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
use crate::{settings::structs::Settings, LemmyError};
|
||||||
|
use chrono::Utc;
|
||||||
|
use jsonwebtoken::{decode, encode, DecodingKey, EncodingKey, Header, TokenData, Validation};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
type Jwt = String;
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
pub struct Claims {
|
||||||
|
/// local_user_id, standard claim by RFC 7519.
|
||||||
|
pub sub: i32,
|
||||||
|
pub iss: String,
|
||||||
|
/// Time when this token was issued as UNIX-timestamp in seconds
|
||||||
|
pub iat: i64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Claims {
|
||||||
|
pub fn decode(jwt: &str, jwt_secret: &[u8]) -> Result<TokenData<Claims>, LemmyError> {
|
||||||
|
let v = Validation {
|
||||||
|
validate_exp: false,
|
||||||
|
..Validation::default()
|
||||||
|
};
|
||||||
|
let key = DecodingKey::from_secret(jwt_secret);
|
||||||
|
Ok(decode::<Claims>(jwt, &key, &v)?)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn jwt(local_user_id: i32, jwt_secret: &[u8]) -> Result<Jwt, LemmyError> {
|
||||||
|
let my_claims = Claims {
|
||||||
|
sub: local_user_id,
|
||||||
|
iss: Settings::get().hostname,
|
||||||
|
iat: Utc::now().timestamp(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let key = EncodingKey::from_secret(jwt_secret);
|
||||||
|
Ok(encode(&Header::default(), &my_claims, &key)?)
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,6 +11,7 @@ pub mod rate_limit;
|
||||||
pub mod request;
|
pub mod request;
|
||||||
pub mod settings;
|
pub mod settings;
|
||||||
|
|
||||||
|
pub mod claims;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test;
|
mod test;
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
|
|
Loading…
Reference in a new issue