nixos/mautrix-discord: Fix registration token generation (#451500)

This commit is contained in:
Guillaume Girol
2025-12-08 21:29:15 +00:00
committed by GitHub
2 changed files with 94 additions and 60 deletions
@@ -13,6 +13,7 @@ let
settingsFile = "${dataDir}/config.yaml";
settingsFileUnformatted = format.generate "discord-config-unsubstituted.yaml" cfg.settings;
default_token = "This value is generated when generating the registration";
in
{
options = {
@@ -415,66 +416,61 @@ in
rm -f '${settingsFile}'
old_umask=$(umask)
umask 0177
envsubst \
-o '${settingsFile}' \
-i '${settingsFileUnformatted}'
config_has_tokens=$(yq '.appservice | has("as_token") and has("hs_token")' '${settingsFile}')
registration_already_exists=$([[ -f '${registrationFile}' ]] && echo "true" || echo "false")
echo "There are tokens in the config: $config_has_tokens"
echo "Registration already existed: $registration_already_exists"
# tokens not configured from config/environment file, and registration file
# is already generated, override tokens in config to make sure they are not lost
if [[ $config_has_tokens == "false" && $registration_already_exists == "true" ]]; then
echo "Copying as_token, hs_token from registration into configuration"
yq -sY '.[0].appservice.as_token = .[1].as_token
| .[0].appservice.hs_token = .[1].hs_token
| .[0]' '${settingsFile}' '${registrationFile}' \
> '${settingsFile}.tmp'
envsubst -o '${settingsFile}' -i '${settingsFileUnformatted}'
# Check if config has tokens or uses defaults
as_token=$(yq -r '.appservice.as_token' '${settingsFile}')
hs_token=$(yq -r '.appservice.hs_token' '${settingsFile}')
config_has_tokens=$([[ "$as_token" != "${default_token}" && "$as_token" != "null" && "$hs_token" != "${default_token}" && "$hs_token" != "null" ]] && echo "true" || echo "false")
if [[ -f '${registrationFile}' ]]; then
registration_exists="true"
else
registration_exists="false"
fi
echo "Config has tokens: $config_has_tokens, Registration exists: $registration_exists"
# If config has default tokens but registration exists, restore tokens from registration
if [[ $config_has_tokens == "false" && $registration_exists == "true" ]]; then
echo "Restoring tokens from existing registration"
yq -sY '.[0].appservice.as_token = .[1].as_token | .[0].appservice.hs_token = .[1].hs_token | .[0]' \
'${settingsFile}' '${registrationFile}' > '${settingsFile}.tmp'
mv '${settingsFile}.tmp' '${settingsFile}'
fi
# make sure --generate-registration does not affect config.yaml
# If config has default tokens and no registration exists, generate new tokens
if [[ $config_has_tokens == "false" && $registration_exists == "false" ]]; then
echo "Generating new tokens for first-time setup"
# Generate random tokens (64 character alphanumeric strings)
new_as_token=$(LC_ALL=C tr -dc 'A-Za-z0-9' < /dev/urandom | head -c 64)
new_hs_token=$(LC_ALL=C tr -dc 'A-Za-z0-9' < /dev/urandom | head -c 64)
# Save generated tokens to config
yq -Y ".appservice.as_token = \"$new_as_token\" | .appservice.hs_token = \"$new_hs_token\"" \
'${settingsFile}' > '${settingsFile}.tmp'
mv '${settingsFile}.tmp' '${settingsFile}'
# Verify tokens were replaced
if [[ $(yq -r '.appservice.as_token' '${settingsFile}') == "${default_token}" ]]; then
echo "ERROR: Failed to replace default tokens"
exit 1
fi
echo "Successfully generated and saved new tokens"
fi
# Generate registration file with tokens from config
cp '${settingsFile}' '${settingsFile}.tmp'
echo "Generating registration file"
mautrix-discord \
--generate-registration \
--config='${settingsFile}.tmp' \
--registration='${registrationFile}'
mautrix-discord --generate-registration --config='${settingsFile}.tmp' --registration='${registrationFile}'
rm '${settingsFile}.tmp'
# no tokens configured, and new were just generated by generate registration for first time
if [[ $config_has_tokens == "false" && $registration_already_exists == "false" ]]; then
echo "Copying newly generated as_token, hs_token from registration into configuration"
yq -sY '.[0].appservice.as_token = .[1].as_token
| .[0].appservice.hs_token = .[1].hs_token
| .[0]' '${settingsFile}' '${registrationFile}' \
> '${settingsFile}.tmp'
mv '${settingsFile}.tmp' '${settingsFile}'
fi
# make sure --generate-registration does not affect config.yaml
cp '${settingsFile}' '${settingsFile}.tmp'
echo "Generating registration file"
mautrix-discord \
--generate-registration \
--config='${settingsFile}.tmp' \
--registration='${registrationFile}'
rm '${settingsFile}.tmp'
# no tokens configured, and new were just generated by generate registration for first time
if [[ $config_has_tokens == "false" && $registration_already_exists == "false" ]]; then
echo "Copying newly generated as_token, hs_token from registration into configuration"
yq -sY '.[0].appservice.as_token = .[1].as_token
| .[0].appservice.hs_token = .[1].hs_token
| .[0]' '${settingsFile}' '${registrationFile}' \
> '${settingsFile}.tmp'
mv '${settingsFile}.tmp' '${settingsFile}'
fi
# Make sure correct tokens are in the registration file
if [[ $config_has_tokens == "true" || $registration_already_exists == "true" ]]; then
echo "Copying as_token, hs_token from configuration to the registration file"
yq -sY '.[1].as_token = .[0].appservice.as_token
| .[1].hs_token = .[0].appservice.hs_token
| .[1]' '${settingsFile}' '${registrationFile}' \
> '${registrationFile}.tmp'
mv '${registrationFile}.tmp' '${registrationFile}'
fi
# Ensure registration file has the same tokens as config (mautrix-discord may regenerate them)
yq -sY '.[1].as_token = .[0].appservice.as_token | .[1].hs_token = .[0].appservice.hs_token | .[1]' \
'${settingsFile}' '${registrationFile}' > '${registrationFile}.tmp'
mv '${registrationFile}.tmp' '${registrationFile}'
umask $old_umask
chown :mautrix-discord-registration '${registrationFile}'
chmod 640 '${registrationFile}'
+43 -5
View File
@@ -1,4 +1,4 @@
{ pkgs, ... }:
{ pkgs, lib, ... }:
let
homeserverUrl = "http://homeserver:8008";
in
@@ -60,9 +60,8 @@ in
displayname = "Discord bridge bot";
avatar = "mxc://maunium.net/nIdEykemnwdisvHbpxflpDlC";
};
# These will be generated automatically
as_token = "generate";
hs_token = "generate";
# Don't override as_token/hs_token - let them use the default placeholder
# which will trigger automatic generation
database = {
type = "sqlite3";
@@ -86,6 +85,7 @@ in
environment.systemPackages = [
pkgs.nettools
pkgs.yq
];
};
@@ -156,7 +156,45 @@ in
with subtest("verify registration file was created"):
homeserver.wait_until_succeeds("test -f /var/lib/mautrix-discord/discord-registration.yaml")
homeserver.succeed("ls -la /var/lib/mautrix-discord/")
# Verify tokens were generated and are not default values
config_as_token = homeserver.succeed("yq -r '.appservice.as_token' /var/lib/mautrix-discord/config.yaml").strip()
config_hs_token = homeserver.succeed("yq -r '.appservice.hs_token' /var/lib/mautrix-discord/config.yaml").strip()
reg_as_token = homeserver.succeed("yq -r '.as_token' /var/lib/mautrix-discord/discord-registration.yaml").strip()
reg_hs_token = homeserver.succeed("yq -r '.hs_token' /var/lib/mautrix-discord/discord-registration.yaml").strip()
print(f"Config as_token: {config_as_token[:20]}...")
print(f"Config hs_token: {config_hs_token[:20]}...")
# Verify tokens are not the default placeholder or "generate"
assert config_as_token not in ["This value is generated when generating the registration", "generate"], \
f"Config as_token was not replaced: {config_as_token}"
assert config_hs_token not in ["This value is generated when generating the registration", "generate"], \
f"Config hs_token was not replaced: {config_hs_token}"
# Verify tokens match between config and registration
assert config_as_token == reg_as_token, \
f"as_token mismatch: config={config_as_token[:20]}... vs reg={reg_as_token[:20]}..."
assert config_hs_token == reg_hs_token, \
f"hs_token mismatch: config={config_hs_token[:20]}... vs reg={reg_hs_token[:20]}..."
print("Tokens generated and synchronized correctly")
with subtest("verify tokens persist after service restart"):
# Restart the registration service to simulate rebuild
homeserver.succeed("systemctl restart mautrix-discord-registration.service")
homeserver.wait_for_unit("mautrix-discord-registration.service")
# Verify tokens were preserved
config_as_token_2 = homeserver.succeed("yq -r '.appservice.as_token' /var/lib/mautrix-discord/config.yaml").strip()
config_hs_token_2 = homeserver.succeed("yq -r '.appservice.hs_token' /var/lib/mautrix-discord/config.yaml").strip()
assert config_as_token_2 == config_as_token, \
f"as_token changed after restart: {config_as_token[:20]}... -> {config_as_token_2[:20]}..."
assert config_hs_token_2 == config_hs_token, \
f"hs_token changed after restart: {config_hs_token[:20]}... -> {config_hs_token_2[:20]}..."
print("Tokens persisted correctly after restart")
with subtest("verify bridge connects to homeserver"):
# Give the bridge a moment to connect