private static IFtpServerBuilder ConfigureServer(this IFtpServerBuilder builder, FtpOptions options) { builder = builder .DisableChecks(); if (options.Connection.Inactivity.Enabled) { builder = builder .EnableIdleCheck(); builder.Services .Configure <FtpConnectionOptions>( opt => opt.InactivityTimeout = ToTimeSpan(options.Connection.Inactivity.InactivityTimeout)); } if (options.Connection.SocketState.Enabled) { builder = builder .EnableConnectionCheck(); } if (options.Ftps.Implicit) { var implicitFtpsCertificate = options.GetCertificate(); if (implicitFtpsCertificate != null) { builder = builder.UseImplicitTls(implicitFtpsCertificate); } } return(builder); }
public static IServiceCollection AddFtpServices( this IServiceCollection services, FtpOptions options) { services .Configure <AuthTlsOptions>( opt => { opt.ServerCertificate = options.GetCertificate(); opt.ImplicitFtps = options.Ftps.Implicit; }) .Configure <FtpConnectionOptions>(opt => opt.DefaultEncoding = Encoding.ASCII) .Configure <FubarDev.FtpServer.FtpServerOptions>( opt => { opt.ServerAddress = options.Server.Address; opt.Port = options.GetServerPort(); opt.MaxActiveConnections = options.Server.MaxActiveConnections ?? 0; }) .Configure <PortCommandOptions>( opt => { if (options.Server.UseFtpDataPort) { opt.DataPort = options.GetServerPort() - 1; } }) .Configure <SimplePasvOptions>( opt => { var portRange = options.GetPasvPortRange(); if (portRange != null) { (opt.PasvMinPort, opt.PasvMaxPort) = portRange.Value; } }) .Configure <PasvCommandOptions>(opt => opt.PromiscuousPasv = options.Server.Pasv.Promiscuous) .Configure <GoogleDriveOptions>(opt => opt.UseBackgroundUpload = options.GoogleDrive.BackgroundUpload) .Configure <PamMembershipProviderOptions>( opt => opt.IgnoreAccountManagement = options.Pam.NoAccountManagement); // Add "Hello" service - unique per FTP connection services.AddScoped <Hello>(); // Add custom command handlers services.AddSingleton <IFtpCommandHandlerScanner>( _ => new AssemblyFtpCommandHandlerScanner(typeof(HelloFtpCommandHandler).Assembly)); // Add custom command handler extensions services.AddSingleton <IFtpCommandHandlerExtensionScanner>( sp => new AssemblyFtpCommandHandlerExtensionScanner( sp.GetRequiredService <IFtpCommandHandlerProvider>(), sp.GetService <ILogger <AssemblyFtpCommandHandlerExtensionScanner> >(), typeof(SiteHelloFtpCommandHandlerExtension).Assembly)); if (options.SetFileSystemId && RuntimeEnvironment.OperatingSystemPlatform != Microsoft.DotNet.PlatformAbstractions.Platform.Windows) { services.AddScoped <IFtpCommandMiddleware, FsIdChanger>(); } switch (options.BackendType) { case FileSystemType.InMemory: services = services .AddFtpServer(sb => sb.ConfigureAuthentication(options).UseInMemoryFileSystem()) .Configure <InMemoryFileSystemOptions>( opt => opt.KeepAnonymousFileSystem = options.InMemory.KeepAnonymous); break; case FileSystemType.SystemIO: services = services .AddFtpServer(sb => sb.ConfigureAuthentication(options).UseDotNetFileSystem()) .Configure <DotNetFileSystemOptions>(opt => opt.RootPath = options.SystemIo.Root); break; case FileSystemType.Unix: services = services .AddFtpServer(sb => sb.ConfigureAuthentication(options).UseUnixFileSystem()) .Configure <UnixFileSystemOptions>(opt => opt.Root = options.Unix.Root); break; case FileSystemType.GoogleDriveUser: var userCredential = GetUserCredential( options.GoogleDrive.User.ClientSecrets ?? throw new ArgumentNullException( nameof(options.GoogleDrive.User.ClientSecrets), "Client secrets file not specified."), options.GoogleDrive.User.UserName ?? throw new ArgumentNullException( nameof(options.GoogleDrive.User.ClientSecrets), "User name not specified."), options.GoogleDrive.User.RefreshToken); services = services .AddFtpServer(sb => sb.ConfigureAuthentication(options).UseGoogleDrive(userCredential)); break; case FileSystemType.GoogleDriveService: var serviceCredential = GoogleCredential .FromFile(options.GoogleDrive.Service.CredentialFile) .CreateScoped(DriveService.Scope.Drive, DriveService.Scope.DriveFile); services = services .AddFtpServer(sb => sb.ConfigureAuthentication(options).UseGoogleDrive(serviceCredential)); break; default: throw new NotSupportedException( $"Backend of type {options.Backend} cannot be run from configuration file options."); } switch (options.LayoutType) { case FileSystemLayoutType.SingleRoot: services.AddSingleton <IAccountDirectoryQuery, SingleRootWithoutHomeAccountDirectoryQuery>(); break; case FileSystemLayoutType.RootPerUser: services .AddSingleton <IAccountDirectoryQuery, RootPerUserAccountDirectoryQuery>() .Configure <RootPerUserAccountDirectoryQueryOptions>(opt => opt.AnonymousRootPerEmail = true); break; case FileSystemLayoutType.PamHome: services .AddSingleton <IAccountDirectoryQuery, PamAccountDirectoryQuery>() .Configure <PamAccountDirectoryQueryOptions>( opt => opt.AnonymousRootDirectory = Path.GetTempPath()); break; case FileSystemLayoutType.PamHomeChroot: services .AddSingleton <IAccountDirectoryQuery, PamAccountDirectoryQuery>() .Configure <PamAccountDirectoryQueryOptions>( opt => { opt.AnonymousRootDirectory = Path.GetTempPath(); opt.UserHomeIsRoot = true; }); break; } if (options.Ftps.Implicit) { var implicitFtpsCertificate = options.GetCertificate(); if (implicitFtpsCertificate != null) { services .AddSingleton(new ImplicitFtpsControlConnectionStreamAdapterOptions(implicitFtpsCertificate)) .AddSingleton <IFtpControlStreamAdapter, ImplicitFtpsControlConnectionStreamAdapter>(); // Ensure that PROT and PBSZ commands are working. services.Decorate <IFtpServer>( (ftpServer, _) => { ftpServer.ConfigureConnection += (s, e) => { var serviceProvider = e.Connection.ConnectionServices; var stateMachine = serviceProvider.GetRequiredService <IFtpLoginStateMachine>(); var authTlsMechanism = serviceProvider.GetRequiredService <IEnumerable <IAuthenticationMechanism> >() .Single(x => x.CanHandle("TLS")); stateMachine.Activate(authTlsMechanism); }; return(ftpServer); }); } } services.Decorate <IFtpServer>( (ftpServer, serviceProvider) => { /* Setting the umask is only valid for non-Windows platforms. */ if (!string.IsNullOrEmpty(options.Umask) && RuntimeEnvironment.OperatingSystemPlatform != Microsoft.DotNet.PlatformAbstractions.Platform.Windows) { var umask = options.Umask !.StartsWith("0") ? Convert.ToInt32(options.Umask, 8) : Convert.ToInt32(options.Umask, 10); Syscall.umask((FilePermissions)umask); } return(ftpServer); }); services.Scan( ts => ts .FromAssemblyOf <HostedFtpService>() .AddClasses(itf => itf.AssignableTo <IModuleInfo>(), true).As <IModuleInfo>() .WithSingletonLifetime()); return(services); }