Moving authentification beahviors to a specific module

This commit is contained in:
Zoe Roux 2021-05-03 01:48:53 +02:00
parent 97511d5988
commit 7613efb4b4
43 changed files with 670 additions and 4036 deletions

View File

@ -0,0 +1,37 @@
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using IdentityServer4.Extensions;
using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.Configuration;
namespace Kyoo.Authentication
{
public class AuthorizationValidatorHandler : AuthorizationHandler<AuthorizationValidator>
{
private readonly IConfiguration _configuration;
public AuthorizationValidatorHandler(IConfiguration configuration)
{
_configuration = configuration;
}
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, AuthorizationValidator requirement)
{
if (!context.User.IsAuthenticated())
{
string defaultPerms = _configuration.GetValue<string>("defaultPermissions");
if (defaultPerms.Split(',').Contains(requirement.Permission.ToLower()))
context.Succeed(requirement);
}
else
{
Claim perms = context.User.Claims.FirstOrDefault(x => x.Type == "permissions");
if (perms != null && perms.Value.Split(",").Contains(requirement.Permission.ToLower()))
context.Succeed(requirement);
}
return Task.CompletedTask;
}
}
}

View File

@ -0,0 +1,14 @@
using Microsoft.AspNetCore.Authorization;
namespace Kyoo.Authentication
{
public class AuthorizationValidator : IAuthorizationRequirement
{
public string Permission { get; }
public AuthorizationValidator(string permission)
{
Permission = permission;
}
}
}

View File

@ -0,0 +1,171 @@
using System;
using System.Collections.Generic;
using IdentityServer4.Extensions;
using IdentityServer4.Services;
using Kyoo.Authentication.Models;
using Kyoo.Controllers;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
namespace Kyoo.Authentication
{
/// <summary>
/// A module that enable OpenID authentication for Kyoo.
/// </summary>
public class AuthenticationModule : IPlugin
{
/// <inheritdoc />
public string Slug => "auth";
/// <inheritdoc />
public string Name => "Authentication";
/// <inheritdoc />
public string Description => "Enable OpenID authentication for Kyoo.";
/// <inheritdoc />
public ICollection<Type> Provides => ArraySegment<Type>.Empty;
/// <inheritdoc />
public ICollection<ConditionalProvide> ConditionalProvides => ArraySegment<ConditionalProvide>.Empty;
/// <inheritdoc />
public ICollection<Type> Requires => ArraySegment<Type>.Empty;
/// <summary>
/// The configuration to use.
/// </summary>
private readonly IConfiguration _configuration;
/// <summary>
/// A logger factory to allow IdentityServer to log things.
/// </summary>
private readonly ILoggerFactory _loggerFactory;
/// <summary>
/// Create a new authentication module instance and use the given configuration and environment.
/// </summary>
/// <param name="configuration">The configuration to use</param>
/// <param name="loggerFactory">The logger factory to allow IdentityServer to log things</param>
public AuthenticationModule(IConfiguration configuration, ILoggerFactory loggerFactory)
{
_configuration = configuration;
_loggerFactory = loggerFactory;
}
/// <inheritdoc />
public IServiceCollection Configure(IServiceCollection services, ICollection<Type> availableTypes)
{
string publicUrl = _configuration.GetValue<string>("public_url");
// services.AddDbContext<IdentityDatabase>(options =>
// {
// options.UseNpgsql(_configuration.GetDatabaseConnection("postgres"));
// });
// services.AddIdentityCore<User>(o =>
// {
// o.Stores.MaxLengthForKeys = 128;
// })
// .AddSignInManager()
// .AddDefaultTokenProviders()
// .AddEntityFrameworkStores<IdentityDatabase>();
CertificateOption certificateOptions = new();
_configuration.GetSection(CertificateOption.Path).Bind(certificateOptions);
services.AddIdentityServer(options =>
{
options.IssuerUri = publicUrl;
options.UserInteraction.LoginUrl = publicUrl + "login";
options.UserInteraction.ErrorUrl = publicUrl + "error";
options.UserInteraction.LogoutUrl = publicUrl + "logout";
})
// .AddAspNetIdentity<User>()
// .AddConfigurationStore(options =>
// {
// options.ConfigureDbContext = builder =>
// builder.UseNpgsql(_configuration.GetDatabaseConnection("postgres"),
// sql => sql.MigrationsAssembly(assemblyName));
// })
// .AddOperationalStore(options =>
// {
// options.ConfigureDbContext = builder =>
// builder.UseNpgsql(_configuration.GetDatabaseConnection("postgres"),
// sql => sql.MigrationsAssembly(assemblyName));
// options.EnableTokenCleanup = true;
// })
.AddInMemoryIdentityResources(IdentityContext.GetIdentityResources())
.AddInMemoryApiScopes(IdentityContext.GetScopes())
.AddInMemoryApiResources(IdentityContext.GetApis())
// .AddProfileService<AccountController>()
.AddSigninKeys(certificateOptions);
services.AddAuthentication(o =>
{
o.DefaultScheme = IdentityConstants.ApplicationScheme;
o.DefaultSignInScheme = IdentityConstants.ExternalScheme;
})
.AddIdentityCookies(_ => { });
services.AddAuthentication()
.AddJwtBearer(options =>
{
options.Authority = publicUrl;
options.Audience = "Kyoo";
options.RequireHttpsMetadata = false;
});
services.AddAuthorization(options =>
{
AuthorizationPolicyBuilder scheme = new(IdentityConstants.ApplicationScheme,
JwtBearerDefaults.AuthenticationScheme);
options.DefaultPolicy = scheme.RequireAuthenticatedUser().Build();
string[] permissions = {"Read", "Write", "Play", "Admin"};
foreach (string permission in permissions)
{
options.AddPolicy(permission, policy =>
{
policy.AuthenticationSchemes.Add(IdentityConstants.ApplicationScheme);
policy.AuthenticationSchemes.Add(JwtBearerDefaults.AuthenticationScheme);
policy.AddRequirements(new AuthorizationValidator(permission));
policy.RequireScope($"kyoo.{permission.ToLower()}");
});
}
});
services.AddSingleton<IAuthorizationHandler, AuthorizationValidatorHandler>();
DefaultCorsPolicyService cors = new(_loggerFactory.CreateLogger<DefaultCorsPolicyService>())
{
AllowedOrigins = {new Uri(publicUrl).GetLeftPart(UriPartial.Authority)}
};
services.AddSingleton<ICorsPolicyService>(cors);
return services;
}
/// <inheritdoc />
public void ConfigureAspNet(IApplicationBuilder app)
{
app.UseAuthorization();
app.UseCookiePolicy(new CookiePolicyOptions
{
MinimumSameSitePolicy = SameSiteMode.Strict
});
app.UseAuthentication();
app.Use((ctx, next) =>
{
ctx.SetIdentityServerOrigin(_configuration.GetValue<string>("public_url"));
return next();
});
app.UseIdentityServer();
}
}
}

View File

@ -0,0 +1,120 @@
using System;
using System.IO;
using System.Security.Cryptography.X509Certificates;
using Kyoo.Authentication.Models;
using Microsoft.Extensions.DependencyInjection;
using Org.BouncyCastle.Asn1.X509;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Generators;
using Org.BouncyCastle.Crypto.Operators;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Pkcs;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Utilities;
using Org.BouncyCastle.X509;
using X509Certificate = Org.BouncyCastle.X509.X509Certificate;
namespace Kyoo.Authentication
{
/// <summary>
/// A class containing multiple extensions methods to manage certificates.
/// </summary>
public static class Certificates
{
/// <summary>
/// Add the certificate file to the identity server. If the certificate will expire soon, automatically renew it.
/// If no certificate exists, one is generated.
/// </summary>
/// <param name="builder">The identity server that will be modified.</param>
/// <param name="options">The certificate options</param>
/// <returns></returns>
public static IIdentityServerBuilder AddSigninKeys(this IIdentityServerBuilder builder,
CertificateOption options)
{
X509Certificate2 certificate = GetCertificate(options);
builder.AddSigningCredential(certificate);
if (certificate.NotAfter.AddDays(7) <= DateTime.UtcNow)
{
Console.WriteLine("Signin certificate will expire soon, renewing it.");
if (File.Exists(options.OldFile))
File.Delete(options.OldFile);
File.Move(options.File, options.OldFile);
builder.AddValidationKey(GenerateCertificate(options.File, options.Password));
}
else if (File.Exists(options.OldFile))
builder.AddValidationKey(GetExistingCredential(options.OldFile, options.Password));
return builder;
}
/// <summary>
/// Get or generate the sign-in certificate.
/// </summary>
/// <param name="options">The certificate options</param>
/// <returns>A valid certificate</returns>
private static X509Certificate2 GetCertificate(CertificateOption options)
{
return File.Exists(options.File)
? GetExistingCredential(options.File, options.Password)
: GenerateCertificate(options.File, options.Password);
}
/// <summary>
/// Load a certificate from a file
/// </summary>
/// <param name="file">The path of the certificate</param>
/// <param name="password">The password of the certificate</param>
/// <returns>The loaded certificate</returns>
private static X509Certificate2 GetExistingCredential(string file, string password)
{
return new(file, password,
X509KeyStorageFlags.MachineKeySet |
X509KeyStorageFlags.PersistKeySet |
X509KeyStorageFlags.Exportable
);
}
/// <summary>
/// Generate a new certificate key and put it in the file at <see cref="file"/>.
/// </summary>
/// <param name="file">The path of the output file</param>
/// <param name="password">The password of the new certificate</param>
/// <returns>The generated certificate</returns>
private static X509Certificate2 GenerateCertificate(string file, string password)
{
SecureRandom random = new();
X509V3CertificateGenerator certificateGenerator = new();
certificateGenerator.SetSerialNumber(BigIntegers.CreateRandomInRange(BigInteger.One,
BigInteger.ValueOf(long.MaxValue), random));
certificateGenerator.SetIssuerDN(new X509Name($"C=NL, O=SDG, CN=Kyoo"));
certificateGenerator.SetSubjectDN(new X509Name($"C=NL, O=SDG, CN=Kyoo"));
certificateGenerator.SetNotBefore(DateTime.UtcNow.Date);
certificateGenerator.SetNotAfter(DateTime.UtcNow.Date.AddMonths(3));
KeyGenerationParameters keyGenerationParameters = new(random, 2048);
RsaKeyPairGenerator keyPairGenerator = new();
keyPairGenerator.Init(keyGenerationParameters);
AsymmetricCipherKeyPair subjectKeyPair = keyPairGenerator.GenerateKeyPair();
certificateGenerator.SetPublicKey(subjectKeyPair.Public);
const string signatureAlgorithm = "MD5WithRSA";
Asn1SignatureFactory signatureFactory = new(signatureAlgorithm, subjectKeyPair.Private);
X509Certificate bouncyCert = certificateGenerator.Generate(signatureFactory);
Pkcs12Store store = new Pkcs12StoreBuilder().Build();
store.SetKeyEntry("Kyoo_key", new AsymmetricKeyEntry(subjectKeyPair.Private), new []
{
new X509CertificateEntry(bouncyCert)
});
using MemoryStream pfxStream = new();
store.Save(pfxStream, password.ToCharArray(), random);
X509Certificate2 certificate = new(pfxStream.ToArray(), password, X509KeyStorageFlags.Exportable);
using FileStream fileStream = File.OpenWrite(file);
pfxStream.WriteTo(fileStream);
return certificate;
}
}
}

View File

@ -1,6 +0,0 @@
using System;
namespace Kyoo.Authentication
{
public class Class1 { }
}

View File

