Update changes

This commit is contained in:
Sangye Ince-Johannsen 2025-03-28 15:56:25 +00:00
parent 58824418f3
commit e387d056e8
10 changed files with 719 additions and 39 deletions

5
.gitignore vendored
View file

@ -29,12 +29,15 @@ Thumbs.db
.classpath
# Project-specific sensitive files
*.txt
.registration_token
config.yaml
registrations.json
banned_emails.txt
banned_ips.txt
refresh_token.shbanned_usernames.txt
refresh_token.sh
banned_usernames.txt
testbench/
# Backup directories
backup/

332
canary.py Normal file
View file

@ -0,0 +1,332 @@
#!/usr/bin/env python3
import yaml
import requests
import feedparser
import datetime
import subprocess
import json
import os
import sys
import asyncio
from time import sleep
from pathlib import Path
# File paths
CONFIG_FILE = "config.yaml"
OUTPUT_FILE = "canary.txt"
TEMP_MESSAGE_FILE = "temp_canary_message.txt"
# Possible attestations
ATTESTATIONS = [
"We have not received any National Security Letters.",
"We have not received any court orders under the Foreign Intelligence Surveillance Act.",
"We have not received any gag orders that prevent us from stating we have received legal process.",
"We have not been required to modify our systems to facilitate surveillance.",
"We have not been subject to any searches or seizures of our servers."
]
def load_config():
"""Load configuration from YAML file."""
try:
if not os.path.exists(CONFIG_FILE):
print(f"Error: Configuration file '{CONFIG_FILE}' not found.")
print("Please create a configuration file with the following structure:")
print("""
gpg:
key_id: YOUR_GPG_KEY_ID
matrix:
enabled: true
homeserver: https://we2.ee
username: @canary:we2.ee
password: YOUR_PASSWORD
room_id: !l7XTTF6tudReoEJEvr:we2.ee
""")
sys.exit(1)
with open(CONFIG_FILE, 'r') as file:
config = yaml.safe_load(file)
# Check for required fields
required_fields = [
('gpg', 'key_id')
]
for section, field in required_fields:
if section not in config or field not in config[section]:
print(f"Error: Required configuration field '{section}.{field}' is missing.")
sys.exit(1)
return config
except Exception as e:
print(f"Error loading configuration: {e}")
sys.exit(1)
def get_current_date():
"""Return the current date in YYYY-MM-DD format."""
return datetime.datetime.now().strftime("%Y-%m-%d")
def get_nist_time():
"""Get the current time from NIST time server."""
try:
response = requests.get("https://timeapi.io/api/Time/current/zone?timeZone=UTC", timeout=10)
if response.status_code == 200:
time_data = response.json()
return f"{time_data['dateTime']} UTC"
else:
print(f"Error fetching NIST time: HTTP {response.status_code}")
return None
except Exception as e:
print(f"Error fetching NIST time: {e}")
return None
def get_democracy_now_headline():
"""Get the latest headline from Democracy Now! RSS feed."""
try:
feed = feedparser.parse("https://www.democracynow.org/democracynow.rss")
if feed.entries and len(feed.entries) > 0:
return feed.entries[0].title
else:
print("No entries found in Democracy Now! RSS feed")
return None
except Exception as e:
print(f"Error fetching Democracy Now! headline: {e}")
return None
def get_bitcoin_latest_block():
"""Get the latest Bitcoin block hash and number."""
try:
response = requests.get("https://blockchain.info/latestblock", timeout=10)
if response.status_code == 200:
data = response.json()
# Get block details
block_response = requests.get(f"https://blockchain.info/rawblock/{data['hash']}", timeout=10)
if block_response.status_code == 200:
block_data = block_response.json()
return {
"height": data["height"],
"hash": data["hash"],
"time": datetime.datetime.fromtimestamp(block_data["time"]).strftime("%Y-%m-%d %H:%M:%S UTC")
}
print(f"Error fetching Bitcoin block: HTTP {response.status_code}")
return None
except Exception as e:
print(f"Error fetching Bitcoin block data: {e}")
return None
def collect_attestations():
"""Prompt user for each attestation."""
selected_attestations = []
print("\nPlease confirm each attestation separately:")
for i, attestation in enumerate(ATTESTATIONS, 1):
while True:
response = input(f"Confirm attestation {i}: '{attestation}' (y/n): ").lower()
if response in ['y', 'n']:
break
print("Please answer 'y' or 'n'.")
if response == 'y':
selected_attestations.append(attestation)
return selected_attestations
def create_warrant_canary_message(config):
"""Create the warrant canary message with attestations and verification elements."""
current_date = get_current_date()
nist_time = get_nist_time()
democracy_now_headline = get_democracy_now_headline()
bitcoin_block = get_bitcoin_latest_block()
# Check if all required elements are available
if not all([nist_time, democracy_now_headline, bitcoin_block]):
missing = []
if not nist_time: missing.append("NIST time")
if not democracy_now_headline: missing.append("Democracy Now! headline")
if not bitcoin_block: missing.append("Bitcoin block data")
print(f"Error: Could not fetch: {', '.join(missing)}")
return None
# Collect attestations from user
attestations = collect_attestations()
if not attestations:
print("Warning: No attestations were confirmed.")
proceed = input("Do you want to proceed without any attestations? (y/n): ").lower()
if proceed != 'y':
print("Operation cancelled")
return None
# Create the message
message = f"""We2.ee Warrant Canary
Date: {current_date}
"""
# Add attestations
for i, attestation in enumerate(attestations, 1):
message += f"{i}. {attestation}\n"
message += f"""
Proofs:
NIST time: {nist_time}
Democracy Now! headline: "{democracy_now_headline}"
Bitcoin block #{bitcoin_block['height']} hash: {bitcoin_block['hash']}
Bitcoin block time: {bitcoin_block['time']}
"""
return message
def sign_with_gpg(message, gpg_key_id):
"""Sign the warrant canary message with GPG."""
try:
# Write message to temporary file
with open(TEMP_MESSAGE_FILE, "w") as f:
f.write(message)
# Sign the message with GPG
cmd = ["gpg", "--clearsign", "--default-key", gpg_key_id, TEMP_MESSAGE_FILE]
subprocess.run(cmd, check=True)
# Read the signed message
with open(f"{TEMP_MESSAGE_FILE}.asc", "r") as f:
signed_message = f.read()
# Clean up temporary files
os.remove(TEMP_MESSAGE_FILE)
os.remove(f"{TEMP_MESSAGE_FILE}.asc")
return signed_message
except subprocess.CalledProcessError as e:
print(f"GPG signing error: {e}")
return None
except Exception as e:
print(f"Error during GPG signing: {e}")
return None
def save_warrant_canary(signed_message):
"""Save the signed warrant canary to a file."""
try:
with open(OUTPUT_FILE, "w") as f:
f.write(signed_message)
print(f"Warrant canary saved to {OUTPUT_FILE}")
return True
except Exception as e:
print(f"Error saving warrant canary: {e}")
return False
async def post_to_matrix(config, signed_message):
"""Post the signed warrant canary to Matrix room using nio library."""
if not config.get('matrix', {}).get('enabled', False):
print("Matrix posting is disabled in config")
return False
try:
from nio import AsyncClient, LoginResponse
# Get Matrix config
homeserver = config['matrix']['homeserver']
username = config['matrix']['username']
password = config['matrix']['password']
room_id = config['matrix']['room_id']
# Extract username without domain for login
user_id = username
if username.startswith('@'):
user_id = username[1:] # Remove @ prefix
if ':' in user_id:
user_id = user_id.split(':')[0] # Remove server part
# Create client
client = AsyncClient(homeserver, username)
# Login
print(f"Logging in as {username} on {homeserver}...")
response = await client.login(password)
if isinstance(response, LoginResponse):
print("Login successful")
else:
print(f"Matrix login failed: {response}")
await client.close()
return False
# Format message for Matrix
print(f"Posting canary to room {room_id}...")
try:
# Use HTML formatting for the message
content = {
"msgtype": "m.text",
"body": signed_message, # Plain text version
"format": "org.matrix.custom.html",
"formatted_body": f"<pre>{signed_message}</pre>" # HTML version with preformatted text
}
response = await client.room_send(
room_id=room_id,
message_type="m.room.message",
content=content
)
print("Successfully posted warrant canary to Matrix room")
except Exception as e:
print(f"Error sending message: {e}")
await client.close()
return False
# Logout and close
await client.logout()
await client.close()
return True
except ImportError:
print("Error: matrix-nio library not installed. Install with: pip install matrix-nio")
return False
except Exception as e:
print(f"Error posting to Matrix: {e}")
return False
def main():
print("Generating We2.ee warrant canary...")
# Load configuration
config = load_config()
gpg_key_id = config['gpg']['key_id']
# Create message
message = create_warrant_canary_message(config)
if not message:
print("Failed to create warrant canary message")
sys.exit(1)
# Display the message
print("\nWarrant Canary Message Preview:")
print("-" * 50)
print(message)
print("-" * 50)
# Confirm with user
user_input = input("\nDo you want to sign this message with GPG? (y/n): ")
if user_input.lower() != 'y':
print("Operation cancelled")
sys.exit(0)
# Sign and save
signed_message = sign_with_gpg(message, gpg_key_id)
if not signed_message:
print("Failed to sign warrant canary message")
sys.exit(1)
if save_warrant_canary(signed_message):
print("Warrant canary generated successfully!")
else:
print("Failed to save warrant canary")
sys.exit(1)
# Post to Matrix if enabled
if config.get('matrix', {}).get('enabled', False):
post_to_matrix_input = input("\nDo you want to post the warrant canary to Matrix? (y/n): ")
if post_to_matrix_input.lower() == 'y':
asyncio.run(post_to_matrix(config, signed_message))
if __name__ == "__main__":
main()

