mirror of
https://github.com/LemmyNet/lemmy.git
synced 2024-11-26 22:31:20 +00:00
Making Secrets a Singleton.
This commit is contained in:
parent
374db38881
commit
3f0838ce80
16 changed files with 93 additions and 91 deletions
|
@ -190,13 +190,13 @@ mod tests {
|
|||
use lemmy_api_common::check_validator_time;
|
||||
use lemmy_db_queries::{
|
||||
establish_unpooled_connection,
|
||||
source::{local_user::LocalUser_, secrets::Secrets_},
|
||||
source::{local_user::LocalUser_, secret::SecretSingleton},
|
||||
Crud,
|
||||
};
|
||||
use lemmy_db_schema::source::{
|
||||
local_user::{LocalUser, LocalUserForm},
|
||||
person::{Person, PersonForm},
|
||||
secrets::Secrets,
|
||||
secret::Secret,
|
||||
};
|
||||
use lemmy_utils::claims::Claims;
|
||||
|
||||
|
@ -219,8 +219,8 @@ mod tests {
|
|||
|
||||
let inserted_local_user = LocalUser::create(&conn, &local_user_form).unwrap();
|
||||
|
||||
let jwt_secret = Secrets::read_jwt_secret(&conn).unwrap();
|
||||
let jwt = Claims::jwt(inserted_local_user.id.0, jwt_secret.as_ref()).unwrap();
|
||||
let jwt_secret = Secret::get().jwt_secret;
|
||||
let jwt = Claims::jwt(inserted_local_user.id.0, &jwt_secret).unwrap();
|
||||
let claims = Claims::decode(&jwt, jwt_secret.as_ref()).unwrap().claims;
|
||||
let check = check_validator_time(&inserted_local_user.validator_time, &claims);
|
||||
assert!(check.is_ok());
|
||||
|
|
|
@ -25,7 +25,7 @@ use lemmy_db_queries::{
|
|||
person_mention::PersonMention_,
|
||||
post::Post_,
|
||||
private_message::PrivateMessage_,
|
||||
secrets::Secrets_,
|
||||
secret::SecretSingleton,
|
||||
},
|
||||
Blockable,
|
||||
Crud,
|
||||
|
@ -44,7 +44,7 @@ use lemmy_db_schema::{
|
|||
person_mention::*,
|
||||
post::Post,
|
||||
private_message::PrivateMessage,
|
||||
secrets::Secrets,
|
||||
secret::Secret,
|
||||
site::*,
|
||||
},
|
||||
};
|
||||
|
@ -105,9 +105,9 @@ impl Perform for Login {
|
|||
}
|
||||
|
||||
// Return the jwt
|
||||
let jwt_secret = blocking(context.pool(), move |conn| Secrets::read_jwt_secret(conn)).await??;
|
||||
let jwt_secret = Secret::get().jwt_secret;
|
||||
Ok(LoginResponse {
|
||||
jwt: Claims::jwt(local_user_view.local_user.id.0, jwt_secret.as_ref())?,
|
||||
jwt: Claims::jwt(local_user_view.local_user.id.0, &jwt_secret)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -271,9 +271,9 @@ impl Perform for SaveUserSettings {
|
|||
};
|
||||
|
||||
// Return the jwt
|
||||
let jwt_secret = blocking(context.pool(), move |conn| Secrets::read_jwt_secret(conn)).await??;
|
||||
let jwt_secret = Secret::get().jwt_secret;
|
||||
Ok(LoginResponse {
|
||||
jwt: Claims::jwt(updated_local_user.id.0, jwt_secret.as_ref())?,
|
||||
jwt: Claims::jwt(updated_local_user.id.0, &jwt_secret)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -315,9 +315,9 @@ impl Perform for ChangePassword {
|
|||
.await??;
|
||||
|
||||
// Return the jwt
|
||||
let jwt_secret = blocking(context.pool(), move |conn| Secrets::read_jwt_secret(conn)).await??;
|
||||
let jwt_secret = Secret::get().jwt_secret;
|
||||
Ok(LoginResponse {
|
||||
jwt: Claims::jwt(updated_local_user.id.0, jwt_secret.as_ref())?,
|
||||
jwt: Claims::jwt(updated_local_user.id.0, &jwt_secret)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -775,9 +775,9 @@ impl Perform for PasswordChange {
|
|||
.map_err(|_| ApiError::err("couldnt_update_user"))?;
|
||||
|
||||
// Return the jwt
|
||||
let jwt_secret = blocking(context.pool(), move |conn| Secrets::read_jwt_secret(conn)).await??;
|
||||
let jwt_secret = Secret::get().jwt_secret;
|
||||
Ok(LoginResponse {
|
||||
jwt: Claims::jwt(updated_local_user.id.0, jwt_secret.as_ref())?,
|
||||
jwt: Claims::jwt(updated_local_user.id.0, &jwt_secret)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ use lemmy_db_queries::{
|
|||
source::{
|
||||
community::{CommunityModerator_, Community_},
|
||||
person_block::PersonBlock_,
|
||||
secrets::Secrets_,
|
||||
secret::SecretSingleton,
|
||||
site::Site_,
|
||||
},
|
||||
Crud,
|
||||
|
@ -26,7 +26,7 @@ use lemmy_db_schema::{
|
|||
person_block::PersonBlock,
|
||||
person_mention::{PersonMention, PersonMentionForm},
|
||||
post::{Post, PostRead, PostReadForm},
|
||||
secrets::Secrets,
|
||||
secret::Secret,
|
||||
site::Site,
|
||||
},
|
||||
CommunityId,
|
||||
|
@ -247,8 +247,8 @@ pub async fn get_local_user_view_from_jwt(
|
|||
jwt: &str,
|
||||
pool: &DbPool,
|
||||
) -> Result<LocalUserView, LemmyError> {
|
||||
let jwt_secret = blocking(pool, move |conn| Secrets::read_jwt_secret(conn)).await??;
|
||||
let claims = Claims::decode(jwt, jwt_secret.as_ref())
|
||||
let jwt_secret = Secret::get().jwt_secret;
|
||||
let claims = Claims::decode(jwt, &jwt_secret)
|
||||
.map_err(|_| ApiError::err("not_logged_in"))?
|
||||
.claims;
|
||||
let local_user_id = LocalUserId(claims.sub);
|
||||
|
@ -296,8 +296,8 @@ pub async fn get_local_user_settings_view_from_jwt(
|
|||
jwt: &str,
|
||||
pool: &DbPool,
|
||||
) -> Result<LocalUserSettingsView, LemmyError> {
|
||||
let jwt_secret = blocking(pool, move |conn| Secrets::read_jwt_secret(conn)).await??;
|
||||
let claims = Claims::decode(jwt, jwt_secret.as_ref())
|
||||
let jwt_secret = Secret::get().jwt_secret;
|
||||
let claims = Claims::decode(jwt, &jwt_secret)
|
||||
.map_err(|_| ApiError::err("not_logged_in"))?
|
||||
.claims;
|
||||
let local_user_id = LocalUserId(claims.sub);
|
||||
|
|
|
@ -9,7 +9,7 @@ use lemmy_apub::{
|
|||
EndpointType,
|
||||
};
|
||||
use lemmy_db_queries::{
|
||||
source::{local_user::LocalUser_, secrets::Secrets_, site::Site_},
|
||||
source::{local_user::LocalUser_, secret::SecretSingleton, site::Site_},
|
||||
Crud,
|
||||
Followable,
|
||||
Joinable,
|
||||
|
@ -21,7 +21,7 @@ use lemmy_db_schema::{
|
|||
community::*,
|
||||
local_user::{LocalUser, LocalUserForm},
|
||||
person::*,
|
||||
secrets::Secrets,
|
||||
secret::Secret,
|
||||
site::*,
|
||||
},
|
||||
CommunityId,
|
||||
|
@ -219,9 +219,9 @@ impl PerformCrud for Register {
|
|||
}
|
||||
|
||||
// Return the jwt
|
||||
let jwt_secret = blocking(context.pool(), move |conn| Secrets::read_jwt_secret(conn)).await??;
|
||||
let jwt_secret = Secret::get().jwt_secret;
|
||||
Ok(LoginResponse {
|
||||
jwt: Claims::jwt(inserted_local_user.id.0, jwt_secret.as_ref())?,
|
||||
jwt: Claims::jwt(inserted_local_user.id.0, &jwt_secret)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,5 +12,5 @@ pub mod person_mention;
|
|||
pub mod post;
|
||||
pub mod post_report;
|
||||
pub mod private_message;
|
||||
pub mod secrets;
|
||||
pub mod secret;
|
||||
pub mod site;
|
||||
|
|
37
crates/db_queries/src/source/secret.rs
Normal file
37
crates/db_queries/src/source/secret.rs
Normal file
|
@ -0,0 +1,37 @@
|
|||
use diesel::{result::Error, *};
|
||||
use lemmy_db_schema::source::secret::Secret;
|
||||
use lemmy_utils::settings::structs::Settings;
|
||||
use std::sync::RwLock;
|
||||
|
||||
use crate::get_database_url_from_env;
|
||||
|
||||
lazy_static! {
|
||||
static ref SECRET: RwLock<Secret> = RwLock::new(init().expect("Failed to load secrets from DB."));
|
||||
}
|
||||
|
||||
pub trait SecretSingleton {
|
||||
fn get() -> Secret;
|
||||
}
|
||||
|
||||
impl SecretSingleton for Secret {
|
||||
/// Returns the Secret as a struct
|
||||
fn get() -> Self {
|
||||
SECRET.read().expect("read secrets").to_owned()
|
||||
}
|
||||
}
|
||||
|
||||
/// Reads the secrets from the DB
|
||||
fn init() -> Result<Secret, Error> {
|
||||
let db_url = match get_database_url_from_env() {
|
||||
Ok(url) => url,
|
||||
Err(_) => Settings::get().get_database_url(),
|
||||
};
|
||||
|
||||
let conn = PgConnection::establish(&db_url).expect("Couldn't get DB connection for Secrets.");
|
||||
read_secrets(&conn)
|
||||
}
|
||||
|
||||
fn read_secrets(conn: &PgConnection) -> Result<Secret, Error> {
|
||||
use lemmy_db_schema::schema::secret::dsl::*;
|
||||
secret.first::<Secret>(conn)
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
use crate::{diesel::RunQueryDsl, lazy_static::__Deref};
|
||||
use diesel::PgConnection;
|
||||
use lemmy_db_schema::source::secrets::Secrets;
|
||||
use lemmy_utils::LemmyError;
|
||||
use std::sync::RwLock;
|
||||
|
||||
pub trait Secrets_ {
|
||||
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 {
|
||||
fn read_jwt_secret(conn: &PgConnection) -> Result<String, LemmyError> {
|
||||
use lemmy_db_schema::schema::secrets::dsl::*;
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -552,7 +552,7 @@ table! {
|
|||
}
|
||||
|
||||
table! {
|
||||
secrets(id) {
|
||||
secret(id) {
|
||||
id -> Int4,
|
||||
jwt_secret -> Varchar,
|
||||
}
|
||||
|
|
|
@ -12,5 +12,5 @@ pub mod person_mention;
|
|||
pub mod post;
|
||||
pub mod post_report;
|
||||
pub mod private_message;
|
||||
pub mod secrets;
|
||||
pub mod secret;
|
||||
pub mod site;
|
||||
|
|
8
crates/db_schema/src/source/secret.rs
Normal file
8
crates/db_schema/src/source/secret.rs
Normal file
|
@ -0,0 +1,8 @@
|
|||
use crate::schema::secret;
|
||||
|
||||
#[derive(Queryable, Identifiable, Clone)]
|
||||
#[table_name = "secret"]
|
||||
pub struct Secret {
|
||||
pub id: i32,
|
||||
pub jwt_secret: String,
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
use crate::schema::secrets;
|
||||
|
||||
#[derive(Queryable, Identifiable)]
|
||||
#[table_name = "secrets"]
|
||||
pub struct Secrets {
|
||||
pub id: i32,
|
||||
pub jwt_secret: String,
|
||||
}
|
|
@ -4,13 +4,13 @@ use chrono::{DateTime, NaiveDateTime, Utc};
|
|||
use diesel::PgConnection;
|
||||
use lemmy_api_common::blocking;
|
||||
use lemmy_db_queries::{
|
||||
source::{community::Community_, person::Person_, secrets::Secrets_},
|
||||
source::{community::Community_, person::Person_, secret::SecretSingleton},
|
||||
Crud,
|
||||
ListingType,
|
||||
SortType,
|
||||
};
|
||||
use lemmy_db_schema::{
|
||||
source::{community::Community, local_user::LocalUser, person::Person, secrets::Secrets},
|
||||
source::{community::Community, local_user::LocalUser, person::Person, secret::Secret},
|
||||
LocalUserId,
|
||||
};
|
||||
use lemmy_db_views::{
|
||||
|
@ -229,8 +229,8 @@ fn get_feed_front(
|
|||
jwt: String,
|
||||
) -> Result<ChannelBuilder, LemmyError> {
|
||||
let site_view = SiteView::read(conn)?;
|
||||
let jwt_secret = Secrets::read_jwt_secret(conn)?;
|
||||
let local_user_id = LocalUserId(Claims::decode(&jwt, jwt_secret.as_ref())?.claims.sub);
|
||||
let jwt_secret = Secret::get().jwt_secret;
|
||||
let local_user_id = LocalUserId(Claims::decode(&jwt, &jwt_secret)?.claims.sub);
|
||||
let local_user = LocalUser::read(conn, local_user_id)?;
|
||||
|
||||
let posts = PostQueryBuilder::create(conn)
|
||||
|
@ -259,8 +259,8 @@ fn get_feed_front(
|
|||
|
||||
fn get_feed_inbox(conn: &PgConnection, jwt: String) -> Result<ChannelBuilder, LemmyError> {
|
||||
let site_view = SiteView::read(conn)?;
|
||||
let jwt_secret = Secrets::read_jwt_secret(conn)?;
|
||||
let local_user_id = LocalUserId(Claims::decode(&jwt, jwt_secret.as_ref())?.claims.sub);
|
||||
let jwt_secret = Secret::get().jwt_secret;
|
||||
let local_user_id = LocalUserId(Claims::decode(&jwt, &jwt_secret)?.claims.sub);
|
||||
let local_user = LocalUser::read(conn, local_user_id)?;
|
||||
let person_id = local_user.person_id;
|
||||
let show_bot_accounts = local_user.show_bot_accounts;
|
||||
|
|
|
@ -2,11 +2,9 @@ use actix_http::http::header::ACCEPT_ENCODING;
|
|||
use actix_web::{body::BodyStream, http::StatusCode, web::Data, *};
|
||||
use anyhow::anyhow;
|
||||
use awc::Client;
|
||||
use lemmy_api_common::blocking;
|
||||
use lemmy_db_queries::source::secrets::Secrets_;
|
||||
use lemmy_db_schema::source::secrets::Secrets;
|
||||
use lemmy_db_queries::source::secret::SecretSingleton;
|
||||
use lemmy_db_schema::source::secret::Secret;
|
||||
use lemmy_utils::{claims::Claims, rate_limit::RateLimit, settings::structs::Settings, LemmyError};
|
||||
use lemmy_websocket::LemmyContext;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::time::Duration;
|
||||
|
||||
|
@ -49,7 +47,6 @@ struct PictrsParams {
|
|||
async fn upload(
|
||||
req: HttpRequest,
|
||||
body: web::Payload,
|
||||
context: web::Data<LemmyContext>,
|
||||
client: web::Data<Client>,
|
||||
) -> Result<HttpResponse, Error> {
|
||||
// TODO: check rate limit here
|
||||
|
@ -57,8 +54,8 @@ async fn upload(
|
|||
.cookie("jwt")
|
||||
.expect("No auth header for picture upload");
|
||||
|
||||
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() {
|
||||
let jwt_secret = Secret::get().jwt_secret;
|
||||
if Claims::decode(jwt.value(), &jwt_secret).is_err() {
|
||||
return Ok(HttpResponse::Unauthorized().finish());
|
||||
};
|
||||
|
||||
|
|
|
@ -15,23 +15,23 @@ pub struct Claims {
|
|||
}
|
||||
|
||||
impl Claims {
|
||||
pub fn decode(jwt: &str, jwt_secret: &[u8]) -> Result<TokenData<Claims>, LemmyError> {
|
||||
pub fn decode(jwt: &str, jwt_secret: &str) -> Result<TokenData<Claims>, LemmyError> {
|
||||
let v = Validation {
|
||||
validate_exp: false,
|
||||
..Validation::default()
|
||||
};
|
||||
let key = DecodingKey::from_secret(jwt_secret);
|
||||
let key = DecodingKey::from_secret(jwt_secret.as_ref());
|
||||
Ok(decode::<Claims>(jwt, &key, &v)?)
|
||||
}
|
||||
|
||||
pub fn jwt(local_user_id: i32, jwt_secret: &[u8]) -> Result<Jwt, LemmyError> {
|
||||
pub fn jwt(local_user_id: i32, jwt_secret: &str) -> 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);
|
||||
let key = EncodingKey::from_secret(jwt_secret.as_ref());
|
||||
Ok(encode(&Header::default(), &my_claims, &key)?)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1 +1 @@
|
|||
drop table secrets;
|
||||
drop table secret;
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
-- generate a jwt secret with 62 possible characters and length 43.
|
||||
-- this gives an entropy of 256 bits
|
||||
-- log2(62^43) = 256
|
||||
-- generate a jwt secret
|
||||
create extension if not exists pgcrypto;
|
||||
|
||||
create table secrets(
|
||||
create table secret(
|
||||
id serial primary key,
|
||||
jwt_secret varchar(43) not null
|
||||
jwt_secret varchar not null default gen_random_uuid()
|
||||
);
|
||||
-- TODO: generate a random string from A-Za-z0-9, length 43, and insert
|
||||
insert into secrets(jwt_secret) values('123');
|
||||
|
||||
insert into secret default values;
|
||||
|
|
Loading…
Reference in a new issue