@ -2,7 +2,7 @@ using System.Collections.Generic;
using System.Linq;
using IdentityServer4.Models;
namespace Kyoo
namespace Kyoo.Authentication
{
public static class IdentityContext
{

View File

@ -0,0 +1,47 @@
// using System.Threading.Tasks;
// using IdentityServer4.EntityFramework.Entities;
// using IdentityServer4.EntityFramework.Extensions;
// using IdentityServer4.EntityFramework.Interfaces;
// using IdentityServer4.EntityFramework.Options;
// using Kyoo.Models;
// using Microsoft.AspNetCore.Identity;
// using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
// using Microsoft.EntityFrameworkCore;
// using Microsoft.Extensions.Options;
//
// namespace Kyoo
// {
// // The configuration's database is named ConfigurationDbContext.
// public class IdentityDatabase : IdentityDbContext<User>, IPersistedGrantDbContext
// {
// private readonly IOptions<OperationalStoreOptions> _operationalStoreOptions;
//
// public IdentityDatabase(DbContextOptions<IdentityDatabase> options, IOptions<OperationalStoreOptions> operationalStoreOptions)
// : base(options)
// {
// _operationalStoreOptions = operationalStoreOptions;
// }
//
// public DbSet<User> Accounts { get; set; }
//
// protected override void OnModelCreating(ModelBuilder modelBuilder)
// {
// base.OnModelCreating(modelBuilder);
// modelBuilder.ConfigurePersistedGrantContext(_operationalStoreOptions.Value);
//
// modelBuilder.Entity<User>().ToTable("User");
// modelBuilder.Entity<IdentityUserRole<string>>().ToTable("UserRole");
// modelBuilder.Entity<IdentityUserLogin<string>>().ToTable("UserLogin");
// modelBuilder.Entity<IdentityUserClaim<string>>().ToTable("UserClaim");
// modelBuilder.Entity<IdentityRole>().ToTable("UserRoles");
// modelBuilder.Entity<IdentityRoleClaim<string>>().ToTable("UserRoleClaim");
// modelBuilder.Entity<IdentityUserToken<string>>().ToTable("UserToken");
// }
//
// public Task<int> SaveChangesAsync() => base.SaveChangesAsync();
//
// public DbSet<PersistedGrant> PersistedGrants { get; set; }
// public DbSet<DeviceFlowCodes> DeviceFlowCodes { get; set; }
//
// }
// }

View File

@ -2,11 +2,12 @@
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<OutputPath>../Kyoo/bin/$(Configuration)/$(TargetFramework)/plugins/postgresql</OutputPath>
<OutputPath>../Kyoo/bin/$(Configuration)/$(TargetFramework)/plugins/authentication</OutputPath>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<ProduceReferenceAssembly>false</ProduceReferenceAssembly>
<GenerateDependencyFile>false</GenerateDependencyFile>
<GenerateRuntimeConfigurationFiles>false</GenerateRuntimeConfigurationFiles>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
<Company>SDG</Company>
<Authors>Zoe Roux</Authors>
@ -14,6 +15,16 @@
<LangVersion>default</LangVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="IdentityServer4" Version="4.1.1" />
<PackageReference Include="IdentityServer4.AspNetIdentity" Version="4.1.1" />
<PackageReference Include="IdentityServer4.EntityFramework" Version="4.1.1" />
<PackageReference Include="IdentityServer4.EntityFramework.Storage" Version="4.1.1" />
<PackageReference Include="IdentityServer4.Storage" Version="4.1.1" />
<PackageReference Include="IdentityServer4.AccessTokenValidation" Version="3.0.1" />
<PackageReference Include="Portable.BouncyCastle" Version="1.8.9" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="../Kyoo.Common/Kyoo.Common.csproj">
<PrivateAssets>all</PrivateAssets>

View File

@ -0,0 +1,26 @@
namespace Kyoo.Authentication.Models
{
/// <summary>
/// A typed option model for the certificate
/// </summary>
public class CertificateOption
{
/// <summary>
/// The path to get this option from the root configuration.
/// </summary>
public const string Path = "authentication:certificate";
/// <summary>
/// The path of the certificate file.
/// </summary>
public string File { get; set; }
/// <summary>
/// The path of the old certificate file.
/// </summary>
public string OldFile { get; set; }
/// <summary>
/// The password of the certificates.
/// </summary>
public string Password { get; set; }
}
}

View File

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using JetBrains.Annotations;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Unity;
namespace Kyoo.Controllers
@ -62,7 +63,25 @@ namespace Kyoo.Controllers
/// <param name="availableTypes">The list of types that are available for this instance. This can be used
/// for conditional type. See <see cref="ProviderCondition.Has(System.Type,System.Collections.Generic.ICollection{System.Type})"/>
/// or <see cref="ProviderCondition.Has(System.Collections.Generic.ICollection{System.Type},System.Collections.Generic.ICollection{System.Type})"/>></param>
void Configure(IUnityContainer container, ICollection<Type> availableTypes);
void Configure(IUnityContainer container, ICollection<Type> availableTypes) {}
/// <summary>
/// An optional configure method that will be run on plugin's startup.
/// This method may be used instead or with the
/// <see cref="Configure(Unity.IUnityContainer,System.Collections.Generic.ICollection{System.Type})"/> method
/// if you use a library that configure itself with a <see cref="IServiceCollection"/>.
/// Every service put in this container will be registered to the unity container after this method.
/// </summary>
/// <param name="services">An empty service container to register new services.</param>
/// <param name="availableTypes">The list of types that are available for this instance. This can be used
/// for conditional type. See <see cref="ProviderCondition.Has(System.Type,System.Collections.Generic.ICollection{System.Type})"/>
/// or <see cref="ProviderCondition.Has(System.Collections.Generic.ICollection{System.Type},System.Collections.Generic.ICollection{System.Type})"/>></param>
/// <returns>You should return the <see cref="services"/> parameter or another container if you want.
/// This container will be added to Kyoo's unity container.</returns>
IServiceCollection Configure(IServiceCollection services, ICollection<Type> availableTypes)
{
return services;
}
/// <summary>
/// An optional configuration step to allow a plugin to change asp net configurations.

View File

@ -28,4 +28,10 @@
<PackageReference Include="Unity.Abstractions" Version="5.11.7" />
</ItemGroup>
<ItemGroup>
<Reference Include="Microsoft.Extensions.DependencyInjection.Abstractions, Version=5.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60">
<HintPath>..\..\..\..\..\..\usr\share\dotnet\shared\Microsoft.AspNetCore.App\5.0.5\Microsoft.Extensions.DependencyInjection.Abstractions.dll</HintPath>
</Reference>
</ItemGroup>
</Project>

View File

@ -0,0 +1,91 @@
using System;
using System.Reflection;
namespace Kyoo
{
/// <summary>
/// Static class containing MethodOf calls.
/// </summary>
public static class MethodOfUtils
{
/// <summary>
/// Get a MethodInfo from a direct method.
/// </summary>
/// <param name="action">The method (without any arguments or return value.</param>
/// <returns>The <see cref="MethodInfo"/> of the given method</returns>
public static MethodInfo MethodOf(Action action)
{
return action.Method;
}
/// <summary>
/// Get a MethodInfo from a direct method.
/// </summary>
/// <param name="action">The method (without any arguments or return value.</param>
/// <returns>The <see cref="MethodInfo"/> of the given method</returns>
public static MethodInfo MethodOf<T>(Action<T> action)
{
return action.Method;
}
/// <summary>
/// Get a MethodInfo from a direct method.
/// </summary>
/// <param name="action">The method (without any arguments or return value.</param>
/// <returns>The <see cref="MethodInfo"/> of the given method</returns>
public static MethodInfo MethodOf<T, T2>(Action<T, T2> action)
{
return action.Method;
}
/// <summary>
/// Get a MethodInfo from a direct method.
/// </summary>
/// <param name="action">The method (without any arguments or return value.</param>
/// <returns>The <see cref="MethodInfo"/> of the given method</returns>
public static MethodInfo MethodOf<T, T2, T3>(Action<T, T2, T3> action)
{
return action.Method;
}
/// <summary>
/// Get a MethodInfo from a direct method.
/// </summary>
/// <param name="action">The method (without any arguments or return value.</param>
/// <returns>The <see cref="MethodInfo"/> of the given method</returns>
public static MethodInfo MethodOf<T>(Func<T> action)
{
return action.Method;
}
/// <summary>
/// Get a MethodInfo from a direct method.
/// </summary>
/// <param name="action">The method (without any arguments or return value.</param>
/// <returns>The <see cref="MethodInfo"/> of the given method</returns>
public static MethodInfo MethodOf<T, T2>(Func<T, T2> action)
{
return action.Method;
}
/// <summary>
/// Get a MethodInfo from a direct method.
/// </summary>
/// <param name="action">The method (without any arguments or return value.</param>
/// <returns>The <see cref="MethodInfo"/> of the given method</returns>
public static MethodInfo MethodOf<T, T2, T3>(Func<T, T2, T3> action)
{
return action.Method;
}
/// <summary>
/// Get a MethodInfo from a direct method.
/// </summary>
/// <param name="action">The method (without any arguments or return value.</param>
/// <returns>The <see cref="MethodInfo"/> of the given method</returns>
public static MethodInfo MethodOf<T, T2, T3, T4>(Func<T, T2, T3, T4> action)
{
return action.Method;
}
}
}

View File

@ -2,10 +2,21 @@ using System;
namespace Kyoo.Models.Attributes
{
public class NotMergableAttribute : Attribute { }
/// <summary>
/// Specify that a property can't be merged.
/// </summary>
[AttributeUsage(AttributeTargets.Property)]
public class NotMergeableAttribute : Attribute { }
/// <summary>
/// An interface with a method called when this object is merged.
/// </summary>
public interface IOnMerge
{
/// <summary>
/// This function is called after the object has been merged.
/// </summary>
/// <param name="merged">The object that has been merged with this.</param>
void OnMerge(object merged);
}
}

View File

@ -0,0 +1,23 @@
using System;
namespace Kyoo.Models.Attributes
{
/// <summary>
/// Specify permissions needed for the API.
/// </summary>
[AttributeUsage(AttributeTargets.Method)]
public class PermissionAttribute : Attribute
{
public enum Kind
{
Read,
Write,
Admin
}
public PermissionAttribute(string type, Kind permission)
{
}
}
}

View File

@ -146,7 +146,7 @@ namespace Kyoo
}
/// <summary>
/// Set every fields of first to those of second. Ignore fields marked with the <see cref="NotMergableAttribute"/> attribute
/// Set every fields of first to those of second. Ignore fields marked with the <see cref="NotMergeableAttribute"/> attribute
/// At the end, the OnMerge method of first will be called if first is a <see cref="IOnMerge"/>
/// </summary>
/// <param name="first">The object to assign</param>
@ -158,7 +158,7 @@ namespace Kyoo
Type type = typeof(T);
IEnumerable<PropertyInfo> properties = type.GetProperties()
.Where(x => x.CanRead && x.CanWrite
&& Attribute.GetCustomAttribute(x, typeof(NotMergableAttribute)) == null);
&& Attribute.GetCustomAttribute(x, typeof(NotMergeableAttribute)) == null);
foreach (PropertyInfo property in properties)
{
@ -191,7 +191,7 @@ namespace Kyoo
Type type = typeof(T);
IEnumerable<PropertyInfo> properties = type.GetProperties()
.Where(x => x.CanRead && x.CanWrite
&& Attribute.GetCustomAttribute(x, typeof(NotMergableAttribute)) == null);
&& Attribute.GetCustomAttribute(x, typeof(NotMergeableAttribute)) == null);
if (where != null)
properties = properties.Where(where);
@ -232,7 +232,7 @@ namespace Kyoo
Type type = typeof(T);
IEnumerable<PropertyInfo> properties = type.GetProperties()
.Where(x => x.CanRead && x.CanWrite
&& Attribute.GetCustomAttribute(x, typeof(NotMergableAttribute)) == null);
&& Attribute.GetCustomAttribute(x, typeof(NotMergeableAttribute)) == null);
foreach (PropertyInfo property in properties)
{

View File

@ -1,5 +1,6 @@
using System;
using System.Linq;
using System.Linq.Expressions;
using System.Threading;
using System.Threading.Tasks;
using Kyoo.Controllers;
@ -463,5 +464,15 @@ namespace Kyoo
entry.State = EntityState.Detached;
}
}
/// <summary>
/// Perform a case insensitive like operation.
/// </summary>
/// <param name="query">An accessor to get the item that will be checked.</param>
/// <param name="format">The second operator of the like format.</param>
/// <typeparam name="T">The type of the item to query</typeparam>
/// <returns>An expression representing the like query. It can directly be passed to a where call.</returns>
public abstract Expression<Func<T, bool>> Like<T>(Expression<Func<T, string>> query, string format);
}
}

View File

@ -1,4 +1,6 @@
using System;
using System.Linq.Expressions;
using System.Reflection;
using Kyoo.Models;
using Microsoft.EntityFrameworkCore;
using Npgsql;
@ -72,5 +74,14 @@ namespace Kyoo.Postgresql
{
return ex.InnerException is PostgresException {SqlState: PostgresErrorCodes.UniqueViolation};
}
/// <inheritdoc />
public override Expression<Func<T, bool>> Like<T>(Expression<Func<T, string>> query, string format)
{
MethodInfo iLike = MethodOfUtils.MethodOf<string, string, bool>(EF.Functions.ILike);
MethodCallExpression call = Expression.Call(iLike, query.Body, Expression.Constant(format));
return Expression.Lambda<Func<T, bool>>(call, query.Parameters);
}
}
}

View File

@ -25,7 +25,7 @@ namespace Kyoo.Postgresql
/// <inheritdoc />
public ICollection<Type> Provides => new[]
{
typeof(PostgresContext)
typeof(DatabaseContext)
};
/// <inheritdoc />

View File

@ -1,137 +0,0 @@
using System;
using System.IO;
using System.Linq;
using System.Security.Claims;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;
using IdentityServer4.Extensions;
using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Org.BouncyCastle.Asn1.X509;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Generators;
using Org.BouncyCastle.Crypto.Operators;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Pkcs;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Utilities;
using Org.BouncyCastle.X509;
using X509Certificate = Org.BouncyCastle.X509.X509Certificate;
namespace Kyoo.Controllers
{
public static class AuthExtension
{
private const string CertificateFile = "certificate.pfx";
private const string OldCertificateFile = "oldCertificate.pfx";
public static IIdentityServerBuilder AddSigninKeys(this IIdentityServerBuilder builder, IConfiguration configuration)
{
X509Certificate2 certificate = GetSiginCredential(configuration);
builder.AddSigningCredential(certificate);
if (certificate.NotAfter.AddDays(7) <= DateTime.UtcNow)
{
Console.WriteLine("Signin certificate will expire soon, renewing it.");
if (File.Exists(OldCertificateFile))
File.Delete(OldCertificateFile);
File.Move(CertificateFile, OldCertificateFile);
builder.AddValidationKey(GenerateCertificate(CertificateFile, configuration.GetValue<string>("certificatePassword")));
}
else if (File.Exists(OldCertificateFile))
builder.AddValidationKey(GetExistingCredential(OldCertificateFile, configuration.GetValue<string>("certificatePassword")));
return builder;
}
private static X509Certificate2 GetSiginCredential(IConfiguration configuration)
{
if (File.Exists(CertificateFile))
return GetExistingCredential(CertificateFile, configuration.GetValue<string>("certificatePassword"));
return GenerateCertificate(CertificateFile, configuration.GetValue<string>("certificatePassword"));
}
private static X509Certificate2 GetExistingCredential(string file, string password)
{
return new X509Certificate2(file, password,
X509KeyStorageFlags.MachineKeySet |
X509KeyStorageFlags.PersistKeySet |
X509KeyStorageFlags.Exportable
);
}
private static X509Certificate2 GenerateCertificate(string file, string password)
{
SecureRandom random = new SecureRandom();
X509V3CertificateGenerator certificateGenerator = new X509V3CertificateGenerator();
certificateGenerator.SetSerialNumber(BigIntegers.CreateRandomInRange(BigInteger.One, BigInteger.ValueOf(Int64.MaxValue), random));
certificateGenerator.SetIssuerDN(new X509Name($"C=NL, O=SDG, CN=Kyoo"));
certificateGenerator.SetSubjectDN(new X509Name($"C=NL, O=SDG, CN=Kyoo"));
certificateGenerator.SetNotBefore(DateTime.UtcNow.Date);
certificateGenerator.SetNotAfter(DateTime.UtcNow.Date.AddMonths(3));
KeyGenerationParameters keyGenerationParameters = new KeyGenerationParameters(random, 2048);
RsaKeyPairGenerator keyPairGenerator = new RsaKeyPairGenerator();
keyPairGenerator.Init(keyGenerationParameters);
AsymmetricCipherKeyPair subjectKeyPair = keyPairGenerator.GenerateKeyPair();
certificateGenerator.SetPublicKey(subjectKeyPair.Public);
AsymmetricCipherKeyPair issuerKeyPair = subjectKeyPair;
const string signatureAlgorithm = "MD5WithRSA";
Asn1SignatureFactory signatureFactory = new Asn1SignatureFactory(signatureAlgorithm, issuerKeyPair.Private);
X509Certificate bouncyCert = certificateGenerator.Generate(signatureFactory);
X509Certificate2 certificate;
Pkcs12Store store = new Pkcs12StoreBuilder().Build();
store.SetKeyEntry("Kyoo_key", new AsymmetricKeyEntry(subjectKeyPair.Private), new [] {new X509CertificateEntry(bouncyCert)});
using MemoryStream pfxStream = new MemoryStream();
store.Save(pfxStream, password.ToCharArray(), random);
certificate = new X509Certificate2(pfxStream.ToArray(), password, X509KeyStorageFlags.Exportable);
using FileStream fileStream = File.OpenWrite(file);
pfxStream.WriteTo(fileStream);
return certificate;
}
}
public class AuthorizationValidatorHandler : AuthorizationHandler<AuthorizationValidator>
{
private readonly IConfiguration _configuration;
public AuthorizationValidatorHandler(IConfiguration configuration)
{
_configuration = configuration;
}
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, AuthorizationValidator requirement)
{
if (!context.User.IsAuthenticated())
{
string defaultPerms = _configuration.GetValue<string>("defaultPermissions");
if (defaultPerms.Split(',').Contains(requirement.Permission.ToLower()))
context.Succeed(requirement);
}
else
{
Claim perms = context.User.Claims.FirstOrDefault(x => x.Type == "permissions");
if (perms != null && perms.Value.Split(",").Contains(requirement.Permission.ToLower()))
context.Succeed(requirement);
}
return Task.CompletedTask;
}
}
public class AuthorizationValidator : IAuthorizationRequirement
{
public string Permission;
public AuthorizationValidator(string permission)
{
Permission = permission;
}
}
}