34
canary.txt Normal file
View file

@ -0,0 +1,34 @@
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512
We2.ee Warrant Canary
Date: 2025-03-27
1. We have not received any National Security Letters.
2. We have not received any court orders under the Foreign Intelligence Surveillance Act.
3. We have not received any gag orders that prevent us from stating we have received legal process.
4. We have not been required to modify our systems to facilitate surveillance.
5. We have not been subject to any searches or seizures of our servers.
Proofs:
NIST time: 2025-03-27T00:32:57.229589 UTC
Democracy Now! headline: "1,400+ Arrested in Turkey as Erdoğan Jails Istanbul Mayor & Intensifies Authoritarian Crackdown"
Bitcoin block #889596 hash: 000000000000000000018c38ea9043fd8710fa40d1cf90d5e541d050cd22b89d
Bitcoin block time: 2025-03-26 23:49:42 UTC
-----BEGIN PGP SIGNATURE-----
iQIzBAEBCgAdFiEEMjqKLEezdiJLNhO3U1smWu2+W0QFAmfknNcACgkQU1smWu2+
W0RrlxAAinoE3ZsIKAEpt/qzKygQyUx06VozLL82wzLPQrICia+jOkzo6UHuYGmY
to4sj4SIOBaEyrdIhLvPG7Q6QRnrbn7NVasawRD484KsiO1+caPrnROFKJWyW/II
UNlAnmOCxGttu14SlKYPpgp/a6LnLQtciNTHEsj6A0i/JgP1kAPRjqOiM0UCXTKf
2MnNgwHHdjJt3f7AVJewzw5EPsW9ouh7VcIiIu9kZeuGotf0Gux5R8iTg9j2Cpum
FrsHhdfwgyFFasTtp+sTnsWvmtw86OpIYuqPpopkIe70e3w4m/+C7ybejqNiNlWh
1HCcFSyP17B6d516BCAKDJlrmCEKEQVz9MkTrqjpEKpZrVzo6Rl9bxQgN0QrohjV
buUQO9Zyu6Xl7BZSD4qPqGgGeTzRt8pi4BTWtrMMs+JKTel4TimzPONqLh8exYBa
Go5uDsbOAwnzbK/0VF9KIYqHc2t9pP5IgtUF3HGVZ0IputxTeDCF3uYJMiwO52cK
XWaSvSlXB+Nc6OIjHHxG35hflk4ch8ZSEchp8OmXIYiy0zC640YwnnAnosg1WCOA
UAeEvTO+QGyN7uP4rzGn9rtZgyoj5WT9GYGaiHFxrToCo9o3npOOQBAumcXLvP+B
6Wkd0RKajppKCVEtEKH0/aH57YGC9V5XdZ9o0aa1yDLpWXw7Ag8=
=5ZtT
-----END PGP SIGNATURE-----

