diff options
Diffstat (limited to 'Jellyfin.Api')
| -rw-r--r-- | Jellyfin.Api/Extensions/ApiApplicationBuilderExtensions.cs | 19 | ||||
| -rw-r--r-- | Jellyfin.Api/Extensions/ApiServiceCollectionExtensions.cs | 72 | ||||
| -rw-r--r-- | Jellyfin.Api/Jellyfin.Api.csproj | 2 | ||||
| -rw-r--r-- | Jellyfin.Api/MvcRoutePrefix.cs | 48 |
4 files changed, 141 insertions, 0 deletions
diff --git a/Jellyfin.Api/Extensions/ApiApplicationBuilderExtensions.cs b/Jellyfin.Api/Extensions/ApiApplicationBuilderExtensions.cs new file mode 100644 index 000000000..18442bf27 --- /dev/null +++ b/Jellyfin.Api/Extensions/ApiApplicationBuilderExtensions.cs @@ -0,0 +1,19 @@ +using Microsoft.AspNetCore.Builder; + +namespace Jellyfin.Api.Extensions +{ + public static class ApiApplicationBuilderExtensions + { + public static IApplicationBuilder UseJellyfinApiSwagger(this IApplicationBuilder applicationBuilder) + { + applicationBuilder.UseSwagger(); + + // Enable middleware to serve swagger-ui (HTML, JS, CSS, etc.), + // specifying the Swagger JSON endpoint. + return applicationBuilder.UseSwaggerUI(c => + { + c.SwaggerEndpoint("/swagger/v1/swagger.json", "Jellyfin API V1"); + }); + } + } +} diff --git a/Jellyfin.Api/Extensions/ApiServiceCollectionExtensions.cs b/Jellyfin.Api/Extensions/ApiServiceCollectionExtensions.cs new file mode 100644 index 000000000..1c682f8e4 --- /dev/null +++ b/Jellyfin.Api/Extensions/ApiServiceCollectionExtensions.cs @@ -0,0 +1,72 @@ +using Emby.Server.Implementations; +using Jellyfin.Api.Auth; +using Jellyfin.Api.Auth.FirstTimeSetupOrElevatedPolicy; +using Jellyfin.Api.Auth.RequiresElevationPolicy; +using Jellyfin.Api.Controllers; +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Authorization; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.OpenApi.Models; + +namespace Jellyfin.Api.Extensions +{ + public static class ApiServiceCollectionExtensions + { + public static IServiceCollection AddJellyfinApiAuthorization(this IServiceCollection serviceCollection) + { + serviceCollection.AddSingleton<IAuthorizationHandler, FirstTimeSetupOrElevatedHandler>(); + serviceCollection.AddSingleton<IAuthorizationHandler, RequiresElevationHandler>(); + return serviceCollection.AddAuthorizationCore(options => + { + options.AddPolicy( + "RequiresElevation", + policy => + { + policy.AddAuthenticationSchemes("CustomAuthentication"); + policy.AddRequirements(new RequiresElevationRequirement()); + }); + options.AddPolicy( + "FirstTimeSetupOrElevated", + policy => + { + policy.AddAuthenticationSchemes("CustomAuthentication"); + policy.AddRequirements(new FirstTimeSetupOrElevatedRequirement()); + }); + }); + } + + public static AuthenticationBuilder AddCustomAuthentication(this IServiceCollection serviceCollection) + { + return serviceCollection.AddAuthentication("CustomAuthentication") + .AddScheme<AuthenticationSchemeOptions, CustomAuthenticationHandler>("CustomAuthentication", null); + } + + public static IMvcBuilder AddJellyfinApi(this IServiceCollection serviceCollection, string baseUrl) + { + return serviceCollection.AddMvc(opts => + { + var policy = new AuthorizationPolicyBuilder() + .RequireAuthenticatedUser() + .Build(); + opts.Filters.Add(new AuthorizeFilter(policy)); + opts.EnableEndpointRouting = false; + opts.UseGeneralRoutePrefix(baseUrl); + }) + .SetCompatibilityVersion(CompatibilityVersion.Version_2_2) + // Clear app parts to avoid other assemblies being picked up + .ConfigureApplicationPartManager(a => a.ApplicationParts.Clear()) + .AddApplicationPart(typeof(StartupController).Assembly) + .AddControllersAsServices(); + } + + public static IServiceCollection AddJellyfinApiSwagger(this IServiceCollection serviceCollection) + { + return serviceCollection.AddSwaggerGen(c => + { + c.SwaggerDoc("v1", new OpenApiInfo { Title = "Jellyfin API", Version = "v1" }); + }); + } + } +} diff --git a/Jellyfin.Api/Jellyfin.Api.csproj b/Jellyfin.Api/Jellyfin.Api.csproj index 647004cb6..d77861cc4 100644 --- a/Jellyfin.Api/Jellyfin.Api.csproj +++ b/Jellyfin.Api/Jellyfin.Api.csproj @@ -6,7 +6,9 @@ <ItemGroup> <PackageReference Include="Microsoft.AspNetCore.Authentication" Version="2.2.0" /> + <PackageReference Include="Microsoft.AspNetCore.Authorization" Version="3.0.0" /> <PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.2.0" /> + <PackageReference Include="Swashbuckle.AspNetCore" Version="5.0.0-rc4" /> </ItemGroup> <ItemGroup> diff --git a/Jellyfin.Api/MvcRoutePrefix.cs b/Jellyfin.Api/MvcRoutePrefix.cs new file mode 100644 index 000000000..974a2a885 --- /dev/null +++ b/Jellyfin.Api/MvcRoutePrefix.cs @@ -0,0 +1,48 @@ +using System.Collections.Generic; +using System.Linq; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.ApplicationModels; + +namespace Emby.Server.Implementations +{ + public static class MvcRoutePrefix + { + public static void UseGeneralRoutePrefix(this MvcOptions opts, params string[] prefixes) + { + opts.Conventions.Insert(0, new RoutePrefixConvention(prefixes)); + } + + private class RoutePrefixConvention : IApplicationModelConvention + { + private readonly AttributeRouteModel[] _routePrefixes; + + public RoutePrefixConvention(IEnumerable<string> prefixes) + { + _routePrefixes = prefixes.Select(p => new AttributeRouteModel(new RouteAttribute(p))).ToArray(); + } + + public void Apply(ApplicationModel application) + { + foreach (var controller in application.Controllers) + { + if (controller.Selectors == null) + { + continue; + } + + var newSelectors = new List<SelectorModel>(); + foreach (var selector in controller.Selectors) + { + newSelectors.AddRange(_routePrefixes.Select(routePrefix => new SelectorModel(selector) + { + AttributeRouteModel = AttributeRouteModel.CombineAttributeRouteModel(routePrefix, selector.AttributeRouteModel) + })); + } + + controller.Selectors.Clear(); + newSelectors.ForEach(selector => controller.Selectors.Add(selector)); + } + } + } + } +} |
