Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/api/client/session/password.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ pub(super) async fn handle_login(

let lowercased_user_id = UserId::parse_with_server_name(
user_id.localpart().to_lowercase(),
&services.config.server_name,
user_id.server_name(),
)?;

let user_is_remote = !services.globals.user_is_local(&user_id)
Expand Down
25 changes: 25 additions & 0 deletions src/core/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,31 @@ pub struct Config {
#[cfg_attr(test, serde(default = "default_server_name"))]
pub server_name: OwnedServerName,

/// Alternate server names this homeserver is authoritative for. Users
/// with a Matrix ID on any of these domains can authenticate and use this
/// server, in addition to users on the primary `server_name`.
///
/// Each name must be a valid Matrix server name.
///
/// Alternate server names can be added after initialization, but should not
/// be removed while there exist accounts or appservice registrations using
/// that domain.
///
/// Each alternate domain must independently satisfy the Matrix
/// well-known/delegation requirements so that federation peers and clients
/// can resolve it to this server.
///
/// Note that servers providing the legacy registration endpoint can block
/// registration of users on alternate server names by including the full
/// User ID (e.g. "@user:example.com") or just the domain (e.g. ":example.com") in
/// `forbidden_usernames`.
///
/// example: ["legacy.example.com", "alias.example.org"]
///
/// default: []
#[serde(default)]
pub alternate_server_names: Vec<OwnedServerName>,

/// This is the only directory where tuwunel will save its data, including
/// media. Note: this was previously "/var/lib/matrix-conduit".
///
Expand Down
81 changes: 81 additions & 0 deletions src/main/tests/alternate_domains.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
#![cfg(test)]

use std::sync::Arc;

use tuwunel::{Args, Runtime, Server};
use tuwunel_core::{
Err, Result, ruma::
UserId
,
};
use tuwunel_service::Services;
use tuwunel_service::users::Register;


const PRIMARY: &str = "primary.example.test";
const ALT: &str = "alt.example.test";

fn alt_domain_user_id() -> &'static UserId {
"@bob:alt.example.test"
.try_into()
.expect("valid user id")
}

#[test]
fn alternate_server_names_register_login_message_federate() -> Result {
let mut args = Args::default_test(&["fresh", "cleanup"]);

args.option
.push(format!("server_name=\"{PRIMARY}\""));
args.option
.push(format!("alternate_server_names=[\"{ALT}\"]"));

args.maintenance = true;

let runtime = Runtime::new(Some(&args))?;
let server = Server::new(Some(&args), Some(&runtime))?;

let result: Result = runtime.block_on(async {
let services = tuwunel::async_start(&server).await?;

let outcome = run_tests(&services).await;

server.server.shutdown()?;
drop(services);
tuwunel::async_run(&server).await?;
tuwunel::async_stop(&server).await?;

outcome
});

drop(runtime);
result
}

async fn run_tests(services: &Arc<Services>) -> Result {
test_register(services).await?;
Ok(())
}

/// Test that an alternate-domain user can be registered.
async fn test_register(services: &Arc<Services>) -> Result {
let alternate_user_id = alt_domain_user_id();

services
.users
.full_register(Register {
user_id: Some(&alternate_user_id),
password: Some("alternateuserpassword"),
is_appservice: false,
is_guest: false,
grant_first_user_admin: false,
..Default::default()
})
.await?;

if !services.users.exists(alternate_user_id).await {
return Err!("({alternate_user_id}) was not found after registration");
}

Ok(())
}
6 changes: 6 additions & 0 deletions src/service/globals/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,12 @@ impl Service {
#[must_use]
pub fn server_is_ours(&self, server_name: &ServerName) -> bool {
server_name == self.server_name()
|| self
.server
.config
.alternate_server_names
.iter()
.any(|s| s == server_name)
}

#[inline]
Expand Down
6 changes: 3 additions & 3 deletions src/service/rooms/timeline/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,9 +160,9 @@ pub async fn build_and_append_pdu(
servers.insert(state_key_uid.server_name().to_owned());
}

// Remove our server from the server list since it will be added to it by
// room_servers() and/or the if statement above
servers.remove(self.services.globals.server_name());
// Remove all servers we are authoritative for from the federation list,
// since they will be added to it by room_servers() and/or the if statement above.
servers.retain(|s| !self.services.globals.server_is_ours(s));

self.services
.sending
Expand Down
23 changes: 23 additions & 0 deletions tuwunel-example.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,29 @@
#
#server_name =

# Alternate server names this homeserver is authoritative for. Users
# with a Matrix ID on any of these domains can authenticate and use this
# server, in addition to users on the primary `server_name`.
#
# Each name must be a valid Matrix server name.
#
# Alternate server names can be added after initialization, but should not
# be removed while there exist accounts or appservice registrations using
# that domain.
#
# Each alternate domain must independently satisfy the Matrix
# well-known/delegation requirements so that federation peers and clients
# can resolve it to this server.
#
# Note that servers providing the legacy registration endpoint can block
# registration of users on alternate server names by including the full
# User ID (e.g. "@user:example.com") or just the domain (e.g. ":example.com") in
# `forbidden_usernames`.
#
# example: ["legacy.example.com", "alias.example.org"]
#
#alternate_server_names = []

# This is the only directory where tuwunel will save its data, including
# media. Note: this was previously "/var/lib/matrix-conduit".
#
Expand Down