133
cleanup.py Normal file
View file

@ -0,0 +1,133 @@
import os
import json
import yaml
import httpx
import logging
from typing import List, Dict
from datetime import datetime, timedelta
# Setup logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)
# Load paths and config
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
CONFIG_PATH = os.path.join(BASE_DIR, "config.yaml")
REGISTRATIONS_PATH = os.path.join(BASE_DIR, "registrations.json")
def load_config() -> dict:
"""Load configuration from yaml file."""
with open(CONFIG_PATH, "r") as f:
return yaml.safe_load(f)
def load_registrations() -> List[Dict]:
"""Load current registrations from JSON file."""
try:
with open(REGISTRATIONS_PATH, "r") as f:
return json.load(f)
except (FileNotFoundError, json.JSONDecodeError):
return []
def save_registrations(registrations: List[Dict]):
"""Save updated registrations back to JSON file."""
with open(REGISTRATIONS_PATH, "w") as f:
json.dump(registrations, f, indent=2)
async def check_username_exists(username: str, homeserver: str) -> bool:
"""
Check if a username exists on the Matrix server.
Returns True if the username exists, False otherwise.
"""
url = f"https://{homeserver}/_matrix/client/v3/register/available?username={username}"
async with httpx.AsyncClient() as client:
try:
response = await client.get(url, timeout=5)
if response.status_code == 200:
# 200 OK with available=true means username exists
return response.json().get("available", False)
elif response.status_code == 400:
# 400 Bad Request means username is not available
return False
except httpx.RequestError as ex:
logger.error(f"Error checking username {username}: {ex}")
return False
return False
async def cleanup_registrations(min_age_hours: int = 24):
"""
Clean up registrations by removing entries for usernames that don't exist on the server,
but only if they're older than min_age_hours.
Never removes entries for existing Matrix users regardless of age.
"""
config = load_config()
registrations = load_registrations()
if not registrations:
logger.info("No registrations found to clean up")
return
logger.info(f"Starting cleanup of {len(registrations)} registrations")
logger.info(f"Will only remove non-existent users registered more than {min_age_hours} hours ago")
# Track which entries to keep
entries_to_keep = []
removed_count = 0
too_new_count = 0
exists_count = 0
current_time = datetime.utcnow()
for entry in registrations:
username = entry["requested_name"]
reg_date = datetime.fromisoformat(entry["datetime"])
age = current_time - reg_date
# First check if the user exists on Matrix
exists = await check_username_exists(username, config["homeserver"])
if exists:
# Always keep entries for existing Matrix users
entries_to_keep.append(entry)
exists_count += 1
logger.info(f"Keeping registration for existing user: {username}")
continue
# For non-existent users, check if they're old enough to remove
if age < timedelta(hours=min_age_hours):
# Keep young entries even if user doesn't exist yet
entries_to_keep.append(entry)
too_new_count += 1
logger.info(f"Keeping recent registration: {username} (age: {age.total_seconds()/3600:.1f} hours)")
else:
# Remove old entries where user doesn't exist
logger.info(f"Removing old registration: {username} (age: {age.total_seconds()/3600:.1f} hours)")
removed_count += 1
# Save updated registrations
save_registrations(entries_to_keep)
logger.info(f"Cleanup complete:")
logger.info(f"- Kept {exists_count} entries for existing Matrix users")
logger.info(f"- Kept {too_new_count} entries younger than {min_age_hours} hours")
logger.info(f"- Removed {removed_count} old entries for non-existent users")
logger.info(f"- Total remaining entries: {len(entries_to_keep)}")
if __name__ == "__main__":
import asyncio
import argparse
parser = argparse.ArgumentParser(description="Clean up Matrix registration entries")
parser.add_argument(
"--min-age-hours",
type=int,
default=24,
help="Minimum age in hours before removing non-existent users (default: 24)"
)
args = parser.parse_args()
asyncio.run(cleanup_registrations(args.min_age_hours))