View File

@ -5,7 +5,9 @@ using System.Linq;
using System.Reflection;
using System.Runtime.Loader;
using Kyoo.Models.Exceptions;
using Kyoo.UnityExtensions;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Unity;
@ -111,7 +113,10 @@ namespace Kyoo.Controllers
_logger.LogCritical(error, "A plugin's dependency could not be met");
}
else
{
plugin.Configure(_container, available);
_container.AddServices(plugin.Configure(new ServiceCollection(), available));
}
}
if (!_plugins.Any())
@ -146,12 +151,16 @@ namespace Kyoo.Controllers
.ToList();
if (!needed.Any())
return true;
_logger.LogWarning("The type {Type} is not available, {Dependencies} could not be met",
conditional.Type.Name,
needed.Select(x => x.Name));
if (log && available.All(x => x != conditional.Type))
{
_logger.LogWarning("The type {Type} is not available, {Dependencies} could not be met",
conditional.Type.Name,
needed.Select(x => x.Name));
}
return false;
}
// ReSharper disable once ForeachCanBeConvertedToQueryUsingAnotherGetEnumerator
foreach (ConditionalProvide conditional in conditionals)
{
if (IsAvailable(conditional, true))

View File

@ -35,7 +35,7 @@ namespace Kyoo.Controllers
public override async Task<ICollection<Collection>> Search(string query)
{
return await _database.Collections
.Where(x => EF.Functions.ILike(x.Name, $"%{query}%"))
.Where(_database.Like<Collection>(x => x.Name, $"%{query}%"))
.OrderBy(DefaultSort)
.Take(20)
.ToListAsync();

View File

@ -156,7 +156,8 @@ namespace Kyoo.Controllers
public override async Task<ICollection<Episode>> Search(string query)
{
List<Episode> episodes = await _database.Episodes
.Where(x => EF.Functions.ILike(x.Title, $"%{query}%") && x.EpisodeNumber != -1)
.Where(x => x.EpisodeNumber != -1)
.Where(_database.Like<Episode>(x => x.Title, $"%{query}%"))
.OrderBy(DefaultSort)
.Take(20)
.ToListAsync();

View File

@ -36,7 +36,7 @@ namespace Kyoo.Controllers
public override async Task<ICollection<Genre>> Search(string query)
{
return await _database.Genres
.Where(genre => EF.Functions.ILike(genre.Name, $"%{query}%"))
.Where(_database.Like<Genre>(x => x.Name, $"%{query}%"))
.OrderBy(DefaultSort)
.Take(20)
.ToListAsync();

View File

@ -101,7 +101,7 @@ namespace Kyoo.Controllers
public override async Task<ICollection<LibraryItem>> Search(string query)
{
return await ItemsQuery
.Where(x => EF.Functions.ILike(x.Title, $"%{query}%"))
.Where(_database.Like<LibraryItem>(x => x.Title, $"%{query}%"))
.OrderBy(DefaultSort)
.Take(20)
.ToListAsync();

View File

@ -43,7 +43,7 @@ namespace Kyoo.Controllers
public override async Task<ICollection<Library>> Search(string query)
{
return await _database.Libraries
.Where(x => EF.Functions.ILike(x.Name, $"%{query}%"))
.Where(_database.Like<Library>(x => x.Name, $"%{query}%"))
.OrderBy(DefaultSort)
.Take(20)
.ToListAsync();

View File

@ -6,7 +6,6 @@ using System.Threading.Tasks;
using Kyoo.Models;
using Kyoo.Models.Exceptions;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
namespace Kyoo.Controllers
{
@ -52,7 +51,7 @@ namespace Kyoo.Controllers
public override async Task<ICollection<People>> Search(string query)
{
return await _database.People
.Where(people => EF.Functions.ILike(people.Name, $"%{query}%"))
.Where(_database.Like<People>(x => x.Name, $"%{query}%"))
.OrderBy(DefaultSort)
.Take(20)
.ToListAsync();

View File

@ -36,7 +36,7 @@ namespace Kyoo.Controllers
public override async Task<ICollection<Provider>> Search(string query)
{
return await _database.Providers
.Where(x => EF.Functions.ILike(x.Name, $"%{query}%"))
.Where(_database.Like<Provider>(x => x.Name, $"%{query}%"))
.OrderBy(DefaultSort)
.Take(20)
.ToListAsync();

View File

@ -121,7 +121,7 @@ namespace Kyoo.Controllers
public override async Task<ICollection<Season>> Search(string query)
{
List<Season> seasons = await _database.Seasons
.Where(x => EF.Functions.ILike(x.Title, $"%{query}%"))
.Where(_database.Like<Season>(x => x.Title, $"%{query}%"))
.OrderBy(DefaultSort)
.Take(20)
.ToListAsync();

View File

@ -79,9 +79,7 @@ namespace Kyoo.Controllers
{
query = $"%{query}%";
return await _database.Shows
.Where(x => EF.Functions.ILike(x.Title, query)
|| EF.Functions.ILike(x.Slug, query)
/*|| x.Aliases.Any(y => EF.Functions.ILike(y, query))*/) // NOT TRANSLATABLE.
.Where(_database.Like<Show>(x => x.Title + " " + x.Slug, query))
.OrderBy(DefaultSort)
.Take(20)
.ToListAsync();

View File

@ -36,7 +36,7 @@ namespace Kyoo.Controllers
public override async Task<ICollection<Studio>> Search(string query)
{
return await _database.Studios
.Where(x => EF.Functions.ILike(x.Name, $"%{query}%"))
.Where(_database.Like<Studio>(x => x.Name, $"%{query}%"))
.OrderBy(DefaultSort)
.Take(20)
.ToListAsync();

View File

@ -35,18 +35,7 @@
<ItemGroup>
<ProjectReference Include="../Kyoo.Common/Kyoo.Common.csproj" />
<ProjectReference Include="../Kyoo.CommonAPI/Kyoo.CommonAPI.csproj" />
<PackageReference Include="IdentityServer4" Version="4.1.1" />
<PackageReference Include="IdentityServer4.AspNetIdentity" Version="4.1.1" />
<PackageReference Include="IdentityServer4.EntityFramework" Version="4.1.1" />
<PackageReference Include="IdentityServer4.EntityFramework.Storage" Version="4.1.1" />
<PackageReference Include="IdentityServer4.Storage" Version="4.1.1" />
<PackageReference Include="IdentityServer4.AccessTokenValidation" Version="3.0.1" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="5.0.3" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="5.0.2" />
<PackageReference Include="Portable.BouncyCastle" Version="1.8.9" />
<PackageReference Include="Microsoft.AspNet.WebApi.Client" Version="5.2.7" />
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="5.0.3" />
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="5.0.3" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="5.0.3" />
<PackageReference Include="Microsoft.AspNetCore.SpaServices" Version="3.1.12" />
<PackageReference Include="Microsoft.AspNetCore.SpaServices.Extensions" Version="5.0.3" />

View File

@ -1,985 +0,0 @@
// <auto-generated />
using System;
using IdentityServer4.EntityFramework.DbContexts;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
namespace Kyoo.Models.DatabaseMigrations.IdentityConfiguration
{
[DbContext(typeof(ConfigurationDbContext))]
[Migration("20210306161631_Initial")]
partial class Initial
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("Relational:MaxIdentifierLength", 63)
.HasAnnotation("ProductVersion", "5.0.3")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResource", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<string>("AllowedAccessTokenSigningAlgorithms")
.HasMaxLength(100)
.HasColumnType("character varying(100)");
b.Property<DateTime>("Created")
.HasColumnType("timestamp without time zone");
b.Property<string>("Description")
.HasMaxLength(1000)
.HasColumnType("character varying(1000)");
b.Property<string>("DisplayName")
.HasMaxLength(200)
.HasColumnType("character varying(200)");
b.Property<bool>("Enabled")
.HasColumnType("boolean");
b.Property<DateTime?>("LastAccessed")
.HasColumnType("timestamp without time zone");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("character varying(200)");
b.Property<bool>("NonEditable")
.HasColumnType("boolean");
b.Property<bool>("ShowInDiscoveryDocument")
.HasColumnType("boolean");
b.Property<DateTime?>("Updated")
.HasColumnType("timestamp without time zone");
b.HasKey("Id");
b.HasIndex("Name")
.IsUnique();
b.ToTable("ApiResources");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceClaim", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<int>("ApiResourceId")
.HasColumnType("integer");
b.Property<string>("Type")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("character varying(200)");
b.HasKey("Id");
b.HasIndex("ApiResourceId");
b.ToTable("ApiResourceClaims");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceProperty", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<int>("ApiResourceId")
.HasColumnType("integer");
b.Property<string>("Key")
.IsRequired()
.HasMaxLength(250)
.HasColumnType("character varying(250)");
b.Property<string>("Value")
.IsRequired()
.HasMaxLength(2000)
.HasColumnType("character varying(2000)");
b.HasKey("Id");
b.HasIndex("ApiResourceId");
b.ToTable("ApiResourceProperties");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceScope", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<int>("ApiResourceId")
.HasColumnType("integer");
b.Property<string>("Scope")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("character varying(200)");
b.HasKey("Id");
b.HasIndex("ApiResourceId");
b.ToTable("ApiResourceScopes");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceSecret", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<int>("ApiResourceId")
.HasColumnType("integer");
b.Property<DateTime>("Created")
.HasColumnType("timestamp without time zone");
b.Property<string>("Description")
.HasMaxLength(1000)
.HasColumnType("character varying(1000)");
b.Property<DateTime?>("Expiration")
.HasColumnType("timestamp without time zone");
b.Property<string>("Type")
.IsRequired()
.HasMaxLength(250)
.HasColumnType("character varying(250)");
b.Property<string>("Value")
.IsRequired()
.HasMaxLength(4000)
.HasColumnType("character varying(4000)");
b.HasKey("Id");
b.HasIndex("ApiResourceId");
b.ToTable("ApiResourceSecrets");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiScope", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<string>("Description")
.HasMaxLength(1000)
.HasColumnType("character varying(1000)");
b.Property<string>("DisplayName")
.HasMaxLength(200)
.HasColumnType("character varying(200)");
b.Property<bool>("Emphasize")
.HasColumnType("boolean");
b.Property<bool>("Enabled")
.HasColumnType("boolean");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("character varying(200)");
b.Property<bool>("Required")
.HasColumnType("boolean");
b.Property<bool>("ShowInDiscoveryDocument")
.HasColumnType("boolean");
b.HasKey("Id");
b.HasIndex("Name")
.IsUnique();
b.ToTable("ApiScopes");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiScopeClaim", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<int>("ScopeId")
.HasColumnType("integer");
b.Property<string>("Type")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("character varying(200)");
b.HasKey("Id");
b.HasIndex("ScopeId");
b.ToTable("ApiScopeClaims");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiScopeProperty", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<string>("Key")
.IsRequired()
.HasMaxLength(250)
.HasColumnType("character varying(250)");
b.Property<int>("ScopeId")
.HasColumnType("integer");
b.Property<string>("Value")
.IsRequired()
.HasMaxLength(2000)
.HasColumnType("character varying(2000)");
b.HasKey("Id");
b.HasIndex("ScopeId");
b.ToTable("ApiScopeProperties");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.Client", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<int>("AbsoluteRefreshTokenLifetime")
.HasColumnType("integer");
b.Property<int>("AccessTokenLifetime")
.HasColumnType("integer");
b.Property<int>("AccessTokenType")
.HasColumnType("integer");
b.Property<bool>("AllowAccessTokensViaBrowser")
.HasColumnType("boolean");
b.Property<bool>("AllowOfflineAccess")
.HasColumnType("boolean");
b.Property<bool>("AllowPlainTextPkce")
.HasColumnType("boolean");
b.Property<bool>("AllowRememberConsent")
.HasColumnType("boolean");
b.Property<string>("AllowedIdentityTokenSigningAlgorithms")
.HasMaxLength(100)
.HasColumnType("character varying(100)");
b.Property<bool>("AlwaysIncludeUserClaimsInIdToken")
.HasColumnType("boolean");
b.Property<bool>("AlwaysSendClientClaims")
.HasColumnType("boolean");
b.Property<int>("AuthorizationCodeLifetime")
.HasColumnType("integer");
b.Property<bool>("BackChannelLogoutSessionRequired")
.HasColumnType("boolean");
b.Property<string>("BackChannelLogoutUri")
.HasMaxLength(2000)
.HasColumnType("character varying(2000)");
b.Property<string>("ClientClaimsPrefix")
.HasMaxLength(200)
.HasColumnType("character varying(200)");
b.Property<string>("ClientId")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("character varying(200)");
b.Property<string>("ClientName")
.HasMaxLength(200)
.HasColumnType("character varying(200)");
b.Property<string>("ClientUri")
.HasMaxLength(2000)
.HasColumnType("character varying(2000)");
b.Property<int?>("ConsentLifetime")
.HasColumnType("integer");
b.Property<DateTime>("Created")
.HasColumnType("timestamp without time zone");
b.Property<string>("Description")
.HasMaxLength(1000)
.HasColumnType("character varying(1000)");
b.Property<int>("DeviceCodeLifetime")
.HasColumnType("integer");
b.Property<bool>("EnableLocalLogin")
.HasColumnType("boolean");
b.Property<bool>("Enabled")
.HasColumnType("boolean");
b.Property<bool>("FrontChannelLogoutSessionRequired")
.HasColumnType("boolean");
b.Property<string>("FrontChannelLogoutUri")
.HasMaxLength(2000)
.HasColumnType("character varying(2000)");
b.Property<int>("IdentityTokenLifetime")
.HasColumnType("integer");
b.Property<bool>("IncludeJwtId")
.HasColumnType("boolean");
b.Property<DateTime?>("LastAccessed")
.HasColumnType("timestamp without time zone");
b.Property<string>("LogoUri")
.HasMaxLength(2000)
.HasColumnType("character varying(2000)");
b.Property<bool>("NonEditable")
.HasColumnType("boolean");
b.Property<string>("PairWiseSubjectSalt")
.HasMaxLength(200)
.HasColumnType("character varying(200)");
b.Property<string>("ProtocolType")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("character varying(200)");
b.Property<int>("RefreshTokenExpiration")
.HasColumnType("integer");
b.Property<int>("RefreshTokenUsage")
.HasColumnType("integer");
b.Property<bool>("RequireClientSecret")
.HasColumnType("boolean");
b.Property<bool>("RequireConsent")
.HasColumnType("boolean");
b.Property<bool>("RequirePkce")
.HasColumnType("boolean");
b.Property<bool>("RequireRequestObject")
.HasColumnType("boolean");
b.Property<int>("SlidingRefreshTokenLifetime")
.HasColumnType("integer");
b.Property<bool>("UpdateAccessTokenClaimsOnRefresh")
.HasColumnType("boolean");
b.Property<DateTime?>("Updated")
.HasColumnType("timestamp without time zone");
b.Property<string>("UserCodeType")
.HasMaxLength(100)
.HasColumnType("character varying(100)");
b.Property<int?>("UserSsoLifetime")
.HasColumnType("integer");
b.HasKey("Id");
b.HasIndex("ClientId")
.IsUnique();
b.ToTable("Clients");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientClaim", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<int>("ClientId")
.HasColumnType("integer");
b.Property<string>("Type")
.IsRequired()
.HasMaxLength(250)
.HasColumnType("character varying(250)");
b.Property<string>("Value")
.IsRequired()
.HasMaxLength(250)
.HasColumnType("character varying(250)");
b.HasKey("Id");
b.HasIndex("ClientId");
b.ToTable("ClientClaims");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientCorsOrigin", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<int>("ClientId")
.HasColumnType("integer");
b.Property<string>("Origin")
.IsRequired()
.HasMaxLength(150)
.HasColumnType("character varying(150)");
b.HasKey("Id");
b.HasIndex("ClientId");
b.ToTable("ClientCorsOrigins");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientGrantType", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<int>("ClientId")
.HasColumnType("integer");
b.Property<string>("GrantType")
.IsRequired()
.HasMaxLength(250)
.HasColumnType("character varying(250)");
b.HasKey("Id");
b.HasIndex("ClientId");
b.ToTable("ClientGrantTypes");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientIdPRestriction", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<int>("ClientId")
.HasColumnType("integer");
b.Property<string>("Provider")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("character varying(200)");
b.HasKey("Id");
b.HasIndex("ClientId");
b.ToTable("ClientIdPRestrictions");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientPostLogoutRedirectUri", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<int>("ClientId")
.HasColumnType("integer");
b.Property<string>("PostLogoutRedirectUri")
.IsRequired()
.HasMaxLength(2000)
.HasColumnType("character varying(2000)");
b.HasKey("Id");
b.HasIndex("ClientId");
b.ToTable("ClientPostLogoutRedirectUris");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientProperty", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<int>("ClientId")
.HasColumnType("integer");
b.Property<string>("Key")
.IsRequired()
.HasMaxLength(250)
.HasColumnType("character varying(250)");
b.Property<string>("Value")
.IsRequired()
.HasMaxLength(2000)
.HasColumnType("character varying(2000)");
b.HasKey("Id");
b.HasIndex("ClientId");
b.ToTable("ClientProperties");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientRedirectUri", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<int>("ClientId")
.HasColumnType("integer");
b.Property<string>("RedirectUri")
.IsRequired()
.HasMaxLength(2000)
.HasColumnType("character varying(2000)");
b.HasKey("Id");
b.HasIndex("ClientId");
b.ToTable("ClientRedirectUris");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientScope", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<int>("ClientId")
.HasColumnType("integer");
b.Property<string>("Scope")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("character varying(200)");
b.HasKey("Id");
b.HasIndex("ClientId");
b.ToTable("ClientScopes");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientSecret", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<int>("ClientId")
.HasColumnType("integer");
b.Property<DateTime>("Created")
.HasColumnType("timestamp without time zone");
b.Property<string>("Description")
.HasMaxLength(2000)
.HasColumnType("character varying(2000)");
b.Property<DateTime?>("Expiration")
.HasColumnType("timestamp without time zone");
b.Property<string>("Type")
.IsRequired()
.HasMaxLength(250)
.HasColumnType("character varying(250)");
b.Property<string>("Value")
.IsRequired()
.HasMaxLength(4000)
.HasColumnType("character varying(4000)");
b.HasKey("Id");
b.HasIndex("ClientId");
b.ToTable("ClientSecrets");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.IdentityResource", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<DateTime>("Created")
.HasColumnType("timestamp without time zone");
b.Property<string>("Description")
.HasMaxLength(1000)
.HasColumnType("character varying(1000)");
b.Property<string>("DisplayName")
.HasMaxLength(200)
.HasColumnType("character varying(200)");
b.Property<bool>("Emphasize")
.HasColumnType("boolean");
b.Property<bool>("Enabled")
.HasColumnType("boolean");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("character varying(200)");
b.Property<bool>("NonEditable")
.HasColumnType("boolean");
b.Property<bool>("Required")
.HasColumnType("boolean");
b.Property<bool>("ShowInDiscoveryDocument")
.HasColumnType("boolean");
b.Property<DateTime?>("Updated")
.HasColumnType("timestamp without time zone");
b.HasKey("Id");
b.HasIndex("Name")
.IsUnique();
b.ToTable("IdentityResources");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.IdentityResourceClaim", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<int>("IdentityResourceId")
.HasColumnType("integer");
b.Property<string>("Type")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("character varying(200)");
b.HasKey("Id");
b.HasIndex("IdentityResourceId");
b.ToTable("IdentityResourceClaims");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.IdentityResourceProperty", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<int>("IdentityResourceId")
.HasColumnType("integer");
b.Property<string>("Key")
.IsRequired()
.HasMaxLength(250)
.HasColumnType("character varying(250)");
b.Property<string>("Value")
.IsRequired()
.HasMaxLength(2000)
.HasColumnType("character varying(2000)");
b.HasKey("Id");
b.HasIndex("IdentityResourceId");
b.ToTable("IdentityResourceProperties");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceClaim", b =>
{
b.HasOne("IdentityServer4.EntityFramework.Entities.ApiResource", "ApiResource")
.WithMany("UserClaims")
.HasForeignKey("ApiResourceId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("ApiResource");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceProperty", b =>
{
b.HasOne("IdentityServer4.EntityFramework.Entities.ApiResource", "ApiResource")
.WithMany("Properties")
.HasForeignKey("ApiResourceId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("ApiResource");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceScope", b =>
{
b.HasOne("IdentityServer4.EntityFramework.Entities.ApiResource", "ApiResource")
.WithMany("Scopes")
.HasForeignKey("ApiResourceId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("ApiResource");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceSecret", b =>
{
b.HasOne("IdentityServer4.EntityFramework.Entities.ApiResource", "ApiResource")
.WithMany("Secrets")
.HasForeignKey("ApiResourceId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("ApiResource");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiScopeClaim", b =>
{
b.HasOne("IdentityServer4.EntityFramework.Entities.ApiScope", "Scope")
.WithMany("UserClaims")
.HasForeignKey("ScopeId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Scope");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiScopeProperty", b =>
{
b.HasOne("IdentityServer4.EntityFramework.Entities.ApiScope", "Scope")
.WithMany("Properties")
.HasForeignKey("ScopeId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Scope");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientClaim", b =>
{
b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client")
.WithMany("Claims")
.HasForeignKey("ClientId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Client");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientCorsOrigin", b =>
{
b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client")
.WithMany("AllowedCorsOrigins")
.HasForeignKey("ClientId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Client");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientGrantType", b =>
{
b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client")
.WithMany("AllowedGrantTypes")
.HasForeignKey("ClientId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Client");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientIdPRestriction", b =>
{
b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client")
.WithMany("IdentityProviderRestrictions")
.HasForeignKey("ClientId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Client");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientPostLogoutRedirectUri", b =>
{
b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client")
.WithMany("PostLogoutRedirectUris")
.HasForeignKey("ClientId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Client");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientProperty", b =>
{
b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client")
.WithMany("Properties")
.HasForeignKey("ClientId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Client");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientRedirectUri", b =>
{
b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client")
.WithMany("RedirectUris")
.HasForeignKey("ClientId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Client");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientScope", b =>
{
b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client")
.WithMany("AllowedScopes")
.HasForeignKey("ClientId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Client");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientSecret", b =>
{
b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client")
.WithMany("ClientSecrets")
.HasForeignKey("ClientId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Client");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.IdentityResourceClaim", b =>
{
b.HasOne("IdentityServer4.EntityFramework.Entities.IdentityResource", "IdentityResource")
.WithMany("UserClaims")
.HasForeignKey("IdentityResourceId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("IdentityResource");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.IdentityResourceProperty", b =>
{
b.HasOne("IdentityServer4.EntityFramework.Entities.IdentityResource", "IdentityResource")
.WithMany("Properties")
.HasForeignKey("IdentityResourceId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("IdentityResource");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResource", b =>
{
b.Navigation("Properties");
b.Navigation("Scopes");
b.Navigation("Secrets");
b.Navigation("UserClaims");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiScope", b =>
{
b.Navigation("Properties");
b.Navigation("UserClaims");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.Client", b =>
{
b.Navigation("AllowedCorsOrigins");
b.Navigation("AllowedGrantTypes");
b.Navigation("AllowedScopes");
b.Navigation("Claims");
b.Navigation("ClientSecrets");
b.Navigation("IdentityProviderRestrictions");
b.Navigation("PostLogoutRedirectUris");
b.Navigation("Properties");
b.Navigation("RedirectUris");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.IdentityResource", b =>
{
b.Navigation("Properties");
b.Navigation("UserClaims");
});
#pragma warning restore 612, 618
}
}
}

View File

@ -1,658 +0,0 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
namespace Kyoo.Models.DatabaseMigrations.IdentityConfiguration
{
public partial class Initial : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "ApiResources",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
Enabled = table.Column<bool>(type: "boolean", nullable: false),
Name = table.Column<string>(type: "character varying(200)", maxLength: 200, nullable: false),
DisplayName = table.Column<string>(type: "character varying(200)", maxLength: 200, nullable: true),
Description = table.Column<string>(type: "character varying(1000)", maxLength: 1000, nullable: true),
AllowedAccessTokenSigningAlgorithms = table.Column<string>(type: "character varying(100)", maxLength: 100, nullable: true),
ShowInDiscoveryDocument = table.Column<bool>(type: "boolean", nullable: false),
Created = table.Column<DateTime>(type: "timestamp without time zone", nullable: false),
Updated = table.Column<DateTime>(type: "timestamp without time zone", nullable: true),
LastAccessed = table.Column<DateTime>(type: "timestamp without time zone", nullable: true),
NonEditable = table.Column<bool>(type: "boolean", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ApiResources", x => x.Id);
});
migrationBuilder.CreateTable(
name: "ApiScopes",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
Enabled = table.Column<bool>(type: "boolean", nullable: false),
Name = table.Column<string>(type: "character varying(200)", maxLength: 200, nullable: false),
DisplayName = table.Column<string>(type: "character varying(200)", maxLength: 200, nullable: true),
Description = table.Column<string>(type: "character varying(1000)", maxLength: 1000, nullable: true),
Required = table.Column<bool>(type: "boolean", nullable: false),
Emphasize = table.Column<bool>(type: "boolean", nullable: false),
ShowInDiscoveryDocument = table.Column<bool>(type: "boolean", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ApiScopes", x => x.Id);
});
migrationBuilder.CreateTable(
name: "Clients",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
Enabled = table.Column<bool>(type: "boolean", nullable: false),
ClientId = table.Column<string>(type: "character varying(200)", maxLength: 200, nullable: false),
ProtocolType = table.Column<string>(type: "character varying(200)", maxLength: 200, nullable: false),
RequireClientSecret = table.Column<bool>(type: "boolean", nullable: false),
ClientName = table.Column<string>(type: "character varying(200)", maxLength: 200, nullable: true),
Description = table.Column<string>(type: "character varying(1000)", maxLength: 1000, nullable: true),
ClientUri = table.Column<string>(type: "character varying(2000)", maxLength: 2000, nullable: true),
LogoUri = table.Column<string>(type: "character varying(2000)", maxLength: 2000, nullable: true),
RequireConsent = table.Column<bool>(type: "boolean", nullable: false),
AllowRememberConsent = table.Column<bool>(type: "boolean", nullable: false),
AlwaysIncludeUserClaimsInIdToken = table.Column<bool>(type: "boolean", nullable: false),
RequirePkce = table.Column<bool>(type: "boolean", nullable: false),
AllowPlainTextPkce = table.Column<bool>(type: "boolean", nullable: false),
RequireRequestObject = table.Column<bool>(type: "boolean", nullable: false),
AllowAccessTokensViaBrowser = table.Column<bool>(type: "boolean", nullable: false),
FrontChannelLogoutUri = table.Column<string>(type: "character varying(2000)", maxLength: 2000, nullable: true),
FrontChannelLogoutSessionRequired = table.Column<bool>(type: "boolean", nullable: false),
BackChannelLogoutUri = table.Column<string>(type: "character varying(2000)", maxLength: 2000, nullable: true),
BackChannelLogoutSessionRequired = table.Column<bool>(type: "boolean", nullable: false),
AllowOfflineAccess = table.Column<bool>(type: "boolean", nullable: false),
IdentityTokenLifetime = table.Column<int>(type: "integer", nullable: false),
AllowedIdentityTokenSigningAlgorithms = table.Column<string>(type: "character varying(100)", maxLength: 100, nullable: true),
AccessTokenLifetime = table.Column<int>(type: "integer", nullable: false),
AuthorizationCodeLifetime = table.Column<int>(type: "integer", nullable: false),
ConsentLifetime = table.Column<int>(type: "integer", nullable: true),
AbsoluteRefreshTokenLifetime = table.Column<int>(type: "integer", nullable: false),
SlidingRefreshTokenLifetime = table.Column<int>(type: "integer", nullable: false),
RefreshTokenUsage = table.Column<int>(type: "integer", nullable: false),
UpdateAccessTokenClaimsOnRefresh = table.Column<bool>(type: "boolean", nullable: false),
RefreshTokenExpiration = table.Column<int>(type: "integer", nullable: false),
AccessTokenType = table.Column<int>(type: "integer", nullable: false),
EnableLocalLogin = table.Column<bool>(type: "boolean", nullable: false),
IncludeJwtId = table.Column<bool>(type: "boolean", nullable: false),
AlwaysSendClientClaims = table.Column<bool>(type: "boolean", nullable: false),
ClientClaimsPrefix = table.Column<string>(type: "character varying(200)", maxLength: 200, nullable: true),
PairWiseSubjectSalt = table.Column<string>(type: "character varying(200)", maxLength: 200, nullable: true),
Created = table.Column<DateTime>(type: "timestamp without time zone", nullable: false),
Updated = table.Column<DateTime>(type: "timestamp without time zone", nullable: true),
LastAccessed = table.Column<DateTime>(type: "timestamp without time zone", nullable: true),
UserSsoLifetime = table.Column<int>(type: "integer", nullable: true),
UserCodeType = table.Column<string>(type: "character varying(100)", maxLength: 100, nullable: true),
DeviceCodeLifetime = table.Column<int>(type: "integer", nullable: false),
NonEditable = table.Column<bool>(type: "boolean", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Clients", x => x.Id);
});
migrationBuilder.CreateTable(
name: "IdentityResources",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
Enabled = table.Column<bool>(type: "boolean", nullable: false),
Name = table.Column<string>(type: "character varying(200)", maxLength: 200, nullable: false),
DisplayName = table.Column<string>(type: "character varying(200)", maxLength: 200, nullable: true),
Description = table.Column<string>(type: "character varying(1000)", maxLength: 1000, nullable: true),
Required = table.Column<bool>(type: "boolean", nullable: false),
Emphasize = table.Column<bool>(type: "boolean", nullable: false),
ShowInDiscoveryDocument = table.Column<bool>(type: "boolean", nullable: false),
Created = table.Column<DateTime>(type: "timestamp without time zone", nullable: false),
Updated = table.Column<DateTime>(type: "timestamp without time zone", nullable: true),
NonEditable = table.Column<bool>(type: "boolean", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_IdentityResources", x => x.Id);
});
migrationBuilder.CreateTable(
name: "ApiResourceClaims",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
ApiResourceId = table.Column<int>(type: "integer", nullable: false),
Type = table.Column<string>(type: "character varying(200)", maxLength: 200, nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ApiResourceClaims", x => x.Id);
table.ForeignKey(
name: "FK_ApiResourceClaims_ApiResources_ApiResourceId",
column: x => x.ApiResourceId,
principalTable: "ApiResources",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "ApiResourceProperties",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
ApiResourceId = table.Column<int>(type: "integer", nullable: false),
Key = table.Column<string>(type: "character varying(250)", maxLength: 250, nullable: false),
Value = table.Column<string>(type: "character varying(2000)", maxLength: 2000, nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ApiResourceProperties", x => x.Id);
table.ForeignKey(
name: "FK_ApiResourceProperties_ApiResources_ApiResourceId",
column: x => x.ApiResourceId,
principalTable: "ApiResources",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "ApiResourceScopes",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
Scope = table.Column<string>(type: "character varying(200)", maxLength: 200, nullable: false),
ApiResourceId = table.Column<int>(type: "integer", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ApiResourceScopes", x => x.Id);
table.ForeignKey(
name: "FK_ApiResourceScopes_ApiResources_ApiResourceId",
column: x => x.ApiResourceId,
principalTable: "ApiResources",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "ApiResourceSecrets",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
ApiResourceId = table.Column<int>(type: "integer", nullable: false),
Description = table.Column<string>(type: "character varying(1000)", maxLength: 1000, nullable: true),
Value = table.Column<string>(type: "character varying(4000)", maxLength: 4000, nullable: false),
Expiration = table.Column<DateTime>(type: "timestamp without time zone", nullable: true),
Type = table.Column<string>(type: "character varying(250)", maxLength: 250, nullable: false),
Created = table.Column<DateTime>(type: "timestamp without time zone", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ApiResourceSecrets", x => x.Id);
table.ForeignKey(
name: "FK_ApiResourceSecrets_ApiResources_ApiResourceId",
column: x => x.ApiResourceId,
principalTable: "ApiResources",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "ApiScopeClaims",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
ScopeId = table.Column<int>(type: "integer", nullable: false),
Type = table.Column<string>(type: "character varying(200)", maxLength: 200, nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ApiScopeClaims", x => x.Id);
table.ForeignKey(
name: "FK_ApiScopeClaims_ApiScopes_ScopeId",
column: x => x.ScopeId,
principalTable: "ApiScopes",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "ApiScopeProperties",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
ScopeId = table.Column<int>(type: "integer", nullable: false),
Key = table.Column<string>(type: "character varying(250)", maxLength: 250, nullable: false),
Value = table.Column<string>(type: "character varying(2000)", maxLength: 2000, nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ApiScopeProperties", x => x.Id);
table.ForeignKey(
name: "FK_ApiScopeProperties_ApiScopes_ScopeId",
column: x => x.ScopeId,
principalTable: "ApiScopes",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "ClientClaims",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
Type = table.Column<string>(type: "character varying(250)", maxLength: 250, nullable: false),
Value = table.Column<string>(type: "character varying(250)", maxLength: 250, nullable: false),
ClientId = table.Column<int>(type: "integer", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ClientClaims", x => x.Id);
table.ForeignKey(
name: "FK_ClientClaims_Clients_ClientId",
column: x => x.ClientId,
principalTable: "Clients",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "ClientCorsOrigins",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
Origin = table.Column<string>(type: "character varying(150)", maxLength: 150, nullable: false),
ClientId = table.Column<int>(type: "integer", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ClientCorsOrigins", x => x.Id);
table.ForeignKey(
name: "FK_ClientCorsOrigins_Clients_ClientId",
column: x => x.ClientId,
principalTable: "Clients",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "ClientGrantTypes",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
GrantType = table.Column<string>(type: "character varying(250)", maxLength: 250, nullable: false),
ClientId = table.Column<int>(type: "integer", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ClientGrantTypes", x => x.Id);
table.ForeignKey(
name: "FK_ClientGrantTypes_Clients_ClientId",
column: x => x.ClientId,
principalTable: "Clients",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "ClientIdPRestrictions",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
Provider = table.Column<string>(type: "character varying(200)", maxLength: 200, nullable: false),
ClientId = table.Column<int>(type: "integer", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ClientIdPRestrictions", x => x.Id);
table.ForeignKey(
name: "FK_ClientIdPRestrictions_Clients_ClientId",
column: x => x.ClientId,
principalTable: "Clients",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "ClientPostLogoutRedirectUris",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
PostLogoutRedirectUri = table.Column<string>(type: "character varying(2000)", maxLength: 2000, nullable: false),
ClientId = table.Column<int>(type: "integer", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ClientPostLogoutRedirectUris", x => x.Id);
table.ForeignKey(
name: "FK_ClientPostLogoutRedirectUris_Clients_ClientId",
column: x => x.ClientId,
principalTable: "Clients",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "ClientProperties",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
ClientId = table.Column<int>(type: "integer", nullable: false),
Key = table.Column<string>(type: "character varying(250)", maxLength: 250, nullable: false),
Value = table.Column<string>(type: "character varying(2000)", maxLength: 2000, nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ClientProperties", x => x.Id);
table.ForeignKey(
name: "FK_ClientProperties_Clients_ClientId",
column: x => x.ClientId,
principalTable: "Clients",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "ClientRedirectUris",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
RedirectUri = table.Column<string>(type: "character varying(2000)", maxLength: 2000, nullable: false),
ClientId = table.Column<int>(type: "integer", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ClientRedirectUris", x => x.Id);
table.ForeignKey(
name: "FK_ClientRedirectUris_Clients_ClientId",
column: x => x.ClientId,
principalTable: "Clients",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "ClientScopes",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
Scope = table.Column<string>(type: "character varying(200)", maxLength: 200, nullable: false),
ClientId = table.Column<int>(type: "integer", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ClientScopes", x => x.Id);
table.ForeignKey(
name: "FK_ClientScopes_Clients_ClientId",
column: x => x.ClientId,
principalTable: "Clients",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "ClientSecrets",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
ClientId = table.Column<int>(type: "integer", nullable: false),
Description = table.Column<string>(type: "character varying(2000)", maxLength: 2000, nullable: true),
Value = table.Column<string>(type: "character varying(4000)", maxLength: 4000, nullable: false),
Expiration = table.Column<DateTime>(type: "timestamp without time zone", nullable: true),
Type = table.Column<string>(type: "character varying(250)", maxLength: 250, nullable: false),
Created = table.Column<DateTime>(type: "timestamp without time zone", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ClientSecrets", x => x.Id);
table.ForeignKey(
name: "FK_ClientSecrets_Clients_ClientId",
column: x => x.ClientId,
principalTable: "Clients",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "IdentityResourceClaims",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
IdentityResourceId = table.Column<int>(type: "integer", nullable: false),
Type = table.Column<string>(type: "character varying(200)", maxLength: 200, nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_IdentityResourceClaims", x => x.Id);
table.ForeignKey(
name: "FK_IdentityResourceClaims_IdentityResources_IdentityResourceId",
column: x => x.IdentityResourceId,
principalTable: "IdentityResources",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "IdentityResourceProperties",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
IdentityResourceId = table.Column<int>(type: "integer", nullable: false),
Key = table.Column<string>(type: "character varying(250)", maxLength: 250, nullable: false),
Value = table.Column<string>(type: "character varying(2000)", maxLength: 2000, nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_IdentityResourceProperties", x => x.Id);
table.ForeignKey(
name: "FK_IdentityResourceProperties_IdentityResources_IdentityResour~",
column: x => x.IdentityResourceId,
principalTable: "IdentityResources",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "IX_ApiResourceClaims_ApiResourceId",
table: "ApiResourceClaims",
column: "ApiResourceId");
migrationBuilder.CreateIndex(
name: "IX_ApiResourceProperties_ApiResourceId",
table: "ApiResourceProperties",
column: "ApiResourceId");
migrationBuilder.CreateIndex(
name: "IX_ApiResources_Name",
table: "ApiResources",
column: "Name",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_ApiResourceScopes_ApiResourceId",
table: "ApiResourceScopes",
column: "ApiResourceId");
migrationBuilder.CreateIndex(
name: "IX_ApiResourceSecrets_ApiResourceId",
table: "ApiResourceSecrets",
column: "ApiResourceId");
migrationBuilder.CreateIndex(
name: "IX_ApiScopeClaims_ScopeId",
table: "ApiScopeClaims",
column: "ScopeId");
migrationBuilder.CreateIndex(
name: "IX_ApiScopeProperties_ScopeId",
table: "ApiScopeProperties",
column: "ScopeId");
migrationBuilder.CreateIndex(
name: "IX_ApiScopes_Name",
table: "ApiScopes",
column: "Name",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_ClientClaims_ClientId",
table: "ClientClaims",
column: "ClientId");
migrationBuilder.CreateIndex(
name: "IX_ClientCorsOrigins_ClientId",
table: "ClientCorsOrigins",
column: "ClientId");
migrationBuilder.CreateIndex(
name: "IX_ClientGrantTypes_ClientId",
table: "ClientGrantTypes",
column: "ClientId");
migrationBuilder.CreateIndex(
name: "IX_ClientIdPRestrictions_ClientId",
table: "ClientIdPRestrictions",
column: "ClientId");
migrationBuilder.CreateIndex(
name: "IX_ClientPostLogoutRedirectUris_ClientId",
table: "ClientPostLogoutRedirectUris",
column: "ClientId");
migrationBuilder.CreateIndex(
name: "IX_ClientProperties_ClientId",
table: "ClientProperties",
column: "ClientId");
migrationBuilder.CreateIndex(
name: "IX_ClientRedirectUris_ClientId",
table: "ClientRedirectUris",
column: "ClientId");
migrationBuilder.CreateIndex(
name: "IX_Clients_ClientId",
table: "Clients",
column: "ClientId",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_ClientScopes_ClientId",
table: "ClientScopes",
column: "ClientId");
migrationBuilder.CreateIndex(
name: "IX_ClientSecrets_ClientId",
table: "ClientSecrets",
column: "ClientId");
migrationBuilder.CreateIndex(
name: "IX_IdentityResourceClaims_IdentityResourceId",
table: "IdentityResourceClaims",
column: "IdentityResourceId");
migrationBuilder.CreateIndex(
name: "IX_IdentityResourceProperties_IdentityResourceId",
table: "IdentityResourceProperties",
column: "IdentityResourceId");
migrationBuilder.CreateIndex(
name: "IX_IdentityResources_Name",
table: "IdentityResources",
column: "Name",
unique: true);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "ApiResourceClaims");
migrationBuilder.DropTable(
name: "ApiResourceProperties");
migrationBuilder.DropTable(
name: "ApiResourceScopes");
migrationBuilder.DropTable(
name: "ApiResourceSecrets");
migrationBuilder.DropTable(
name: "ApiScopeClaims");
migrationBuilder.DropTable(
name: "ApiScopeProperties");
migrationBuilder.DropTable(
name: "ClientClaims");
migrationBuilder.DropTable(
name: "ClientCorsOrigins");
migrationBuilder.DropTable(
name: "ClientGrantTypes");
migrationBuilder.DropTable(
name: "ClientIdPRestrictions");
migrationBuilder.DropTable(
name: "ClientPostLogoutRedirectUris");
migrationBuilder.DropTable(
name: "ClientProperties");
migrationBuilder.DropTable(
name: "ClientRedirectUris");
migrationBuilder.DropTable(
name: "ClientScopes");
migrationBuilder.DropTable(
name: "ClientSecrets");
migrationBuilder.DropTable(
name: "IdentityResourceClaims");
migrationBuilder.DropTable(
name: "IdentityResourceProperties");
migrationBuilder.DropTable(
name: "ApiResources");
migrationBuilder.DropTable(
name: "ApiScopes");
migrationBuilder.DropTable(
name: "Clients");
migrationBuilder.DropTable(
name: "IdentityResources");
}
}
}

View File

@ -1,983 +0,0 @@
// <auto-generated />
using System;
using IdentityServer4.EntityFramework.DbContexts;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
namespace Kyoo.Models.DatabaseMigrations.IdentityConfiguration
{
[DbContext(typeof(ConfigurationDbContext))]
partial class ConfigurationDbContextModelSnapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("Relational:MaxIdentifierLength", 63)
.HasAnnotation("ProductVersion", "5.0.3")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResource", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<string>("AllowedAccessTokenSigningAlgorithms")
.HasMaxLength(100)
.HasColumnType("character varying(100)");
b.Property<DateTime>("Created")
.HasColumnType("timestamp without time zone");
b.Property<string>("Description")
.HasMaxLength(1000)
.HasColumnType("character varying(1000)");
b.Property<string>("DisplayName")
.HasMaxLength(200)
.HasColumnType("character varying(200)");
b.Property<bool>("Enabled")
.HasColumnType("boolean");
b.Property<DateTime?>("LastAccessed")
.HasColumnType("timestamp without time zone");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("character varying(200)");
b.Property<bool>("NonEditable")
.HasColumnType("boolean");
b.Property<bool>("ShowInDiscoveryDocument")
.HasColumnType("boolean");
b.Property<DateTime?>("Updated")
.HasColumnType("timestamp without time zone");
b.HasKey("Id");
b.HasIndex("Name")
.IsUnique();
b.ToTable("ApiResources");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceClaim", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<int>("ApiResourceId")
.HasColumnType("integer");
b.Property<string>("Type")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("character varying(200)");
b.HasKey("Id");
b.HasIndex("ApiResourceId");
b.ToTable("ApiResourceClaims");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceProperty", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<int>("ApiResourceId")
.HasColumnType("integer");
b.Property<string>("Key")
.IsRequired()
.HasMaxLength(250)
.HasColumnType("character varying(250)");
b.Property<string>("Value")
.IsRequired()
.HasMaxLength(2000)
.HasColumnType("character varying(2000)");
b.HasKey("Id");
b.HasIndex("ApiResourceId");
b.ToTable("ApiResourceProperties");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceScope", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<int>("ApiResourceId")
.HasColumnType("integer");
b.Property<string>("Scope")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("character varying(200)");
b.HasKey("Id");
b.HasIndex("ApiResourceId");
b.ToTable("ApiResourceScopes");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceSecret", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<int>("ApiResourceId")
.HasColumnType("integer");
b.Property<DateTime>("Created")
.HasColumnType("timestamp without time zone");
b.Property<string>("Description")
.HasMaxLength(1000)
.HasColumnType("character varying(1000)");
b.Property<DateTime?>("Expiration")
.HasColumnType("timestamp without time zone");
b.Property<string>("Type")
.IsRequired()
.HasMaxLength(250)
.HasColumnType("character varying(250)");
b.Property<string>("Value")
.IsRequired()
.HasMaxLength(4000)
.HasColumnType("character varying(4000)");
b.HasKey("Id");
b.HasIndex("ApiResourceId");
b.ToTable("ApiResourceSecrets");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiScope", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<string>("Description")
.HasMaxLength(1000)
.HasColumnType("character varying(1000)");
b.Property<string>("DisplayName")
.HasMaxLength(200)
.HasColumnType("character varying(200)");
b.Property<bool>("Emphasize")
.HasColumnType("boolean");
b.Property<bool>("Enabled")
.HasColumnType("boolean");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("character varying(200)");
b.Property<bool>("Required")
.HasColumnType("boolean");
b.Property<bool>("ShowInDiscoveryDocument")
.HasColumnType("boolean");
b.HasKey("Id");
b.HasIndex("Name")
.IsUnique();
b.ToTable("ApiScopes");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiScopeClaim", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<int>("ScopeId")
.HasColumnType("integer");
b.Property<string>("Type")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("character varying(200)");
b.HasKey("Id");
b.HasIndex("ScopeId");
b.ToTable("ApiScopeClaims");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiScopeProperty", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<string>("Key")
.IsRequired()
.HasMaxLength(250)
.HasColumnType("character varying(250)");
b.Property<int>("ScopeId")
.HasColumnType("integer");
b.Property<string>("Value")
.IsRequired()
.HasMaxLength(2000)
.HasColumnType("character varying(2000)");
b.HasKey("Id");
b.HasIndex("ScopeId");
b.ToTable("ApiScopeProperties");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.Client", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<int>("AbsoluteRefreshTokenLifetime")
.HasColumnType("integer");
b.Property<int>("AccessTokenLifetime")
.HasColumnType("integer");
b.Property<int>("AccessTokenType")
.HasColumnType("integer");
b.Property<bool>("AllowAccessTokensViaBrowser")
.HasColumnType("boolean");
b.Property<bool>("AllowOfflineAccess")
.HasColumnType("boolean");
b.Property<bool>("AllowPlainTextPkce")
.HasColumnType("boolean");
b.Property<bool>("AllowRememberConsent")
.HasColumnType("boolean");
b.Property<string>("AllowedIdentityTokenSigningAlgorithms")
.HasMaxLength(100)
.HasColumnType("character varying(100)");
b.Property<bool>("AlwaysIncludeUserClaimsInIdToken")
.HasColumnType("boolean");
b.Property<bool>("AlwaysSendClientClaims")
.HasColumnType("boolean");
b.Property<int>("AuthorizationCodeLifetime")
.HasColumnType("integer");
b.Property<bool>("BackChannelLogoutSessionRequired")
.HasColumnType("boolean");
b.Property<string>("BackChannelLogoutUri")
.HasMaxLength(2000)
.HasColumnType("character varying(2000)");
b.Property<string>("ClientClaimsPrefix")
.HasMaxLength(200)
.HasColumnType("character varying(200)");
b.Property<string>("ClientId")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("character varying(200)");
b.Property<string>("ClientName")
.HasMaxLength(200)
.HasColumnType("character varying(200)");
b.Property<string>("ClientUri")
.HasMaxLength(2000)
.HasColumnType("character varying(2000)");
b.Property<int?>("ConsentLifetime")
.HasColumnType("integer");
b.Property<DateTime>("Created")
.HasColumnType("timestamp without time zone");
b.Property<string>("Description")
.HasMaxLength(1000)
.HasColumnType("character varying(1000)");
b.Property<int>("DeviceCodeLifetime")
.HasColumnType("integer");
b.Property<bool>("EnableLocalLogin")
.HasColumnType("boolean");
b.Property<bool>("Enabled")
.HasColumnType("boolean");
b.Property<bool>("FrontChannelLogoutSessionRequired")
.HasColumnType("boolean");
b.Property<string>("FrontChannelLogoutUri")
.HasMaxLength(2000)
.HasColumnType("character varying(2000)");
b.Property<int>("IdentityTokenLifetime")
.HasColumnType("integer");
b.Property<bool>("IncludeJwtId")
.HasColumnType("boolean");
b.Property<DateTime?>("LastAccessed")
.HasColumnType("timestamp without time zone");
b.Property<string>("LogoUri")
.HasMaxLength(2000)
.HasColumnType("character varying(2000)");
b.Property<bool>("NonEditable")
.HasColumnType("boolean");
b.Property<string>("PairWiseSubjectSalt")
.HasMaxLength(200)
.HasColumnType("character varying(200)");
b.Property<string>("ProtocolType")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("character varying(200)");
b.Property<int>("RefreshTokenExpiration")
.HasColumnType("integer");
b.Property<int>("RefreshTokenUsage")
.HasColumnType("integer");
b.Property<bool>("RequireClientSecret")
.HasColumnType("boolean");
b.Property<bool>("RequireConsent")
.HasColumnType("boolean");
b.Property<bool>("RequirePkce")
.HasColumnType("boolean");
b.Property<bool>("RequireRequestObject")
.HasColumnType("boolean");
b.Property<int>("SlidingRefreshTokenLifetime")
.HasColumnType("integer");
b.Property<bool>("UpdateAccessTokenClaimsOnRefresh")
.HasColumnType("boolean");
b.Property<DateTime?>("Updated")
.HasColumnType("timestamp without time zone");
b.Property<string>("UserCodeType")
.HasMaxLength(100)
.HasColumnType("character varying(100)");
b.Property<int?>("UserSsoLifetime")
.HasColumnType("integer");
b.HasKey("Id");
b.HasIndex("ClientId")
.IsUnique();
b.ToTable("Clients");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientClaim", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<int>("ClientId")
.HasColumnType("integer");
b.Property<string>("Type")
.IsRequired()
.HasMaxLength(250)
.HasColumnType("character varying(250)");
b.Property<string>("Value")
.IsRequired()
.HasMaxLength(250)
.HasColumnType("character varying(250)");
b.HasKey("Id");
b.HasIndex("ClientId");
b.ToTable("ClientClaims");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientCorsOrigin", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<int>("ClientId")
.HasColumnType("integer");
b.Property<string>("Origin")
.IsRequired()
.HasMaxLength(150)
.HasColumnType("character varying(150)");
b.HasKey("Id");
b.HasIndex("ClientId");
b.ToTable("ClientCorsOrigins");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientGrantType", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<int>("ClientId")
.HasColumnType("integer");
b.Property<string>("GrantType")
.IsRequired()
.HasMaxLength(250)
.HasColumnType("character varying(250)");
b.HasKey("Id");
b.HasIndex("ClientId");
b.ToTable("ClientGrantTypes");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientIdPRestriction", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<int>("ClientId")
.HasColumnType("integer");
b.Property<string>("Provider")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("character varying(200)");
b.HasKey("Id");
b.HasIndex("ClientId");
b.ToTable("ClientIdPRestrictions");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientPostLogoutRedirectUri", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<int>("ClientId")
.HasColumnType("integer");
b.Property<string>("PostLogoutRedirectUri")
.IsRequired()
.HasMaxLength(2000)
.HasColumnType("character varying(2000)");
b.HasKey("Id");
b.HasIndex("ClientId");
b.ToTable("ClientPostLogoutRedirectUris");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientProperty", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<int>("ClientId")
.HasColumnType("integer");
b.Property<string>("Key")
.IsRequired()
.HasMaxLength(250)
.HasColumnType("character varying(250)");
b.Property<string>("Value")
.IsRequired()
.HasMaxLength(2000)
.HasColumnType("character varying(2000)");
b.HasKey("Id");
b.HasIndex("ClientId");
b.ToTable("ClientProperties");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientRedirectUri", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<int>("ClientId")
.HasColumnType("integer");
b.Property<string>("RedirectUri")
.IsRequired()
.HasMaxLength(2000)
.HasColumnType("character varying(2000)");
b.HasKey("Id");
b.HasIndex("ClientId");
b.ToTable("ClientRedirectUris");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientScope", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<int>("ClientId")
.HasColumnType("integer");
b.Property<string>("Scope")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("character varying(200)");
b.HasKey("Id");
b.HasIndex("ClientId");
b.ToTable("ClientScopes");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientSecret", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<int>("ClientId")
.HasColumnType("integer");
b.Property<DateTime>("Created")
.HasColumnType("timestamp without time zone");
b.Property<string>("Description")
.HasMaxLength(2000)
.HasColumnType("character varying(2000)");
b.Property<DateTime?>("Expiration")
.HasColumnType("timestamp without time zone");
b.Property<string>("Type")
.IsRequired()
.HasMaxLength(250)
.HasColumnType("character varying(250)");
b.Property<string>("Value")
.IsRequired()
.HasMaxLength(4000)
.HasColumnType("character varying(4000)");
b.HasKey("Id");
b.HasIndex("ClientId");
b.ToTable("ClientSecrets");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.IdentityResource", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<DateTime>("Created")
.HasColumnType("timestamp without time zone");
b.Property<string>("Description")
.HasMaxLength(1000)
.HasColumnType("character varying(1000)");
b.Property<string>("DisplayName")
.HasMaxLength(200)
.HasColumnType("character varying(200)");
b.Property<bool>("Emphasize")
.HasColumnType("boolean");
b.Property<bool>("Enabled")
.HasColumnType("boolean");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("character varying(200)");
b.Property<bool>("NonEditable")
.HasColumnType("boolean");
b.Property<bool>("Required")
.HasColumnType("boolean");
b.Property<bool>("ShowInDiscoveryDocument")
.HasColumnType("boolean");
b.Property<DateTime?>("Updated")
.HasColumnType("timestamp without time zone");
b.HasKey("Id");
b.HasIndex("Name")
.IsUnique();
b.ToTable("IdentityResources");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.IdentityResourceClaim", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<int>("IdentityResourceId")
.HasColumnType("integer");
b.Property<string>("Type")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("character varying(200)");
b.HasKey("Id");
b.HasIndex("IdentityResourceId");
b.ToTable("IdentityResourceClaims");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.IdentityResourceProperty", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<int>("IdentityResourceId")
.HasColumnType("integer");
b.Property<string>("Key")
.IsRequired()
.HasMaxLength(250)
.HasColumnType("character varying(250)");
b.Property<string>("Value")
.IsRequired()
.HasMaxLength(2000)
.HasColumnType("character varying(2000)");
b.HasKey("Id");
b.HasIndex("IdentityResourceId");
b.ToTable("IdentityResourceProperties");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceClaim", b =>
{
b.HasOne("IdentityServer4.EntityFramework.Entities.ApiResource", "ApiResource")
.WithMany("UserClaims")
.HasForeignKey("ApiResourceId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("ApiResource");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceProperty", b =>
{
b.HasOne("IdentityServer4.EntityFramework.Entities.ApiResource", "ApiResource")
.WithMany("Properties")
.HasForeignKey("ApiResourceId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("ApiResource");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceScope", b =>
{
b.HasOne("IdentityServer4.EntityFramework.Entities.ApiResource", "ApiResource")
.WithMany("Scopes")
.HasForeignKey("ApiResourceId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("ApiResource");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceSecret", b =>
{
b.HasOne("IdentityServer4.EntityFramework.Entities.ApiResource", "ApiResource")
.WithMany("Secrets")
.HasForeignKey("ApiResourceId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("ApiResource");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiScopeClaim", b =>
{
b.HasOne("IdentityServer4.EntityFramework.Entities.ApiScope", "Scope")
.WithMany("UserClaims")
.HasForeignKey("ScopeId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Scope");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiScopeProperty", b =>
{
b.HasOne("IdentityServer4.EntityFramework.Entities.ApiScope", "Scope")
.WithMany("Properties")
.HasForeignKey("ScopeId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Scope");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientClaim", b =>
{
b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client")
.WithMany("Claims")
.HasForeignKey("ClientId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Client");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientCorsOrigin", b =>
{
b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client")
.WithMany("AllowedCorsOrigins")
.HasForeignKey("ClientId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Client");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientGrantType", b =>
{
b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client")
.WithMany("AllowedGrantTypes")
.HasForeignKey("ClientId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Client");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientIdPRestriction", b =>
{
b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client")
.WithMany("IdentityProviderRestrictions")
.HasForeignKey("ClientId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Client");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientPostLogoutRedirectUri", b =>
{
b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client")
.WithMany("PostLogoutRedirectUris")
.HasForeignKey("ClientId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Client");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientProperty", b =>
{
b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client")
.WithMany("Properties")
.HasForeignKey("ClientId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Client");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientRedirectUri", b =>
{
b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client")
.WithMany("RedirectUris")
.HasForeignKey("ClientId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Client");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientScope", b =>
{
b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client")
.WithMany("AllowedScopes")
.HasForeignKey("ClientId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Client");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientSecret", b =>
{
b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client")
.WithMany("ClientSecrets")
.HasForeignKey("ClientId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Client");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.IdentityResourceClaim", b =>
{
b.HasOne("IdentityServer4.EntityFramework.Entities.IdentityResource", "IdentityResource")
.WithMany("UserClaims")
.HasForeignKey("IdentityResourceId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("IdentityResource");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.IdentityResourceProperty", b =>
{
b.HasOne("IdentityServer4.EntityFramework.Entities.IdentityResource", "IdentityResource")
.WithMany("Properties")
.HasForeignKey("IdentityResourceId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("IdentityResource");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResource", b =>
{
b.Navigation("Properties");
b.Navigation("Scopes");
b.Navigation("Secrets");
b.Navigation("UserClaims");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiScope", b =>
{
b.Navigation("Properties");
b.Navigation("UserClaims");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.Client", b =>
{
b.Navigation("AllowedCorsOrigins");
b.Navigation("AllowedGrantTypes");
b.Navigation("AllowedScopes");
b.Navigation("Claims");
b.Navigation("ClientSecrets");
b.Navigation("IdentityProviderRestrictions");
b.Navigation("PostLogoutRedirectUris");
b.Navigation("Properties");
b.Navigation("RedirectUris");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.IdentityResource", b =>
{
b.Navigation("Properties");
b.Navigation("UserClaims");
});
#pragma warning restore 612, 618
}
}
}

View File

@ -1,384 +0,0 @@
// <auto-generated />
using System;
using Kyoo;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
namespace Kyoo.Kyoo.Models.DatabaseMigrations.IdentityDatbase
{
[DbContext(typeof(IdentityDatabase))]
[Migration("20210216205030_Initial")]
partial class Initial
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("Relational:MaxIdentifierLength", 63)
.HasAnnotation("ProductVersion", "5.0.3")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.DeviceFlowCodes", b =>
{
b.Property<string>("UserCode")
.HasMaxLength(200)
.HasColumnType("character varying(200)");
b.Property<string>("ClientId")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("character varying(200)");
b.Property<DateTime>("CreationTime")
.HasColumnType("timestamp without time zone");
b.Property<string>("Data")
.IsRequired()
.HasMaxLength(50000)
.HasColumnType("character varying(50000)");
b.Property<string>("Description")
.HasMaxLength(200)
.HasColumnType("character varying(200)");
b.Property<string>("DeviceCode")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("character varying(200)");
b.Property<DateTime?>("Expiration")
.IsRequired()
.HasColumnType("timestamp without time zone");
b.Property<string>("SessionId")
.HasMaxLength(100)
.HasColumnType("character varying(100)");
b.Property<string>("SubjectId")
.HasMaxLength(200)
.HasColumnType("character varying(200)");
b.HasKey("UserCode");
b.HasIndex("DeviceCode")
.IsUnique();
b.HasIndex("Expiration");
b.ToTable("DeviceCodes");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.PersistedGrant", b =>
{
b.Property<string>("Key")
.HasMaxLength(200)
.HasColumnType("character varying(200)");
b.Property<string>("ClientId")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("character varying(200)");
b.Property<DateTime?>("ConsumedTime")
.HasColumnType("timestamp without time zone");
b.Property<DateTime>("CreationTime")
.HasColumnType("timestamp without time zone");
b.Property<string>("Data")
.IsRequired()
.HasMaxLength(50000)
.HasColumnType("character varying(50000)");
b.Property<string>("Description")
.HasMaxLength(200)
.HasColumnType("character varying(200)");
b.Property<DateTime?>("Expiration")
.HasColumnType("timestamp without time zone");
b.Property<string>("SessionId")
.HasMaxLength(100)
.HasColumnType("character varying(100)");
b.Property<string>("SubjectId")
.HasMaxLength(200)
.HasColumnType("character varying(200)");
b.Property<string>("Type")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("character varying(50)");
b.HasKey("Key");
b.HasIndex("Expiration");
b.HasIndex("SubjectId", "ClientId", "Type");
b.HasIndex("SubjectId", "SessionId", "Type");
b.ToTable("PersistedGrants");
});
modelBuilder.Entity("Kyoo.Models.User", b =>
{
b.Property<string>("Id")
.HasColumnType("text");
b.Property<int>("AccessFailedCount")
.HasColumnType("integer");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("text");
b.Property<string>("Email")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<bool>("EmailConfirmed")
.HasColumnType("boolean");
b.Property<bool>("LockoutEnabled")
.HasColumnType("boolean");
b.Property<DateTimeOffset?>("LockoutEnd")
.HasColumnType("timestamp with time zone");
b.Property<string>("NormalizedEmail")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<string>("NormalizedUserName")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<string>("OTAC")
.HasColumnType("text");
b.Property<DateTime?>("OTACExpires")
.HasColumnType("timestamp without time zone");
b.Property<string>("PasswordHash")
.HasColumnType("text");
b.Property<string>("PhoneNumber")
.HasColumnType("text");
b.Property<bool>("PhoneNumberConfirmed")
.HasColumnType("boolean");
b.Property<string>("SecurityStamp")
.HasColumnType("text");
b.Property<bool>("TwoFactorEnabled")
.HasColumnType("boolean");
b.Property<string>("UserName")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.HasKey("Id");
b.HasIndex("NormalizedEmail")
.HasDatabaseName("EmailIndex");
b.HasIndex("NormalizedUserName")
.IsUnique()
.HasDatabaseName("UserNameIndex");
b.ToTable("User");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
{
b.Property<string>("Id")
.HasColumnType("text");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("text");
b.Property<string>("Name")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<string>("NormalizedName")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.HasKey("Id");
b.HasIndex("NormalizedName")
.IsUnique()
.HasDatabaseName("RoleNameIndex");
b.ToTable("UserRoles");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<string>("ClaimType")
.HasColumnType("text");
b.Property<string>("ClaimValue")
.HasColumnType("text");
b.Property<string>("RoleId")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("RoleId");
b.ToTable("UserRoleClaim");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<string>("ClaimType")
.HasColumnType("text");
b.Property<string>("ClaimValue")
.HasColumnType("text");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("UserClaim");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.Property<string>("LoginProvider")
.HasMaxLength(128)
.HasColumnType("character varying(128)");
b.Property<string>("ProviderKey")
.HasMaxLength(128)
.HasColumnType("character varying(128)");
b.Property<string>("ProviderDisplayName")
.HasColumnType("text");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("text");
b.HasKey("LoginProvider", "ProviderKey");
b.HasIndex("UserId");
b.ToTable("UserLogin");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.Property<string>("UserId")
.HasColumnType("text");
b.Property<string>("RoleId")
.HasColumnType("text");
b.HasKey("UserId", "RoleId");
b.HasIndex("RoleId");
b.ToTable("UserRole");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.Property<string>("UserId")
.HasColumnType("text");
b.Property<string>("LoginProvider")
.HasMaxLength(128)
.HasColumnType("character varying(128)");
b.Property<string>("Name")
.HasMaxLength(128)
.HasColumnType("character varying(128)");
b.Property<string>("Value")
.HasColumnType("text");
b.HasKey("UserId", "LoginProvider", "Name");
b.ToTable("UserToken");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.HasOne("Kyoo.Models.User", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.HasOne("Kyoo.Models.User", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Kyoo.Models.User", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.HasOne("Kyoo.Models.User", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
#pragma warning restore 612, 618
}
}
}

View File

@ -1,291 +0,0 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
namespace Kyoo.Kyoo.Models.DatabaseMigrations.IdentityDatbase
{
public partial class Initial : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "DeviceCodes",
columns: table => new
{
UserCode = table.Column<string>(type: "character varying(200)", maxLength: 200, nullable: false),
DeviceCode = table.Column<string>(type: "character varying(200)", maxLength: 200, nullable: false),
SubjectId = table.Column<string>(type: "character varying(200)", maxLength: 200, nullable: true),
SessionId = table.Column<string>(type: "character varying(100)", maxLength: 100, nullable: true),
ClientId = table.Column<string>(type: "character varying(200)", maxLength: 200, nullable: false),
Description = table.Column<string>(type: "character varying(200)", maxLength: 200, nullable: true),
CreationTime = table.Column<DateTime>(type: "timestamp without time zone", nullable: false),
Expiration = table.Column<DateTime>(type: "timestamp without time zone", nullable: false),
Data = table.Column<string>(type: "character varying(50000)", maxLength: 50000, nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_DeviceCodes", x => x.UserCode);
});
migrationBuilder.CreateTable(
name: "PersistedGrants",
columns: table => new
{
Key = table.Column<string>(type: "character varying(200)", maxLength: 200, nullable: false),
Type = table.Column<string>(type: "character varying(50)", maxLength: 50, nullable: false),
SubjectId = table.Column<string>(type: "character varying(200)", maxLength: 200, nullable: true),
SessionId = table.Column<string>(type: "character varying(100)", maxLength: 100, nullable: true),
ClientId = table.Column<string>(type: "character varying(200)", maxLength: 200, nullable: false),
Description = table.Column<string>(type: "character varying(200)", maxLength: 200, nullable: true),
CreationTime = table.Column<DateTime>(type: "timestamp without time zone", nullable: false),
Expiration = table.Column<DateTime>(type: "timestamp without time zone", nullable: true),
ConsumedTime = table.Column<DateTime>(type: "timestamp without time zone", nullable: true),
Data = table.Column<string>(type: "character varying(50000)", maxLength: 50000, nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_PersistedGrants", x => x.Key);
});
migrationBuilder.CreateTable(
name: "User",
columns: table => new
{
Id = table.Column<string>(type: "text", nullable: false),
OTAC = table.Column<string>(type: "text", nullable: true),
OTACExpires = table.Column<DateTime>(type: "timestamp without time zone", nullable: true),
UserName = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
NormalizedUserName = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
Email = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
NormalizedEmail = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
EmailConfirmed = table.Column<bool>(type: "boolean", nullable: false),
PasswordHash = table.Column<string>(type: "text", nullable: true),
SecurityStamp = table.Column<string>(type: "text", nullable: true),
ConcurrencyStamp = table.Column<string>(type: "text", nullable: true),
PhoneNumber = table.Column<string>(type: "text", nullable: true),
PhoneNumberConfirmed = table.Column<bool>(type: "boolean", nullable: false),
TwoFactorEnabled = table.Column<bool>(type: "boolean", nullable: false),
LockoutEnd = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: true),
LockoutEnabled = table.Column<bool>(type: "boolean", nullable: false),
AccessFailedCount = table.Column<int>(type: "integer", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_User", x => x.Id);
});
migrationBuilder.CreateTable(
name: "UserRoles",
columns: table => new
{
Id = table.Column<string>(type: "text", nullable: false),
Name = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
NormalizedName = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
ConcurrencyStamp = table.Column<string>(type: "text", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_UserRoles", x => x.Id);
});
migrationBuilder.CreateTable(
name: "UserClaim",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
UserId = table.Column<string>(type: "text", nullable: false),
ClaimType = table.Column<string>(type: "text", nullable: true),
ClaimValue = table.Column<string>(type: "text", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_UserClaim", x => x.Id);
table.ForeignKey(
name: "FK_UserClaim_User_UserId",
column: x => x.UserId,
principalTable: "User",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "UserLogin",
columns: table => new
{
LoginProvider = table.Column<string>(type: "character varying(128)", maxLength: 128, nullable: false),
ProviderKey = table.Column<string>(type: "character varying(128)", maxLength: 128, nullable: false),
ProviderDisplayName = table.Column<string>(type: "text", nullable: true),
UserId = table.Column<string>(type: "text", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_UserLogin", x => new { x.LoginProvider, x.ProviderKey });
table.ForeignKey(
name: "FK_UserLogin_User_UserId",
column: x => x.UserId,
principalTable: "User",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "UserToken",
columns: table => new
{
UserId = table.Column<string>(type: "text", nullable: false),
LoginProvider = table.Column<string>(type: "character varying(128)", maxLength: 128, nullable: false),
Name = table.Column<string>(type: "character varying(128)", maxLength: 128, nullable: false),
Value = table.Column<string>(type: "text", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_UserToken", x => new { x.UserId, x.LoginProvider, x.Name });
table.ForeignKey(
name: "FK_UserToken_User_UserId",
column: x => x.UserId,
principalTable: "User",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "UserRole",
columns: table => new
{
UserId = table.Column<string>(type: "text", nullable: false),
RoleId = table.Column<string>(type: "text", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_UserRole", x => new { x.UserId, x.RoleId });
table.ForeignKey(
name: "FK_UserRole_User_UserId",
column: x => x.UserId,
principalTable: "User",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_UserRole_UserRoles_RoleId",
column: x => x.RoleId,
principalTable: "UserRoles",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "UserRoleClaim",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
RoleId = table.Column<string>(type: "text", nullable: false),
ClaimType = table.Column<string>(type: "text", nullable: true),
ClaimValue = table.Column<string>(type: "text", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_UserRoleClaim", x => x.Id);
table.ForeignKey(
name: "FK_UserRoleClaim_UserRoles_RoleId",
column: x => x.RoleId,
principalTable: "UserRoles",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "IX_DeviceCodes_DeviceCode",
table: "DeviceCodes",
column: "DeviceCode",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_DeviceCodes_Expiration",
table: "DeviceCodes",
column: "Expiration");
migrationBuilder.CreateIndex(
name: "IX_PersistedGrants_Expiration",
table: "PersistedGrants",
column: "Expiration");
migrationBuilder.CreateIndex(
name: "IX_PersistedGrants_SubjectId_ClientId_Type",
table: "PersistedGrants",
columns: new[] { "SubjectId", "ClientId", "Type" });
migrationBuilder.CreateIndex(
name: "IX_PersistedGrants_SubjectId_SessionId_Type",
table: "PersistedGrants",
columns: new[] { "SubjectId", "SessionId", "Type" });
migrationBuilder.CreateIndex(
name: "EmailIndex",
table: "User",
column: "NormalizedEmail");
migrationBuilder.CreateIndex(
name: "UserNameIndex",
table: "User",
column: "NormalizedUserName",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_UserClaim_UserId",
table: "UserClaim",
column: "UserId");
migrationBuilder.CreateIndex(
name: "IX_UserLogin_UserId",
table: "UserLogin",
column: "UserId");
migrationBuilder.CreateIndex(
name: "IX_UserRole_RoleId",
table: "UserRole",
column: "RoleId");
migrationBuilder.CreateIndex(
name: "IX_UserRoleClaim_RoleId",
table: "UserRoleClaim",
column: "RoleId");
migrationBuilder.CreateIndex(
name: "RoleNameIndex",
table: "UserRoles",
column: "NormalizedName",
unique: true);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "DeviceCodes");
migrationBuilder.DropTable(
name: "PersistedGrants");
migrationBuilder.DropTable(
name: "UserClaim");
migrationBuilder.DropTable(
name: "UserLogin");
migrationBuilder.DropTable(
name: "UserRole");
migrationBuilder.DropTable(
name: "UserRoleClaim");
migrationBuilder.DropTable(
name: "UserToken");
migrationBuilder.DropTable(
name: "UserRoles");
migrationBuilder.DropTable(
name: "User");
}
}
}

View File

@ -1,382 +0,0 @@
// <auto-generated />
using System;
using Kyoo;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
namespace Kyoo.Kyoo.Models.DatabaseMigrations.IdentityDatbase
{
[DbContext(typeof(IdentityDatabase))]
partial class IdentityDatabaseModelSnapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("Relational:MaxIdentifierLength", 63)
.HasAnnotation("ProductVersion", "5.0.3")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.DeviceFlowCodes", b =>
{
b.Property<string>("UserCode")
.HasMaxLength(200)
.HasColumnType("character varying(200)");
b.Property<string>("ClientId")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("character varying(200)");
b.Property<DateTime>("CreationTime")
.HasColumnType("timestamp without time zone");
b.Property<string>("Data")
.IsRequired()
.HasMaxLength(50000)
.HasColumnType("character varying(50000)");
b.Property<string>("Description")
.HasMaxLength(200)
.HasColumnType("character varying(200)");
b.Property<string>("DeviceCode")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("character varying(200)");
b.Property<DateTime?>("Expiration")
.IsRequired()
.HasColumnType("timestamp without time zone");
b.Property<string>("SessionId")
.HasMaxLength(100)
.HasColumnType("character varying(100)");
b.Property<string>("SubjectId")
.HasMaxLength(200)
.HasColumnType("character varying(200)");
b.HasKey("UserCode");
b.HasIndex("DeviceCode")
.IsUnique();
b.HasIndex("Expiration");
b.ToTable("DeviceCodes");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.PersistedGrant", b =>
{
b.Property<string>("Key")
.HasMaxLength(200)
.HasColumnType("character varying(200)");
b.Property<string>("ClientId")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("character varying(200)");
b.Property<DateTime?>("ConsumedTime")
.HasColumnType("timestamp without time zone");
b.Property<DateTime>("CreationTime")
.HasColumnType("timestamp without time zone");
b.Property<string>("Data")
.IsRequired()
.HasMaxLength(50000)
.HasColumnType("character varying(50000)");
b.Property<string>("Description")
.HasMaxLength(200)
.HasColumnType("character varying(200)");
b.Property<DateTime?>("Expiration")
.HasColumnType("timestamp without time zone");
b.Property<string>("SessionId")
.HasMaxLength(100)
.HasColumnType("character varying(100)");
b.Property<string>("SubjectId")
.HasMaxLength(200)
.HasColumnType("character varying(200)");
b.Property<string>("Type")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("character varying(50)");
b.HasKey("Key");
b.HasIndex("Expiration");
b.HasIndex("SubjectId", "ClientId", "Type");
b.HasIndex("SubjectId", "SessionId", "Type");
b.ToTable("PersistedGrants");
});
modelBuilder.Entity("Kyoo.Models.User", b =>
{
b.Property<string>("Id")
.HasColumnType("text");
b.Property<int>("AccessFailedCount")
.HasColumnType("integer");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("text");
b.Property<string>("Email")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<bool>("EmailConfirmed")
.HasColumnType("boolean");
b.Property<bool>("LockoutEnabled")
.HasColumnType("boolean");
b.Property<DateTimeOffset?>("LockoutEnd")
.HasColumnType("timestamp with time zone");
b.Property<string>("NormalizedEmail")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<string>("NormalizedUserName")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<string>("OTAC")
.HasColumnType("text");
b.Property<DateTime?>("OTACExpires")
.HasColumnType("timestamp without time zone");
b.Property<string>("PasswordHash")
.HasColumnType("text");
b.Property<string>("PhoneNumber")
.HasColumnType("text");
b.Property<bool>("PhoneNumberConfirmed")
.HasColumnType("boolean");
b.Property<string>("SecurityStamp")
.HasColumnType("text");
b.Property<bool>("TwoFactorEnabled")
.HasColumnType("boolean");
b.Property<string>("UserName")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.HasKey("Id");
b.HasIndex("NormalizedEmail")
.HasDatabaseName("EmailIndex");
b.HasIndex("NormalizedUserName")
.IsUnique()
.HasDatabaseName("UserNameIndex");
b.ToTable("User");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
{
b.Property<string>("Id")
.HasColumnType("text");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("text");
b.Property<string>("Name")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<string>("NormalizedName")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.HasKey("Id");
b.HasIndex("NormalizedName")
.IsUnique()
.HasDatabaseName("RoleNameIndex");
b.ToTable("UserRoles");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<string>("ClaimType")
.HasColumnType("text");
b.Property<string>("ClaimValue")
.HasColumnType("text");
b.Property<string>("RoleId")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("RoleId");
b.ToTable("UserRoleClaim");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<string>("ClaimType")
.HasColumnType("text");
b.Property<string>("ClaimValue")
.HasColumnType("text");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("UserClaim");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.Property<string>("LoginProvider")
.HasMaxLength(128)
.HasColumnType("character varying(128)");
b.Property<string>("ProviderKey")
.HasMaxLength(128)
.HasColumnType("character varying(128)");
b.Property<string>("ProviderDisplayName")
.HasColumnType("text");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("text");
b.HasKey("LoginProvider", "ProviderKey");
b.HasIndex("UserId");
b.ToTable("UserLogin");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.Property<string>("UserId")
.HasColumnType("text");
b.Property<string>("RoleId")
.HasColumnType("text");
b.HasKey("UserId", "RoleId");
b.HasIndex("RoleId");
b.ToTable("UserRole");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.Property<string>("UserId")
.HasColumnType("text");
b.Property<string>("LoginProvider")
.HasMaxLength(128)
.HasColumnType("character varying(128)");
b.Property<string>("Name")
.HasMaxLength(128)
.HasColumnType("character varying(128)");
b.Property<string>("Value")
.HasColumnType("text");
b.HasKey("UserId", "LoginProvider", "Name");
b.ToTable("UserToken");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.HasOne("Kyoo.Models.User", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.HasOne("Kyoo.Models.User", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Kyoo.Models.User", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.HasOne("Kyoo.Models.User", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
#pragma warning restore 612, 618
}
}
}

View File

@ -1,47 +0,0 @@
using System.Threading.Tasks;
using IdentityServer4.EntityFramework.Entities;
using IdentityServer4.EntityFramework.Extensions;
using IdentityServer4.EntityFramework.Interfaces;
using IdentityServer4.EntityFramework.Options;
using Kyoo.Models;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;
namespace Kyoo
{
// The configuration's database is named ConfigurationDbContext.
public class IdentityDatabase : IdentityDbContext<User>, IPersistedGrantDbContext
{
private readonly IOptions<OperationalStoreOptions> _operationalStoreOptions;
public IdentityDatabase(DbContextOptions<IdentityDatabase> options, IOptions<OperationalStoreOptions> operationalStoreOptions)
: base(options)
{
_operationalStoreOptions = operationalStoreOptions;
}
public DbSet<User> Accounts { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.ConfigurePersistedGrantContext(_operationalStoreOptions.Value);
modelBuilder.Entity<User>().ToTable("User");
modelBuilder.Entity<IdentityUserRole<string>>().ToTable("UserRole");
modelBuilder.Entity<IdentityUserLogin<string>>().ToTable("UserLogin");
modelBuilder.Entity<IdentityUserClaim<string>>().ToTable("UserClaim");
modelBuilder.Entity<IdentityRole>().ToTable("UserRoles");
modelBuilder.Entity<IdentityRoleClaim<string>>().ToTable("UserRoleClaim");
modelBuilder.Entity<IdentityUserToken<string>>().ToTable("UserToken");
}
public Task<int> SaveChangesAsync() => base.SaveChangesAsync();
public DbSet<PersistedGrant> PersistedGrants { get; set; }
public DbSet<DeviceFlowCodes> DeviceFlowCodes { get; set; }
}
}

View File

@ -1,25 +1,13 @@
using System;
using System.IO;
using System.Reflection;
using IdentityServer4.Extensions;
using IdentityServer4.Services;
using Kyoo.Api;
using Kyoo.Controllers;
using Kyoo.Models;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.SpaServices.AngularCli;
using Microsoft.AspNetCore.StaticFiles;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Unity;
using Unity.Lifetime;
@ -31,13 +19,11 @@ namespace Kyoo
public class Startup
{
private readonly IConfiguration _configuration;
private readonly ILoggerFactory _loggerFactory;
public Startup(IConfiguration configuration, ILoggerFactory loggerFactory)
public Startup(IConfiguration configuration)
{
_configuration = configuration;
_loggerFactory = loggerFactory;
}
public void ConfigureServices(IServiceCollection services)
@ -62,86 +48,17 @@ namespace Kyoo
x.SerializerSettings.Converters.Add(new PeopleRoleConverter());
});
services.AddHttpClient();
services.AddDbContext<IdentityDatabase>(options =>
{
options.UseNpgsql(_configuration.GetDatabaseConnection("postgres"));
});
string assemblyName = typeof(Startup).GetTypeInfo().Assembly.GetName().Name;
services.AddIdentityCore<User>(o =>
{
o.Stores.MaxLengthForKeys = 128;
})
.AddSignInManager()
.AddDefaultTokenProviders()
.AddEntityFrameworkStores<IdentityDatabase>();
services.AddIdentityServer(options =>
{
options.IssuerUri = publicUrl;
options.UserInteraction.LoginUrl = publicUrl + "login";
options.UserInteraction.ErrorUrl = publicUrl + "error";
options.UserInteraction.LogoutUrl = publicUrl + "logout";
})
.AddAspNetIdentity<User>()
.AddConfigurationStore(options =>
{
options.ConfigureDbContext = builder =>
builder.UseNpgsql(_configuration.GetDatabaseConnection("postgres"),
sql => sql.MigrationsAssembly(assemblyName));
})
.AddOperationalStore(options =>
{
options.ConfigureDbContext = builder =>
builder.UseNpgsql(_configuration.GetDatabaseConnection("postgres"),
sql => sql.MigrationsAssembly(assemblyName));
options.EnableTokenCleanup = true;
})
.AddInMemoryIdentityResources(IdentityContext.GetIdentityResources())
.AddInMemoryApiScopes(IdentityContext.GetScopes())
.AddInMemoryApiResources(IdentityContext.GetApis())
.AddProfileService<AccountController>()
.AddSigninKeys(_configuration);
services.AddAuthentication(o =>
{
o.DefaultScheme = IdentityConstants.ApplicationScheme;
o.DefaultSignInScheme = IdentityConstants.ExternalScheme;
})
.AddIdentityCookies(_ => { });
services.AddAuthentication()
.AddJwtBearer(options =>
{
options.Authority = publicUrl;
options.Audience = "Kyoo";
options.RequireHttpsMetadata = false;
});
services.AddAuthorization(options =>
{
AuthorizationPolicyBuilder scheme = new(IdentityConstants.ApplicationScheme, JwtBearerDefaults.AuthenticationScheme);
options.DefaultPolicy = scheme.RequireAuthenticatedUser().Build();
string[] permissions = {"Read", "Write", "Play", "Admin"};
foreach (string permission in permissions)
{
options.AddPolicy(permission, policy =>
{
policy.AuthenticationSchemes.Add(IdentityConstants.ApplicationScheme);
policy.AuthenticationSchemes.Add(JwtBearerDefaults.AuthenticationScheme);
policy.AddRequirements(new AuthorizationValidator(permission));
// policy.RequireScope($"kyoo.{permission.ToLower()}");
});
}
});
services.AddSingleton<IAuthorizationHandler, AuthorizationValidatorHandler>();
services.AddSingleton<ICorsPolicyService>(new DefaultCorsPolicyService(_loggerFactory.CreateLogger<DefaultCorsPolicyService>())
{
AllowedOrigins = { new Uri(publicUrl).GetLeftPart(UriPartial.Authority) }
});
// services.AddAuthorization(options =>
// {
// string[] permissions = {"Read", "Write", "Play", "Admin"};
// foreach (string permission in permissions)
// options.AddPolicy(permission, policy =>
// {
// policy.AddRequirements(new AuthorizationValidator(permission));
// });
// });
// services.AddAuthentication()
services.AddSingleton<ITaskManager, TaskManager>();
services.AddHostedService(x => x.GetService<ITaskManager>() as TaskManager);
@ -152,9 +69,7 @@ namespace Kyoo
public void Configure(IUnityContainer container, IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
@ -172,6 +87,7 @@ namespace Kyoo
app.UseSpaStaticFiles();
app.UseRouting();
// app.UseAuthorization();
app.Use((ctx, next) =>
{
@ -186,36 +102,26 @@ namespace Kyoo
return next();
});
app.UseResponseCompression();
app.UseCookiePolicy(new CookiePolicyOptions
{
MinimumSameSitePolicy = SameSiteMode.Strict
});
app.UseAuthentication();
app.Use((ctx, next) =>
{
ctx.SetIdentityServerOrigin(_configuration.GetValue<string>("public_url"));
return next();
});
app.UseIdentityServer();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute("Kyoo", "api/{controller=Home}/{action=Index}/{id?}");
});
app.UseSpa(spa =>
{
spa.Options.SourcePath = Path.Join(AppDomain.CurrentDomain.BaseDirectory, "Kyoo.WebApp");
if (env.IsDevelopment())
spa.UseAngularCliServer("start");
});
// app.UseSpa(spa =>
// {
// spa.Options.SourcePath = Path.Join(AppDomain.CurrentDomain.BaseDirectory, "Kyoo.WebApp");
//
// if (env.IsDevelopment())
// spa.UseAngularCliServer("start");
// });
//
container.RegisterType<IPluginManager, PluginManager>(new SingletonLifetimeManager());
// container.Resolve<IConfiguration>();
IPluginManager pluginManager = container.Resolve<IPluginManager>();
pluginManager.ReloadPlugins();
foreach (IPlugin plugin in pluginManager.GetAllPlugins())
plugin.ConfigureAspNet(app);
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute("Kyoo", "api/{controller=Home}/{action=Index}/{id?}");
});
}
}
}

View File

@ -2,15 +2,17 @@
using System.Collections.Generic;
using Microsoft.AspNetCore.Mvc;
using Kyoo.Controllers;
using Kyoo.Models.Attributes;
using Kyoo.Models.Exceptions;
using Microsoft.AspNetCore.Authorization;
using static Kyoo.Models.Attributes.PermissionAttribute;
namespace Kyoo.Api
{
[Route("api/task")]
[Route("api/tasks")]
[ApiController]
[Authorize(Policy="Admin")]
// [Authorize(Policy="Admin")]
public class TaskApi : ControllerBase
{
private readonly ITaskManager _taskManager;
@ -22,6 +24,7 @@ namespace Kyoo.Api
[HttpGet]
[Permission("task", Kind.Read)]
public ActionResult<ICollection<ITask>> GetTasks()
{
return Ok(_taskManager.GetAllTasks());

View File

@ -17,21 +17,25 @@
"logging": {
"logLevel": {
"default": "Warning",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information",
"default": "Trace",
"Kyoo": "Trace"
}
},
"authentication": {
"certificate": {
"file": "certificate.pfx",
"oldFile": "oldCertificate.pfx",
"password": "passphrase"
}
},
"parallelTasks": "1",
"scheduledTasks": {
"scan": "24:00:00"
},
"certificatePassword": "passphrase",
"transmuxTempPath": "cached/kyoo/transmux",
"transcodeTempPath": "cached/kyoo/transcode",