diff --git a/extra/admin-api/Interop/Spacebar.Interop.Replication.Abstractions/ISpacebarReplication.cs b/extra/admin-api/Interop/Spacebar.Interop.Replication.Abstractions/ISpacebarReplication.cs
index 95ee07f3..9398eedf 100644
--- a/extra/admin-api/Interop/Spacebar.Interop.Replication.Abstractions/ISpacebarReplication.cs
+++ b/extra/admin-api/Interop/Spacebar.Interop.Replication.Abstractions/ISpacebarReplication.cs
@@ -3,4 +3,4 @@
public interface ISpacebarReplication {
public Task InitializeAsync();
public Task SendAsync(ReplicationMessage message);
-}
\ No newline at end of file
+}
diff --git a/extra/admin-api/Models/Spacebar.Models.Db/Models/User.cs b/extra/admin-api/Models/Spacebar.Models.Db/Models/User.cs
index 70fe581d..f0aa0879 100644
--- a/extra/admin-api/Models/Spacebar.Models.Db/Models/User.cs
+++ b/extra/admin-api/Models/Spacebar.Models.Db/Models/User.cs
@@ -89,7 +89,7 @@ public partial class User
[Column("email", TypeName = "character varying")]
public string? Email { get; set; }
- [Column("flags", TypeName = "character varying")]
+ [Column("flags")]
public ulong Flags { get; set; }
[Column("public_flags")]
diff --git a/extra/admin-api/Spacebar.UApi/Services/TemplateImportService.cs b/extra/admin-api/Spacebar.UApi/Services/TemplateImportService.cs
index ae7b86a2..89c2bfbc 100644
--- a/extra/admin-api/Spacebar.UApi/Services/TemplateImportService.cs
+++ b/extra/admin-api/Spacebar.UApi/Services/TemplateImportService.cs
@@ -9,5 +9,5 @@ public class TemplateImportService(SpacebarDbContext db) {
return "";
}
- public async Task<>
+ // public async Task<>
}
\ No newline at end of file
diff --git a/nix/modules/default/cs/admin-api.nix b/nix/modules/default/cs/admin-api.nix
new file mode 100644
index 00000000..a4e0a4d7
--- /dev/null
+++ b/nix/modules/default/cs/admin-api.nix
@@ -0,0 +1,163 @@
+self:
+{
+ config,
+ lib,
+ pkgs,
+ spacebar,
+ ...
+}:
+
+let
+ secrets = import ../secrets.nix { inherit lib config; };
+ cfg = config.services.spacebarchat-server;
+ jsonFormat = pkgs.formats.json { };
+in
+{
+ imports = [ ];
+ options.services.spacebarchat-server.adminApi = lib.mkOption {
+ default = { };
+ description = "Configuration for admin api.";
+ type = lib.types.submodule {
+ options = {
+ enable = lib.mkEnableOption "Enable admin api.";
+ extraConfiguration = lib.mkOption {
+ type = jsonFormat.type;
+ default = import ./default-appsettings-json.nix;
+ description = "Extra appsettings.json configuration for the gateway offload daemon.";
+ };
+ };
+ };
+ };
+
+ config = lib.mkIf cfg.adminApi.enable (
+ let
+ makeServerTsService = (
+ conf:
+ lib.recursiveUpdate
+ (lib.recursiveUpdate {
+ documentation = [ "https://docs.spacebar.chat/" ];
+ wantedBy = [ "multi-user.target" ];
+ wants = [ "network-online.target" ];
+ after = [ "network-online.target" ];
+ environment = secrets.systemdEnvironment;
+ serviceConfig = {
+ LoadCredential = secrets.systemdLoadCredentials;
+
+ User = "spacebarchat";
+ Group = "spacebarchat";
+ DynamicUser = false;
+
+ LockPersonality = true;
+ NoNewPrivileges = true;
+
+ ProtectClock = true;
+ ProtectControlGroups = true;
+ ProtectHostname = true;
+ ProtectKernelLogs = true;
+ ProtectKernelModules = true;
+ ProtectKernelTunables = true;
+ PrivateDevices = true;
+ PrivateMounts = true;
+ PrivateUsers = true;
+ RestrictAddressFamilies = [
+ "AF_INET"
+ "AF_INET6"
+ "AF_UNIX"
+ ];
+ RestrictNamespaces = true;
+ RestrictRealtime = true;
+ SystemCallArchitectures = "native";
+ SystemCallFilter = [
+ "@system-service"
+ "~@privileged"
+ "@chown" # Required for copying files with FICLONE, apparently.
+ ];
+ CapabilityBoundingSet = [
+ "~CAP_SYS_ADMIN"
+ "~CAP_AUDIT_*"
+ "~CAP_NET_(BIND_SERVICE|BROADCAST|RAW)"
+ "~CAP_NET_ADMIN" # No use for this as we don't currently use iptables for enforcing instance bans
+ "~CAP_SYS_TIME"
+ "~CAP_KILL"
+ "~CAP_(DAC_*|FOWNER|IPC_OWNER)"
+ "~CAP_LINUX_IMMUTABLE"
+ "~CAP_IPC_LOCK"
+ "~CAP_BPF"
+ "~CAP_SYS_TTY_CONFIG"
+ "~CAP_SYS_BOOT"
+ "~CAP_SYS_CHROOT"
+ "~CAP_BLOCK_SUSPEND"
+ "~CAP_LEASE"
+ "~CAP_(CHOWN|FSETID|FSETFCAP)" # Check if we need CAP_CHOWN for `fchown()` (FICLONE)?
+ "~CAP_SET(UID|GID|PCAP)"
+ "~CAP_MAC_*"
+ "~CAP_SYS_PTRACE"
+ "~CAP_SYS_(NICE|RESOURCE)"
+ "~CAP_SYS_RAWIO"
+ "~CAP_SYSLOG"
+ ];
+ RestrictSUIDSGID = true;
+
+ WorkingDirectory = "/var/lib/spacebar";
+ StateDirectory = "spacebar";
+ StateDirectoryMode = "0750";
+ RuntimeDirectory = "spacebar";
+ RuntimeDirectoryMode = "0750";
+ ReadWritePaths = [ cfg.cdnPath ];
+ NoExecPaths = [ cfg.cdnPath ];
+
+ Restart = "on-failure";
+ RestartSec = 10;
+ StartLimitBurst = 5;
+ UMask = "077";
+ }
+ // lib.optionalAttrs (cfg.databaseFile != null) { EnvironmentFile = cfg.databaseFile; };
+ } conf)
+ {
+ }
+ );
+ in
+ {
+ assertions = [
+ {
+ assertion =
+ cfg.adminApi.extraConfiguration ? ConnectionStrings
+ && cfg.adminApi.extraConfiguration.ConnectionStrings ? Spacebar
+ && cfg.adminApi.extraConfiguration.ConnectionStrings.Spacebar != null;
+ message = ''
+ Admin API: Setting a database connection string in extraConfiguration (`extraConfiguration.ConnectionStrings.Spacebar`) is required when using C# services.
+ Example: Host=127.0.0.1; Username=Spacebar; Password=SuperSecurePassword12; Database=spacebar; Port=5432; Include Error Detail=true; Maximum Pool Size=1000; Command Timeout=6000; Timeout=600;
+ '';
+ }
+ ];
+
+ services.spacebarchat-server.settings.admin = {
+ endpointPublic = "http${if cfg.adminApiEndpoint.useSsl then "s" else ""}://${cfg.adminApiEndpoint.host}:${toString cfg.adminApiEndpoint.publicPort}";
+ endpointPrivate = "http://127.0.0.1:${builtins.toString cfg.adminApiEndpoint.localPort}";
+ };
+
+ systemd.services.spacebar-admin-api = makeServerTsService {
+ description = "Spacebar Server - Admin API";
+ environment = builtins.mapAttrs (_: val: builtins.toString val) (
+ {
+ # things we set by default...
+ EVENT_TRANSMISSION = "unix";
+ EVENT_SOCKET_PATH = "/run/spacebar/";
+ }
+ // cfg.extraEnvironment
+ // {
+ # things we force...
+ # CONFIG_PATH = configFile;
+ CONFIG_READONLY = 1;
+ ASPNETCORE_URLS = "http://127.0.0.1:${toString cfg.adminApiEndpoint.localPort}";
+ STORAGE_LOCATION = cfg.cdnPath;
+ APPSETTINGS_PATH = jsonFormat.generate "appsettings.spacebar-adminapi.json" (lib.recursiveUpdate (import ./default-appsettings-json.nix) cfg.adminApi.extraConfiguration);
+ }
+ );
+ serviceConfig = {
+ ExecStart = "${self.packages.${pkgs.stdenv.hostPlatform.system}.Spacebar-AdminApi}/bin/Spacebar.AdminApi";
+ };
+ };
+ }
+ );
+}
diff --git a/nix/modules/default/cs/default-appsettings-json.nix b/nix/modules/default/cs/default-appsettings-json.nix
index e6bb6323..1ed1c28c 100644
--- a/nix/modules/default/cs/default-appsettings-json.nix
+++ b/nix/modules/default/cs/default-appsettings-json.nix
@@ -12,5 +12,8 @@
PrivateKeyPath = "./jwt.key";
PublicKeyPath = "./jwt.key.pub";
};
+ UnixSocketReplication = {
+ SocketDir = "/run/spacebar";
+ };
};
}
diff --git a/nix/modules/default/cs/gateway-offload-cs.nix b/nix/modules/default/cs/gateway-offload-cs.nix
index 54e84bc3..76f97dde 100644
--- a/nix/modules/default/cs/gateway-offload-cs.nix
+++ b/nix/modules/default/cs/gateway-offload-cs.nix
@@ -133,7 +133,7 @@ in
&& cfg.gatewayOffload.extraConfiguration.ConnectionStrings ? Spacebar
&& cfg.gatewayOffload.extraConfiguration.ConnectionStrings.Spacebar != null;
message = ''
- Setting a database connection string in extraConfiguration (`extraConfiguration.ConnectionStrings.Spacebar`) is required when using C# services.
+ Gateway Offload: Setting a database connection string in extraConfiguration (`extraConfiguration.ConnectionStrings.Spacebar`) is required when using C# services.
Example: Host=127.0.0.1; Username=Spacebar; Password=SuperSecurePassword12; Database=spacebar; Port=5432; Include Error Detail=true; Maximum Pool Size=1000; Command Timeout=6000; Timeout=600;
'';
}
@@ -162,6 +162,7 @@ in
CONFIG_READONLY = 1;
ASPNETCORE_URLS = "http://127.0.0.1:${toString cfg.gatewayOffload.listenPort}";
STORAGE_LOCATION = cfg.cdnPath;
+ APPSETTINGS_PATH = jsonFormat.generate "appsettings.spacebar-gateway-offload.json" (lib.recursiveUpdate (import ./default-appsettings-json.nix) cfg.gatewayOffload.extraConfiguration);
}
);
serviceConfig = {
diff --git a/nix/modules/default/default.nix b/nix/modules/default/default.nix
index c4f9e4cd..ac20d3cd 100644
--- a/nix/modules/default/default.nix
+++ b/nix/modules/default/default.nix
@@ -46,6 +46,7 @@ in
./integration-nginx.nix
./users.nix
(import ./cs/gateway-offload-cs.nix self)
+ (import ./cs/admin-api.nix self)
];
options.services.spacebarchat-server =
let
diff --git a/nix/modules/default/integration-nginx.nix b/nix/modules/default/integration-nginx.nix
index 70e4b2e1..718e5728 100644
--- a/nix/modules/default/integration-nginx.nix
+++ b/nix/modules/default/integration-nginx.nix
@@ -38,7 +38,13 @@ in
proxyPass = "http://127.0.0.1:${toString cfg.cdnEndpoint.localPort}/";
};
};
-
+ "${cfg.adminApiEndpoint.host}" = lib.mkIf cfg.adminApi.enable {
+ enableACME = cfg.adminApiEndpoint.useSsl;
+ forceSSL = cfg.adminApiEndpoint.useSsl;
+ locations."/" = {
+ proxyPass = "http://127.0.0.1:${toString cfg.adminApiEndpoint.localPort}/";
+ };
+ };
};
};
};
diff --git a/nix/testVm/configuration.nix b/nix/testVm/configuration.nix
index 2b1c19a5..71c2451f 100644
--- a/nix/testVm/configuration.nix
+++ b/nix/testVm/configuration.nix
@@ -15,9 +15,11 @@ in
services.nginx.virtualHosts."api.sb.localhost" = nginxTestSigning;
services.nginx.virtualHosts."gw.sb.localhost" = nginxTestSigning;
services.nginx.virtualHosts."cdn.sb.localhost" = nginxTestSigning;
+ services.nginx.virtualHosts."admin.sb.localhost" = nginxTestSigning;
services.spacebarchat-server =
let
+ csConnectionString = "Host=127.0.0.1; Username=postgres; Password=postgres; Database=spacebar; Port=5432; Include Error Detail=true; Maximum Pool Size=1000; Command Timeout=6000; Timeout=600;";
cfg = {
enable = true;
apiEndpoint = {
@@ -38,12 +40,22 @@ in
localPort = 3003;
publicPort = 8080;
};
+ adminApiEndpoint = {
+ useSsl = false;
+ host = "admin.sb.localhost";
+ localPort = 3005;
+ publicPort = 8080;
+ };
nginx.enable = true;
serverName = "sb.localhost";
gatewayOffload = {
enable = true;
enableGuildSync = true;
- extraConfiguration.ConnectionStrings.Spacebar = "Host=127.0.0.1; Username=Spacebar; Password=postgres; Database=spacebar; Port=5432; Include Error Detail=true; Maximum Pool Size=1000; Command Timeout=6000; Timeout=600;";
+ extraConfiguration.ConnectionStrings.Spacebar = csConnectionString;
+ };
+ adminApi = {
+ enable = true;
+ extraConfiguration.ConnectionStrings.Spacebar = csConnectionString;
};
extraEnvironment = {
DATABASE = "postgres://postgres:postgres@127.0.0.1/spacebar";
|