74
conduwuit_logs.txt Normal file
View file

@ -0,0 +1,74 @@
2025-03-24T04:11:24.174302Z  WARN conduwuit_core::config::check: Config parameter "log_level" is unknown to conduwuit, ignoring.
2025-03-24T04:11:24.174516Z  INFO conduwuit::server: 0.5.0 (b6e9dc3) server_name=we2.ee database_path="/var/lib/conduwuit/conduwuit.db" log_levels=info
2025-03-24T04:11:24.999106Z  INFO main:start:open: conduwuit_database::engine::open: Opened database. columns=87 sequence=1216675526 time=788.193091ms
2025-03-24T04:11:25.232053Z  INFO main:start: conduwuit_service::migrations: Loaded RocksDB database with schema version 17
2025-03-24T04:11:25.625176Z  INFO conduwuit_router::serve::plain: Listening on [0.0.0.0:8008]
2025-03-24T04:11:25.690807Z ERROR conduwuit_service::sending::sender: Missing pusher, user_id: "@sij:we2.ee", pushkey: "SlcxERw6XkNKx6Vu2GR4F4U1cvf98nyBM/Q6MIZ9TJg="
at src/service/sending/sender.rs:761 on conduwuit:worker ThreadId(3)
in conduwuit_service::sending::sender::push with user_id="@sij:we2.ee" pushkey="SlcxERw6XkNKx6Vu2GR4F4U1cvf98nyBM/Q6MIZ9TJg=" events=1
2025-03-24T04:11:25.696119Z ERROR conduwuit_service::sending::sender: Missing pusher, user_id: "@tomasz:we2.ee", pushkey: "https://ntfy.schildi.chat/up66QHbupxHL1u?up=1"
at src/service/sending/sender.rs:761 on conduwuit:worker ThreadId(7)
in conduwuit_service::sending::sender::push with user_id="@tomasz:we2.ee" pushkey="https://ntfy.schildi.chat/up66QHbupxHL1u?up=1" events=1
2025-03-24T04:11:25.724057Z ERROR conduwuit_service::sending::sender: Missing pusher, user_id: "@tomasz:we2.ee", pushkey: "https://ntfy.schildi.chat/upd06nnOhELBFx?up=1"
at src/service/sending/sender.rs:761 on conduwuit:worker ThreadId(14)
in conduwuit_service::sending::sender::push with user_id="@tomasz:we2.ee" pushkey="https://ntfy.schildi.chat/upd06nnOhELBFx?up=1" events=1
2025-03-24T04:11:25.806002Z ERROR conduwuit_service::sending::sender: Missing pusher, user_id: "@tomasz:we2.ee", pushkey: "https://ntfy.schildi.chat/upclfCDJ0va5d9?up=1"
at src/service/sending/sender.rs:761 on conduwuit:worker ThreadId(7)
in conduwuit_service::sending::sender::push with user_id="@tomasz:we2.ee" pushkey="https://ntfy.schildi.chat/upclfCDJ0va5d9?up=1" events=1
2025-03-24T04:11:25.835727Z ERROR conduwuit_service::sending::sender: Missing pusher, user_id: "@sij:we2.ee", pushkey: "M8ltVIFwxX/M1kKNuCGB7tQWAYppEJO6dkdY0JHJEvg="
at src/service/sending/sender.rs:761 on conduwuit:worker ThreadId(14)
in conduwuit_service::sending::sender::push with user_id="@sij:we2.ee" pushkey="M8ltVIFwxX/M1kKNuCGB7tQWAYppEJO6dkdY0JHJEvg=" events=1
2025-03-24T04:11:25.910755Z ERROR conduwuit_service::sending::sender: Missing pusher, user_id: "@tomasz:we2.ee", pushkey: "https://ntfy.schildi.chat/upkzMxi8WiQ5U5?up=1"
at src/service/sending/sender.rs:761 on conduwuit:worker ThreadId(14)
in conduwuit_service::sending::sender::push with user_id="@tomasz:we2.ee" pushkey="https://ntfy.schildi.chat/upkzMxi8WiQ5U5?up=1" events=1
2025-03-24T04:11:25.912156Z ERROR conduwuit_service::sending::sender: Missing pusher, user_id: "@sij:we2.ee", pushkey: "ly2ipat4bxsv/fQ0TRswYlU9zD5yhVb9mnrQ2NZ5e1A="
at src/service/sending/sender.rs:761 on conduwuit:worker ThreadId(14)
in conduwuit_service::sending::sender::push with user_id="@sij:we2.ee" pushkey="ly2ipat4bxsv/fQ0TRswYlU9zD5yhVb9mnrQ2NZ5e1A=" events=1
2025-03-24T04:11:25.933229Z ERROR conduwuit_service::sending::sender: Missing pusher, user_id: "@tomasz:we2.ee", pushkey: "https://ntfy.schildi.chat/upfxUUwV0ecpTR?up=1"
at src/service/sending/sender.rs:761 on conduwuit:worker ThreadId(7)
in conduwuit_service::sending::sender::push with user_id="@tomasz:we2.ee" pushkey="https://ntfy.schildi.chat/upfxUUwV0ecpTR?up=1" events=1
2025-03-24T04:11:26.118584Z ERROR conduwuit_service::sending::sender: Missing pusher, user_id: "@tomasz:we2.ee", pushkey: "https://ntfy.schildi.chat/upxH2vJWhUrLsD?up=1"
at src/service/sending/sender.rs:761 on conduwuit:worker ThreadId(14)
in conduwuit_service::sending::sender::push with user_id="@tomasz:we2.ee" pushkey="https://ntfy.schildi.chat/upxH2vJWhUrLsD?up=1" events=1
2025-03-24T04:11:26.206792Z ERROR conduwuit_service::sending::sender: Missing pusher, user_id: "@tomasz:we2.ee", pushkey: "https://ntfy.sh/up4KrJgOMfmGxD?up=1"
at src/service/sending/sender.rs:761 on conduwuit:worker ThreadId(7)
in conduwuit_service::sending::sender::push with user_id="@tomasz:we2.ee" pushkey="https://ntfy.sh/up4KrJgOMfmGxD?up=1" events=1
2025-03-24T04:11:26.488520Z ERROR conduwuit_service::sending::sender: Missing pusher, user_id: "@tomasz:we2.ee", pushkey: "https://ntfy.schildi.chat/up2nJSKdtIoisj?up=1"
at src/service/sending/sender.rs:761 on conduwuit:worker ThreadId(14)
in conduwuit_service::sending::sender::push with user_id="@tomasz:we2.ee" pushkey="https://ntfy.schildi.chat/up2nJSKdtIoisj?up=1" events=1
2025-03-24T04:11:26.528252Z ERROR conduwuit_service::sending::sender: Missing pusher, user_id: "@sij:we2.ee", pushkey: "TjhzIT+QrIPqAAdaxzmfxtraX3xlYN9CRx3T8snGJsY="
at src/service/sending/sender.rs:761 on conduwuit:worker ThreadId(14)
in conduwuit_service::sending::sender::push with user_id="@sij:we2.ee" pushkey="TjhzIT+QrIPqAAdaxzmfxtraX3xlYN9CRx3T8snGJsY=" events=1
2025-03-24T04:11:26.898903Z ERROR conduwuit_service::sending::sender: Missing pusher, user_id: "@sij:we2.ee", pushkey: "kVAJHyqTY6nD3fXuMOz5uFQy11KF6nNw9jzZT9vH8lc="
at src/service/sending/sender.rs:761 on conduwuit:worker ThreadId(2)
in conduwuit_service::sending::sender::push with user_id="@sij:we2.ee" pushkey="kVAJHyqTY6nD3fXuMOz5uFQy11KF6nNw9jzZT9vH8lc=" events=1
2025-03-24T04:11:26.905588Z ERROR conduwuit_service::sending::sender: Missing pusher, user_id: "@oddlid:we2.ee", pushkey: "oUT1KtxnLMQxuG7otnPxZlY28ZFP7dyC0B3LQlQJm70="
at src/service/sending/sender.rs:761 on conduwuit:worker ThreadId(7)
in conduwuit_service::sending::sender::push with user_id="@oddlid:we2.ee" pushkey="oUT1KtxnLMQxuG7otnPxZlY28ZFP7dyC0B3LQlQJm70=" events=1
2025-03-24T04:11:27.008417Z ERROR conduwuit_service::sending::sender: Missing pusher, user_id: "@sij:we2.ee", pushkey: "yBBcAp+lJHry3qIkOnjtuXQ+fvXsmOqIJT3s+723Wf0="
at src/service/sending/sender.rs:761 on conduwuit:worker ThreadId(7)
in conduwuit_service::sending::sender::push with user_id="@sij:we2.ee" pushkey="yBBcAp+lJHry3qIkOnjtuXQ+fvXsmOqIJT3s+723Wf0=" events=1
2025-03-24T04:11:27.111117Z ERROR conduwuit_service::sending::sender: Missing pusher, user_id: "@coldsideofyourpillow:we2.ee", pushkey: "https://updates.push.services.mozilla.com/wpush/v1/gAAAAABngkOarCdQHaOOcbWvEq2NRTaqanvveX2x7tORFgnhjomYiTMOjaPw9zTrQVe8ConiPBHKvNAMd96-jLQURG5Q83zk1d3lT2mPW6ek6MatC7-f3ipoxJC-8hwiXLtARI5WfNl-"
at src/service/sending/sender.rs:761 on conduwuit:worker ThreadId(2)
in conduwuit_service::sending::sender::push with user_id="@coldsideofyourpillow:we2.ee" pushkey="https://updates.push.services.mozilla.com/wpush/v1/gAAAAABngkOarCdQHaOOcbWvEq2NRTaqanvveX2x7tORFgnhjomYiTMOjaPw9zTrQVe8ConiPBHKvNAMd96-jLQURG5Q83zk1d3lT2mPW6ek6MatC7-f3ipoxJC-8hwiXLtARI5WfNl-" events=1
2025-03-24T04:11:27.141576Z ERROR conduwuit_service::sending::sender: Missing pusher, user_id: "@tomasz:we2.ee", pushkey: "https://ntfy.schildi.chat/upqkpYOQT8t3jd?up=1"
at src/service/sending/sender.rs:761 on conduwuit:worker ThreadId(14)
in conduwuit_service::sending::sender::push with user_id="@tomasz:we2.ee" pushkey="https://ntfy.schildi.chat/upqkpYOQT8t3jd?up=1" events=1
2025-03-24T04:11:36.014821Z  WARN hickory_proto::udp::udp_client_stream: expected message id: 35283 got: 31381, dropped

