hostname: "{{ domain }}"
# the port where lemmy should listen for incoming requests
port: 8536
- # json web token for authorization between server and client
- jwt_secret: "{{ jwt_password }}"
# whether tls is required for activitypub. only disable this for debugging, never for producion.
tls_enabled: true
# address where pictrs is available
port: 8536
# whether tls is required for activitypub. only disable this for debugging, never for producion.
tls_enabled: true
- # json web token for authorization between server and client
- jwt_secret: "changeme"
# address where pictrs is available
pictrs_url: "http://pictrs:8080"
# maximum length of local community and user names
#[cfg(test)]
mod tests {
use lemmy_api_common::check_validator_time;
- use lemmy_db_queries::{establish_unpooled_connection, source::local_user::LocalUser_, Crud};
+ use lemmy_db_queries::{
+ establish_unpooled_connection,
+ source::{local_user::LocalUser_, secret::SecretSingleton},
+ Crud,
+ };
use lemmy_db_schema::source::{
local_user::{LocalUser, LocalUserForm},
person::{Person, PersonForm},
+ secret::Secret,
};
use lemmy_utils::claims::Claims;
let inserted_local_user = LocalUser::create(&conn, &local_user_form).unwrap();
- let jwt = Claims::jwt(inserted_local_user.id.0).unwrap();
- let claims = Claims::decode(&jwt).unwrap().claims;
+ 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());
person_mention::PersonMention_,
post::Post_,
private_message::PrivateMessage_,
+ secret::SecretSingleton,
},
Blockable,
Crud,
person_mention::*,
post::Post,
private_message::PrivateMessage,
+ secret::Secret,
site::*,
},
};
}
// Return the jwt
+ let jwt_secret = Secret::get().jwt_secret;
Ok(LoginResponse {
- jwt: Claims::jwt(local_user_view.local_user.id.0)?,
+ jwt: Claims::jwt(local_user_view.local_user.id.0, &jwt_secret)?,
})
}
}
};
// Return the jwt
+ let jwt_secret = Secret::get().jwt_secret;
Ok(LoginResponse {
- jwt: Claims::jwt(updated_local_user.id.0)?,
+ jwt: Claims::jwt(updated_local_user.id.0, &jwt_secret)?,
})
}
}
.await??;
// Return the jwt
+ let jwt_secret = Secret::get().jwt_secret;
Ok(LoginResponse {
- jwt: Claims::jwt(updated_local_user.id.0)?,
+ jwt: Claims::jwt(updated_local_user.id.0, &jwt_secret)?,
})
}
}
.map_err(|_| ApiError::err("couldnt_update_user"))?;
// Return the jwt
+ let jwt_secret = Secret::get().jwt_secret;
Ok(LoginResponse {
- jwt: Claims::jwt(updated_local_user.id.0)?,
+ jwt: Claims::jwt(updated_local_user.id.0, &jwt_secret)?,
})
}
}
source::{
community::{CommunityModerator_, Community_},
person_block::PersonBlock_,
+ secret::SecretSingleton,
site::Site_,
},
Crud,
person_block::PersonBlock,
person_mention::{PersonMention, PersonMentionForm},
post::{Post, PostRead, PostReadForm},
+ secret::Secret,
site::Site,
},
CommunityId,
jwt: &str,
pool: &DbPool,
) -> Result<LocalUserView, LemmyError> {
- let claims = Claims::decode(jwt)
+ 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);
jwt: &str,
pool: &DbPool,
) -> Result<LocalUserSettingsView, LemmyError> {
- let claims = Claims::decode(jwt)
+ 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);
EndpointType,
};
use lemmy_db_queries::{
- source::{local_user::LocalUser_, site::Site_},
+ source::{local_user::LocalUser_, secret::SecretSingleton, site::Site_},
Crud,
Followable,
Joinable,
community::*,
local_user::{LocalUser, LocalUserForm},
person::*,
+ secret::Secret,
site::*,
},
CommunityId,
}
// Return the jwt
+ let jwt_secret = Secret::get().jwt_secret;
Ok(LoginResponse {
- jwt: Claims::jwt(inserted_local_user.id.0)?,
+ jwt: Claims::jwt(inserted_local_user.id.0, &jwt_secret)?,
})
}
}
pub mod post;
pub mod post_report;
pub mod private_message;
+pub mod secret;
pub mod site;
--- /dev/null
+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)
+}
}
}
+table! {
+ secret(id) {
+ id -> Int4,
+ jwt_secret -> Varchar,
+ }
+}
+
joinable!(comment_alias_1 -> person_alias_1 (creator_id));
joinable!(comment -> comment_alias_1 (parent_id));
joinable!(person_mention -> person_alias_1 (recipient_id));
pub mod post;
pub mod post_report;
pub mod private_message;
+pub mod secret;
pub mod site;
--- /dev/null
+use crate::schema::secret;
+
+#[derive(Queryable, Identifiable, Clone)]
+#[table_name = "secret"]
+pub struct Secret {
+ pub id: i32,
+ pub jwt_secret: String,
+}
use diesel::PgConnection;
use lemmy_api_common::blocking;
use lemmy_db_queries::{
- source::{community::Community_, person::Person_},
+ source::{community::Community_, person::Person_, secret::SecretSingleton},
Crud,
ListingType,
SortType,
};
use lemmy_db_schema::{
- source::{community::Community, local_user::LocalUser, person::Person},
+ source::{community::Community, local_user::LocalUser, person::Person, secret::Secret},
LocalUserId,
};
use lemmy_db_views::{
jwt: String,
) -> Result<ChannelBuilder, LemmyError> {
let site_view = SiteView::read(conn)?;
- let local_user_id = LocalUserId(Claims::decode(&jwt)?.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;
- let show_read_posts = local_user.show_read_posts;
let posts = PostQueryBuilder::create(conn)
.listing_type(ListingType::Subscribed)
- .my_person_id(person_id)
- .show_bot_accounts(show_bot_accounts)
- .show_read_posts(show_read_posts)
+ .my_person_id(local_user.person_id)
+ .show_bot_accounts(local_user.show_bot_accounts)
+ .show_read_posts(local_user.show_read_posts)
.sort(*sort_type)
.list()?;
fn get_feed_inbox(conn: &PgConnection, jwt: String) -> Result<ChannelBuilder, LemmyError> {
let site_view = SiteView::read(conn)?;
- let local_user_id = LocalUserId(Claims::decode(&jwt)?.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;
use actix_web::{body::BodyStream, http::StatusCode, web::Data, *};
use anyhow::anyhow;
use awc::Client;
+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 serde::{Deserialize, Serialize};
use std::time::Duration;
.cookie("jwt")
.expect("No auth header for picture upload");
- if Claims::decode(jwt.value()).is_err() {
+ let jwt_secret = Secret::get().jwt_secret;
+ if Claims::decode(jwt.value(), &jwt_secret).is_err() {
return Ok(HttpResponse::Unauthorized().finish());
};
futures = "0.3.16"
diesel = "1.4.7"
http = "0.2.4"
-jsonwebtoken = "7.2.0"
deser-hjson = "1.0.2"
smart-default = "0.6.0"
webpage = { version = "1.3.0", default-features = false, features = ["serde"] }
+jsonwebtoken = "7.2.0"
-use crate::settings::structs::Settings;
+use crate::{settings::structs::Settings, LemmyError};
use chrono::Utc;
use jsonwebtoken::{decode, encode, DecodingKey, EncodingKey, Header, TokenData, Validation};
use serde::{Deserialize, Serialize};
}
impl Claims {
- pub fn decode(jwt: &str) -> Result<TokenData<Claims>, jsonwebtoken::errors::Error> {
+ pub fn decode(jwt: &str, jwt_secret: &str) -> Result<TokenData<Claims>, LemmyError> {
let v = Validation {
validate_exp: false,
..Validation::default()
};
- decode::<Claims>(
- jwt,
- &DecodingKey::from_secret(Settings::get().jwt_secret.as_ref()),
- &v,
- )
+ let key = DecodingKey::from_secret(jwt_secret.as_ref());
+ Ok(decode::<Claims>(jwt, &key, &v)?)
}
- pub fn jwt(local_user_id: i32) -> Result<Jwt, jsonwebtoken::errors::Error> {
+ 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(),
};
- encode(
- &Header::default(),
- &my_claims,
- &EncodingKey::from_secret(Settings::get().jwt_secret.as_ref()),
- )
+
+ let key = EncodingKey::from_secret(jwt_secret.as_ref());
+ Ok(encode(&Header::default(), &my_claims, &key)?)
}
}
extern crate smart_default;
pub mod apub;
-pub mod claims;
pub mod email;
pub mod rate_limit;
pub mod request;
pub mod settings;
+pub mod claims;
#[cfg(test)]
mod test;
pub mod utils;
pub port: u16,
#[default(true)]
pub tls_enabled: bool,
- #[default("changeme")]
- pub jwt_secret: String,
#[default(None)]
pub pictrs_url: Option<String>,
#[default(None)]
hostname: lemmy-alpha:8541
port: 8541
tls_enabled: false
- jwt_secret: changeme
setup: {
admin_username: lemmy_alpha
admin_password: lemmylemmy
hostname: lemmy-beta:8551
port: 8551
tls_enabled: false
- jwt_secret: changeme
setup: {
admin_username: lemmy_beta
admin_password: lemmylemmy
hostname: lemmy-delta:8571
port: 8571
tls_enabled: false
- jwt_secret: changeme
setup: {
admin_username: lemmy_delta
admin_password: lemmylemmy
hostname: lemmy-epsilon:8581
port: 8581
tls_enabled: false
- jwt_secret: changeme
setup: {
admin_username: lemmy_epsilon
admin_password: lemmylemmy
hostname: lemmy-gamma:8561
port: 8561
tls_enabled: false
- jwt_secret: changeme
setup: {
admin_username: lemmy_gamma
admin_password: lemmylemmy
bind: "0.0.0.0"
# port where lemmy should listen for incoming requests
port: 8536
- # json web token for authorization between server and client
- jwt_secret: "changeme"
# settings related to the postgresql database
# address where pictrs is available
pictrs_url: "http://pictrs:8080"
--- /dev/null
+drop table secret;
--- /dev/null
+-- generate a jwt secret
+create extension if not exists pgcrypto;
+
+create table secret(
+ id serial primary key,
+ jwt_secret varchar not null default gen_random_uuid()
+);
+
+insert into secret default values;