tgstation-server 6.8.0
The /tg/station 13 server suite
Loading...
Searching...
No Matches
Application.cs
Go to the documentation of this file.
1using System;
2using System.Collections.Frozen;
3using System.Collections.Generic;
4using System.Globalization;
5using System.Threading.Tasks;
6
7using Cyberboss.AspNetCore.AsyncInitializer;
8
9using Elastic.CommonSchema.Serilog;
10
11using Microsoft.AspNetCore.Authentication;
12using Microsoft.AspNetCore.Authentication.JwtBearer;
13using Microsoft.AspNetCore.Builder;
14using Microsoft.AspNetCore.Cors.Infrastructure;
15using Microsoft.AspNetCore.Hosting;
16using Microsoft.AspNetCore.Http;
17using Microsoft.AspNetCore.Http.Connections;
18using Microsoft.AspNetCore.Identity;
19using Microsoft.AspNetCore.Mvc.Infrastructure;
20using Microsoft.AspNetCore.SignalR;
21using Microsoft.Extensions.Configuration;
22using Microsoft.Extensions.DependencyInjection;
23using Microsoft.Extensions.Hosting;
24using Microsoft.Extensions.Logging;
25using Microsoft.Extensions.Options;
26
27using Newtonsoft.Json;
28
29using Serilog;
30using Serilog.Events;
31using Serilog.Formatting.Display;
32using Serilog.Sinks.Elasticsearch;
33
64
66{
70#pragma warning disable CA1506
71 public sealed class Application : SetupApplication
72 {
76 readonly IWebHostEnvironment hostingEnvironment;
77
82
88 {
89 var assemblyInformationProvider = new AssemblyInformationProvider();
90 var ioManager = new DefaultIOManager();
91 return new ServerFactory(
92 assemblyInformationProvider,
93 ioManager);
94 }
95
102 static void AddWatchdog<TSystemWatchdogFactory>(IServiceCollection services, IPostSetupServices postSetupServices)
103 where TSystemWatchdogFactory : class, IWatchdogFactory
104 {
105 if (postSetupServices.GeneralConfiguration.UseBasicWatchdog)
106 services.AddSingleton<IWatchdogFactory, WatchdogFactory>();
107 else
108 services.AddSingleton<IWatchdogFactory, TSystemWatchdogFactory>();
109 }
110
117 IConfiguration configuration,
118 IWebHostEnvironment hostingEnvironment)
119 : base(configuration)
120 {
121 this.hostingEnvironment = hostingEnvironment ?? throw new ArgumentNullException(nameof(hostingEnvironment));
122 }
123
131 public void ConfigureServices(
132 IServiceCollection services,
133 IAssemblyInformationProvider assemblyInformationProvider,
134 IIOManager ioManager,
135 IPostSetupServices postSetupServices)
136 {
137 ConfigureServices(services, assemblyInformationProvider, ioManager);
138
139 ArgumentNullException.ThrowIfNull(postSetupServices);
140
141 // configure configuration
142 services.UseStandardConfig<UpdatesConfiguration>(Configuration);
143 services.UseStandardConfig<ControlPanelConfiguration>(Configuration);
144 services.UseStandardConfig<SwarmConfiguration>(Configuration);
145 services.UseStandardConfig<SessionConfiguration>(Configuration);
146
147 // enable options which give us config reloading
148 services.AddOptions();
149
150 // Set the timeout for IHostedService.StopAsync
151 services.Configure<HostOptions>(
152 opts => opts.ShutdownTimeout = TimeSpan.FromMinutes(postSetupServices.GeneralConfiguration.RestartTimeoutMinutes));
153
154 static LogEventLevel? ConvertSeriLogLevel(LogLevel logLevel) =>
155 logLevel switch
156 {
157 LogLevel.Critical => LogEventLevel.Fatal,
158 LogLevel.Debug => LogEventLevel.Debug,
159 LogLevel.Error => LogEventLevel.Error,
160 LogLevel.Information => LogEventLevel.Information,
161 LogLevel.Trace => LogEventLevel.Verbose,
162 LogLevel.Warning => LogEventLevel.Warning,
163 LogLevel.None => null,
164 _ => throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, "Invalid log level {0}", logLevel)),
165 };
166
167 var microsoftEventLevel = ConvertSeriLogLevel(postSetupServices.FileLoggingConfiguration.MicrosoftLogLevel);
168 var elasticsearchConfiguration = postSetupServices.ElasticsearchConfiguration;
169 services.SetupLogging(
170 config =>
171 {
172 if (microsoftEventLevel.HasValue)
173 {
174 config.MinimumLevel.Override("Microsoft", microsoftEventLevel.Value);
175 config.MinimumLevel.Override("System.Net.Http.HttpClient", microsoftEventLevel.Value);
176 }
177 },
178 sinkConfig =>
179 {
180 if (postSetupServices.FileLoggingConfiguration.Disable)
181 return;
182
183 var logPath = postSetupServices.FileLoggingConfiguration.GetFullLogDirectory(
184 ioManager,
185 assemblyInformationProvider,
186 postSetupServices.PlatformIdentifier);
187
188 var logEventLevel = ConvertSeriLogLevel(postSetupServices.FileLoggingConfiguration.LogLevel);
189
190 var formatter = new MessageTemplateTextFormatter(
191 "{Timestamp:o} "
193 + "): [{Level:u3}] {SourceContext:l}: {Message} ({EventId:x8}){NewLine}{Exception}",
194 null);
195
196 logPath = ioManager.ConcatPath(logPath, "tgs-.log");
197 var rollingFileConfig = sinkConfig.File(
198 formatter,
199 logPath,
200 logEventLevel ?? LogEventLevel.Verbose,
201 50 * 1024 * 1024, // 50MB max size
202 flushToDiskInterval: TimeSpan.FromSeconds(2),
203 rollingInterval: RollingInterval.Day,
204 rollOnFileSizeLimit: true);
205 },
206 elasticsearchConfiguration.Enable
207 ? new ElasticsearchSinkOptions(elasticsearchConfiguration.Host ?? throw new InvalidOperationException($"Missing {ElasticsearchConfiguration.Section}:{nameof(elasticsearchConfiguration.Host)}!"))
208 {
209 // Yes I know this means they cannot use a self signed cert unless they also have authentication, but lets be real here
210 // No one is going to be doing one of those but not the other
211 ModifyConnectionSettings = connectionConfigration => (!String.IsNullOrWhiteSpace(elasticsearchConfiguration.Username) && !String.IsNullOrWhiteSpace(elasticsearchConfiguration.Password))
212 ? connectionConfigration
213 .BasicAuthentication(
214 elasticsearchConfiguration.Username,
215 elasticsearchConfiguration.Password)
216 .ServerCertificateValidationCallback((o, certificate, chain, errors) => true)
217 : null,
218 CustomFormatter = new EcsTextFormatter(),
219 AutoRegisterTemplate = true,
220 AutoRegisterTemplateVersion = AutoRegisterTemplateVersion.ESv7,
221 IndexFormat = "tgs-logs",
222 }
223 : null,
224 postSetupServices.InternalConfiguration,
225 postSetupServices.FileLoggingConfiguration);
226
227 // configure authentication pipeline
229
230 // add mvc, configure the json serializer settings
231 var jsonVersionConverterList = new List<JsonConverter>
232 {
233 new VersionConverter(),
234 };
235
236 void ConfigureNewtonsoftJsonSerializerSettingsForApi(JsonSerializerSettings settings)
237 {
238 settings.NullValueHandling = NullValueHandling.Ignore;
239 settings.CheckAdditionalContent = true;
240 settings.MissingMemberHandling = MissingMemberHandling.Error;
241 settings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
242 settings.Converters = jsonVersionConverterList;
243 }
244
245 services
246 .AddMvc(options =>
247 {
248 options.ReturnHttpNotAcceptable = true;
249 options.RespectBrowserAcceptHeader = true;
250 })
251 .AddNewtonsoftJson(options =>
252 {
253 options.AllowInputFormatterExceptionMessages = true;
254 ConfigureNewtonsoftJsonSerializerSettingsForApi(options.SerializerSettings);
255 });
256
257 services.AddSignalR(
258 options =>
259 {
260 options.AddFilter<AuthorizationContextHubFilter>();
261 })
262 .AddNewtonsoftJsonProtocol(options =>
263 {
264 ConfigureNewtonsoftJsonSerializerSettingsForApi(options.PayloadSerializerSettings);
265 });
266
267 services.AddHub<JobsHub, IJobsHub>();
268
269 if (postSetupServices.GeneralConfiguration.HostApiDocumentation)
270 {
271 string GetDocumentationFilePath(string assemblyLocation) => ioManager.ConcatPath(ioManager.GetDirectoryName(assemblyLocation), String.Concat(ioManager.GetFileNameWithoutExtension(assemblyLocation), ".xml"));
272 var assemblyDocumentationPath = GetDocumentationFilePath(GetType().Assembly.Location);
273 var apiDocumentationPath = GetDocumentationFilePath(typeof(ApiHeaders).Assembly.Location);
274 services.AddSwaggerGen(genOptions => SwaggerConfiguration.Configure(genOptions, assemblyDocumentationPath, apiDocumentationPath));
275 services.AddSwaggerGenNewtonsoftSupport();
276 }
277
278 // CORS conditionally enabled later
279 services.AddCors();
280
281 // Enable managed HTTP clients
282 services.AddHttpClient();
284
285 void AddTypedContext<TContext>()
286 where TContext : DatabaseContext
287 {
288 var configureAction = DatabaseContext.GetConfigureAction<TContext>();
289
290 services.AddDbContextPool<TContext>((serviceProvider, builder) =>
291 {
292 if (hostingEnvironment.IsDevelopment())
293 builder.EnableSensitiveDataLogging();
294
295 var databaseConfigOptions = serviceProvider.GetRequiredService<IOptions<DatabaseConfiguration>>();
296 var databaseConfig = databaseConfigOptions.Value ?? throw new InvalidOperationException("DatabaseConfiguration missing!");
297 configureAction(builder, databaseConfig);
298 });
299 services.AddScoped<IDatabaseContext>(x => x.GetRequiredService<TContext>());
300 }
301
302 // add the correct database context type
303 var dbType = postSetupServices.DatabaseConfiguration.DatabaseType;
304 switch (dbType)
305 {
306 case DatabaseType.MySql:
307 case DatabaseType.MariaDB:
308 AddTypedContext<MySqlDatabaseContext>();
309 break;
310 case DatabaseType.SqlServer:
311 AddTypedContext<SqlServerDatabaseContext>();
312 break;
313 case DatabaseType.Sqlite:
314 AddTypedContext<SqliteDatabaseContext>();
315 break;
316 case DatabaseType.PostgresSql:
317 AddTypedContext<PostgresSqlDatabaseContext>();
318 break;
319 default:
320 throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, "Invalid {0}: {1}!", nameof(DatabaseType), dbType));
321 }
322
323 // configure other database services
324 services.AddSingleton<IDatabaseContextFactory, DatabaseContextFactory>();
325 services.AddSingleton<IDatabaseSeeder, DatabaseSeeder>();
326
327 // configure other security services
328 services.AddSingleton<IOAuthProviders, OAuthProviders>();
329 services.AddSingleton<IIdentityCache, IdentityCache>();
330 services.AddSingleton<ICryptographySuite, CryptographySuite>();
331 services.AddSingleton<ITokenFactory, TokenFactory>();
332 services.AddSingleton<IPasswordHasher<Models.User>, PasswordHasher<Models.User>>();
333
334 // configure platform specific services
335 if (postSetupServices.PlatformIdentifier.IsWindows)
336 {
337 AddWatchdog<WindowsWatchdogFactory>(services, postSetupServices);
340 services.AddSingleton<ByondInstallerBase, WindowsByondInstaller>();
341 services.AddSingleton<OpenDreamInstaller, WindowsOpenDreamInstaller>();
342 services.AddSingleton<IPostWriteHandler, WindowsPostWriteHandler>();
343 services.AddSingleton<IProcessFeatures, WindowsProcessFeatures>();
344
345 services.AddSingleton<WindowsNetworkPromptReaper>();
346 services.AddSingleton<INetworkPromptReaper>(x => x.GetRequiredService<WindowsNetworkPromptReaper>());
347 services.AddSingleton<IHostedService>(x => x.GetRequiredService<WindowsNetworkPromptReaper>());
348 }
349 else
350 {
351 AddWatchdog<PosixWatchdogFactory>(services, postSetupServices);
352 services.AddSingleton<ISystemIdentityFactory, PosixSystemIdentityFactory>();
353 services.AddSingleton<IFilesystemLinkFactory, PosixFilesystemLinkFactory>();
354 services.AddSingleton<ByondInstallerBase, PosixByondInstaller>();
355 services.AddSingleton<OpenDreamInstaller>();
356 services.AddSingleton<IPostWriteHandler, PosixPostWriteHandler>();
357
358 services.AddSingleton<IProcessFeatures, PosixProcessFeatures>();
359 services.AddHostedService<PosixProcessFeatures>();
360
361 // PosixProcessFeatures also needs a IProcessExecutor for gcore
362 services.AddSingleton(x => new Lazy<IProcessExecutor>(() => x.GetRequiredService<IProcessExecutor>(), true));
363 services.AddSingleton<INetworkPromptReaper, PosixNetworkPromptReaper>();
364
365 services.AddHostedService<PosixSignalHandler>();
366 }
367
368 // only global repo manager should be for the OD repo
369 // god help me if we need more
370 var openDreamRepositoryDirectory = ioManager.ConcatPath(
371 ioManager.GetPathInLocalDirectory(assemblyInformationProvider),
372 "OpenDreamRepository");
373 services.AddSingleton(
374 services => services
375 .GetRequiredService<IRepositoryManagerFactory>()
376 .CreateRepositoryManager(
378 services.GetRequiredService<IIOManager>(),
379 openDreamRepositoryDirectory),
380 new NoopEventConsumer()));
381
382 services.AddSingleton(
383 serviceProvider => new Dictionary<EngineType, IEngineInstaller>
384 {
385 { EngineType.Byond, serviceProvider.GetRequiredService<ByondInstallerBase>() },
386 { EngineType.OpenDream, serviceProvider.GetRequiredService<OpenDreamInstaller>() },
387 }
388 .ToFrozenDictionary());
389 services.AddSingleton<IEngineInstaller, DelegatingEngineInstaller>();
390
391 if (postSetupServices.InternalConfiguration.UsingSystemD)
392 services.AddHostedService<SystemDManager>();
393
394 // configure file transfer services
395 services.AddSingleton<FileTransferService>();
396 services.AddSingleton<IFileTransferStreamHandler>(x => x.GetRequiredService<FileTransferService>());
397 services.AddSingleton<IFileTransferTicketProvider>(x => x.GetRequiredService<FileTransferService>());
399
400 // configure swarm service
401 services.AddSingleton<SwarmService>();
402 services.AddSingleton<ISwarmService>(x => x.GetRequiredService<SwarmService>());
403 services.AddSingleton<ISwarmOperations>(x => x.GetRequiredService<SwarmService>());
404 services.AddSingleton<ISwarmServiceController>(x => x.GetRequiredService<SwarmService>());
405
406 // configure component services
407 services.AddSingleton<IPortAllocator, PortAllocator>();
408 services.AddSingleton<IInstanceFactory, InstanceFactory>();
409 services.AddSingleton<IGitRemoteFeaturesFactory, GitRemoteFeaturesFactory>();
410 services.AddSingleton<ILibGit2RepositoryFactory, LibGit2RepositoryFactory>();
411 services.AddSingleton<ILibGit2Commands, LibGit2Commands>();
412 services.AddSingleton<IRepositoryManagerFactory, RepostoryManagerFactory>();
414 services.AddChatProviderFactory();
415 services.AddSingleton<IChatManagerFactory, ChatManagerFactory>();
416 services.AddSingleton<IServerUpdater, ServerUpdater>();
417 services.AddSingleton<IServerUpdateInitiator, ServerUpdateInitiator>();
418 services.AddSingleton<IDotnetDumpService, DotnetDumpService>();
419
420 // configure misc services
421 services.AddSingleton<IProcessExecutor, ProcessExecutor>();
422 services.AddSingleton<ISynchronousIOManager, SynchronousIOManager>();
423 services.AddSingleton<IServerPortProvider, ServerPortProivder>();
424 services.AddSingleton<ITopicClientFactory, TopicClientFactory>();
425 services.AddHostedService<CommandPipeManager>();
426
427 services.AddFileDownloader();
428 services.AddGitHub();
429
430 // configure root services
431 services.AddSingleton<JobService>();
432 services.AddSingleton<IJobService>(provider => provider.GetRequiredService<JobService>());
433 services.AddSingleton<IJobsHubUpdater>(provider => provider.GetRequiredService<JobService>());
434 services.AddSingleton<IJobManager>(x => x.GetRequiredService<IJobService>());
435 services.AddSingleton<JobsHubGroupMapper>();
436 services.AddSingleton<IPermissionsUpdateNotifyee>(provider => provider.GetRequiredService<JobsHubGroupMapper>());
437 services.AddSingleton<IHostedService>(x => x.GetRequiredService<JobsHubGroupMapper>()); // bit of a hack, but we need this to load immediated
438
439 services.AddSingleton<InstanceManager>();
440 services.AddSingleton<IBridgeDispatcher>(x => x.GetRequiredService<InstanceManager>());
441 services.AddSingleton<IInstanceManager>(x => x.GetRequiredService<InstanceManager>());
442 }
443
456 public void Configure(
457 IApplicationBuilder applicationBuilder,
458 IServerControl serverControl,
460 IServerPortProvider serverPortProvider,
461 IAssemblyInformationProvider assemblyInformationProvider,
462 IOptions<ControlPanelConfiguration> controlPanelConfigurationOptions,
463 IOptions<GeneralConfiguration> generalConfigurationOptions,
464 IOptions<SwarmConfiguration> swarmConfigurationOptions,
465 ILogger<Application> logger)
466 {
467 ArgumentNullException.ThrowIfNull(applicationBuilder);
468 ArgumentNullException.ThrowIfNull(serverControl);
469
470 this.tokenFactory = tokenFactory ?? throw new ArgumentNullException(nameof(tokenFactory));
471
472 ArgumentNullException.ThrowIfNull(serverPortProvider);
473 ArgumentNullException.ThrowIfNull(assemblyInformationProvider);
474
475 var controlPanelConfiguration = controlPanelConfigurationOptions?.Value ?? throw new ArgumentNullException(nameof(controlPanelConfigurationOptions));
476 var generalConfiguration = generalConfigurationOptions?.Value ?? throw new ArgumentNullException(nameof(generalConfigurationOptions));
477 var swarmConfiguration = swarmConfigurationOptions?.Value ?? throw new ArgumentNullException(nameof(swarmConfigurationOptions));
478
479 ArgumentNullException.ThrowIfNull(logger);
480
481 logger.LogDebug("Content Root: {contentRoot}", hostingEnvironment.ContentRootPath);
482 logger.LogTrace("Web Root: {webRoot}", hostingEnvironment.WebRootPath);
483
484 // setup the HTTP request pipeline
485 // Add additional logging context to the request
486 applicationBuilder.UseAdditionalRequestLoggingContext(swarmConfiguration);
487
488 // Wrap exceptions in a 500 (ErrorMessage) response
489 applicationBuilder.UseServerErrorHandling();
490
491 // Add the X-Powered-By response header
492 applicationBuilder.UseServerBranding(assemblyInformationProvider);
493
494 // Add the X-Accel-Buffering response header
495 applicationBuilder.UseDisabledNginxProxyBuffering();
496
497 // suppress OperationCancelledExceptions, they are just aborted HTTP requests
498 applicationBuilder.UseCancelledRequestSuppression();
499
500 // 503 requests made while the application is starting
501 applicationBuilder.UseAsyncInitialization<IInstanceManager>(
502 (instanceManager, cancellationToken) => instanceManager.Ready.WaitAsync(cancellationToken));
503
504 if (generalConfiguration.HostApiDocumentation)
505 {
506 var siteDocPath = Routes.ApiRoot + $"doc/{SwaggerConfiguration.DocumentName}.json";
507 if (!String.IsNullOrWhiteSpace(controlPanelConfiguration.PublicPath))
508 siteDocPath = controlPanelConfiguration.PublicPath.TrimEnd('/') + siteDocPath;
509
510 applicationBuilder.UseSwagger(options =>
511 {
512 options.RouteTemplate = Routes.ApiRoot + "doc/{documentName}.{json|yaml}";
513 });
514 applicationBuilder.UseSwaggerUI(options =>
515 {
517 options.SwaggerEndpoint(siteDocPath, "TGS API");
518 });
519 logger.LogTrace("Swagger API generation enabled");
520 }
521
522 // spa loading if necessary
523 if (controlPanelConfiguration.Enable)
524 {
525 logger.LogInformation("Web control panel enabled.");
526 applicationBuilder.UseFileServer(new FileServerOptions
527 {
529 EnableDefaultFiles = true,
530 EnableDirectoryBrowsing = false,
531 RedirectToAppendTrailingSlash = false,
532 });
533 }
534 else
535#if NO_WEBPANEL
536 logger.LogDebug("Web control panel was not included in TGS build!");
537#else
538 logger.LogTrace("Web control panel disabled!");
539#endif
540
541 // Enable endpoint routing
542 applicationBuilder.UseRouting();
543
544 // Set up CORS based on configuration if necessary
545 Action<CorsPolicyBuilder>? corsBuilder = null;
546 if (controlPanelConfiguration.AllowAnyOrigin)
547 {
548 logger.LogTrace("Access-Control-Allow-Origin: *");
549 corsBuilder = builder => builder.SetIsOriginAllowed(_ => true);
550 }
551 else if (controlPanelConfiguration.AllowedOrigins?.Count > 0)
552 {
553 logger.LogTrace("Access-Control-Allow-Origin: {allowedOrigins}", String.Join(',', controlPanelConfiguration.AllowedOrigins));
554 corsBuilder = builder => builder.WithOrigins([.. controlPanelConfiguration.AllowedOrigins]);
555 }
556
557 var originalBuilder = corsBuilder;
558 corsBuilder = builder =>
559 {
560 builder
561 .AllowAnyHeader()
562 .AllowAnyMethod()
563 .AllowCredentials()
564 .SetPreflightMaxAge(TimeSpan.FromDays(1));
565 originalBuilder?.Invoke(builder);
566 };
567 applicationBuilder.UseCors(corsBuilder);
568
569 // validate the API version
570 applicationBuilder.UseApiCompatibility();
571
572 // authenticate JWT tokens using our security pipeline if present, returns 401 if bad
573 applicationBuilder.UseAuthentication();
574
575 // enable authorization on endpoints
576 applicationBuilder.UseAuthorization();
577
578 // suppress and log database exceptions
579 applicationBuilder.UseDbConflictHandling();
580
581 // setup endpoints
582 applicationBuilder.UseEndpoints(endpoints =>
583 {
584 // access to the signalR jobs hub
585 endpoints.MapHub<JobsHub>(
587 options =>
588 {
589 options.Transports = HttpTransportType.ServerSentEvents;
590 options.CloseOnAuthenticationExpiration = true;
591 })
592 .RequireAuthorization()
593 .RequireCors(corsBuilder);
594
595 // majority of handling is done in the controllers
596 endpoints.MapControllers();
597 });
598
599 // 404 anything that gets this far
600 // End of request pipeline setup
601 logger.LogTrace("Configuration version: {configVersion}", GeneralConfiguration.CurrentConfigVersion);
602 logger.LogTrace("DMAPI Interop version: {interopVersion}", DMApiConstants.InteropVersion);
603 if (controlPanelConfiguration.Enable)
604 logger.LogTrace("Webpanel version: {webCPVersion}", MasterVersionsAttribute.Instance.RawWebpanelVersion);
605
606 logger.LogDebug("Starting hosting on port {httpApiPort}...", serverPortProvider.HttpApiPort);
607 }
608
610 protected override void ConfigureHostedService(IServiceCollection services)
611 => services.AddSingleton<IHostedService>(x => x.GetRequiredService<InstanceManager>());
612
617 void ConfigureAuthenticationPipeline(IServiceCollection services)
618 {
619 services.AddHttpContextAccessor();
620 services.AddScoped<IApiHeadersProvider, ApiHeadersProvider>();
621 services.AddScoped<AuthenticationContextFactory>();
622 services.AddScoped<IAuthenticationContextFactory>(provider => provider.GetRequiredService<AuthenticationContextFactory>());
623
624 // what if you
625 // wanted to just do this:
626 // return provider.GetRequiredService<AuthenticationContextFactory>().CurrentAuthenticationContext
627 // But M$ said
628 // https://stackoverflow.com/questions/56792917/scoped-services-in-asp-net-core-with-signalr-hubs
629 services.AddScoped(provider => (provider
630 .GetRequiredService<IHttpContextAccessor>()
631 .HttpContext ?? throw new InvalidOperationException($"Unable to resolve {nameof(IAuthenticationContext)} due to no HttpContext being available!"))
632 .RequestServices
633 .GetRequiredService<AuthenticationContextFactory>()
634 .CurrentAuthenticationContext);
636
637 services
638 .AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
639 .AddJwtBearer(jwtBearerOptions =>
640 {
641 // this line isn't actually run until the first request is made
642 // at that point tokenFactory will be populated
643 jwtBearerOptions.TokenValidationParameters = tokenFactory?.ValidationParameters ?? throw new InvalidOperationException("tokenFactory not initialized!");
644 jwtBearerOptions.MapInboundClaims = false;
645 jwtBearerOptions.Events = new JwtBearerEvents
646 {
647 OnMessageReceived = context =>
648 {
649 if (String.IsNullOrWhiteSpace(context.Token))
650 {
651 var accessToken = context.Request.Query["access_token"];
652 var path = context.HttpContext.Request.Path;
653
654 if (!String.IsNullOrWhiteSpace(accessToken) &&
655 path.StartsWithSegments(Routes.HubsRoot, StringComparison.OrdinalIgnoreCase))
656 {
657 context.Token = accessToken;
658 }
659 }
660
661 return Task.CompletedTask;
662 },
663 };
664 });
665 }
666 }
667}
Represents the header that must be present for every server request.
Definition: ApiHeaders.cs:25
Routes to a server actions.
Definition: Routes.cs:9
const string HubsRoot
The root route of all hubs.
Definition: Routes.cs:18
const string JobsHub
The root route of all hubs.
Definition: Routes.cs:113
Base implementation of IEngineInstaller for EngineType.Byond.
Implementation of IEngineInstaller that forwards calls to different IEngineInstaller based on their a...
Implementation of IEngineInstaller for EngineType.OpenDream.
Implementation of OpenDreamInstaller for Windows systems.
Constants used for communication with the DMAPI.
static readonly Version InteropVersion
The DMAPI InteropVersion being used.
DatabaseType DatabaseType
The Configuration.DatabaseType to create.
LogLevel MicrosoftLogLevel
The minimum Microsoft.Extensions.Logging.LogLevel to display in logs for Microsoft library sources.
string GetFullLogDirectory(IIOManager ioManager, IAssemblyInformationProvider assemblyInformationProvider, IPlatformIdentifier platformIdentifier)
Gets the evaluated log Directory.
LogLevel LogLevel
The minimum Microsoft.Extensions.Logging.LogLevel to display in logs.
static readonly Version CurrentConfigVersion
The current ConfigVersion.
bool HostApiDocumentation
If the swagger documentation and UI should be made avaiable.
uint RestartTimeoutMinutes
The timeout minutes for restarting the server.
bool UsingSystemD
If the server is running under SystemD.
Configuration options for the game sessions.
Configuration for the server swarm system.
Configuration for the automatic update system.
const string ControlPanelRoute
Route to the ControlPanelController.
IActionResultExecutor<TResult> for LimitedStreamResults.
Sets up dependency injection.
Definition: Application.cs:72
override void ConfigureHostedService(IServiceCollection services)
Configures the IHostedService.
static void AddWatchdog< TSystemWatchdogFactory >(IServiceCollection services, IPostSetupServices postSetupServices)
Adds the IWatchdogFactory implementation.
Definition: Application.cs:102
void ConfigureServices(IServiceCollection services, IAssemblyInformationProvider assemblyInformationProvider, IIOManager ioManager, IPostSetupServices postSetupServices)
Configure the Application's services .
Definition: Application.cs:131
static IServerFactory CreateDefaultServerFactory()
Create the default IServerFactory.
Definition: Application.cs:87
void ConfigureAuthenticationPipeline(IServiceCollection services)
Configure the services for the authentication pipeline.
Definition: Application.cs:617
ITokenFactory? tokenFactory
The ITokenFactory for the Application.
Definition: Application.cs:81
void Configure(IApplicationBuilder applicationBuilder, IServerControl serverControl, ITokenFactory tokenFactory, IServerPortProvider serverPortProvider, IAssemblyInformationProvider assemblyInformationProvider, IOptions< ControlPanelConfiguration > controlPanelConfigurationOptions, IOptions< GeneralConfiguration > generalConfigurationOptions, IOptions< SwarmConfiguration > swarmConfigurationOptions, ILogger< Application > logger)
Configure the Application.
Definition: Application.cs:456
Application(IConfiguration configuration, IWebHostEnvironment hostingEnvironment)
Initializes a new instance of the Application class.
Definition: Application.cs:116
readonly IWebHostEnvironment hostingEnvironment
The IWebHostEnvironment for the Application.
Definition: Application.cs:76
Reads from the command pipe opened by the host watchdog.
Backend abstract implementation of IDatabaseContext.
IIOManager that resolves paths to Environment.CurrentDirectory.
IPostWriteHandler for POSIX systems.
An IIOManager that resolve relative paths from another IIOManager to a subdirectory of that.
IPostWriteHandler for Windows systems.
Handles mapping groups for the JobsHub.
A SignalR Hub for pushing job updates.
Definition: JobsHub.cs:16
Attribute for bringing in the master versions list from MSBuild that aren't embedded into assemblies ...
string RawWebpanelVersion
The Version string of the control panel version built.
static MasterVersionsAttribute Instance
Return the Assembly's instance of the MasterVersionsAttribute.
A IClaimsTransformation that maps Claims using an IAuthenticationContext.
An IHubFilter that denies method calls and connections if the IAuthenticationContext is not valid for...
ISystemIdentityFactory for windows systems. Uses long running tasks due to potential networked domain...
Implementation of IServerFactory.
DI root for configuring a SetupWizard.
IConfiguration Configuration
The IConfiguration for the SetupApplication.
Helps keep servers connected to the same database in sync by coordinating updates.
Definition: SwarmService.cs:36
Implements the SystemD notify service protocol.
Implementation of the file transfer service.
Helpers for manipulating the Serilog.Context.LogContext.
static string Template
Common template used for adding our custom log context to serilog.
Implements various filters for Swashbuckle.
const string DocumentationSiteRouteExtension
The path to the hosted documentation site.
static void Configure(SwaggerGenOptions swaggerGenOptions, string assemblyDocumentationPath, string apiDocumentationPath)
Configure the swagger settings.
JsonConverter and IYamlTypeConverter for serializing global::System.Versions in semver format.
SignalR client methods for receiving JobResponses.
Definition: IJobsHub.cs:12
For downloading and installing game engines for a given system.
Task Ready
Task that completes when the IInstanceManager finishes initializing.
For low level interactions with a LibGit2Sharp.IRepository.
Represents a service that may take an updated Host assembly and run it, stopping the current assembly...
Provides access to the server's HttpApiPort.
ushort HttpApiPort
The port the server listens on.
Factory for scoping usage of IDatabaseContexts. Meant for use by Components.
For initially setting up a database.
Interface for using filesystems.
Definition: IIOManager.cs:13
string ConcatPath(params string[] paths)
Combines an array of strings into a path.
string GetDirectoryName(string path)
Gets the directory portion of a given path .
string GetFileNameWithoutExtension(string path)
Gets the file name portion of a path with.
Handles changing file modes/permissions after writing.
For accessing the disk in a synchronous manner.
Manages the runtime of Jobs.
Definition: IJobManager.cs:13
The service that manages everything to do with jobs.
Definition: IJobService.cs:9
Allows manually triggering jobs hub updates.
Contains various cryptographic functions.
Receives notifications about permissions updates.
TokenValidationParameters ValidationParameters
The TokenValidationParameters for the ITokenFactory.
Set of objects needed to configure an Core.Application.
ElasticsearchConfiguration ElasticsearchConfiguration
The Configuration.ElasticsearchConfiguration.
InternalConfiguration InternalConfiguration
The Configuration.InternalConfiguration.
GeneralConfiguration GeneralConfiguration
The Configuration.GeneralConfiguration.
DatabaseConfiguration DatabaseConfiguration
The Configuration.DatabaseConfiguration.
IPlatformIdentifier PlatformIdentifier
The IPlatformIdentifier.
FileLoggingConfiguration FileLoggingConfiguration
The Configuration.FileLoggingConfiguration.
Swarm service operations for the Controllers.SwarmController.
Start and stop controllers for a swarm service.
Used for swarm operations. Functions may be no-op based on configuration.
Service for managing the dotnet-dump installation.
On Windows, DreamDaemon will show an unskippable prompt when using /world/proc/OpenPort()....
bool IsWindows
If the current platform is a Windows platform.
Abstraction for suspending and resuming processes.
Reads and writes to Streams associated with FileTicketResponses.
Service for temporarily storing files to be downloaded or uploaded.
Gets unassigned ports for use by TGS.
EngineType
The type of engine the codebase is using.
Definition: EngineType.cs:7
DatabaseType
Type of database to user.
Definition: DatabaseType.cs:7