View file

@ -6,29 +6,21 @@ TOKEN_FILE="$BASE_PATH/.registration_token"
LOG_FILE="$BASE_PATH/token_refresh.log"
BACKUP_PATH="/home/sij/conduwuit_backup"
# Server configuration
# Server/domain info
SERVER_DOMAIN="we2.ee"
HOST_PORT=8448
CONTAINER_PORT=6167
CONTAINER_NAME="conduwuit"
CONTAINER_IMAGE="ghcr.io/girlbossceo/conduwuit:v0.5.0-rc3-b6e9dc3d98704c56027219d3775336910a0136c6"
# Performance tuning
DB_READ_CACHE_MB=16384 # 16GB for read cache
DB_WRITE_BUFFER_MB=2048 # 2GB write buffer
CACHE_MODIFIER=4.0 # 4x default LRU caches
DB_POOL_WORKERS=128 # Optimized for NVMe
STREAM_WIDTH_SCALE=2.0 # Concurrent operations scaling
STREAM_AMPLIFICATION=4096 # Batch size for operations
MAX_REQUEST_SIZE=104857600 # 100MB uploads
BLURHASH_MAX_SIZE=134217728 # 128MB for blurhash processing
CONTAINER_IMAGE="conduwuit:custom"
ADDRESS='["0.0.0.0", "::"]'
PORT=8008
# Auto-join room configuration
AUTO_JOIN_ROOMS="[\"#pub:$SERVER_DOMAIN\",\"#home:$SERVER_DOMAIN\"]"
AUTO_JOIN_ROOMS='["#server:we2.ee"]'
# Function to log with timestamp
# Function to log with timestamp to both file and terminal
log() {
echo "$(date --iso-8601=seconds) $1" >> "$LOG_FILE"
local message="$(date --iso-8601=seconds) $1"
echo "$message" >> "$LOG_FILE" # Write to log file
echo "$message" # Print to terminal
}
# Generate new token (6 random hex characters)
@ -43,13 +35,13 @@ fi
log "Generated new registration token"
# Recreate conduwuit container
docker stop $CONTAINER_NAME
docker rm $CONTAINER_NAME
# Stop and remove existing container
docker stop "$CONTAINER_NAME" 2>/dev/null
docker rm "$CONTAINER_NAME" 2>/dev/null
# Launch new container
docker run -d \
-p 0.0.0.0:${HOST_PORT}:${CONTAINER_PORT} \
-v db:/var/lib/conduwuit/ \
-v "db:/var/lib/conduwuit/" \
-v "${TOKEN_FILE}:/.registration_token:ro" \
-v "${BACKUP_PATH}:/backup" \
-e CONDUWUIT_SERVER_NAME="$SERVER_DOMAIN" \
@ -57,28 +49,44 @@ docker run -d \
-e CONDUWUIT_DATABASE_BACKUP_PATH="/backup" \
-e CONDUWUIT_ALLOW_REGISTRATION=true \
-e CONDUWUIT_REGISTRATION_TOKEN_FILE="/.registration_token" \
-e CONDUWUIT_PORT=$CONTAINER_PORT \
-e CONDUWUIT_ADDRESS="0.0.0.0" \
-e CONDUWUIT_ADDRESS="$ADDRESS" \
-e CONDUWUIT_PORT="$PORT" \
-e CONDUWUIT_NEW_USER_DISPLAYNAME_SUFFIX="" \
-e CONDUWUIT_AUTO_JOIN_ROOMS="$AUTO_JOIN_ROOMS" \
-e CONDUWUIT_FORGET_FORCED_UPON_LEAVE=true \
-e CONDUWUIT_DB_CACHE_CAPACITY_MB=1024 \
-e CONDUWUIT_DB_WRITE_BUFFER_CAPACITY_MB=256 \
-e CONDUWUIT_DB_POOL_WORKERS=64 \
-e CONDUWUIT_DB_POOL_WORKERS_LIMIT=128 \
-e CONDUWUIT_STREAM_AMPLIFICATION=8192 \
-e CONDUWUIT_MAX_REQUEST_SIZE=33554432 \
-e CONDUWUIT_CACHE_CAPACITY_MODIFIER=1.5 \
-e CONDUWUIT_ALLOW_FEDERATION=true \
-e CONDUWUIT_ALLOW_PUBLIC_ROOM_DIRECTORY_OVER_FEDERATION=true \
-e CONDUWUIT_ALLOW_PUBLIC_ROOM_DIRECTORY_WITHOUT_AUTH=true \
-e CONDUWUIT_ALLOW_FEDERATION=true \
-e CONDUWUIT_AUTO_JOIN_ROOMS="$AUTO_JOIN_ROOMS" \
-e CONDUWUIT_DB_CACHE_CAPACITY_MB=$DB_READ_CACHE_MB \
-e CONDUWUIT_DB_WRITE_BUFFER_CAPACITY_MB=$DB_WRITE_BUFFER_MB \
-e CONDUWUIT_CACHE_CAPACITY_MODIFIER=$CACHE_MODIFIER \
-e CONDUWUIT_DB_POOL_WORKERS=$DB_POOL_WORKERS \
-e CONDUWUIT_STREAM_WIDTH_SCALE=$STREAM_WIDTH_SCALE \
-e CONDUWUIT_STREAM_AMPLIFICATION=$STREAM_AMPLIFICATION \
-e CONDUWUIT_MAX_REQUEST_SIZE=$MAX_REQUEST_SIZE \
-e CONDUWUIT_BLURHASH_MAX_RAW_SIZE=$BLURHASH_MAX_SIZE \
--name $CONTAINER_NAME \
-e CONDUWUIT_WELL_KNOWN_CONN_TIMEOUT=30 \
-e CONDUWUIT_FEDERATION_TIMEOUT=600 \
-e CONDUWUIT_FEDERATION_IDLE_TIMEOUT=60 \
-e CONDUWUIT_SENDER_TIMEOUT=600 \
-e CONDUWUIT_SENDER_IDLE_TIMEOUT=360 \
-e CONDUWUIT_SENDER_SHUTDOWN_TIMEOUT=30 \
-e CONDUWUIT_DNS_CACHE_ENTRIES=1000 \
-e CONDUWUIT_DNS_MIN_TTL=300 \
-e CONDUWUIT_DNS_MIN_TTL_NXDOMAIN=600 \
-e CONDUWUIT_DNS_TCP_FALLBACK=true \
-e CONDUWUIT_IP_LOOKUP_STRATEGY=3 \
-e RUST_LOG="conduwuit=trace,reqwest=trace,hickory_proto=trace" \
--network host \
--name "$CONTAINER_NAME" \
--restart unless-stopped \
$CONTAINER_IMAGE
"$CONTAINER_IMAGE"
if [ $? -ne 0 ]; then
log "ERROR: Failed to create new conduwuit container"
exit 1
fi
log "Successfully recreated conduwuit container with new token"
log "Successfully recreated container \"$CONTAINER_NAME\" with image \"$CONTAINER_IMAGE\" and these parameters:"
log " - domain: $SERVER_DOMAIN"
log " - address: $ADDRESS"
log " - port: $PORT"
log " - auto-join rooms: $AUTO_JOIN_ROOMS"

