mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-07-09 03:04:20 -04:00
Rewoking the login workflow
This commit is contained in:
parent
62753b20bb
commit
4bdaba4643
@ -6,6 +6,7 @@
|
|||||||
<TypeScriptToolsVersion>Latest</TypeScriptToolsVersion>
|
<TypeScriptToolsVersion>Latest</TypeScriptToolsVersion>
|
||||||
<IsPackable>false</IsPackable>
|
<IsPackable>false</IsPackable>
|
||||||
<SpaRoot>Views/WebClient/</SpaRoot>
|
<SpaRoot>Views/WebClient/</SpaRoot>
|
||||||
|
<LoginRoot>Views/Login/</LoginRoot>
|
||||||
<TranscoderRoot>../transcoder</TranscoderRoot>
|
<TranscoderRoot>../transcoder</TranscoderRoot>
|
||||||
<DefaultItemExcludes>$(DefaultItemExcludes);$(SpaRoot)node_modules/**</DefaultItemExcludes>
|
<DefaultItemExcludes>$(DefaultItemExcludes);$(SpaRoot)node_modules/**</DefaultItemExcludes>
|
||||||
|
|
||||||
@ -44,6 +45,8 @@
|
|||||||
<Content Remove="$(SpaRoot)**" />
|
<Content Remove="$(SpaRoot)**" />
|
||||||
<None Include="$(SpaRoot)**" Exclude="$(SpaRoot)node_modules\**" />
|
<None Include="$(SpaRoot)**" Exclude="$(SpaRoot)node_modules\**" />
|
||||||
<StaticFiles Include="$(SpaRoot)static/**" />
|
<StaticFiles Include="$(SpaRoot)static/**" />
|
||||||
|
<LoginFiles Include="$(LoginRoot)**" />
|
||||||
|
<StaticFiles Include="Views\Login\material-icons.css" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<Target Name="PublishRunWebpack" AfterTargets="ComputeFilesToPublish">
|
<Target Name="PublishRunWebpack" AfterTargets="ComputeFilesToPublish">
|
||||||
@ -64,11 +67,17 @@
|
|||||||
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
||||||
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
|
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
|
||||||
</ResolvedFileToPublish>
|
</ResolvedFileToPublish>
|
||||||
|
<ResolvedFileToPublish Include="@(LoginFiles->'%(FullPath)')" Exclude="@(ResolvedFileToPublish)">
|
||||||
|
<RelativePath>login/%(LoginFiles.RecursiveDir)%(LoginFiles.Filename)%(LoginFiles.Extension)</RelativePath>
|
||||||
|
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
||||||
|
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
|
||||||
|
</ResolvedFileToPublish>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Target>
|
</Target>
|
||||||
|
|
||||||
<Target Name="Prepare the web app" AfterTargets="Build" Condition="$(Configuration) == 'Debug'">
|
<Target Name="Prepare the web app" AfterTargets="Build" Condition="$(Configuration) == 'Debug'">
|
||||||
<Copy SourceFiles="@(StaticFiles)" DestinationFolder="$(OutputPath)/wwwroot/%(RecursiveDir)" />
|
<Copy SourceFiles="@(StaticFiles)" DestinationFolder="$(OutputPath)/wwwroot/%(RecursiveDir)" />
|
||||||
|
<Copy SourceFiles="@(LoginFiles)" DestinationFolder="$(OutputPath)/login/%(RecursiveDir)" />
|
||||||
<Exec WorkingDirectory="$(SpaRoot)" Command="npm install" />
|
<Exec WorkingDirectory="$(SpaRoot)" Command="npm install" />
|
||||||
</Target>
|
</Target>
|
||||||
|
|
||||||
@ -87,8 +96,4 @@
|
|||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<Target Name="CreatePluginFolder" AfterTargets="Build">
|
|
||||||
<MakeDir Directories="$(OutputPath)/plugins" />
|
|
||||||
</Target>
|
|
||||||
</Project>
|
</Project>
|
||||||
|
@ -22,14 +22,16 @@ namespace Kyoo
|
|||||||
new Client
|
new Client
|
||||||
{
|
{
|
||||||
ClientId = "kyoo.webapp",
|
ClientId = "kyoo.webapp",
|
||||||
|
|
||||||
|
AccessTokenType = AccessTokenType.Jwt,
|
||||||
AllowedGrantTypes = GrantTypes.Code,
|
AllowedGrantTypes = GrantTypes.Code,
|
||||||
RequirePkce = true,
|
RequirePkce = true,
|
||||||
AllowAccessTokensViaBrowser = true,
|
|
||||||
AlwaysIncludeUserClaimsInIdToken = true,
|
|
||||||
AllowOfflineAccess = true,
|
|
||||||
RequireClientSecret = false,
|
RequireClientSecret = false,
|
||||||
|
|
||||||
|
AllowAccessTokensViaBrowser = true,
|
||||||
|
AllowOfflineAccess = true,
|
||||||
RequireConsent = false,
|
RequireConsent = false,
|
||||||
AccessTokenType = AccessTokenType.Jwt,
|
|
||||||
AllowedScopes = { "openid", "profile", "kyoo.read", "kyoo.write", "kyoo.play", "kyoo.download", "kyoo.admin" },
|
AllowedScopes = { "openid", "profile", "kyoo.read", "kyoo.write", "kyoo.play", "kyoo.download", "kyoo.admin" },
|
||||||
RedirectUris = { "/", "/silent" },
|
RedirectUris = { "/", "/silent" },
|
||||||
PostLogoutRedirectUris = { "/logout" }
|
PostLogoutRedirectUris = { "/logout" }
|
||||||
|
@ -15,7 +15,7 @@ namespace Kyoo
|
|||||||
|
|
||||||
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
|
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
|
||||||
WebHost.CreateDefaultBuilder(args)
|
WebHost.CreateDefaultBuilder(args)
|
||||||
.UseKestrel((config) => { config.AddServerHeader = false; })
|
.UseKestrel(config => { config.AddServerHeader = false; })
|
||||||
.UseUrls("http://*:5000")
|
.UseUrls("http://*:5000")
|
||||||
.UseStartup<Startup>();
|
.UseStartup<Startup>();
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ using Microsoft.AspNetCore.Authentication.JwtBearer;
|
|||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Identity;
|
using Microsoft.AspNetCore.Identity;
|
||||||
using Microsoft.AspNetCore.SpaServices.AngularCli;
|
using Microsoft.AspNetCore.SpaServices.AngularCli;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
@ -145,6 +146,10 @@ namespace Kyoo
|
|||||||
app.UseAuthentication();
|
app.UseAuthentication();
|
||||||
app.UseIdentityServer();
|
app.UseIdentityServer();
|
||||||
app.UseAuthorization();
|
app.UseAuthorization();
|
||||||
|
app.UseCookiePolicy(new CookiePolicyOptions
|
||||||
|
{
|
||||||
|
MinimumSameSitePolicy = SameSiteMode.Lax
|
||||||
|
});
|
||||||
|
|
||||||
app.UseEndpoints(endpoints =>
|
app.UseEndpoints(endpoints =>
|
||||||
{
|
{
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Security.Claims;
|
using System.Security.Claims;
|
||||||
@ -11,6 +12,7 @@ using Microsoft.AspNetCore.Authorization;
|
|||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Identity;
|
using Microsoft.AspNetCore.Identity;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.AspNetCore.StaticFiles;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using SignInResult = Microsoft.AspNetCore.Identity.SignInResult;
|
using SignInResult = Microsoft.AspNetCore.Identity.SignInResult;
|
||||||
|
|
||||||
@ -32,7 +34,8 @@ namespace Kyoo.Api
|
|||||||
|
|
||||||
public class OtacRequest
|
public class OtacRequest
|
||||||
{
|
{
|
||||||
public string Otac;
|
public string Otac { get; set; }
|
||||||
|
public bool StayLoggedIn { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class AccountData
|
public class AccountData
|
||||||
@ -45,6 +48,28 @@ namespace Kyoo.Api
|
|||||||
public IFormFile Picture { get; set; }
|
public IFormFile Picture { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[ApiController]
|
||||||
|
public class AccountUiController : Controller
|
||||||
|
{
|
||||||
|
[HttpGet("login")]
|
||||||
|
public IActionResult Index()
|
||||||
|
{
|
||||||
|
return new PhysicalFileResult(Path.GetFullPath("login/login.html"), "text/html");
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("login/{*file}")]
|
||||||
|
public IActionResult Index(string file)
|
||||||
|
{
|
||||||
|
string path = Path.Combine(Path.GetFullPath("login/"), file);
|
||||||
|
if (!System.IO.File.Exists(path))
|
||||||
|
return NotFound();
|
||||||
|
FileExtensionContentTypeProvider provider = new FileExtensionContentTypeProvider();
|
||||||
|
if (!provider.TryGetContentType(path, out string contentType))
|
||||||
|
contentType = "text/plain";
|
||||||
|
return new PhysicalFileResult(path, contentType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[Route("api/[controller]")]
|
[Route("api/[controller]")]
|
||||||
[ApiController]
|
[ApiController]
|
||||||
public class AccountController : Controller, IProfileService
|
public class AccountController : Controller, IProfileService
|
||||||
@ -74,6 +99,10 @@ namespace Kyoo.Api
|
|||||||
{
|
{
|
||||||
if (!ModelState.IsValid)
|
if (!ModelState.IsValid)
|
||||||
return BadRequest(user);
|
return BadRequest(user);
|
||||||
|
if (user.Username.Length < 4)
|
||||||
|
return BadRequest(new[] {new {code = "username", description = "Username must be at least 4 characters."}});
|
||||||
|
if (!new EmailAddressAttribute().IsValid(user.Email))
|
||||||
|
return BadRequest(new[] {new {code = "email", description = "Email must be valid."}});
|
||||||
User account = new User {UserName = user.Username, Email = user.Email};
|
User account = new User {UserName = user.Username, Email = user.Email};
|
||||||
IdentityResult result = await _userManager.CreateAsync(account, user.Password);
|
IdentityResult result = await _userManager.CreateAsync(account, user.Password);
|
||||||
if (!result.Succeeded)
|
if (!result.Succeeded)
|
||||||
@ -81,7 +110,7 @@ namespace Kyoo.Api
|
|||||||
string otac = account.GenerateOTAC(TimeSpan.FromMinutes(1));
|
string otac = account.GenerateOTAC(TimeSpan.FromMinutes(1));
|
||||||
await _userManager.UpdateAsync(account);
|
await _userManager.UpdateAsync(account);
|
||||||
await _userManager.AddClaimsAsync(account, defaultClaims);
|
await _userManager.AddClaimsAsync(account, defaultClaims);
|
||||||
return Ok(otac);
|
return Ok(new {otac});
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost("login")]
|
[HttpPost("login")]
|
||||||
@ -98,12 +127,14 @@ namespace Kyoo.Api
|
|||||||
[HttpPost("otac-login")]
|
[HttpPost("otac-login")]
|
||||||
public async Task<IActionResult> OtacLogin([FromBody] OtacRequest otac)
|
public async Task<IActionResult> OtacLogin([FromBody] OtacRequest otac)
|
||||||
{
|
{
|
||||||
|
if (!ModelState.IsValid)
|
||||||
|
return BadRequest(otac);
|
||||||
User user = _userManager.Users.FirstOrDefault(x => x.OTAC == otac.Otac);
|
User user = _userManager.Users.FirstOrDefault(x => x.OTAC == otac.Otac);
|
||||||
if (user == null)
|
if (user == null)
|
||||||
return BadRequest(new [] { new {code = "InvalidOTAC", description = "No user was found for this OTAC."}});
|
return BadRequest(new [] { new {code = "InvalidOTAC", description = "No user was found for this OTAC."}});
|
||||||
if (user.OTACExpires <= DateTime.UtcNow)
|
if (user.OTACExpires <= DateTime.UtcNow)
|
||||||
return BadRequest(new [] { new {code = "ExpiredOTAC", description = "The OTAC has expired. Try to login with your password."}});
|
return BadRequest(new [] { new {code = "ExpiredOTAC", description = "The OTAC has expired. Try to login with your password."}});
|
||||||
await _signInManager.SignInAsync(user, true);
|
await _signInManager.SignInAsync(user, otac.StayLoggedIn);
|
||||||
return Ok();
|
return Ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
1
Kyoo/Views/Login/lib/bootstrap.min.css
vendored
Normal file
1
Kyoo/Views/Login/lib/bootstrap.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
7
Kyoo/Views/Login/lib/bootstrap.min.js
vendored
Normal file
7
Kyoo/Views/Login/lib/bootstrap.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
2
Kyoo/Views/Login/lib/jquery.min.js
vendored
Normal file
2
Kyoo/Views/Login/lib/jquery.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
16
Kyoo/Views/Login/login.css
Normal file
16
Kyoo/Views/Login/login.css
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
.nav-tabs .nav-link, a
|
||||||
|
{
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-tabs .nav-item.show .nav-link, .nav-tabs .nav-link.active
|
||||||
|
{
|
||||||
|
background-color: #343a40;
|
||||||
|
color: white;
|
||||||
|
border-color: #343a40;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-control:focus
|
||||||
|
{
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
90
Kyoo/Views/Login/login.html
Normal file
90
Kyoo/Views/Login/login.html
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Kyoo - Login</title>
|
||||||
|
<link rel="stylesheet" type="text/css" href="login/lib/bootstrap.min.css" />
|
||||||
|
<link rel="stylesheet" type="text/css" href="login/login.css" />
|
||||||
|
<link rel="stylesheet" type="text/css" href="login/material-icons.css" />
|
||||||
|
<script src="login/lib/jquery.min.js"></script>
|
||||||
|
<script src="login/lib/bootstrap.min.js"></script>
|
||||||
|
</head>
|
||||||
|
<body style="height: 100vh; align-items: center;" class="d-flex">
|
||||||
|
<div class="container pb-5">
|
||||||
|
<div class="card bg-dark mb-5">
|
||||||
|
<div class="card-header bg-secondary text-white">
|
||||||
|
<ul class="nav nav-tabs card-header-tabs navbar-dark" role="tablist" id="tabs">
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link active" id="login-tab" data-toggle="tab" href="#login" role="tab" aria-selected="true">Login</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="#register" role="tab" aria-selected="false">Register</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="card-body tab-content">
|
||||||
|
<div class="tab-pane fade show active" id="login" role="tabpanel" aria-labelledby="login-tab">
|
||||||
|
<div class="alert alert-danger" role="alert" id="login-error" style="display: none;"></div>
|
||||||
|
<form>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="login-username">Username</label>
|
||||||
|
<input autocomplete="username" class="form-control" id="login-username">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="login-password">Password</label>
|
||||||
|
<div class="input-group">
|
||||||
|
<input autocomplete="current-password" type="password" class="form-control" id="login-password">
|
||||||
|
<div class="input-group-append password-visibility">
|
||||||
|
<a class="input-group-text" href="#"><i class="material-icons">visibility</i></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group form-check">
|
||||||
|
<input type="checkbox" class="form-check-input" id="remember-me">
|
||||||
|
<label class="form-check-label" for="remember-me">Remember me</label>
|
||||||
|
</div>
|
||||||
|
<button id="login-btn" type="submit" class="btn" style="background-color: #e23c00;">Login</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div class="tab-pane fade" id="register" role="tabpanel" aria-labelledby="register-tab">
|
||||||
|
<div class="alert alert-danger" role="alert" id="register-error" style="display: none;"></div>
|
||||||
|
<form>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="register-email">Email</label>
|
||||||
|
<input type="email" class="form-control" id="register-email">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="register-username">Username</label>
|
||||||
|
<input autocomplete="username" class="form-control" id="register-username">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="register-password">Password</label>
|
||||||
|
<div class="input-group">
|
||||||
|
<input autocomplete="new-password" type="password" class="form-control" id="register-password">
|
||||||
|
<div class="input-group-append password-visibility">
|
||||||
|
<a class="input-group-text" href="#"><i class="material-icons">visibility</i></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="register-password-confirm">Confirm Password</label>
|
||||||
|
<div class="input-group">
|
||||||
|
<input autocomplete="new-password" type="password" class="form-control" id="register-password-confirm">
|
||||||
|
<div class="input-group-append password-visibility">
|
||||||
|
<a class="input-group-text" href="#"><i class="material-icons">visibility</i></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group form-check">
|
||||||
|
<input type="checkbox" class="form-check-input" id="stay-logged-in">
|
||||||
|
<label class="form-check-label" for="stay-logged-in">Stay logged in</label>
|
||||||
|
</div>
|
||||||
|
<button id="register-btn" type="submit" class="btn" style="background-color: #e23c00;">Register</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script src="login/login.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
127
Kyoo/Views/Login/login.js
Normal file
127
Kyoo/Views/Login/login.js
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
$("#tabs a").on("click", function (e)
|
||||||
|
{
|
||||||
|
e.preventDefault();
|
||||||
|
$(this).tab("show");
|
||||||
|
});
|
||||||
|
|
||||||
|
$(".password-visibility a").on("click", function(e)
|
||||||
|
{
|
||||||
|
e.preventDefault();
|
||||||
|
let password = $(this).parent().siblings("input");
|
||||||
|
let toggle = $(this).children("i");
|
||||||
|
|
||||||
|
if (password.attr("type") === "text")
|
||||||
|
{
|
||||||
|
password.attr("type", "password");
|
||||||
|
toggle.text("visibility");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
toggle.text("visibility_off");
|
||||||
|
password.attr("type", "text");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#login-btn").on("click", function (e)
|
||||||
|
{
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
let user = {
|
||||||
|
username: $("#login-username")[0].value,
|
||||||
|
password: $("#login-password")[0].value,
|
||||||
|
stayLoggedIn: $("#remember-me")[0].checked
|
||||||
|
};
|
||||||
|
|
||||||
|
$.ajax(
|
||||||
|
{
|
||||||
|
url: "/api/account/login",
|
||||||
|
type: "POST",
|
||||||
|
contentType: 'application/json;charset=UTF-8',
|
||||||
|
data: JSON.stringify(user),
|
||||||
|
success: function ()
|
||||||
|
{
|
||||||
|
let returnUrl = new URLSearchParams(window.location.search).get("ReturnUrl");
|
||||||
|
|
||||||
|
if (returnUrl == null)
|
||||||
|
window.location.href = "/unauthorized";
|
||||||
|
else
|
||||||
|
window.location.href = returnUrl;
|
||||||
|
},
|
||||||
|
error: function(xhr)
|
||||||
|
{
|
||||||
|
let error = $("#login-error");
|
||||||
|
error.show();
|
||||||
|
error.text(JSON.parse(xhr.responseText)[0].description);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#register-btn").on("click", function (e)
|
||||||
|
{
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
let user = {
|
||||||
|
email: $("#register-email")[0].value,
|
||||||
|
username: $("#register-username")[0].value,
|
||||||
|
password: $("#register-password")[0].value
|
||||||
|
};
|
||||||
|
|
||||||
|
if (user.password !== $("#register-password-confirm")[0].value)
|
||||||
|
{
|
||||||
|
let error = $("#register-error");
|
||||||
|
error.show();
|
||||||
|
error.text("Passwords don't match.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$.ajax(
|
||||||
|
{
|
||||||
|
url: "/api/account/register",
|
||||||
|
type: "POST",
|
||||||
|
contentType: 'application/json;charset=UTF-8',
|
||||||
|
dataType: 'json',
|
||||||
|
data: JSON.stringify(user),
|
||||||
|
success: function(res)
|
||||||
|
{
|
||||||
|
useOtac(res.otac);
|
||||||
|
},
|
||||||
|
error: function(xhr)
|
||||||
|
{
|
||||||
|
let error = $("#register-error");
|
||||||
|
error.show();
|
||||||
|
error.text(JSON.parse(xhr.responseText)[0].description);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function useOtac(otac)
|
||||||
|
{
|
||||||
|
$.ajax(
|
||||||
|
{
|
||||||
|
url: "/api/account/otac-login",
|
||||||
|
type: "POST",
|
||||||
|
contentType: 'application/json;charset=UTF-8',
|
||||||
|
data: JSON.stringify({otac: otac, tayLoggedIn: $("#stay-logged-in")[0].checked}),
|
||||||
|
success: function()
|
||||||
|
{
|
||||||
|
let returnUrl = new URLSearchParams(window.location.search).get("ReturnUrl");
|
||||||
|
|
||||||
|
if (returnUrl == null)
|
||||||
|
window.location.href = "/unauthorized";
|
||||||
|
else
|
||||||
|
window.location.href = returnUrl;
|
||||||
|
},
|
||||||
|
error: function(xhr)
|
||||||
|
{
|
||||||
|
let error = $("#register-error");
|
||||||
|
error.show();
|
||||||
|
error.text(JSON.parse(xhr.responseText)[0].description);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
let otac = new URLSearchParams(window.location.search).get("otac");
|
||||||
|
if (otac != null)
|
||||||
|
useOtac(otac);
|
36
Kyoo/Views/Login/material-icons.css
Normal file
36
Kyoo/Views/Login/material-icons.css
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
@font-face {
|
||||||
|
font-family: 'Material Icons';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
src: url(/iconfont/MaterialIcons-Regular.eot); /* For IE6-8 */
|
||||||
|
src: local('Material Icons'),
|
||||||
|
local('MaterialIcons-Regular'),
|
||||||
|
url(/iconfont/MaterialIcons-Regular.woff2) format('woff2'),
|
||||||
|
url(/iconfont/MaterialIcons-Regular.woff) format('woff'),
|
||||||
|
url(/iconfont/MaterialIcons-Regular.ttf) format('truetype');
|
||||||
|
}
|
||||||
|
|
||||||
|
.material-icons {
|
||||||
|
font-family: 'Material Icons';
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: normal;
|
||||||
|
font-size: 24px; /* Preferred icon size */
|
||||||
|
display: inline-block;
|
||||||
|
line-height: 1;
|
||||||
|
text-transform: none;
|
||||||
|
letter-spacing: normal;
|
||||||
|
word-wrap: normal;
|
||||||
|
white-space: nowrap;
|
||||||
|
direction: ltr;
|
||||||
|
|
||||||
|
/* Support for all WebKit browsers. */
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
/* Support for Safari and Chrome. */
|
||||||
|
text-rendering: optimizeLegibility;
|
||||||
|
|
||||||
|
/* Support for Firefox. */
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
|
||||||
|
/* Support for IE. */
|
||||||
|
font-feature-settings: 'liga';
|
||||||
|
}
|
@ -1 +1 @@
|
|||||||
Subproject commit 3f56ef31b8e2cc86d806ef422885ae5c1b802898
|
Subproject commit f5deefafa4d30d1259c44166e23ad5f806ec0768
|
@ -1,6 +1,7 @@
|
|||||||
{
|
{
|
||||||
"server.urls": "http://0.0.0.0:5000",
|
"server.urls": "http://0.0.0.0:5000",
|
||||||
"public_url": "http://localhost:5000/",
|
"public_url": "http://localhost:5000/",
|
||||||
|
"http_port": 5000,
|
||||||
"https_port": 44300,
|
"https_port": 44300,
|
||||||
"Logging": {
|
"Logging": {
|
||||||
"LogLevel": {
|
"LogLevel": {
|
||||||
|
@ -1 +1 @@
|
|||||||
Subproject commit a8e443545aa2963d995b6b2937d61a77620899b0
|
Subproject commit 59da0095a85914eabde9900973331a25a16088b3
|
Loading…
x
Reference in New Issue
Block a user