mirror of
https://git.teknik.io/Teknikode/Teknik.git
synced 2023-08-02 14:16:22 +02:00
Added two factor auth checking for users that have it enabled.
This commit is contained in:
parent
54a9d8e4f0
commit
c95849f468
1
.gitignore
vendored
1
.gitignore
vendored
@ -194,3 +194,4 @@ ModelManifest.xml
|
||||
/Teknik/TransformWebConfig/assist/Web.config
|
||||
/Teknik/Properties/PublishProfiles/IIS.pubxml
|
||||
/Teknik/App_Data/ConnectionStrings.config
|
||||
/Teknik/App_Data/Config.json.old
|
||||
|
@ -28,6 +28,7 @@ namespace Teknik.Areas.Users.Controllers
|
||||
{
|
||||
public class UserController : DefaultController
|
||||
{
|
||||
private static readonly UsedCodesManager usedCodesManager = new UsedCodesManager();
|
||||
private TeknikEntities db = new TeknikEntities();
|
||||
|
||||
// GET: Profile/Profile
|
||||
@ -102,6 +103,8 @@ namespace Teknik.Areas.Users.Controllers
|
||||
|
||||
if (user != null)
|
||||
{
|
||||
Session["AuthenticatedUser"] = user;
|
||||
|
||||
ViewBag.Title = "Settings - " + Config.Title;
|
||||
ViewBag.Description = "Your " + Config.Title + " Settings";
|
||||
|
||||
@ -164,16 +167,31 @@ namespace Teknik.Areas.Users.Controllers
|
||||
bool userValid = UserHelper.UserPasswordCorrect(db, Config, user, model.Password);
|
||||
if (userValid)
|
||||
{
|
||||
UserHelper.TransferUser(db, Config, user, model.Password);
|
||||
user.LastSeen = DateTime.Now;
|
||||
db.Entry(user).State = EntityState.Modified;
|
||||
db.SaveChanges();
|
||||
HttpCookie authcookie = UserHelper.CreateAuthCookie(model.Username, model.RememberMe, Request.Url.Host.GetDomain(), Request.IsLocal);
|
||||
Response.Cookies.Add(authcookie);
|
||||
string returnUrl = model.ReturnUrl;
|
||||
if (user.SecuritySettings.TwoFactorEnabled)
|
||||
{
|
||||
// We need to check their device, and two factor them
|
||||
Session["AuthenticatedUser"] = user;
|
||||
if (string.IsNullOrEmpty(model.ReturnUrl))
|
||||
returnUrl = Request.UrlReferrer.AbsoluteUri.ToString();
|
||||
returnUrl = Url.SubRouteUrl("user", "User.CheckAuthenticatorCode", new { returnUrl = returnUrl, rememberMe = model.RememberMe });
|
||||
model.ReturnUrl = string.Empty;
|
||||
}
|
||||
else
|
||||
{
|
||||
returnUrl = Request.UrlReferrer.AbsoluteUri.ToString();
|
||||
// They don't need two factor auth.
|
||||
UserHelper.TransferUser(db, Config, user, model.Password);
|
||||
user.LastSeen = DateTime.Now;
|
||||
db.Entry(user).State = EntityState.Modified;
|
||||
db.SaveChanges();
|
||||
HttpCookie authcookie = UserHelper.CreateAuthCookie(model.Username, model.RememberMe, Request.Url.Host.GetDomain(), Request.IsLocal);
|
||||
Response.Cookies.Add(authcookie);
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(model.ReturnUrl))
|
||||
{
|
||||
return Json(new { result = "true" });
|
||||
return Json(new { result = returnUrl });
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -188,7 +206,7 @@ namespace Teknik.Areas.Users.Controllers
|
||||
public ActionResult Logout()
|
||||
{
|
||||
// Get cookie
|
||||
HttpCookie authCookie = Utility.UserHelper.CreateAuthCookie(User.Identity.Name, false, Request.Url.Host.GetDomain(), Request.IsLocal);
|
||||
HttpCookie authCookie = UserHelper.CreateAuthCookie(User.Identity.Name, false, Request.Url.Host.GetDomain(), Request.IsLocal);
|
||||
|
||||
// Signout
|
||||
FormsAuthentication.SignOut();
|
||||
@ -529,8 +547,52 @@ namespace Teknik.Areas.Users.Controllers
|
||||
return Json(new { error = "Unable to reset user password" });
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[AllowAnonymous]
|
||||
public ActionResult ConfirmTwoFactorAuth(string returnUrl, bool rememberMe)
|
||||
{
|
||||
ViewBag.Title = "Unknown Device - " + Config.Title;
|
||||
ViewBag.Description = "We do not recognize this device.";
|
||||
LoginViewModel model = new LoginViewModel();
|
||||
model.ReturnUrl = returnUrl;
|
||||
model.RememberMe = rememberMe;
|
||||
|
||||
return View("/Areas/User/Views/User/TwoFactorCheck.cshtml", model);
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public ActionResult ConfirmAuthenticatorCode(string code)
|
||||
[AllowAnonymous]
|
||||
public ActionResult ConfirmAuthenticatorCode(string code, string returnUrl, bool rememberMe)
|
||||
{
|
||||
User user = (User)Session["AuthenticatedUser"];
|
||||
if (user != null)
|
||||
{
|
||||
if (user.SecuritySettings.TwoFactorEnabled)
|
||||
{
|
||||
string key = user.SecuritySettings.TwoFactorKey;
|
||||
|
||||
TimeAuthenticator ta = new TimeAuthenticator(usedCodeManager: usedCodesManager);
|
||||
bool isValid = ta.CheckCode(key, code, user);
|
||||
|
||||
if (isValid)
|
||||
{
|
||||
// the code was valid, let's log them in!
|
||||
HttpCookie authcookie = UserHelper.CreateAuthCookie(user.Username, rememberMe, Request.Url.Host.GetDomain(), Request.IsLocal);
|
||||
Response.Cookies.Add(authcookie);
|
||||
|
||||
if (string.IsNullOrEmpty(returnUrl))
|
||||
returnUrl = Request.UrlReferrer.AbsoluteUri.ToString();
|
||||
return Json(new { result = returnUrl });
|
||||
}
|
||||
return Json(new { error = "Invalid Authentication Code" });
|
||||
}
|
||||
return Json(new { error = "User does not have Two Factor Authentication enabled" });
|
||||
}
|
||||
return Json(new { error = "User does not exist" });
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public ActionResult VerifyAuthenticatorCode(string code)
|
||||
{
|
||||
User user = UserHelper.GetUser(db, User.Identity.Name);
|
||||
if (user != null)
|
||||
@ -539,21 +601,27 @@ namespace Teknik.Areas.Users.Controllers
|
||||
{
|
||||
string key = user.SecuritySettings.TwoFactorKey;
|
||||
|
||||
TimeAuthenticator ta = new TimeAuthenticator();
|
||||
bool isValid = false;
|
||||
TimeAuthenticator ta = new TimeAuthenticator(usedCodeManager: usedCodesManager);
|
||||
bool isValid = ta.CheckCode(key, code, user);
|
||||
|
||||
return Json(new { result = true });
|
||||
if (isValid)
|
||||
{
|
||||
return Json(new { result = true });
|
||||
}
|
||||
return Json(new { error = "Invalid Authentication Code" });
|
||||
}
|
||||
return Json(new { error = "User does not have Two Factor Authentication enabled" });
|
||||
}
|
||||
return Json(new { error = "User does not exist" });
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public ActionResult GenerateQrCode(string content)
|
||||
[HttpGet]
|
||||
public ActionResult GenerateAuthQrCode(string key)
|
||||
{
|
||||
var ProvisionUrl = string.Format("otpauth://totp/{0}:{1}?secret={2}", Config.Title, User.Identity.Name, key);
|
||||
|
||||
QRCodeGenerator qrGenerator = new QRCodeGenerator();
|
||||
QRCodeData qrCodeData = qrGenerator.CreateQrCode(content, QRCodeGenerator.ECCLevel.Q);
|
||||
QRCodeData qrCodeData = qrGenerator.CreateQrCode(ProvisionUrl, QRCodeGenerator.ECCLevel.Q);
|
||||
SvgQRCode qrCode = new SvgQRCode(qrCodeData);
|
||||
string qrCodeImage = qrCode.GetGraphic(20);
|
||||
return File(Encoding.UTF8.GetBytes(qrCodeImage), "image/svg+xml");
|
||||
|
34
Teknik/Areas/User/Scripts/CheckAuthCode.js
Normal file
34
Teknik/Areas/User/Scripts/CheckAuthCode.js
Normal file
@ -0,0 +1,34 @@
|
||||
$(document).ready(function () {
|
||||
$("#authCheckStatus").css('display', 'none', 'important');
|
||||
|
||||
$("#verifyCodeSubmit").click(function () {
|
||||
setCode = $("#code").val();
|
||||
returnUrl = $("#returnUrl").val();
|
||||
rememberMe = $("#rememberMe").val();
|
||||
if (rememberMe == '') {
|
||||
rememberMe = false;
|
||||
}
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: confirmAuthCodeURL,
|
||||
data: {
|
||||
code: setCode,
|
||||
returnUrl: returnUrl,
|
||||
rememberMe: rememberMe
|
||||
},
|
||||
xhrFields: {
|
||||
withCredentials: true
|
||||
},
|
||||
success: function (html) {
|
||||
if (html.result) {
|
||||
window.location = html.result;
|
||||
}
|
||||
else {
|
||||
$("#authCheckStatus").css('display', 'inline', 'important');
|
||||
$("#authCheckStatus").html('<div class="alert alert-danger alert-dismissable"><button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>' + html.error + '</div>');
|
||||
}
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
});
|
@ -1,6 +1,7 @@
|
||||
$(document).ready(function () {
|
||||
$("[name='update_upload_saveKey']").bootstrapSwitch();
|
||||
$("[name='update_upload_serverSideEncrypt']").bootstrapSwitch();
|
||||
$("[name='update_security_two_factor']").bootstrapSwitch();
|
||||
|
||||
$('#ResendVerification').click(function () {
|
||||
$.ajax({
|
||||
@ -26,6 +27,41 @@
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
$('#authenticatorSetup').on('hide.bs.modal', function (e) {
|
||||
$("#authSetupStatus").css('display', 'none', 'important');
|
||||
$("#authSetupStatus").html('');
|
||||
$('#auth_setup_code').val('');
|
||||
});
|
||||
|
||||
$('#auth_setup_confirm').click(function () {
|
||||
setCode = $("#auth_setup_code").val();
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: confirmAuthSetupURL,
|
||||
data: {
|
||||
code: setCode
|
||||
},
|
||||
success: function (html) {
|
||||
if (html.result) {
|
||||
$("#authSetupStatus").css('display', 'inline', 'important');
|
||||
$("#authSetupStatus").html('<div class="alert alert-success alert-dismissable"><button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>Success!</div>');
|
||||
}
|
||||
else {
|
||||
errorMsg = html;
|
||||
if (html.error) {
|
||||
errorMsg = html.error;
|
||||
if (html.error.message) {
|
||||
errorMsg = html.error.message;
|
||||
}
|
||||
}
|
||||
$("#authSetupStatus").css('display', 'inline', 'important');
|
||||
$("#authSetupStatus").html('<div class="alert alert-danger alert-dismissable"><button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>' + errorMsg + '</div>');
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$('#delete_account').click(function () {
|
||||
bootbox.confirm("Are you sure you want to delete your account?", function (result) {
|
||||
if (result) {
|
||||
@ -62,7 +98,7 @@
|
||||
password = $("#update_password").val();
|
||||
password_confirm = $("#update_password_confirm").val();
|
||||
update_pgp_public_key = $("#update_pgp_public_key").val();
|
||||
update_security_two_factor = $("#update_security_two_factor").val();
|
||||
update_security_two_factor = $("#update_security_two_factor").is(":checked");
|
||||
recovery = $("#update_recovery_email").val();
|
||||
website = $("#update_website").val();
|
||||
quote = $("#update_quote").val();
|
||||
@ -79,6 +115,7 @@
|
||||
newPass: password,
|
||||
newPassConfirm: password_confirm,
|
||||
pgpPublicKey: update_pgp_public_key,
|
||||
twoFactorEnabled: update_security_two_factor,
|
||||
recoveryEmail: recovery,
|
||||
website: website,
|
||||
quote: quote,
|
||||
|
@ -74,6 +74,14 @@ namespace Teknik.Areas.Users
|
||||
new { controller = "User", action = "VerifyRecoveryEmail" }, // Parameter defaults
|
||||
new[] { typeof(Controllers.UserController).Namespace }
|
||||
);
|
||||
context.MapSubdomainRoute(
|
||||
"User.CheckAuthenticatorCode", // Route name
|
||||
new List<string>() { "user" }, // Subdomains
|
||||
new List<string>() { config.Host }, // domains
|
||||
"CheckAuthCode", // URL with parameters
|
||||
new { controller = "User", action = "ConfirmTwoFactorAuth" }, // Parameter defaults
|
||||
new[] { typeof(Controllers.UserController).Namespace }
|
||||
);
|
||||
context.MapSubdomainRoute(
|
||||
"User.Index", // Route name
|
||||
new List<string>() { "user" }, // Subdomains
|
||||
@ -106,6 +114,10 @@ namespace Teknik.Areas.Users
|
||||
"~/Scripts/bootstrap-switch.js",
|
||||
"~/Areas/User/Scripts/User.js"));
|
||||
|
||||
// Register Script Bundle
|
||||
BundleTable.Bundles.Add(new ScriptBundle("~/bundles/checkAuthCode").Include(
|
||||
"~/Areas/User/Scripts/CheckAuthCode.js"));
|
||||
|
||||
// Register Style Bundles
|
||||
BundleTable.Bundles.Add(new StyleBundle("~/Content/user").Include(
|
||||
"~/Content/bootstrap-switch/bootstrap3/bootstrap-switch.css"));
|
||||
|
@ -1 +0,0 @@
|
||||
|
@ -7,6 +7,7 @@
|
||||
var editUserURL = '@Url.SubRouteUrl("user", "User.Action", new { action = "Edit" })';
|
||||
var deleteUserURL = '@Url.SubRouteUrl("user", "User.Action", new { action = "Delete" })';
|
||||
var resendVerifyURL = '@Url.SubRouteUrl("user", "User.Action", new { action = "ResendVerifyRecoveryEmail"})';
|
||||
var confirmAuthSetupURL = '@Url.SubRouteUrl("user", "User.Action", new { action = "VerifyAuthenticatorCode" })';
|
||||
</script>
|
||||
|
||||
@Styles.Render("~/Content/user")
|
||||
@ -23,45 +24,44 @@
|
||||
<h4 class="modal-title" id="authSetupTitleLabel">Set Up a Third Party App to Generate Codes</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="row">
|
||||
<div class="col-sm-12 text-center">
|
||||
<div id="authSetupStatus"></div>
|
||||
</div>
|
||||
</div>
|
||||
@if (Model.SecuritySettings.TwoFactorEnabled)
|
||||
{
|
||||
<form class="form" action="@Url.SubRouteUrl("user", "User.Action", new { action = "ConfirmAuthenticatorCode" })" method="post" id="confirmAuthSetup">
|
||||
<form class="form" action="##" method="post" id="confirmAuthSetup">
|
||||
<p>To get a third party app working, either scan the QR code below or type the secret key into the app.</p>
|
||||
<div class="row">
|
||||
<div class="col-sm-2">
|
||||
QR Code:
|
||||
<div class="col-sm-4">
|
||||
<p class="text-muted">QR Code:</p>
|
||||
</div>
|
||||
<div class="col-sm-10 text-right">
|
||||
<!-- QR Code -->
|
||||
<img src="@Url.SubRouteUrl("user", "User.Action", new { action = "GenerateQRCode", content = Model.SecuritySettings.TwoFactorKey })" alt="qr code" />
|
||||
<div class="col-sm-8">
|
||||
<img src="@Url.SubRouteUrl("user", "User.Action", new { action = "GenerateAuthQrCode", key = Model.SecuritySettings.TwoFactorKey })" width="200" height="200" alt="qr code" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-2">
|
||||
Secret Key:
|
||||
<div class="col-sm-4">
|
||||
<p class="text-muted">Secret Key:</p>
|
||||
</div>
|
||||
<div class="col-sm-10">
|
||||
<span class="text-success" id="authSetupSecretKey"></span>
|
||||
<div class="col-sm-8">
|
||||
<span class="text-success" id="authSetupSecretKey">@Model.SecuritySettings.TwoFactorKey</span>
|
||||
</div>
|
||||
</div>
|
||||
<hr />
|
||||
<p>To confirm the third party app is set up correctly, enter the security code that appears on your phone.</p>
|
||||
<div class="row">
|
||||
<div class="col-sm-2">
|
||||
Security Code:
|
||||
<div class="col-sm-4">
|
||||
<p class="text-muted">Security Code:</p>
|
||||
</div>
|
||||
<div class="col-sm-10">
|
||||
<div class="col-sm-6">
|
||||
<input class="form-control" id="auth_setup_code" name="auth_setup_code" title="Authenticator Security Code" type="text" />
|
||||
</div>
|
||||
</div>
|
||||
<hr />
|
||||
<br />
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<div class="form-group text-right">
|
||||
<button class="btn btn-primary" id="auth_setup_confirm" type="submit" name="auth_setup_confirm">Confirm</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group text-right">
|
||||
<button class="btn btn-primary" id="auth_setup_confirm" type="button" name="auth_setup_confirm">Confirm</button>
|
||||
</div>
|
||||
</form>
|
||||
}
|
||||
@ -128,6 +128,22 @@
|
||||
<textarea class="form-control" id="update_pgp_public_key" name="update_pgp_public_key" placeholder="Public Key Here" title="enter your pgp public key" rows="15">@Model.SecuritySettings.PGPSignature</textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-6 text-left">
|
||||
<label for="update_security_two_factor"><h4>Enable Two Factor Authentication</h4></label>
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
<input id="update_security_two_factor" name="update_security_two_factor" title="whether the key should be saved on the server or not" type="checkbox" value="true" @(Model.SecuritySettings.TwoFactorEnabled ? "checked" : string.Empty) />
|
||||
</label>
|
||||
</div>
|
||||
@if (Model.SecuritySettings.TwoFactorEnabled)
|
||||
{
|
||||
<p class="form-control-static">
|
||||
<small><a href="#" class="text-primary" id="SetupAuthenticator" data-toggle="modal" data-target="#authenticatorSetup"><i class="fa fa-lock"></i> Set Up Authenticator</a></small>
|
||||
</p>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-4">
|
||||
<div class="row">
|
||||
@ -151,23 +167,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-6">
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
<label for="update_security_two_factor"><h4>Enable Two Factor Authentication</h4></label>
|
||||
<input id="update_security_two_factor" name="update_security_two_factor" title="whether the key should be saved on the server or not" type="checkbox" value="true" @(Model.SecuritySettings.TwoFactorEnabled ? "checked" : string.Empty) />
|
||||
@if (Model.SecuritySettings.TwoFactorEnabled)
|
||||
{
|
||||
<p class="form-control-static">
|
||||
<small><a href="#" class="text-primary" id="SetupAuthenticator"><i class="fa fa-lock"></i> Set Up Authenticator</a></small>
|
||||
</p>
|
||||
}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Blog Settings -->
|
||||
<div class="tab-pane" id="blog">
|
||||
<div class="row">
|
||||
|
42
Teknik/Areas/User/Views/User/TwoFactorCheck.cshtml
Normal file
42
Teknik/Areas/User/Views/User/TwoFactorCheck.cshtml
Normal file
@ -0,0 +1,42 @@
|
||||
@model Teknik.Areas.Users.ViewModels.LoginViewModel
|
||||
|
||||
@using Teknik.Helpers
|
||||
|
||||
<script>
|
||||
var confirmAuthCodeURL = '@Url.SubRouteUrl("user", "User.Action", new { action = "ConfirmAuthenticatorCode" })';
|
||||
</script>
|
||||
|
||||
@Scripts.Render("~/bundles/checkAuthCode")
|
||||
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="text-center">
|
||||
<h1>Two-factor authentication</h1>
|
||||
<div class="col-md-4 col-md-offset-4">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-body">
|
||||
<div class="row">
|
||||
<div class="col-sm-12 text-center">
|
||||
<div id="authCheckStatus"></div>
|
||||
</div>
|
||||
</div>
|
||||
<form role="form" id="twoFactorCheckForm" action="##" method="post" accept-charset="UTF-8">
|
||||
<input name="returnUrl" id="returnUrl" type="hidden" value="@Model.ReturnUrl" />
|
||||
<input name="rememberMe" id="rememberMe" type="hidden" value="@Model.RememberMe" />
|
||||
<div class="form-group text-left">
|
||||
<label for="update_website">Authentication code</label>
|
||||
<input type="text" class="form-control" id="code" name="code" data-val-required="The Authentication Code is required." data-val="true" />
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<button class="btn btn-primary btn-block" id="verifyCodeSubmit" type="button" name="verifyCodeSubmit">Verify</button>
|
||||
</div>
|
||||
</form>
|
||||
<p class="text-left">Open the two-factor authentication app on your device to view your authentication code and verify your identity.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
BIN
Teknik/Images/logo-black.png
Normal file
BIN
Teknik/Images/logo-black.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 24 MiB |
BIN
Teknik/Images/logo-blue.png
Normal file
BIN
Teknik/Images/logo-blue.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 24 MiB |
@ -20,7 +20,7 @@
|
||||
},
|
||||
success: function (html) {
|
||||
if (html.result) {
|
||||
window.location.reload();
|
||||
window.location = html.result;
|
||||
}
|
||||
else {
|
||||
$("#loginStatus").css('display', 'inline', 'important');
|
||||
|
Binary file not shown.
@ -342,6 +342,7 @@
|
||||
<Content Include="Areas\Podcast\Content\Podcast.css" />
|
||||
<Content Include="Areas\Podcast\Scripts\Podcast.js" />
|
||||
<Content Include="Areas\Transparency\Scripts\Transparency.js" />
|
||||
<Content Include="Areas\User\Scripts\CheckAuthCode.js" />
|
||||
<Content Include="Areas\User\Scripts\User.js" />
|
||||
<Content Include="Areas\Shortener\Scripts\Shortener.js" />
|
||||
<Content Include="Areas\Upload\Scripts\Download.js" />
|
||||
@ -556,7 +557,7 @@
|
||||
<Content Include="Areas\User\Views\User\ViewRecoveryEmailVerification.cshtml" />
|
||||
<Content Include="Areas\User\Views\User\ResetPasswordVerification.cshtml" />
|
||||
<Content Include="Areas\User\Views\User\ResetPassword.cshtml" />
|
||||
<Content Include="Areas\User\Views\User\AuthenticatorSetup.cshtml" />
|
||||
<Content Include="Areas\User\Views\User\TwoFactorCheck.cshtml" />
|
||||
<None Include="Properties\PublishProfiles\Teknik Dev.pubxml" />
|
||||
<None Include="Properties\PublishProfiles\Teknik Production.pubxml" />
|
||||
<None Include="Scripts\jquery-2.1.4.intellisense.js" />
|
||||
|
Loading…
Reference in New Issue
Block a user