View file

@ -368,6 +368,8 @@ async def register(
raise HTTPException(status_code=500, detail="Registration token file not found.")
time_until_reset = get_time_until_reset_str(now)
# Plain text email body
email_body = config["email_body"].format(
homeserver=config["homeserver"],
registration_token=token,
@ -375,9 +377,23 @@ async def register(
utc_time=now.strftime("%H:%M:%S"),
time_until_reset=time_until_reset
)
# HTML email body
email_body_html = config.get("email_body_html", "").format(
homeserver=config["homeserver"],
registration_token=token,
requested_username=requested_username,
utc_time=now.strftime("%H:%M:%S"),
time_until_reset=time_until_reset
)
msg = EmailMessage()
msg.set_content(email_body)
# Add HTML version if configured
if email_body_html:
msg.add_alternative(email_body_html, subtype='html')
msg["Subject"] = config["email_subject"].format(homeserver=config["homeserver"])
msg["From"] = config["smtp"]["username"]
msg["To"] = email

61
relaunch_without_refresh.sh Executable file
View file

@ -0,0 +1,61 @@
#!/bin/bash
# File paths
BASE_PATH="/home/sij/hand_of_morpheus"
TOKEN_FILE="$BASE_PATH/.registration_token"
BACKUP_PATH="/home/sij/conduwuit_backup"
# Server/domain info
SERVER_DOMAIN="we2.ee"
HOST="127.0.0.1"
HOST_PORT=8448
CONTAINER_PORT=6167
CONTAINER_NAME="conduwuit"
CONTAINER_IMAGE="ghcr.io/girlbossceo/conduwuit:v0.5.0-rc3-b6e9dc3d98704c56027219d3775336910a0136c6"
# Keep max request size
MAX_REQUEST_SIZE=33554432 # 32MB
# Auto-join room configuration
AUTO_JOIN_ROOMS="[\"#pub:we2.ee\",\"#home:we2.ee\"]"
TRUSTED_SERVERS="[\"matrix.org\",\"envs.net\",\"tchncs.de\"]"
BANNED_SERVERS="[\"tzchat.org\"]"
NO_MEDIA_FROM="[\"bark.lgbt\",\"cutefunny.art\",\"tzchat.org\",\"nitro.chat\",\"lolispace.moe\",\"lolisho.chat\",\"midov.pl\"]"
# Recreate Conduwuit container
docker stop "$CONTAINER_NAME"
docker rm "$CONTAINER_NAME"
docker run -d \
-p "${HOST}:${HOST_PORT}:${CONTAINER_PORT}" \
-v "db:/var/lib/conduwuit/" \
-v "${TOKEN_FILE}:/.registration_token:ro" \
-v "${BACKUP_PATH}:/backup" \
-e CONDUWUIT_SERVER_NAME="$SERVER_DOMAIN" \
-e CONDUWUIT_DATABASE_PATH="/var/lib/conduwuit/conduwuit.db" \
-e CONDUWUIT_DATABASE_BACKUP_PATH="/backup" \
-e CONDUWUIT_ALLOW_REGISTRATION=true \
-e CONDUWUIT_REGISTRATION_TOKEN_FILE="/.registration_token" \
-e CONDUWUIT_PORT=$CONTAINER_PORT \
-e CONDUWUIT_ADDRESS="0.0.0.0" \
-e CONDUWUIT_NEW_USER_DISPLAYNAME_SUFFIX="" \
-e CONDUWUIT_ALLOW_PUBLIC_ROOM_DIRECTORY_OVER_FEDERATION=true \
-e CONDUWUIT_ALLOW_PUBLIC_ROOM_DIRECTORY_WITHOUT_AUTH=false \
-e CONDUWUIT_ALLOW_FEDERATION=true \
-e CONDUWUIT_AUTO_JOIN_ROOMS="$AUTO_JOIN_ROOMS" \
-e CONDUWUIT_MAX_REQUEST_SIZE=$MAX_REQUEST_SIZE \
-e CONDUWUIT_LOG=debug \
-e CONDUWUIT_LOG_SPAN_EVENTS=all \
-e CONDUWUIT_LOG_COLORS=true \
-e CONDUWUIT_TRUSTED_SERVERS=$TRUSTED_SERVERS \
-e CONDUWUIT_PRUNE_MISSING_MEDIA=true \
-e CONDUWUIT_ALLOW_LEGACY_MEDIA=false \
-e CONDUWUIT_IP_RANGE_DENYLIST="[]" \
-e CONDUWUIT_AUTO_DEACTIVATE_BANNED_ROOM_ATTEMPTS=true \
-e CONDUWUIT_PREVENT_MEDIA_DOWNLOADS_FROM=$NO_MEDIA_FROM \
-e CONDUWUIT_IP_LOOKUP_STRATEGY="1" \
-e CONDUWUIT_QUERY_OVER_TCP_ONLY=true \
-e CONDUWUIT_QUERY_ALL_NAMESERVERS=false \
--name "$CONTAINER_NAME" \
--restart unless-stopped \
"$CONTAINER_IMAGE"

19
update_conduwuit.sh Normal file
View file

@ -0,0 +1,19 @@
#!/bin/bash
# Navigate to the repository directory
cd "$HOME/conduwuit" || exit
# Pull the latest changes
git pull
# Build the Docker image using Nix
nix build -L --extra-experimental-features "nix-command flakes" .#oci-image-x86_64-linux-musl-all-features
# Extract the image tarball path from the build result
IMAGE_TAR_PATH=$(nix path-info -r .#oci-image-x86_64-linux-musl-all-features)/image.tar.gz
# Load the image into Docker and tag it
docker load < "$IMAGE_TAR_PATH" | awk '/Loaded image:/ { print $3 }' | xargs -I {} docker tag {} conduwuit:custom
# Confirm tagging
echo "Docker image tagged as conduwuit:custom"