Major architecture update: stable identity, component validation, media indexing, and protocol docs

This commit is contained in:
Foxyz committed 2026-02-27 19:33:35 +03:00
1 parent ce7c97d13a
commit 01c110bbe1
16 files changed
+2718 -468

No files matched your search

+158 -10
View File
@@ -1,14 +1,162 @@
import 'dart:io';
import 'dart:convert';
import 'dart:math';
import 'package:yaml/yaml.dart';
class Config {
// Server settings
static const int port = 9870;
static late String bindHost;
static late int bindPort;
static late String publicBaseUrl;
static late String serverName;
static late String jwtSecret;
static late bool configured;
static late bool setupMode;
static late int bootstrapAdminLimit;
static late bool devDbTools;
// IMPORTANT: Set this to your actual server host/domain
// Used for generating userId: "username@serverHost"
static const String serverHost = 'localhost:9870';
static const String serverName = 'Chat Server';
// JWT settings
// TODO: Move to environment variable in production
static const String jwtSecret = 'your_super_secret_key_change_in_production';
static const Duration tokenExpiry = Duration(days: 7);
static void initialize() {
final configFile = File('config.yaml');
if (!configFile.existsSync()) {
final generatedSecret = _generateJwtSecret();
configFile.writeAsStringSync(_defaultConfig(generatedSecret));
print('✅ Generated config.yaml (first run).');
print('⚠️ Review server.public_base_url and security.jwt_secret before production use.');
}
final yamlString = configFile.readAsStringSync();
final yamlMap = loadYaml(yamlString) as YamlMap;
final serverMap = yamlMap['server'] as YamlMap?;
final securityMap = yamlMap['security'] as YamlMap?;
serverName = (serverMap?['name'] as String?)?.trim() ?? '';
bindHost = (serverMap?['bind_host'] as String?)?.trim() ?? (serverMap?['host'] as String?)?.trim() ?? '127.0.0.1';
bindPort = (serverMap?['bind_port'] as int?) ?? (serverMap?['port'] as int?) ?? 9870;
final rawPublicBaseUrl =
(serverMap?['public_base_url'] as String?)?.trim() ?? _legacyPublicBaseUrlFromHost((serverMap?['host'] as String?)?.trim());
publicBaseUrl = _normalizePublicBaseUrl(rawPublicBaseUrl) ?? '';
configured = (serverMap?['configured'] as bool?) ?? false;
setupMode = (serverMap?['first_setup'] as bool?) ?? false;
bootstrapAdminLimit = (serverMap?['bootstrap_admin_limit'] as int?) ?? 1;
devDbTools = (serverMap?['dev_db_tools'] as bool?) ?? false;
jwtSecret = (securityMap?['jwt_secret'] as String?)?.trim() ?? '';
if (serverName.isEmpty) {
throw StateError('config.yaml: server.name is required.');
}
if (bindHost.isEmpty) {
throw StateError('config.yaml: server.bind_host is required.');
}
if (bindPort <= 0 || bindPort > 65535) {
throw StateError('config.yaml: server.bind_port must be between 1 and 65535.');
}
if (publicBaseUrl.isEmpty) {
throw StateError(
'config.yaml: server.public_base_url is required (example: https://chat.example.com).',
);
}
if (jwtSecret.isEmpty) {
throw StateError('config.yaml: security.jwt_secret is required.');
}
if (!configured) {
throw StateError(
'Server setup is not complete.\n'
'Edit config.yaml and set:\n'
' server.configured: true\n'
'After reviewing server.public_base_url and security.jwt_secret.',
);
}
if (bootstrapAdminLimit < 0) {
throw StateError('config.yaml: server.bootstrap_admin_limit must be >= 0.');
}
print(
'🚀 Server Config Loaded: $serverName (bind=$bindHost:$bindPort, public=$publicBaseUrl, configured=$configured, setupMode=$setupMode, bootstrapAdminLimit=$bootstrapAdminLimit, devDbTools=$devDbTools)',
);
}
static String _generateJwtSecret() {
final random = Random.secure();
final bytes = List<int>.generate(32, (_) => random.nextInt(256));
return base64UrlEncode(bytes);
}
static String _defaultConfig(String generatedSecret) => '''
# Reliquary Server Configuration
server:
# Display name shown in clients
name: "Reliquary Server"
# Local bind address for the HTTP server
bind_host: "127.0.0.1"
# Local bind port for the HTTP server
bind_port: 9870
# Public base URL used for identity, handles, and cross-server references
# Dev example: http://localhost:9870
# Prod example: https://chat.example.com
public_base_url: "http://localhost:9870"
# Set to true after reviewing this file; server refuses to start while false
configured: false
# First local registration becomes admin
first_setup: true
# Number of local registrations auto-promoted to admin while first_setup=true
bootstrap_admin_limit: 1
# Testing-only DB admin/debug endpoints
dev_db_tools: true
security:
# Auto-generated on first run; replace for production
jwt_secret: "$generatedSecret"
''';
static String get publicHost {
final uri = Uri.tryParse(publicBaseUrl);
if (uri == null || uri.host.isEmpty) {
return publicBaseUrl;
}
return uri.hasPort ? '${uri.host}:${uri.port}' : uri.host;
}
static String? _normalizePublicBaseUrl(String? value) {
if (value == null || value.trim().isEmpty) {
return null;
}
final uri = Uri.tryParse(value.trim());
if (uri == null || uri.host.isEmpty) {
return null;
}
if (uri.scheme != 'http' && uri.scheme != 'https') {
return null;
}
return Uri(
scheme: uri.scheme,
host: uri.host,
port: uri.hasPort ? uri.port : null,
).toString().replaceAll(RegExp(r'/$'), '');
}
static String? _legacyPublicBaseUrlFromHost(String? hostValue) {
if (hostValue == null || hostValue.trim().isEmpty) {
return null;
}
final host = hostValue.trim();
if (host.contains('://')) {
return host;
}
final lower = host.toLowerCase();
final isLocal = lower.startsWith('localhost') || lower.startsWith('127.') || lower.startsWith('[::1]');
final scheme = isLocal ? 'http' : 'https';
return '$scheme://$host';
}
}