diff --git a/CHANGELOG.md b/CHANGELOG.md index 27472e5..2cff696 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ### Added - Added `approval_required` and `invites_enabled` flags to `/api/v1/instance` endpoint response. +- Added `registration.type` configuration option (replaces `registrations_open`). + +### Deprecated + +- `registrations_open` configuration option. ### Removed diff --git a/config.yaml.example b/config.yaml.example index 5420cc9..9191687 100644 --- a/config.yaml.example +++ b/config.yaml.example @@ -9,7 +9,9 @@ instance_uri: 127.0.0.1:8380 instance_title: Mitra instance_short_description: My instance instance_description: My instance -registrations_open: true + +registration: + type: open blockchains: # Parameters for hardhat local node diff --git a/contrib/mitra_config.yaml b/contrib/mitra_config.yaml index a9990bb..2c2ed60 100644 --- a/contrib/mitra_config.yaml +++ b/contrib/mitra_config.yaml @@ -18,7 +18,9 @@ instance_short_description: my instance # Long description can contain markdown syntax instance_description: my instance -registrations_open: false +registration: + # Possible values: open, invite + type: invite # EIP-4361 login message #login_message: 'Do not sign this message on other sites!' diff --git a/mitra-cli/src/main.rs b/mitra-cli/src/main.rs index 749f9e7..c2a556f 100644 --- a/mitra-cli/src/main.rs +++ b/mitra-cli/src/main.rs @@ -17,9 +17,13 @@ async fn main() { SubCommand::GenerateEthereumAddress(cmd) => cmd.execute(), subcmd => { // Other commands require initialized app - let config = parse_config(); + let (config, config_warnings) = parse_config(); configure_logger(config.log_level); log::info!("config loaded from {}", config.config_path); + for warning in config_warnings { + log::warn!("{}", warning); + }; + let db_config = config.database_url.parse().unwrap(); let db_client = &mut create_database_client(&db_config).await; apply_migrations(db_client).await; diff --git a/src/config/loader.rs b/src/config/loader.rs index 2c90d94..c5dd859 100644 --- a/src/config/loader.rs +++ b/src/config/loader.rs @@ -12,7 +12,7 @@ use crate::utils::crypto_rsa::{ use crate::utils::files::{set_file_permissions, write_file}; use super::environment::Environment; -use super::main::Config; +use super::main::{Config, RegistrationType}; struct EnvConfig { config_path: String, @@ -78,12 +78,14 @@ fn read_instance_rsa_key(storage_dir: &Path) -> RsaPrivateKey { } } -pub fn parse_config() -> Config { +pub fn parse_config() -> (Config, Vec<&'static str>) { let env = parse_env(); let config_yaml = std::fs::read_to_string(&env.config_path) .expect("failed to load config file"); let mut config = serde_yaml::from_str::(&config_yaml) .expect("invalid yaml data"); + let mut warnings = vec![]; + // Set parameters from environment config.config_path = env.config_path; if let Some(environment) = env.environment { @@ -109,8 +111,18 @@ pub fn parse_config() -> Config { panic!("both ipfs_api_url and ipfs_gateway_url must be set"); }; + if let Some(registrations_open) = config.registrations_open { + // Change type if 'registrations_open' parameter is used + warnings.push("'registrations_open' setting is deprecated, use 'registration' instead"); + if registrations_open { + config.registration.registration_type = RegistrationType::Open; + } else { + config.registration.registration_type = RegistrationType::Invite; + }; + }; + // Insert instance RSA key config.instance_rsa_key = Some(read_instance_rsa_key(&config.storage_dir)); - config + (config, warnings) } diff --git a/src/config/main.rs b/src/config/main.rs index f6529f7..14d4b4e 100644 --- a/src/config/main.rs +++ b/src/config/main.rs @@ -2,7 +2,11 @@ use std::path::PathBuf; use log::{Level as LogLevel}; use rsa::RsaPrivateKey; -use serde::Deserialize; +use serde::{ + Deserialize, + Deserializer, + de::Error as DeserializerError, +}; use url::Url; use crate::activitypub::constants::ACTOR_KEY_SUFFIX; @@ -14,6 +18,36 @@ use super::blockchain::BlockchainConfig; use super::environment::Environment; use super::MITRA_VERSION; +#[derive(Clone, PartialEq)] +pub enum RegistrationType { + Open, + Invite, +} + +impl Default for RegistrationType { + fn default() -> Self { Self::Invite } +} + +impl<'de> Deserialize<'de> for RegistrationType { + fn deserialize(deserializer: D) -> Result + where D: Deserializer<'de> + { + let registration_type_str = String::deserialize(deserializer)?; + let registration_type = match registration_type_str.as_str() { + "open" => Self::Open, + "invite" => Self::Invite, + _ => return Err(DeserializerError::custom("unknown registration type")), + }; + Ok(registration_type) + } +} + +#[derive(Clone, Default, Deserialize)] +pub struct RegistrationConfig { + #[serde(rename = "type")] + pub registration_type: RegistrationType, +} + fn default_log_level() -> LogLevel { LogLevel::Info } fn default_login_message() -> String { "Do not sign this message on other sites!".to_string() } @@ -52,8 +86,10 @@ pub struct Config { #[serde(skip)] pub(super) instance_rsa_key: Option, + pub(super) registrations_open: Option, // deprecated + #[serde(default)] - pub registrations_open: bool, // default is false + pub registration: RegistrationConfig, // EIP-4361 login message #[serde(default = "default_login_message")] diff --git a/src/config/mod.rs b/src/config/mod.rs index 7b4ca6d..ac75e8f 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -10,6 +10,6 @@ pub use blockchain::{ }; pub use environment::Environment; pub use loader::parse_config; -pub use main::{Config, Instance}; +pub use main::{Config, Instance, RegistrationType}; pub const MITRA_VERSION: &str = env!("CARGO_PKG_VERSION"); diff --git a/src/main.rs b/src/main.rs index c822f87..e7e0b22 100644 --- a/src/main.rs +++ b/src/main.rs @@ -39,9 +39,12 @@ use mitra::web_client::views as web_client; #[actix_web::main] async fn main() -> std::io::Result<()> { - let config = parse_config(); + let (config, config_warnings) = parse_config(); configure_logger(config.log_level); log::info!("config loaded from {}", config.config_path); + for warning in config_warnings { + log::warn!("{}", warning); + }; let db_pool = create_pool(&config.database_url); let mut db_client = get_database_client(&db_pool).await.unwrap(); diff --git a/src/mastodon_api/accounts/views.rs b/src/mastodon_api/accounts/views.rs index c77eae2..b66a134 100644 --- a/src/mastodon_api/accounts/views.rs +++ b/src/mastodon_api/accounts/views.rs @@ -12,7 +12,7 @@ use crate::activitypub::builders::{ prepare_update_person, }, }; -use crate::config::Config; +use crate::config::{Config, RegistrationType}; use crate::database::{get_database_client, DatabaseError, DbPool}; use crate::errors::{HttpError, ValidationError}; use crate::ethereum::contracts::ContractSet; @@ -111,7 +111,7 @@ pub async fn create_account( let db_client = &mut **get_database_client(&db_pool).await?; // Validate account_data.clean()?; - if !config.registrations_open { + if config.registration.registration_type == RegistrationType::Invite { let invite_code = account_data.invite_code.as_ref() .ok_or(ValidationError("invite code is required"))?; if !is_valid_invite_code(db_client, invite_code).await? { diff --git a/src/mastodon_api/instance/types.rs b/src/mastodon_api/instance/types.rs index 162040b..e8ba909 100644 --- a/src/mastodon_api/instance/types.rs +++ b/src/mastodon_api/instance/types.rs @@ -1,7 +1,12 @@ use serde::Serialize; use serde_json::{to_value, Value}; -use crate::config::{BlockchainConfig, Config, MITRA_VERSION}; +use crate::config::{ + BlockchainConfig, + Config, + RegistrationType, + MITRA_VERSION, +}; use crate::ethereum::contracts::ContractSet; use crate::mastodon_api::{ MASTODON_API_VERSION, @@ -139,9 +144,13 @@ impl InstanceInfo { description: markdown_to_html(&config.instance_description), description_source: config.instance_description.clone(), version: get_full_api_version(MITRA_VERSION), - registrations: config.registrations_open, + registrations: + config.registration.registration_type != + RegistrationType::Invite, approval_required: false, - invites_enabled: !config.registrations_open, + invites_enabled: + config.registration.registration_type == + RegistrationType::Invite, stats: InstanceStats { user_count, status_count: post_count, diff --git a/src/nodeinfo/types.rs b/src/nodeinfo/types.rs index c696c25..59365da 100644 --- a/src/nodeinfo/types.rs +++ b/src/nodeinfo/types.rs @@ -2,7 +2,7 @@ use serde::Serialize; -use crate::config::{Config, MITRA_VERSION}; +use crate::config::{Config, RegistrationType, MITRA_VERSION}; #[derive(Serialize)] struct Software { @@ -66,7 +66,9 @@ impl NodeInfo20 { software, protocols: vec!["activitypub".to_string()], services, - open_registrations: config.registrations_open, + open_registrations: + config.registration.registration_type != + RegistrationType::Invite, usage, metadata, }