├── DosFactores
├── wwwroot
│ ├── js
│ │ ├── site.min.js
│ │ └── site.js
│ ├── favicon.ico
│ ├── lib
│ │ ├── bootstrap
│ │ │ ├── dist
│ │ │ │ ├── fonts
│ │ │ │ │ ├── glyphicons-halflings-regular.eot
│ │ │ │ │ ├── glyphicons-halflings-regular.ttf
│ │ │ │ │ ├── glyphicons-halflings-regular.woff
│ │ │ │ │ └── glyphicons-halflings-regular.woff2
│ │ │ │ └── js
│ │ │ │ │ └── npm.js
│ │ │ ├── .bower.json
│ │ │ └── LICENSE
│ │ ├── jquery
│ │ │ ├── .bower.json
│ │ │ └── LICENSE.txt
│ │ ├── jquery-validation
│ │ │ ├── .bower.json
│ │ │ ├── LICENSE.md
│ │ │ └── dist
│ │ │ │ └── additional-methods.min.js
│ │ └── jquery-validation-unobtrusive
│ │ │ ├── .bower.json
│ │ │ └── jquery.validate.unobtrusive.min.js
│ ├── css
│ │ ├── site.min.css
│ │ └── site.css
│ └── images
│ │ ├── banner2.svg
│ │ ├── banner1.svg
│ │ ├── banner3.svg
│ │ └── banner4.svg
├── .bowerrc
├── Views
│ ├── _ViewStart.cshtml
│ ├── Home
│ │ ├── About.cshtml
│ │ ├── Contact.cshtml
│ │ └── Index.cshtml
│ ├── Account
│ │ ├── ForgotPasswordConfirmation.cshtml
│ │ ├── ExternalLoginFailure.cshtml
│ │ ├── AccessDenied.cshtml
│ │ ├── Lockout.cshtml
│ │ ├── ResetPasswordConfirmation.cshtml
│ │ ├── ConfirmEmail.cshtml
│ │ ├── SendCode.cshtml
│ │ ├── ForgotPassword.cshtml
│ │ ├── ExternalLoginConfirmation.cshtml
│ │ ├── VerifyCode.cshtml
│ │ ├── Register.cshtml
│ │ ├── ResetPassword.cshtml
│ │ └── Login.cshtml
│ ├── _ViewImports.cshtml
│ ├── Shared
│ │ ├── Error.cshtml
│ │ ├── _LoginPartial.cshtml
│ │ ├── _ValidationScriptsPartial.cshtml
│ │ └── _Layout.cshtml
│ └── Manage
│ │ ├── AddPhoneNumber.cshtml
│ │ ├── VerifyPhoneNumber.cshtml
│ │ ├── SetPassword.cshtml
│ │ ├── ChangePassword.cshtml
│ │ ├── ManageLogins.cshtml
│ │ └── Index.cshtml
├── appsettings.Development.json
├── bower.json
├── Services
│ ├── ISmsSender.cs
│ ├── IEmailSender.cs
│ └── MessageServices.cs
├── Models
│ ├── ManageViewModels
│ │ ├── FactorViewModel.cs
│ │ ├── RemoveLoginViewModel.cs
│ │ ├── AddPhoneNumberViewModel.cs
│ │ ├── ConfigureTwoFactorViewModel.cs
│ │ ├── ManageLoginsViewModel.cs
│ │ ├── VerifyPhoneNumberViewModel.cs
│ │ ├── IndexViewModel.cs
│ │ ├── SetPasswordViewModel.cs
│ │ └── ChangePasswordViewModel.cs
│ ├── AccountViewModels
│ │ ├── ForgotPasswordViewModel.cs
│ │ ├── ExternalLoginConfirmationViewModel.cs
│ │ ├── SendCodeViewModel.cs
│ │ ├── LoginViewModel.cs
│ │ ├── VerifyCodeViewModel.cs
│ │ ├── ResetPasswordViewModel.cs
│ │ └── RegisterViewModel.cs
│ └── ApplicationUser.cs
├── appsettings.json
├── Program.cs
├── bundleconfig.json
├── Properties
│ └── launchSettings.json
├── Controllers
│ ├── HomeController.cs
│ └── ManageController.cs
├── Data
│ ├── ApplicationDbContext.cs
│ └── Migrations
│ │ ├── ApplicationDbContextModelSnapshot.cs
│ │ ├── 00000000000000_CreateIdentitySchema.Designer.cs
│ │ └── 00000000000000_CreateIdentitySchema.cs
├── Providers
│ └── GoogleAuthenticatorProvider.cs
├── DosFactores.csproj
└── Startup.cs
├── README.md
├── Google.Authenticator
├── Google.Authenticator.csproj
├── SetupCode.cs
└── TwoFactorAuthentication.cs
├── DosFactores.sln
├── Instrucciones.md
└── .gitignore
/DosFactores/wwwroot/js/site.min.js:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/DosFactores/.bowerrc:
--------------------------------------------------------------------------------
1 | {
2 | "directory": "wwwroot/lib"
3 | }
4 |
--------------------------------------------------------------------------------
/DosFactores/wwwroot/js/site.js:
--------------------------------------------------------------------------------
1 | // Write your Javascript code.
2 |
--------------------------------------------------------------------------------
/DosFactores/Views/_ViewStart.cshtml:
--------------------------------------------------------------------------------
1 | @{
2 | Layout = "_Layout";
3 | }
4 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # DosFactores
2 | Autenticación de dos factores en ASP.NET Core
3 |
--------------------------------------------------------------------------------
/DosFactores/wwwroot/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thatcsharpguy/DosFactores/master/DosFactores/wwwroot/favicon.ico
--------------------------------------------------------------------------------
/Google.Authenticator/Google.Authenticator.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp1.1
5 |
6 |
7 |
--------------------------------------------------------------------------------
/DosFactores/Views/Home/About.cshtml:
--------------------------------------------------------------------------------
1 | @{
2 | ViewData["Title"] = "About";
3 | }
4 |
@ViewData["Title"].
5 | @ViewData["Message"]
6 |
7 | Use this area to provide additional information.
8 |
--------------------------------------------------------------------------------
/DosFactores/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thatcsharpguy/DosFactores/master/DosFactores/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.eot
--------------------------------------------------------------------------------
/DosFactores/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thatcsharpguy/DosFactores/master/DosFactores/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.ttf
--------------------------------------------------------------------------------
/DosFactores/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thatcsharpguy/DosFactores/master/DosFactores/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.woff
--------------------------------------------------------------------------------
/DosFactores/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thatcsharpguy/DosFactores/master/DosFactores/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.woff2
--------------------------------------------------------------------------------
/DosFactores/Views/Account/ForgotPasswordConfirmation.cshtml:
--------------------------------------------------------------------------------
1 | @{
2 | ViewData["Title"] = "Forgot Password Confirmation";
3 | }
4 |
5 | @ViewData["Title"].
6 |
7 | Please check your email to reset your password.
8 |
9 |
--------------------------------------------------------------------------------
/DosFactores/Views/Account/ExternalLoginFailure.cshtml:
--------------------------------------------------------------------------------
1 | @{
2 | ViewData["Title"] = "Login Failure";
3 | }
4 |
5 |
9 |
--------------------------------------------------------------------------------
/DosFactores/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "IncludeScopes": false,
4 | "LogLevel": {
5 | "Default": "Debug",
6 | "System": "Information",
7 | "Microsoft": "Information"
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/DosFactores/Views/Account/AccessDenied.cshtml:
--------------------------------------------------------------------------------
1 | @{
2 | ViewData["Title"] = "Access Denied";
3 | }
4 |
5 |
9 |
--------------------------------------------------------------------------------
/DosFactores/Views/Account/Lockout.cshtml:
--------------------------------------------------------------------------------
1 | @{
2 | ViewData["Title"] = "Locked out";
3 | }
4 |
5 |
9 |
--------------------------------------------------------------------------------
/DosFactores/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "asp.net",
3 | "private": true,
4 | "dependencies": {
5 | "bootstrap": "3.3.7",
6 | "jquery": "2.2.0",
7 | "jquery-validation": "1.14.0",
8 | "jquery-validation-unobtrusive": "3.2.6"
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/DosFactores/Views/_ViewImports.cshtml:
--------------------------------------------------------------------------------
1 | @using DosFactores
2 | @using DosFactores.Models
3 | @using DosFactores.Models.AccountViewModels
4 | @using DosFactores.Models.ManageViewModels
5 | @using Microsoft.AspNetCore.Identity
6 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
7 |
--------------------------------------------------------------------------------
/DosFactores/Views/Account/ResetPasswordConfirmation.cshtml:
--------------------------------------------------------------------------------
1 | @{
2 | ViewData["Title"] = "Reset password confirmation";
3 | }
4 |
5 | @ViewData["Title"].
6 |
7 | Your password has been reset. Please Click here to log in.
8 |
9 |
--------------------------------------------------------------------------------
/DosFactores/Views/Account/ConfirmEmail.cshtml:
--------------------------------------------------------------------------------
1 | @{
2 | ViewData["Title"] = "Confirm Email";
3 | }
4 |
5 | @ViewData["Title"].
6 |
11 |
--------------------------------------------------------------------------------
/DosFactores/Services/ISmsSender.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 |
6 | namespace DosFactores.Services
7 | {
8 | public interface ISmsSender
9 | {
10 | Task SendSmsAsync(string number, string message);
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/DosFactores/Models/ManageViewModels/FactorViewModel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 |
6 | namespace DosFactores.Models.ManageViewModels
7 | {
8 | public class FactorViewModel
9 | {
10 | public string Purpose { get; set; }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/DosFactores/Services/IEmailSender.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 |
6 | namespace DosFactores.Services
7 | {
8 | public interface IEmailSender
9 | {
10 | Task SendEmailAsync(string email, string subject, string message);
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/DosFactores/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "ConnectionStrings": {
3 | "DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=aspnet-DosFactores-b96d62e5-2472-4f50-a45e-7c211bd2a738;Trusted_Connection=True;MultipleActiveResultSets=true"
4 | },
5 | "Logging": {
6 | "IncludeScopes": false,
7 | "LogLevel": {
8 | "Default": "Warning"
9 | }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Google.Authenticator/SetupCode.cs:
--------------------------------------------------------------------------------
1 | namespace Google.Authenticator
2 | {
3 | public class SetupCode
4 | {
5 | public string Account { get; internal set; }
6 | public string AccountSecretKey { get; internal set; }
7 | public string ManualEntryKey { get; internal set; }
8 | public string QrCodeSetupImageUrl { get; internal set; }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/DosFactores/Models/AccountViewModels/ForgotPasswordViewModel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel.DataAnnotations;
4 | using System.Linq;
5 | using System.Threading.Tasks;
6 |
7 | namespace DosFactores.Models.AccountViewModels
8 | {
9 | public class ForgotPasswordViewModel
10 | {
11 | [Required]
12 | [EmailAddress]
13 | public string Email { get; set; }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/DosFactores/Models/ManageViewModels/RemoveLoginViewModel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel.DataAnnotations;
4 | using System.Linq;
5 | using System.Threading.Tasks;
6 |
7 | namespace DosFactores.Models.ManageViewModels
8 | {
9 | public class RemoveLoginViewModel
10 | {
11 | public string LoginProvider { get; set; }
12 | public string ProviderKey { get; set; }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/DosFactores/wwwroot/css/site.min.css:
--------------------------------------------------------------------------------
1 | body{padding-top:50px;padding-bottom:20px}.body-content{padding-left:15px;padding-right:15px}input,select,textarea{max-width:280px}.carousel-caption p{font-size:20px;line-height:1.4}.btn-bracketed::before{display:inline-block;content:"[";padding-right:.5em}.btn-bracketed::after{display:inline-block;content:"]";padding-left:.5em}.carousel-inner .item img[src$=".svg"]{width:100%}@media screen and (max-width:767px){.carousel-caption{display:none}}
--------------------------------------------------------------------------------
/DosFactores/Models/AccountViewModels/ExternalLoginConfirmationViewModel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel.DataAnnotations;
4 | using System.Linq;
5 | using System.Threading.Tasks;
6 |
7 | namespace DosFactores.Models.AccountViewModels
8 | {
9 | public class ExternalLoginConfirmationViewModel
10 | {
11 | [Required]
12 | [EmailAddress]
13 | public string Email { get; set; }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/DosFactores/Models/ApplicationUser.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
6 |
7 | namespace DosFactores.Models
8 | {
9 | // Add profile data for application users by adding properties to the ApplicationUser class
10 | public class ApplicationUser : IdentityUser
11 | {
12 | public virtual string TfaKey { get; set; }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/DosFactores/Models/ManageViewModels/AddPhoneNumberViewModel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel.DataAnnotations;
4 | using System.Linq;
5 | using System.Threading.Tasks;
6 |
7 | namespace DosFactores.Models.ManageViewModels
8 | {
9 | public class AddPhoneNumberViewModel
10 | {
11 | [Required]
12 | [Phone]
13 | [Display(Name = "Phone number")]
14 | public string PhoneNumber { get; set; }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/DosFactores/Models/ManageViewModels/ConfigureTwoFactorViewModel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using Microsoft.AspNetCore.Mvc.Rendering;
6 |
7 | namespace DosFactores.Models.ManageViewModels
8 | {
9 | public class ConfigureTwoFactorViewModel
10 | {
11 | public string SelectedProvider { get; set; }
12 |
13 | public ICollection Providers { get; set; }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/DosFactores/Models/ManageViewModels/ManageLoginsViewModel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using Microsoft.AspNetCore.Http.Authentication;
6 | using Microsoft.AspNetCore.Identity;
7 |
8 | namespace DosFactores.Models.ManageViewModels
9 | {
10 | public class ManageLoginsViewModel
11 | {
12 | public IList CurrentLogins { get; set; }
13 |
14 | public IList OtherLogins { get; set; }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/DosFactores/Views/Home/Contact.cshtml:
--------------------------------------------------------------------------------
1 | @{
2 | ViewData["Title"] = "Contact";
3 | }
4 | @ViewData["Title"].
5 | @ViewData["Message"]
6 |
7 |
8 | One Microsoft Way
9 | Redmond, WA 98052-6399
10 | P:
11 | 425.555.0100
12 |
13 |
14 |
15 | Support: Support@example.com
16 | Marketing: Marketing@example.com
17 |
18 |
--------------------------------------------------------------------------------
/DosFactores/wwwroot/lib/bootstrap/dist/js/npm.js:
--------------------------------------------------------------------------------
1 | // This file is autogenerated via the `commonjs` Grunt task. You can require() this file in a CommonJS environment.
2 | require('../../js/transition.js')
3 | require('../../js/alert.js')
4 | require('../../js/button.js')
5 | require('../../js/carousel.js')
6 | require('../../js/collapse.js')
7 | require('../../js/dropdown.js')
8 | require('../../js/modal.js')
9 | require('../../js/tooltip.js')
10 | require('../../js/popover.js')
11 | require('../../js/scrollspy.js')
12 | require('../../js/tab.js')
13 | require('../../js/affix.js')
--------------------------------------------------------------------------------
/DosFactores/Models/ManageViewModels/VerifyPhoneNumberViewModel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel.DataAnnotations;
4 | using System.Linq;
5 | using System.Threading.Tasks;
6 |
7 | namespace DosFactores.Models.ManageViewModels
8 | {
9 | public class VerifyPhoneNumberViewModel
10 | {
11 | [Required]
12 | public string Code { get; set; }
13 |
14 | [Required]
15 | [Phone]
16 | [Display(Name = "Phone number")]
17 | public string PhoneNumber { get; set; }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/DosFactores/Models/AccountViewModels/SendCodeViewModel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using Microsoft.AspNetCore.Mvc.Rendering;
6 |
7 | namespace DosFactores.Models.AccountViewModels
8 | {
9 | public class SendCodeViewModel
10 | {
11 | public string SelectedProvider { get; set; }
12 |
13 | public ICollection Providers { get; set; }
14 |
15 | public string ReturnUrl { get; set; }
16 |
17 | public bool RememberMe { get; set; }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/DosFactores/Models/AccountViewModels/LoginViewModel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel.DataAnnotations;
4 | using System.Linq;
5 | using System.Threading.Tasks;
6 |
7 | namespace DosFactores.Models.AccountViewModels
8 | {
9 | public class LoginViewModel
10 | {
11 | [Required]
12 | [EmailAddress]
13 | public string Email { get; set; }
14 |
15 | [Required]
16 | [DataType(DataType.Password)]
17 | public string Password { get; set; }
18 |
19 | [Display(Name = "Remember me?")]
20 | public bool RememberMe { get; set; }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/DosFactores/wwwroot/lib/jquery/.bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "jquery",
3 | "main": "dist/jquery.js",
4 | "license": "MIT",
5 | "ignore": [
6 | "package.json"
7 | ],
8 | "keywords": [
9 | "jquery",
10 | "javascript",
11 | "browser",
12 | "library"
13 | ],
14 | "homepage": "https://github.com/jquery/jquery-dist",
15 | "version": "2.2.0",
16 | "_release": "2.2.0",
17 | "_resolution": {
18 | "type": "version",
19 | "tag": "2.2.0",
20 | "commit": "6fc01e29bdad0964f62ef56d01297039cdcadbe5"
21 | },
22 | "_source": "git://github.com/jquery/jquery-dist.git",
23 | "_target": "2.2.0",
24 | "_originalSource": "jquery"
25 | }
--------------------------------------------------------------------------------
/DosFactores/Models/ManageViewModels/IndexViewModel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using Microsoft.AspNetCore.Identity;
6 |
7 | namespace DosFactores.Models.ManageViewModels
8 | {
9 | public class IndexViewModel
10 | {
11 | public bool HasPassword { get; set; }
12 |
13 | public IList Logins { get; set; }
14 |
15 | public string PhoneNumber { get; set; }
16 |
17 | public string TwoFactorAuthenticatorQrCode { get; set; }
18 |
19 | public bool TwoFactor { get; set; }
20 |
21 | public bool BrowserRemembered { get; set; }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/DosFactores/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Threading.Tasks;
6 | using Microsoft.AspNetCore.Hosting;
7 |
8 | namespace DosFactores
9 | {
10 | public class Program
11 | {
12 | public static void Main(string[] args)
13 | {
14 | var host = new WebHostBuilder()
15 | .UseKestrel()
16 | .UseContentRoot(Directory.GetCurrentDirectory())
17 | .UseIISIntegration()
18 | .UseStartup()
19 | .UseApplicationInsights()
20 | .Build();
21 |
22 | host.Run();
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/DosFactores/bundleconfig.json:
--------------------------------------------------------------------------------
1 | // Configure bundling and minification for the project.
2 | // More info at https://go.microsoft.com/fwlink/?LinkId=808241
3 | [
4 | {
5 | "outputFileName": "wwwroot/css/site.min.css",
6 | // An array of relative input file paths. Globbing patterns supported
7 | "inputFiles": [
8 | "wwwroot/css/site.css"
9 | ]
10 | },
11 | {
12 | "outputFileName": "wwwroot/js/site.min.js",
13 | "inputFiles": [
14 | "wwwroot/js/site.js"
15 | ],
16 | // Optionally specify minification options
17 | "minify": {
18 | "enabled": true,
19 | "renameLocals": true
20 | },
21 | // Optionally generate .map file
22 | "sourceMap": false
23 | }
24 | ]
25 |
--------------------------------------------------------------------------------
/DosFactores/Models/AccountViewModels/VerifyCodeViewModel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel.DataAnnotations;
4 | using System.Linq;
5 | using System.Threading.Tasks;
6 |
7 | namespace DosFactores.Models.AccountViewModels
8 | {
9 | public class VerifyCodeViewModel
10 | {
11 | [Required]
12 | public string Provider { get; set; }
13 |
14 | [Required]
15 | public string Code { get; set; }
16 |
17 | public string ReturnUrl { get; set; }
18 |
19 | [Display(Name = "Remember this browser?")]
20 | public bool RememberBrowser { get; set; }
21 |
22 | [Display(Name = "Remember me?")]
23 | public bool RememberMe { get; set; }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/DosFactores/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "iisSettings": {
3 | "windowsAuthentication": false,
4 | "anonymousAuthentication": true,
5 | "iisExpress": {
6 | "applicationUrl": "https://localhost:44385/",
7 | "sslPort": 44385
8 | }
9 | },
10 | "profiles": {
11 | "IIS Express": {
12 | "commandName": "IISExpress",
13 | "launchBrowser": true,
14 | "environmentVariables": {
15 | "ASPNETCORE_ENVIRONMENT": "Development"
16 | }
17 | },
18 | "DosFactores": {
19 | "commandName": "Project",
20 | "launchBrowser": true,
21 | "environmentVariables": {
22 | "ASPNETCORE_ENVIRONMENT": "Development"
23 | },
24 | "applicationUrl": "http://localhost:52051"
25 | }
26 | }
27 | }
--------------------------------------------------------------------------------
/DosFactores/Views/Shared/Error.cshtml:
--------------------------------------------------------------------------------
1 | @{
2 | ViewData["Title"] = "Error";
3 | }
4 |
5 | Error.
6 | An error occurred while processing your request.
7 |
8 | Development Mode
9 |
10 | Swapping to Development environment will display more detailed information about the error that occurred.
11 |
12 |
13 | Development environment should not be enabled in deployed applications, as it can result in sensitive information from exceptions being displayed to end users. For local debugging, development environment can be enabled by setting the ASPNETCORE_ENVIRONMENT environment variable to Development, and restarting the application.
14 |
15 |
--------------------------------------------------------------------------------
/DosFactores/Views/Account/SendCode.cshtml:
--------------------------------------------------------------------------------
1 | @model SendCodeViewModel
2 | @{
3 | ViewData["Title"] = "Send Verification Code";
4 | }
5 |
6 | @ViewData["Title"].
7 |
8 |
18 |
19 | @section Scripts {
20 | @{await Html.RenderPartialAsync("_ValidationScriptsPartial"); }
21 | }
22 |
--------------------------------------------------------------------------------
/DosFactores/Controllers/HomeController.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using Microsoft.AspNetCore.Mvc;
6 |
7 | namespace DosFactores.Controllers
8 | {
9 | public class HomeController : Controller
10 | {
11 | public IActionResult Index()
12 | {
13 | return View();
14 | }
15 |
16 | public IActionResult About()
17 | {
18 | ViewData["Message"] = "Your application description page.";
19 |
20 | return View();
21 | }
22 |
23 | public IActionResult Contact()
24 | {
25 | ViewData["Message"] = "Your contact page.";
26 |
27 | return View();
28 | }
29 |
30 | public IActionResult Error()
31 | {
32 | return View();
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/DosFactores/Models/ManageViewModels/SetPasswordViewModel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel.DataAnnotations;
4 | using System.Linq;
5 | using System.Threading.Tasks;
6 |
7 | namespace DosFactores.Models.ManageViewModels
8 | {
9 | public class SetPasswordViewModel
10 | {
11 | [Required]
12 | [StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)]
13 | [DataType(DataType.Password)]
14 | [Display(Name = "New password")]
15 | public string NewPassword { get; set; }
16 |
17 | [DataType(DataType.Password)]
18 | [Display(Name = "Confirm new password")]
19 | [Compare("NewPassword", ErrorMessage = "The new password and confirmation password do not match.")]
20 | public string ConfirmPassword { get; set; }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/DosFactores/Services/MessageServices.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 |
6 | namespace DosFactores.Services
7 | {
8 | // This class is used by the application to send Email and SMS
9 | // when you turn on two-factor authentication in ASP.NET Identity.
10 | // For more details see this link https://go.microsoft.com/fwlink/?LinkID=532713
11 | public class AuthMessageSender : IEmailSender, ISmsSender
12 | {
13 | public Task SendEmailAsync(string email, string subject, string message)
14 | {
15 | // Plug in your email service here to send an email.
16 | return Task.FromResult(0);
17 | }
18 |
19 | public Task SendSmsAsync(string number, string message)
20 | {
21 | // Plug in your SMS service here to send a text message.
22 | return Task.FromResult(0);
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/DosFactores/Data/ApplicationDbContext.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
6 | using Microsoft.EntityFrameworkCore;
7 | using DosFactores.Models;
8 |
9 | namespace DosFactores.Data
10 | {
11 | public class ApplicationDbContext : IdentityDbContext
12 | {
13 | public ApplicationDbContext(DbContextOptions options)
14 | : base(options)
15 | {
16 | }
17 |
18 | protected override void OnModelCreating(ModelBuilder builder)
19 | {
20 | base.OnModelCreating(builder);
21 | // Customize the ASP.NET Identity model and override the defaults if needed.
22 | // For example, you can rename the ASP.NET Identity table names and more.
23 | // Add your customizations after calling base.OnModelCreating(builder);
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/DosFactores/Models/AccountViewModels/ResetPasswordViewModel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel.DataAnnotations;
4 | using System.Linq;
5 | using System.Threading.Tasks;
6 |
7 | namespace DosFactores.Models.AccountViewModels
8 | {
9 | public class ResetPasswordViewModel
10 | {
11 | [Required]
12 | [EmailAddress]
13 | public string Email { get; set; }
14 |
15 | [Required]
16 | [StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)]
17 | [DataType(DataType.Password)]
18 | public string Password { get; set; }
19 |
20 | [DataType(DataType.Password)]
21 | [Display(Name = "Confirm password")]
22 | [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
23 | public string ConfirmPassword { get; set; }
24 |
25 | public string Code { get; set; }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/DosFactores/Models/AccountViewModels/RegisterViewModel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel.DataAnnotations;
4 | using System.Linq;
5 | using System.Threading.Tasks;
6 |
7 | namespace DosFactores.Models.AccountViewModels
8 | {
9 | public class RegisterViewModel
10 | {
11 | [Required]
12 | [EmailAddress]
13 | [Display(Name = "Email")]
14 | public string Email { get; set; }
15 |
16 | [Required]
17 | [StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)]
18 | [DataType(DataType.Password)]
19 | [Display(Name = "Password")]
20 | public string Password { get; set; }
21 |
22 | [DataType(DataType.Password)]
23 | [Display(Name = "Confirm password")]
24 | [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
25 | public string ConfirmPassword { get; set; }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/DosFactores/Views/Manage/AddPhoneNumber.cshtml:
--------------------------------------------------------------------------------
1 | @model AddPhoneNumberViewModel
2 | @{
3 | ViewData["Title"] = "Add Phone Number";
4 | }
5 |
6 | @ViewData["Title"].
7 |
24 |
25 | @section Scripts {
26 | @{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); }
27 | }
28 |
--------------------------------------------------------------------------------
/DosFactores/Models/ManageViewModels/ChangePasswordViewModel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel.DataAnnotations;
4 | using System.Linq;
5 | using System.Threading.Tasks;
6 |
7 | namespace DosFactores.Models.ManageViewModels
8 | {
9 | public class ChangePasswordViewModel
10 | {
11 | [Required]
12 | [DataType(DataType.Password)]
13 | [Display(Name = "Current password")]
14 | public string OldPassword { get; set; }
15 |
16 | [Required]
17 | [StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)]
18 | [DataType(DataType.Password)]
19 | [Display(Name = "New password")]
20 | public string NewPassword { get; set; }
21 |
22 | [DataType(DataType.Password)]
23 | [Display(Name = "Confirm new password")]
24 | [Compare("NewPassword", ErrorMessage = "The new password and confirmation password do not match.")]
25 | public string ConfirmPassword { get; set; }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/DosFactores/Views/Shared/_LoginPartial.cshtml:
--------------------------------------------------------------------------------
1 | @using Microsoft.AspNetCore.Identity
2 | @using DosFactores.Models
3 |
4 | @inject SignInManager SignInManager
5 | @inject UserManager UserManager
6 |
7 | @if (SignInManager.IsSignedIn(User))
8 | {
9 |
19 | }
20 | else
21 | {
22 |
26 | }
27 |
--------------------------------------------------------------------------------
/DosFactores/wwwroot/lib/jquery-validation/.bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "jquery-validation",
3 | "homepage": "http://jqueryvalidation.org/",
4 | "repository": {
5 | "type": "git",
6 | "url": "git://github.com/jzaefferer/jquery-validation.git"
7 | },
8 | "authors": [
9 | "Jörn Zaefferer "
10 | ],
11 | "description": "Form validation made easy",
12 | "main": "dist/jquery.validate.js",
13 | "keywords": [
14 | "forms",
15 | "validation",
16 | "validate"
17 | ],
18 | "license": "MIT",
19 | "ignore": [
20 | "**/.*",
21 | "node_modules",
22 | "bower_components",
23 | "test",
24 | "demo",
25 | "lib"
26 | ],
27 | "dependencies": {
28 | "jquery": ">= 1.7.2"
29 | },
30 | "version": "1.14.0",
31 | "_release": "1.14.0",
32 | "_resolution": {
33 | "type": "version",
34 | "tag": "1.14.0",
35 | "commit": "c1343fb9823392aa9acbe1c3ffd337b8c92fed48"
36 | },
37 | "_source": "git://github.com/jzaefferer/jquery-validation.git",
38 | "_target": ">=1.8",
39 | "_originalSource": "jquery-validation"
40 | }
--------------------------------------------------------------------------------
/DosFactores/wwwroot/lib/bootstrap/.bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "bootstrap",
3 | "description": "The most popular front-end framework for developing responsive, mobile first projects on the web.",
4 | "keywords": [
5 | "css",
6 | "js",
7 | "less",
8 | "mobile-first",
9 | "responsive",
10 | "front-end",
11 | "framework",
12 | "web"
13 | ],
14 | "homepage": "http://getbootstrap.com",
15 | "license": "MIT",
16 | "moduleType": "globals",
17 | "main": [
18 | "less/bootstrap.less",
19 | "dist/js/bootstrap.js"
20 | ],
21 | "ignore": [
22 | "/.*",
23 | "_config.yml",
24 | "CNAME",
25 | "composer.json",
26 | "CONTRIBUTING.md",
27 | "docs",
28 | "js/tests",
29 | "test-infra"
30 | ],
31 | "dependencies": {
32 | "jquery": "1.9.1 - 3"
33 | },
34 | "version": "3.3.7",
35 | "_release": "3.3.7",
36 | "_resolution": {
37 | "type": "version",
38 | "tag": "v3.3.7",
39 | "commit": "0b9c4a4007c44201dce9a6cc1a38407005c26c86"
40 | },
41 | "_source": "https://github.com/twbs/bootstrap.git",
42 | "_target": "v3.3.7",
43 | "_originalSource": "bootstrap",
44 | "_direct": true
45 | }
--------------------------------------------------------------------------------
/DosFactores/Views/Manage/VerifyPhoneNumber.cshtml:
--------------------------------------------------------------------------------
1 | @model VerifyPhoneNumberViewModel
2 | @{
3 | ViewData["Title"] = "Verify Phone Number";
4 | }
5 |
6 | @ViewData["Title"].
7 |
8 |
27 |
28 | @section Scripts {
29 | @{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); }
30 | }
31 |
--------------------------------------------------------------------------------
/DosFactores/wwwroot/lib/bootstrap/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2011-2016 Twitter, Inc.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/DosFactores/Views/Account/ForgotPassword.cshtml:
--------------------------------------------------------------------------------
1 | @model ForgotPasswordViewModel
2 | @{
3 | ViewData["Title"] = "Forgot your password?";
4 | }
5 |
6 | @ViewData["Title"]
7 |
8 | For more information on how to enable reset password please see this article.
9 |
10 |
11 | @**@
28 |
29 | @section Scripts {
30 | @{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); }
31 | }
32 |
--------------------------------------------------------------------------------
/DosFactores/wwwroot/css/site.css:
--------------------------------------------------------------------------------
1 | body {
2 | padding-top: 50px;
3 | padding-bottom: 20px;
4 | }
5 |
6 | /* Wrapping element */
7 | /* Set some basic padding to keep content from hitting the edges */
8 | .body-content {
9 | padding-left: 15px;
10 | padding-right: 15px;
11 | }
12 |
13 | /* Set widths on the form inputs since otherwise they're 100% wide */
14 | input,
15 | select,
16 | textarea {
17 | max-width: 280px;
18 | }
19 |
20 | /* Carousel */
21 | .carousel-caption p {
22 | font-size: 20px;
23 | line-height: 1.4;
24 | }
25 |
26 | /* buttons and links extension to use brackets: [ click me ] */
27 | .btn-bracketed::before {
28 | display: inline-block;
29 | content: "[";
30 | padding-right: 0.5em;
31 | }
32 |
33 | .btn-bracketed::after {
34 | display: inline-block;
35 | content: "]";
36 | padding-left: 0.5em;
37 | }
38 |
39 | /* Make .svg files in the carousel display properly in older browsers */
40 | .carousel-inner .item img[src$=".svg"] {
41 | width: 100%;
42 | }
43 |
44 | /* Hide/rearrange for smaller screens */
45 | @media screen and (max-width: 767px) {
46 | /* Hide captions */
47 | .carousel-caption {
48 | display: none;
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/DosFactores/wwwroot/lib/jquery-validation/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 | =====================
3 |
4 | Copyright Jörn Zaefferer
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in
14 | all copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | THE SOFTWARE.
23 |
--------------------------------------------------------------------------------
/DosFactores/Views/Shared/_ValidationScriptsPartial.cshtml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
12 |
18 |
19 |
--------------------------------------------------------------------------------
/DosFactores/wwwroot/lib/jquery-validation-unobtrusive/.bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "jquery-validation-unobtrusive",
3 | "version": "3.2.6",
4 | "homepage": "https://github.com/aspnet/jquery-validation-unobtrusive",
5 | "description": "Add-on to jQuery Validation to enable unobtrusive validation options in data-* attributes.",
6 | "main": [
7 | "jquery.validate.unobtrusive.js"
8 | ],
9 | "ignore": [
10 | "**/.*",
11 | "*.json",
12 | "*.md",
13 | "*.txt",
14 | "gulpfile.js"
15 | ],
16 | "keywords": [
17 | "jquery",
18 | "asp.net",
19 | "mvc",
20 | "validation",
21 | "unobtrusive"
22 | ],
23 | "authors": [
24 | "Microsoft"
25 | ],
26 | "license": "http://www.microsoft.com/web/webpi/eula/net_library_eula_enu.htm",
27 | "repository": {
28 | "type": "git",
29 | "url": "git://github.com/aspnet/jquery-validation-unobtrusive.git"
30 | },
31 | "dependencies": {
32 | "jquery-validation": ">=1.8",
33 | "jquery": ">=1.8"
34 | },
35 | "_release": "3.2.6",
36 | "_resolution": {
37 | "type": "version",
38 | "tag": "v3.2.6",
39 | "commit": "13386cd1b5947d8a5d23a12b531ce3960be1eba7"
40 | },
41 | "_source": "git://github.com/aspnet/jquery-validation-unobtrusive.git",
42 | "_target": "3.2.6",
43 | "_originalSource": "jquery-validation-unobtrusive"
44 | }
--------------------------------------------------------------------------------
/DosFactores/Views/Account/ExternalLoginConfirmation.cshtml:
--------------------------------------------------------------------------------
1 | @model ExternalLoginConfirmationViewModel
2 | @{
3 | ViewData["Title"] = "Register";
4 | }
5 |
6 | @ViewData["Title"].
7 | Associate your @ViewData["LoginProvider"] account.
8 |
9 |
32 |
33 | @section Scripts {
34 | @{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); }
35 | }
36 |
--------------------------------------------------------------------------------
/DosFactores/Views/Account/VerifyCode.cshtml:
--------------------------------------------------------------------------------
1 | @model VerifyCodeViewModel
2 | @{
3 | ViewData["Title"] = "Verify";
4 | }
5 |
6 | @ViewData["Title"].
7 |
8 |
35 |
36 | @section Scripts {
37 | @{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); }
38 | }
39 |
--------------------------------------------------------------------------------
/DosFactores/Views/Manage/SetPassword.cshtml:
--------------------------------------------------------------------------------
1 | @model SetPasswordViewModel
2 | @{
3 | ViewData["Title"] = "Set Password";
4 | }
5 |
6 |
7 | You do not have a local username/password for this site. Add a local
8 | account so you can log in without an external login.
9 |
10 |
11 |
35 |
36 | @section Scripts {
37 | @{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); }
38 | }
39 |
--------------------------------------------------------------------------------
/DosFactores.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.26228.4
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DosFactores", "DosFactores\DosFactores.csproj", "{10BA64ED-1909-4436-AEFA-8E283BAFB06F}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Google.Authenticator", "Google.Authenticator\Google.Authenticator.csproj", "{B2034AF9-BC36-4A1F-8115-3EA705BA03E4}"
9 | EndProject
10 | Global
11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
12 | Debug|Any CPU = Debug|Any CPU
13 | Release|Any CPU = Release|Any CPU
14 | EndGlobalSection
15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
16 | {10BA64ED-1909-4436-AEFA-8E283BAFB06F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
17 | {10BA64ED-1909-4436-AEFA-8E283BAFB06F}.Debug|Any CPU.Build.0 = Debug|Any CPU
18 | {10BA64ED-1909-4436-AEFA-8E283BAFB06F}.Release|Any CPU.ActiveCfg = Release|Any CPU
19 | {10BA64ED-1909-4436-AEFA-8E283BAFB06F}.Release|Any CPU.Build.0 = Release|Any CPU
20 | {B2034AF9-BC36-4A1F-8115-3EA705BA03E4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21 | {B2034AF9-BC36-4A1F-8115-3EA705BA03E4}.Debug|Any CPU.Build.0 = Debug|Any CPU
22 | {B2034AF9-BC36-4A1F-8115-3EA705BA03E4}.Release|Any CPU.ActiveCfg = Release|Any CPU
23 | {B2034AF9-BC36-4A1F-8115-3EA705BA03E4}.Release|Any CPU.Build.0 = Release|Any CPU
24 | EndGlobalSection
25 | GlobalSection(SolutionProperties) = preSolution
26 | HideSolutionNode = FALSE
27 | EndGlobalSection
28 | EndGlobal
29 |
--------------------------------------------------------------------------------
/DosFactores/Views/Account/Register.cshtml:
--------------------------------------------------------------------------------
1 | @model RegisterViewModel
2 | @{
3 | ViewData["Title"] = "Register";
4 | }
5 |
6 | @ViewData["Title"].
7 |
8 |
39 |
40 | @section Scripts {
41 | @{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); }
42 | }
43 |
--------------------------------------------------------------------------------
/DosFactores/Views/Manage/ChangePassword.cshtml:
--------------------------------------------------------------------------------
1 | @model ChangePasswordViewModel
2 | @{
3 | ViewData["Title"] = "Change Password";
4 | }
5 |
6 | @ViewData["Title"].
7 |
8 |
39 |
40 | @section Scripts {
41 | @{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); }
42 | }
43 |
--------------------------------------------------------------------------------
/DosFactores/Views/Account/ResetPassword.cshtml:
--------------------------------------------------------------------------------
1 | @model ResetPasswordViewModel
2 | @{
3 | ViewData["Title"] = "Reset password";
4 | }
5 |
6 | @ViewData["Title"].
7 |
8 |
40 |
41 | @section Scripts {
42 | @{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); }
43 | }
44 |
--------------------------------------------------------------------------------
/DosFactores/wwwroot/lib/jquery/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright jQuery Foundation and other contributors, https://jquery.org/
2 |
3 | This software consists of voluntary contributions made by many
4 | individuals. For exact contribution history, see the revision history
5 | available at https://github.com/jquery/jquery
6 |
7 | The following license applies to all parts of this software except as
8 | documented below:
9 |
10 | ====
11 |
12 | Permission is hereby granted, free of charge, to any person obtaining
13 | a copy of this software and associated documentation files (the
14 | "Software"), to deal in the Software without restriction, including
15 | without limitation the rights to use, copy, modify, merge, publish,
16 | distribute, sublicense, and/or sell copies of the Software, and to
17 | permit persons to whom the Software is furnished to do so, subject to
18 | the following conditions:
19 |
20 | The above copyright notice and this permission notice shall be
21 | included in all copies or substantial portions of the Software.
22 |
23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 |
31 | ====
32 |
33 | All files located in the node_modules and external directories are
34 | externally maintained libraries used by this software which have their
35 | own licenses; we recommend you read them, as their terms may differ from
36 | the terms above.
37 |
--------------------------------------------------------------------------------
/DosFactores/Providers/GoogleAuthenticatorProvider.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 | using DosFactores.Data;
3 | using DosFactores.Models;
4 | using Google.Authenticator;
5 | using Microsoft.AspNetCore.Identity;
6 |
7 | namespace DosFactores.Providers
8 | {
9 | public class GoogleAuthenticatorProvider : IUserTwoFactorTokenProvider
10 | {
11 | public static readonly string ProviderName = "GoogleAuthenticator";
12 |
13 | private readonly ApplicationDbContext _dbContext;
14 |
15 | public GoogleAuthenticatorProvider(ApplicationDbContext dbContext)
16 | {
17 | _dbContext = dbContext;
18 | }
19 |
20 | public async Task GenerateAsync(string purpose, UserManager manager, ApplicationUser user)
21 | {
22 | var userName = await manager.GetUserNameAsync(user);
23 | var authenticator = new TwoFactorAuthenticator();
24 | var code = authenticator.GenerateSetupCode(userName, userName, 100, 100);
25 | return code.ManualEntryKey;
26 | }
27 |
28 | public Task ValidateAsync(string purpose, string token, UserManager manager, ApplicationUser user)
29 | {
30 | return Task.Factory.StartNew(() =>
31 | {
32 | var authenticator = new TwoFactorAuthenticator();
33 | return authenticator.ValidateTwoFactorPIN(user.TfaKey, token);
34 | });
35 | }
36 |
37 | public Task CanGenerateTwoFactorTokenAsync(UserManager manager, ApplicationUser user)
38 | {
39 | return Task.Factory.StartNew(() =>
40 | {
41 | // Verify if the user is ellegible for 2FA
42 | return true;
43 | });
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/DosFactores/Views/Manage/ManageLogins.cshtml:
--------------------------------------------------------------------------------
1 | @model ManageLoginsViewModel
2 | @using Microsoft.AspNetCore.Http.Authentication
3 | @{
4 | ViewData["Title"] = "Manage your external logins";
5 | }
6 |
7 | @ViewData["Title"].
8 |
9 | @ViewData["StatusMessage"]
10 | @if (Model.CurrentLogins.Count > 0)
11 | {
12 | Registered Logins
13 |
14 |
15 | @for (var index = 0; index < Model.CurrentLogins.Count; index++)
16 | {
17 |
18 | | @Model.CurrentLogins[index].LoginProvider |
19 |
20 | @if ((bool)ViewData["ShowRemoveButton"])
21 | {
22 |
29 | }
30 | else
31 | {
32 | @:
33 | }
34 | |
35 |
36 | }
37 |
38 |
39 | }
40 | @if (Model.OtherLogins.Count > 0)
41 | {
42 | Add another service to log in.
43 |
44 |
54 | }
55 |
--------------------------------------------------------------------------------
/DosFactores/DosFactores.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp1.1
5 |
6 |
7 |
8 | $(PackageTargetFallback);portable-net45+win8+wp8+wpa81;
9 |
10 |
11 |
12 | aspnet-DosFactores-89d873e4-498b-4126-920c-68524dfd9718
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/DosFactores/Views/Manage/Index.cshtml:
--------------------------------------------------------------------------------
1 | @model IndexViewModel
2 | @{
3 | ViewData["Title"] = "Manage your account";
4 | }
5 |
6 | @ViewData["Title"].
7 | @ViewData["StatusMessage"]
8 |
9 |
10 |
Change your account settings
11 |
12 |
13 | - Password:
14 | -
15 | @if (Model.HasPassword)
16 | {
17 | Change
18 | }
19 | else
20 | {
21 | Create
22 | }
23 |
24 | - External Logins:
25 | -
26 |
27 | @Model.Logins.Count Manage
28 |
29 | - Phone Number:
30 | -
31 |
32 | Phone Numbers can be used as a second factor of verification in two-factor authentication.
33 | See this article
34 | for details on setting up this ASP.NET application to support two-factor authentication using SMS.
35 |
36 | @*@(Model.PhoneNumber ?? "None")
37 | @if (Model.PhoneNumber != null)
38 | {
39 |
40 | Change
41 |
44 | }
45 | else
46 | {
47 | Add
48 | }*@
49 |
50 |
51 | - Two-Factor Authentication:
52 | -
53 | @if (Model.TwoFactorAuthenticatorQrCode != null)
54 | {
55 |
56 |
59 | }
60 | else
61 | {
62 | if (Model.TwoFactor)
63 | {
64 |
67 | }
68 | else
69 | {
70 |
73 | }
74 | }
75 |
76 |
77 |
78 |
--------------------------------------------------------------------------------
/DosFactores/Views/Shared/_Layout.cshtml:
--------------------------------------------------------------------------------
1 | @inject Microsoft.ApplicationInsights.AspNetCore.JavaScriptSnippet JavaScriptSnippet
2 |
3 |
4 |
5 |
6 |
7 | @ViewData["Title"] - DosFactores
8 |
9 |
10 |
11 |
12 |
13 |
14 |
17 |
18 |
19 | @Html.Raw(JavaScriptSnippet.FullScript)
20 |
21 |
22 |
43 |
44 | @RenderBody()
45 |
46 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
63 |
69 |
70 |
71 |
72 | @RenderSection("Scripts", required: false)
73 |
74 |
75 |
--------------------------------------------------------------------------------
/Instrucciones.md:
--------------------------------------------------------------------------------
1 | 1. Nuevo proyecto: ASP.NET Core Web Application (.NET Core)
2 | 2. Template: Web Application
3 | 3. Change Authentication: Individual User Accounts
4 | 4. Agregar el paquete Microsoft.AspNetCore.Rewrite
5 | 5. Agregar el código en Startup.cs:44
6 |
7 | ```
8 | // Enforce SSL
9 | services.Configure(options =>
10 | {
11 | options.Filters.Add(new RequireHttpsAttribute());
12 | });
13 | ```
14 |
15 | 6. Agregar el código en Startup.cs:81
16 |
17 | ```
18 | // Requires using Microsoft.AspNetCore.Rewrite;
19 | var options = new RewriteOptions()
20 | .AddRedirectToHttps();
21 | ```
22 |
23 | 7. Habilitar SSL en Propiedades -> Debug
24 | 8. Agregar el código en ApplicationUser.cs:12
25 |
26 | ```
27 | public virtual string TfaKey { get; set; }
28 | ```
29 |
30 | 9. Agregar el código en 00000000000000_CreateIdentitySchema.cs:60
31 |
32 | ```
33 | TfaKey = table.Column(maxLength: 32, nullable: true),
34 | ```
35 |
36 | 10. Agregar paquete Microsoft.AspNetCore.Session
37 | 11. Agregar el código en Startup.cs:60
38 |
39 | ```
40 | // Add session support
41 | services.AddSession(options =>
42 | {
43 | // Set a short timeout for easy testing.
44 | options.IdleTimeout = TimeSpan.FromSeconds(10);
45 | options.CookieHttpOnly = true;
46 | });
47 | ```
48 |
49 | 12. Agrear el código en Startup.cs:98
50 |
51 | ```
52 | app.UseSession();
53 | ```
54 |
55 | 13. Agregar nuevo proyecto (Google.Authenticator): Class Library (.NET Core)
56 | 14. Añadir clases: SetupCode y TwoFactorAuthenticator (Ver https://github.com/BrandonPotter/GoogleAuthenticator)
57 | 15. Agregar referencia de Goolge.Authenticator -> DosFactores
58 | 16. Agregar clase GoogleAuthenticatorProvider (Ver: http://www.domstamand.com/two-factor-authentication-in-asp-net-identity-3-using-totp-authenticator/)
59 | 17. Agregar el código en Startup.cs:57
60 |
61 | ```
62 | .AddTokenProvider(GoogleAuthenticatorProvider.ProviderName, typeof(GoogleAuthenticatorProvider))
63 | ```
64 |
65 | 18. Agregar el código en IndexViewModel.cs:17
66 |
67 | ```
68 | public string TwoFactorAuthenticatorQrCode { get; set; }
69 | ```
70 |
71 | 19. Agregar el código correspondiente para la generación del QR en el archivo ManageController.cs: (64, 123 y 168)
72 |
73 | ```
74 | TwoFactorAuthenticatorQrCode = TempData["AuthenticatorQr"]?.ToString(),
75 | ```
76 |
77 | ```
78 | // POST: /Manage/RequestTwoFactorAuthentication
79 | [HttpPost]
80 | [ValidateAntiForgeryToken]
81 | public async Task RequestTwoFactorAuthentication()
82 | {
83 | var user = await GetCurrentUserAsync();
84 | if (user != null)
85 | {
86 | var tfaKey = Guid.NewGuid().ToString("N");
87 | user.TfaKey = tfaKey;
88 | await _userManager.UpdateAsync(user);
89 | var authenticator = new TwoFactorAuthenticator();
90 | var code = authenticator.GenerateSetupCode(user.UserName, tfaKey, 300, 300);
91 | TempData["AuthenticatorQr"] = code.QrCodeSetupImageUrl;
92 | _logger.LogInformation(1, "User enabled two-factor authentication.");
93 | }
94 | return RedirectToAction(nameof(Index), "Manage");
95 | }
96 | ```
97 |
98 | ```
99 | user.TfaKey = null;
100 | await _userManager.UpdateAsync(user);
101 | ```
102 |
103 | 20. Reemplazar el código del de la autenticación de dos factores por
104 |
105 | ```
106 | @if (Model.TwoFactorAuthenticatorQrCode != null)
107 | {
108 |
109 |
112 | }
113 | else
114 | {
115 | if (Model.TwoFactor)
116 | {
117 |
120 | }
121 | else
122 | {
123 |
126 | }
127 | }
128 | ```
129 |
130 | 21. Ejecutar Update-Database
--------------------------------------------------------------------------------
/DosFactores/Views/Account/Login.cshtml:
--------------------------------------------------------------------------------
1 | @using System.Collections.Generic
2 | @using Microsoft.AspNetCore.Http
3 | @using Microsoft.AspNetCore.Http.Authentication
4 | @model LoginViewModel
5 | @inject SignInManager SignInManager
6 |
7 | @{
8 | ViewData["Title"] = "Log in";
9 | }
10 |
11 | @ViewData["Title"].
12 |
13 |
57 |
58 |
59 | Use another service to log in.
60 |
61 | @{
62 | var loginProviders = SignInManager.GetExternalAuthenticationSchemes().ToList();
63 | if (loginProviders.Count == 0)
64 | {
65 |
66 |
67 | There are no external authentication services configured. See this article
68 | for details on setting up this ASP.NET application to support logging in via external services.
69 |
70 |
71 | }
72 | else
73 | {
74 |
84 | }
85 | }
86 |
87 |
88 |
89 |
90 | @section Scripts {
91 | @{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); }
92 | }
93 |
--------------------------------------------------------------------------------
/DosFactores/Startup.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using Microsoft.AspNetCore.Builder;
6 | using Microsoft.AspNetCore.Hosting;
7 | using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
8 | using Microsoft.EntityFrameworkCore;
9 | using Microsoft.Extensions.Configuration;
10 | using Microsoft.Extensions.DependencyInjection;
11 | using Microsoft.Extensions.Logging;
12 | using DosFactores.Data;
13 | using DosFactores.Models;
14 | using DosFactores.Providers;
15 | using DosFactores.Services;
16 | using Microsoft.AspNetCore.Mvc;
17 | using Microsoft.AspNetCore.Rewrite;
18 |
19 | namespace DosFactores
20 | {
21 | public class Startup
22 | {
23 | public Startup(IHostingEnvironment env)
24 | {
25 | var builder = new ConfigurationBuilder()
26 | .SetBasePath(env.ContentRootPath)
27 | .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
28 | .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true);
29 |
30 | if (env.IsDevelopment())
31 | {
32 | // For more details on using the user secret store see https://go.microsoft.com/fwlink/?LinkID=532709
33 | builder.AddUserSecrets();
34 | }
35 |
36 | builder.AddEnvironmentVariables();
37 | Configuration = builder.Build();
38 | }
39 |
40 | public IConfigurationRoot Configuration { get; }
41 |
42 | // This method gets called by the runtime. Use this method to add services to the container.
43 | public void ConfigureServices(IServiceCollection services)
44 | {
45 | // Enforce SSL
46 | services.Configure(options =>
47 | {
48 | options.Filters.Add(new RequireHttpsAttribute());
49 | });
50 |
51 | // Add framework services.
52 | services.AddDbContext(options =>
53 | options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
54 |
55 | services.AddIdentity()
56 | .AddEntityFrameworkStores()
57 | .AddTokenProvider(GoogleAuthenticatorProvider.ProviderName, typeof(GoogleAuthenticatorProvider))
58 | .AddDefaultTokenProviders();
59 |
60 | services.AddMvc();
61 |
62 | // Add session support
63 | services.AddSession(options =>
64 | {
65 | // Set a short timeout for easy testing.
66 | options.IdleTimeout = TimeSpan.FromSeconds(10);
67 | options.CookieHttpOnly = true;
68 | });
69 |
70 | // Add application services.
71 | services.AddTransient();
72 | services.AddTransient();
73 | }
74 |
75 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
76 | public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
77 | {
78 | loggerFactory.AddConsole(Configuration.GetSection("Logging"));
79 | loggerFactory.AddDebug();
80 |
81 | if (env.IsDevelopment())
82 | {
83 | app.UseDeveloperExceptionPage();
84 | app.UseDatabaseErrorPage();
85 | app.UseBrowserLink();
86 | }
87 | else
88 | {
89 | app.UseExceptionHandler("/Home/Error");
90 | }
91 |
92 | // Requires using Microsoft.AspNetCore.Rewrite;
93 | var options = new RewriteOptions()
94 | .AddRedirectToHttps();
95 |
96 | app.UseStaticFiles();
97 |
98 | app.UseIdentity();
99 |
100 | app.UseSession();
101 |
102 | // Add external authentication middleware below. To configure them please see https://go.microsoft.com/fwlink/?LinkID=532715
103 |
104 | app.UseMvc(routes =>
105 | {
106 | routes.MapRoute(
107 | name: "default",
108 | template: "{controller=Home}/{action=Index}/{id?}");
109 | });
110 | }
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.userosscache
8 | *.sln.docstates
9 |
10 | # User-specific files (MonoDevelop/Xamarin Studio)
11 | *.userprefs
12 |
13 | # Build results
14 | [Dd]ebug/
15 | [Dd]ebugPublic/
16 | [Rr]elease/
17 | [Rr]eleases/
18 | x64/
19 | x86/
20 | build/
21 | bld/
22 | [Bb]in/
23 | [Oo]bj/
24 |
25 | # Visual Studio 2015 cache/options directory
26 | .vs/
27 | # Uncomment if you have tasks that create the project's static files in wwwroot
28 | #wwwroot/
29 |
30 | # MSTest test Results
31 | [Tt]est[Rr]esult*/
32 | [Bb]uild[Ll]og.*
33 |
34 | # NUNIT
35 | *.VisualState.xml
36 | TestResult.xml
37 |
38 | # Build Results of an ATL Project
39 | [Dd]ebugPS/
40 | [Rr]eleasePS/
41 | dlldata.c
42 |
43 | # DNX
44 | project.lock.json
45 | artifacts/
46 |
47 | *_i.c
48 | *_p.c
49 | *_i.h
50 | *.ilk
51 | *.meta
52 | *.obj
53 | *.pch
54 | *.pdb
55 | *.pgc
56 | *.pgd
57 | *.rsp
58 | *.sbr
59 | *.tlb
60 | *.tli
61 | *.tlh
62 | *.tmp
63 | *.tmp_proj
64 | *.log
65 | *.vspscc
66 | *.vssscc
67 | .builds
68 | *.pidb
69 | *.svclog
70 | *.scc
71 |
72 | # Chutzpah Test files
73 | _Chutzpah*
74 |
75 | # Visual C++ cache files
76 | ipch/
77 | *.aps
78 | *.ncb
79 | *.opendb
80 | *.opensdf
81 | *.sdf
82 | *.cachefile
83 |
84 | # Visual Studio profiler
85 | *.psess
86 | *.vsp
87 | *.vspx
88 | *.sap
89 |
90 | # TFS 2012 Local Workspace
91 | $tf/
92 |
93 | # Guidance Automation Toolkit
94 | *.gpState
95 |
96 | # ReSharper is a .NET coding add-in
97 | _ReSharper*/
98 | *.[Rr]e[Ss]harper
99 | *.DotSettings.user
100 |
101 | # JustCode is a .NET coding add-in
102 | .JustCode
103 |
104 | # TeamCity is a build add-in
105 | _TeamCity*
106 |
107 | # DotCover is a Code Coverage Tool
108 | *.dotCover
109 |
110 | # NCrunch
111 | _NCrunch_*
112 | .*crunch*.local.xml
113 | nCrunchTemp_*
114 |
115 | # MightyMoose
116 | *.mm.*
117 | AutoTest.Net/
118 |
119 | # Web workbench (sass)
120 | .sass-cache/
121 |
122 | # Installshield output folder
123 | [Ee]xpress/
124 |
125 | # DocProject is a documentation generator add-in
126 | DocProject/buildhelp/
127 | DocProject/Help/*.HxT
128 | DocProject/Help/*.HxC
129 | DocProject/Help/*.hhc
130 | DocProject/Help/*.hhk
131 | DocProject/Help/*.hhp
132 | DocProject/Help/Html2
133 | DocProject/Help/html
134 |
135 | # Click-Once directory
136 | publish/
137 |
138 | # Publish Web Output
139 | *.[Pp]ublish.xml
140 | *.azurePubxml
141 | # TODO: Comment the next line if you want to checkin your web deploy settings
142 | # but database connection strings (with potential passwords) will be unencrypted
143 | *.pubxml
144 | *.publishproj
145 |
146 | # NuGet Packages
147 | *.nupkg
148 | # The packages folder can be ignored because of Package Restore
149 | **/packages/*
150 | # except build/, which is used as an MSBuild target.
151 | !**/packages/build/
152 | # Uncomment if necessary however generally it will be regenerated when needed
153 | #!**/packages/repositories.config
154 |
155 | # Microsoft Azure Build Output
156 | csx/
157 | *.build.csdef
158 |
159 | # Microsoft Azure Emulator
160 | ecf/
161 | rcf/
162 |
163 | # Microsoft Azure ApplicationInsights config file
164 | ApplicationInsights.config
165 |
166 | # Windows Store app package directory
167 | AppPackages/
168 | BundleArtifacts/
169 |
170 | # Visual Studio cache files
171 | # files ending in .cache can be ignored
172 | *.[Cc]ache
173 | # but keep track of directories ending in .cache
174 | !*.[Cc]ache/
175 |
176 | # Others
177 | ClientBin/
178 | ~$*
179 | *~
180 | *.dbmdl
181 | *.dbproj.schemaview
182 | *.pfx
183 | *.publishsettings
184 | node_modules/
185 | orleans.codegen.cs
186 |
187 | # RIA/Silverlight projects
188 | Generated_Code/
189 |
190 | # Backup & report files from converting an old project file
191 | # to a newer Visual Studio version. Backup files are not needed,
192 | # because we have git ;-)
193 | _UpgradeReport_Files/
194 | Backup*/
195 | UpgradeLog*.XML
196 | UpgradeLog*.htm
197 |
198 | # SQL Server files
199 | *.mdf
200 | *.ldf
201 |
202 | # Business Intelligence projects
203 | *.rdl.data
204 | *.bim.layout
205 | *.bim_*.settings
206 |
207 | # Microsoft Fakes
208 | FakesAssemblies/
209 |
210 | # GhostDoc plugin setting file
211 | *.GhostDoc.xml
212 |
213 | # Node.js Tools for Visual Studio
214 | .ntvs_analysis.dat
215 |
216 | # Visual Studio 6 build log
217 | *.plg
218 |
219 | # Visual Studio 6 workspace options file
220 | *.opt
221 |
222 | # Visual Studio LightSwitch build output
223 | **/*.HTMLClient/GeneratedArtifacts
224 | **/*.DesktopClient/GeneratedArtifacts
225 | **/*.DesktopClient/ModelManifest.xml
226 | **/*.Server/GeneratedArtifacts
227 | **/*.Server/ModelManifest.xml
228 | _Pvt_Extensions
229 |
230 | # Paket dependency manager
231 | .paket/paket.exe
232 |
233 | # FAKE - F# Make
234 | .fake/
--------------------------------------------------------------------------------
/DosFactores/wwwroot/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js:
--------------------------------------------------------------------------------
1 | /*
2 | ** Unobtrusive validation support library for jQuery and jQuery Validate
3 | ** Copyright (C) Microsoft Corporation. All rights reserved.
4 | */
5 | !function(a){function e(a,e,n){a.rules[e]=n,a.message&&(a.messages[e]=a.message)}function n(a){return a.replace(/^\s+|\s+$/g,"").split(/\s*,\s*/g)}function t(a){return a.replace(/([!"#$%&'()*+,./:;<=>?@\[\\\]^`{|}~])/g,"\\$1")}function r(a){return a.substr(0,a.lastIndexOf(".")+1)}function i(a,e){return 0===a.indexOf("*.")&&(a=a.replace("*.",e)),a}function o(e,n){var r=a(this).find("[data-valmsg-for='"+t(n[0].name)+"']"),i=r.attr("data-valmsg-replace"),o=i?a.parseJSON(i)!==!1:null;r.removeClass("field-validation-valid").addClass("field-validation-error"),e.data("unobtrusiveContainer",r),o?(r.empty(),e.removeClass("input-validation-error").appendTo(r)):e.hide()}function d(e,n){var t=a(this).find("[data-valmsg-summary=true]"),r=t.find("ul");r&&r.length&&n.errorList.length&&(r.empty(),t.addClass("validation-summary-errors").removeClass("validation-summary-valid"),a.each(n.errorList,function(){a("").html(this.message).appendTo(r)}))}function s(e){var n=e.data("unobtrusiveContainer");if(n){var t=n.attr("data-valmsg-replace"),r=t?a.parseJSON(t):null;n.addClass("field-validation-valid").removeClass("field-validation-error"),e.removeData("unobtrusiveContainer"),r&&n.empty()}}function l(e){var n=a(this),t="__jquery_unobtrusive_validation_form_reset";if(!n.data(t)){n.data(t,!0);try{n.data("validator").resetForm()}finally{n.removeData(t)}n.find(".validation-summary-errors").addClass("validation-summary-valid").removeClass("validation-summary-errors"),n.find(".field-validation-error").addClass("field-validation-valid").removeClass("field-validation-error").removeData("unobtrusiveContainer").find(">*").removeData("unobtrusiveContainer")}}function m(e){var n=a(e),t=n.data(v),r=a.proxy(l,e),i=p.unobtrusive.options||{},m=function(n,t){var r=i[n];r&&a.isFunction(r)&&r.apply(e,t)};return t||(t={options:{errorClass:i.errorClass||"input-validation-error",errorElement:i.errorElement||"span",errorPlacement:function(){o.apply(e,arguments),m("errorPlacement",arguments)},invalidHandler:function(){d.apply(e,arguments),m("invalidHandler",arguments)},messages:{},rules:{},success:function(){s.apply(e,arguments),m("success",arguments)}},attachValidation:function(){n.off("reset."+v,r).on("reset."+v,r).validate(this.options)},validate:function(){return n.validate(),n.valid()}},n.data(v,t)),t}var u,p=a.validator,v="unobtrusiveValidation";p.unobtrusive={adapters:[],parseElement:function(e,n){var t,r,i,o=a(e),d=o.parents("form")[0];d&&(t=m(d),t.options.rules[e.name]=r={},t.options.messages[e.name]=i={},a.each(this.adapters,function(){var n="data-val-"+this.name,t=o.attr(n),s={};void 0!==t&&(n+="-",a.each(this.params,function(){s[this]=o.attr(n+this)}),this.adapt({element:e,form:d,message:t,params:s,rules:r,messages:i}))}),a.extend(r,{__dummy__:!0}),n||t.attachValidation())},parse:function(e){var n=a(e),t=n.parents().addBack().filter("form").add(n.find("form")).has("[data-val=true]");n.find("[data-val=true]").each(function(){p.unobtrusive.parseElement(this,!0)}),t.each(function(){var a=m(this);a&&a.attachValidation()})}},u=p.unobtrusive.adapters,u.add=function(a,e,n){return n||(n=e,e=[]),this.push({name:a,params:e,adapt:n}),this},u.addBool=function(a,n){return this.add(a,function(t){e(t,n||a,!0)})},u.addMinMax=function(a,n,t,r,i,o){return this.add(a,[i||"min",o||"max"],function(a){var i=a.params.min,o=a.params.max;i&&o?e(a,r,[i,o]):i?e(a,n,i):o&&e(a,t,o)})},u.addSingleVal=function(a,n,t){return this.add(a,[n||"val"],function(r){e(r,t||a,r.params[n])})},p.addMethod("__dummy__",function(a,e,n){return!0}),p.addMethod("regex",function(a,e,n){var t;return this.optional(e)?!0:(t=new RegExp(n).exec(a),t&&0===t.index&&t[0].length===a.length)}),p.addMethod("nonalphamin",function(a,e,n){var t;return n&&(t=a.match(/\W/g),t=t&&t.length>=n),t}),p.methods.extension?(u.addSingleVal("accept","mimtype"),u.addSingleVal("extension","extension")):u.addSingleVal("extension","extension","accept"),u.addSingleVal("regex","pattern"),u.addBool("creditcard").addBool("date").addBool("digits").addBool("email").addBool("number").addBool("url"),u.addMinMax("length","minlength","maxlength","rangelength").addMinMax("range","min","max","range"),u.addMinMax("minlength","minlength").addMinMax("maxlength","minlength","maxlength"),u.add("equalto",["other"],function(n){var o=r(n.element.name),d=n.params.other,s=i(d,o),l=a(n.form).find(":input").filter("[name='"+t(s)+"']")[0];e(n,"equalTo",l)}),u.add("required",function(a){("INPUT"!==a.element.tagName.toUpperCase()||"CHECKBOX"!==a.element.type.toUpperCase())&&e(a,"required",!0)}),u.add("remote",["url","type","additionalfields"],function(o){var d={url:o.params.url,type:o.params.type||"GET",data:{}},s=r(o.element.name);a.each(n(o.params.additionalfields||o.element.name),function(e,n){var r=i(n,s);d.data[r]=function(){var e=a(o.form).find(":input").filter("[name='"+t(r)+"']");return e.is(":checkbox")?e.filter(":checked").val()||e.filter(":hidden").val()||"":e.is(":radio")?e.filter(":checked").val()||"":e.val()}}),e(o,"remote",d)}),u.add("password",["min","nonalphamin","regex"],function(a){a.params.min&&e(a,"minlength",a.params.min),a.params.nonalphamin&&e(a,"nonalphamin",a.params.nonalphamin),a.params.regex&&e(a,"regex",a.params.regex)}),a(function(){p.unobtrusive.parse(document)})}(jQuery);
--------------------------------------------------------------------------------
/DosFactores/Views/Home/Index.cshtml:
--------------------------------------------------------------------------------
1 | @{
2 | ViewData["Title"] = "Home Page";
3 | }
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |

15 |
16 |
17 | Learn how to build ASP.NET apps that can run anywhere.
18 |
19 | Learn More
20 |
21 |
22 |
23 |
24 |
25 |

26 |
27 |
28 | There are powerful new features in Visual Studio for building modern web apps.
29 |
30 | Learn More
31 |
32 |
33 |
34 |
35 |
36 |

37 |
38 |
39 | Bring in libraries from NuGet, Bower, and npm, and automate tasks using Grunt or Gulp.
40 |
41 | Learn More
42 |
43 |
44 |
45 |
46 |
47 |

48 |
49 |
50 | Learn how Microsoft's Azure cloud platform allows you to build, deploy, and scale web apps.
51 |
52 | Learn More
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 | Previous
61 |
62 |
63 |
64 | Next
65 |
66 |
67 |
68 |
69 |
70 |
Application uses
71 |
72 | - Sample pages using ASP.NET Core MVC
73 | - Bower for managing client-side libraries
74 | - Theming using Bootstrap
75 |
76 |
77 |
88 |
100 |
101 |
Run & Deploy
102 |
107 |
108 |
109 |
--------------------------------------------------------------------------------
/DosFactores/wwwroot/images/banner2.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/DosFactores/Data/Migrations/ApplicationDbContextModelSnapshot.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using Microsoft.EntityFrameworkCore;
6 | using Microsoft.EntityFrameworkCore.Infrastructure;
7 | using Microsoft.EntityFrameworkCore.Metadata;
8 | using Microsoft.EntityFrameworkCore.Migrations;
9 |
10 | namespace DosFactores.Data.Migrations
11 | {
12 | [DbContext(typeof(ApplicationDbContext))]
13 | partial class ApplicationDbContextModelSnapshot : ModelSnapshot
14 | {
15 | protected override void BuildModel(ModelBuilder modelBuilder)
16 | {
17 | modelBuilder
18 | .HasAnnotation("ProductVersion", "1.0.0-rc3")
19 | .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
20 |
21 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole", b =>
22 | {
23 | b.Property("Id");
24 |
25 | b.Property("ConcurrencyStamp")
26 | .IsConcurrencyToken();
27 |
28 | b.Property("Name")
29 | .HasAnnotation("MaxLength", 256);
30 |
31 | b.Property("NormalizedName")
32 | .HasAnnotation("MaxLength", 256);
33 |
34 | b.HasKey("Id");
35 |
36 | b.HasIndex("NormalizedName")
37 | .HasName("RoleNameIndex");
38 |
39 | b.ToTable("AspNetRoles");
40 | });
41 |
42 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRoleClaim", b =>
43 | {
44 | b.Property("Id")
45 | .ValueGeneratedOnAdd();
46 |
47 | b.Property("ClaimType");
48 |
49 | b.Property("ClaimValue");
50 |
51 | b.Property("RoleId")
52 | .IsRequired();
53 |
54 | b.HasKey("Id");
55 |
56 | b.HasIndex("RoleId");
57 |
58 | b.ToTable("AspNetRoleClaims");
59 | });
60 |
61 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserClaim", b =>
62 | {
63 | b.Property("Id")
64 | .ValueGeneratedOnAdd();
65 |
66 | b.Property("ClaimType");
67 |
68 | b.Property("ClaimValue");
69 |
70 | b.Property("UserId")
71 | .IsRequired();
72 |
73 | b.HasKey("Id");
74 |
75 | b.HasIndex("UserId");
76 |
77 | b.ToTable("AspNetUserClaims");
78 | });
79 |
80 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserLogin", b =>
81 | {
82 | b.Property("LoginProvider");
83 |
84 | b.Property("ProviderKey");
85 |
86 | b.Property("ProviderDisplayName");
87 |
88 | b.Property("UserId")
89 | .IsRequired();
90 |
91 | b.HasKey("LoginProvider", "ProviderKey");
92 |
93 | b.HasIndex("UserId");
94 |
95 | b.ToTable("AspNetUserLogins");
96 | });
97 |
98 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserRole", b =>
99 | {
100 | b.Property("UserId");
101 |
102 | b.Property("RoleId");
103 |
104 | b.HasKey("UserId", "RoleId");
105 |
106 | b.HasIndex("RoleId");
107 |
108 | b.HasIndex("UserId");
109 |
110 | b.ToTable("AspNetUserRoles");
111 | });
112 |
113 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserToken", b =>
114 | {
115 | b.Property("UserId");
116 |
117 | b.Property("LoginProvider");
118 |
119 | b.Property("Name");
120 |
121 | b.Property("Value");
122 |
123 | b.HasKey("UserId", "LoginProvider", "Name");
124 |
125 | b.ToTable("AspNetUserTokens");
126 | });
127 |
128 | modelBuilder.Entity("DosFactores.Models.ApplicationUser", b =>
129 | {
130 | b.Property("Id");
131 |
132 | b.Property("AccessFailedCount");
133 |
134 | b.Property("ConcurrencyStamp")
135 | .IsConcurrencyToken();
136 |
137 | b.Property("Email")
138 | .HasAnnotation("MaxLength", 256);
139 |
140 | b.Property("EmailConfirmed");
141 |
142 | b.Property("LockoutEnabled");
143 |
144 | b.Property("LockoutEnd");
145 |
146 | b.Property("NormalizedEmail")
147 | .HasAnnotation("MaxLength", 256);
148 |
149 | b.Property("NormalizedUserName")
150 | .HasAnnotation("MaxLength", 256);
151 |
152 | b.Property("PasswordHash");
153 |
154 | b.Property("PhoneNumber");
155 |
156 | b.Property("PhoneNumberConfirmed");
157 |
158 | b.Property("SecurityStamp");
159 |
160 | b.Property("TwoFactorEnabled");
161 |
162 | b.Property("UserName")
163 | .HasAnnotation("MaxLength", 256);
164 |
165 | b.HasKey("Id");
166 |
167 | b.HasIndex("NormalizedEmail")
168 | .HasName("EmailIndex");
169 |
170 | b.HasIndex("NormalizedUserName")
171 | .IsUnique()
172 | .HasName("UserNameIndex");
173 |
174 | b.ToTable("AspNetUsers");
175 | });
176 |
177 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRoleClaim", b =>
178 | {
179 | b.HasOne("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole")
180 | .WithMany("Claims")
181 | .HasForeignKey("RoleId")
182 | .OnDelete(DeleteBehavior.Cascade);
183 | });
184 |
185 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserClaim", b =>
186 | {
187 | b.HasOne("DosFactores.Models.ApplicationUser")
188 | .WithMany("Claims")
189 | .HasForeignKey("UserId")
190 | .OnDelete(DeleteBehavior.Cascade);
191 | });
192 |
193 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserLogin", b =>
194 | {
195 | b.HasOne("DosFactores.Models.ApplicationUser")
196 | .WithMany("Logins")
197 | .HasForeignKey("UserId")
198 | .OnDelete(DeleteBehavior.Cascade);
199 | });
200 |
201 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserRole", b =>
202 | {
203 | b.HasOne("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole")
204 | .WithMany("Users")
205 | .HasForeignKey("RoleId")
206 | .OnDelete(DeleteBehavior.Cascade);
207 |
208 | b.HasOne("DosFactores.Models.ApplicationUser")
209 | .WithMany("Roles")
210 | .HasForeignKey("UserId")
211 | .OnDelete(DeleteBehavior.Cascade);
212 | });
213 | }
214 | }
215 | }
216 |
--------------------------------------------------------------------------------
/DosFactores/Data/Migrations/00000000000000_CreateIdentitySchema.Designer.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using Microsoft.EntityFrameworkCore;
6 | using Microsoft.EntityFrameworkCore.Infrastructure;
7 | using Microsoft.EntityFrameworkCore.Metadata;
8 | using Microsoft.EntityFrameworkCore.Migrations;
9 |
10 | namespace DosFactores.Data.Migrations
11 | {
12 | [DbContext(typeof(ApplicationDbContext))]
13 | [Migration("00000000000000_CreateIdentitySchema")]
14 | partial class CreateIdentitySchema
15 | {
16 | protected override void BuildTargetModel(ModelBuilder modelBuilder)
17 | {
18 | modelBuilder
19 | .HasAnnotation("ProductVersion", "1.0.0-rc3")
20 | .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
21 |
22 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole", b =>
23 | {
24 | b.Property("Id");
25 |
26 | b.Property("ConcurrencyStamp")
27 | .IsConcurrencyToken();
28 |
29 | b.Property("Name")
30 | .HasAnnotation("MaxLength", 256);
31 |
32 | b.Property("NormalizedName")
33 | .HasAnnotation("MaxLength", 256);
34 |
35 | b.HasKey("Id");
36 |
37 | b.HasIndex("NormalizedName")
38 | .HasName("RoleNameIndex");
39 |
40 | b.ToTable("AspNetRoles");
41 | });
42 |
43 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRoleClaim", b =>
44 | {
45 | b.Property("Id")
46 | .ValueGeneratedOnAdd();
47 |
48 | b.Property("ClaimType");
49 |
50 | b.Property("ClaimValue");
51 |
52 | b.Property("RoleId")
53 | .IsRequired();
54 |
55 | b.HasKey("Id");
56 |
57 | b.HasIndex("RoleId");
58 |
59 | b.ToTable("AspNetRoleClaims");
60 | });
61 |
62 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserClaim", b =>
63 | {
64 | b.Property("Id")
65 | .ValueGeneratedOnAdd();
66 |
67 | b.Property("ClaimType");
68 |
69 | b.Property("ClaimValue");
70 |
71 | b.Property("UserId")
72 | .IsRequired();
73 |
74 | b.HasKey("Id");
75 |
76 | b.HasIndex("UserId");
77 |
78 | b.ToTable("AspNetUserClaims");
79 | });
80 |
81 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserLogin", b =>
82 | {
83 | b.Property("LoginProvider");
84 |
85 | b.Property("ProviderKey");
86 |
87 | b.Property("ProviderDisplayName");
88 |
89 | b.Property("UserId")
90 | .IsRequired();
91 |
92 | b.HasKey("LoginProvider", "ProviderKey");
93 |
94 | b.HasIndex("UserId");
95 |
96 | b.ToTable("AspNetUserLogins");
97 | });
98 |
99 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserRole", b =>
100 | {
101 | b.Property("UserId");
102 |
103 | b.Property("RoleId");
104 |
105 | b.HasKey("UserId", "RoleId");
106 |
107 | b.HasIndex("RoleId");
108 |
109 | b.HasIndex("UserId");
110 |
111 | b.ToTable("AspNetUserRoles");
112 | });
113 |
114 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserToken", b =>
115 | {
116 | b.Property("UserId");
117 |
118 | b.Property("LoginProvider");
119 |
120 | b.Property("Name");
121 |
122 | b.Property("Value");
123 |
124 | b.HasKey("UserId", "LoginProvider", "Name");
125 |
126 | b.ToTable("AspNetUserTokens");
127 | });
128 |
129 | modelBuilder.Entity("DosFactores.Models.ApplicationUser", b =>
130 | {
131 | b.Property("Id");
132 |
133 | b.Property("AccessFailedCount");
134 |
135 | b.Property("ConcurrencyStamp")
136 | .IsConcurrencyToken();
137 |
138 | b.Property("Email")
139 | .HasAnnotation("MaxLength", 256);
140 |
141 | b.Property("EmailConfirmed");
142 |
143 | b.Property("LockoutEnabled");
144 |
145 | b.Property("LockoutEnd");
146 |
147 | b.Property("NormalizedEmail")
148 | .HasAnnotation("MaxLength", 256);
149 |
150 | b.Property("NormalizedUserName")
151 | .HasAnnotation("MaxLength", 256);
152 |
153 | b.Property("PasswordHash");
154 |
155 | b.Property("PhoneNumber");
156 |
157 | b.Property("PhoneNumberConfirmed");
158 |
159 | b.Property("SecurityStamp");
160 |
161 | b.Property("TwoFactorEnabled");
162 |
163 | b.Property("UserName")
164 | .HasAnnotation("MaxLength", 256);
165 |
166 | b.HasKey("Id");
167 |
168 | b.HasIndex("NormalizedEmail")
169 | .HasName("EmailIndex");
170 |
171 | b.HasIndex("NormalizedUserName")
172 | .IsUnique()
173 | .HasName("UserNameIndex");
174 |
175 | b.ToTable("AspNetUsers");
176 | });
177 |
178 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRoleClaim", b =>
179 | {
180 | b.HasOne("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole")
181 | .WithMany("Claims")
182 | .HasForeignKey("RoleId")
183 | .OnDelete(DeleteBehavior.Cascade);
184 | });
185 |
186 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserClaim", b =>
187 | {
188 | b.HasOne("DosFactores.Models.ApplicationUser")
189 | .WithMany("Claims")
190 | .HasForeignKey("UserId")
191 | .OnDelete(DeleteBehavior.Cascade);
192 | });
193 |
194 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserLogin", b =>
195 | {
196 | b.HasOne("DosFactores.Models.ApplicationUser")
197 | .WithMany("Logins")
198 | .HasForeignKey("UserId")
199 | .OnDelete(DeleteBehavior.Cascade);
200 | });
201 |
202 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserRole", b =>
203 | {
204 | b.HasOne("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole")
205 | .WithMany("Users")
206 | .HasForeignKey("RoleId")
207 | .OnDelete(DeleteBehavior.Cascade);
208 |
209 | b.HasOne("DosFactores.Models.ApplicationUser")
210 | .WithMany("Roles")
211 | .HasForeignKey("UserId")
212 | .OnDelete(DeleteBehavior.Cascade);
213 | });
214 | }
215 | }
216 | }
217 |
--------------------------------------------------------------------------------
/DosFactores/wwwroot/images/banner1.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/DosFactores/Data/Migrations/00000000000000_CreateIdentitySchema.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using Microsoft.EntityFrameworkCore.Metadata;
6 | using Microsoft.EntityFrameworkCore.Migrations;
7 |
8 | namespace DosFactores.Data.Migrations
9 | {
10 | public partial class CreateIdentitySchema : Migration
11 | {
12 | protected override void Up(MigrationBuilder migrationBuilder)
13 | {
14 | migrationBuilder.CreateTable(
15 | name: "AspNetRoles",
16 | columns: table => new
17 | {
18 | Id = table.Column(nullable: false),
19 | ConcurrencyStamp = table.Column(nullable: true),
20 | Name = table.Column(maxLength: 256, nullable: true),
21 | NormalizedName = table.Column(maxLength: 256, nullable: true)
22 | },
23 | constraints: table =>
24 | {
25 | table.PrimaryKey("PK_AspNetRoles", x => x.Id);
26 | });
27 |
28 | migrationBuilder.CreateTable(
29 | name: "AspNetUserTokens",
30 | columns: table => new
31 | {
32 | UserId = table.Column(nullable: false),
33 | LoginProvider = table.Column(nullable: false),
34 | Name = table.Column(nullable: false),
35 | Value = table.Column(nullable: true)
36 | },
37 | constraints: table =>
38 | {
39 | table.PrimaryKey("PK_AspNetUserTokens", x => new { x.UserId, x.LoginProvider, x.Name });
40 | });
41 |
42 | migrationBuilder.CreateTable(
43 | name: "AspNetUsers",
44 | columns: table => new
45 | {
46 | Id = table.Column(nullable: false),
47 | AccessFailedCount = table.Column(nullable: false),
48 | ConcurrencyStamp = table.Column(nullable: true),
49 | Email = table.Column(maxLength: 256, nullable: true),
50 | EmailConfirmed = table.Column(nullable: false),
51 | LockoutEnabled = table.Column(nullable: false),
52 | LockoutEnd = table.Column(nullable: true),
53 | NormalizedEmail = table.Column(maxLength: 256, nullable: true),
54 | NormalizedUserName = table.Column(maxLength: 256, nullable: true),
55 | PasswordHash = table.Column(nullable: true),
56 | PhoneNumber = table.Column(nullable: true),
57 | PhoneNumberConfirmed = table.Column(nullable: false),
58 | SecurityStamp = table.Column(nullable: true),
59 | TwoFactorEnabled = table.Column(nullable: false),
60 | TfaKey = table.Column(maxLength: 32, nullable: true),
61 | UserName = table.Column(maxLength: 256, nullable: true)
62 | },
63 | constraints: table =>
64 | {
65 | table.PrimaryKey("PK_AspNetUsers", x => x.Id);
66 | });
67 |
68 | migrationBuilder.CreateTable(
69 | name: "AspNetRoleClaims",
70 | columns: table => new
71 | {
72 | Id = table.Column(nullable: false)
73 | .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn),
74 | ClaimType = table.Column(nullable: true),
75 | ClaimValue = table.Column(nullable: true),
76 | RoleId = table.Column(nullable: false)
77 | },
78 | constraints: table =>
79 | {
80 | table.PrimaryKey("PK_AspNetRoleClaims", x => x.Id);
81 | table.ForeignKey(
82 | name: "FK_AspNetRoleClaims_AspNetRoles_RoleId",
83 | column: x => x.RoleId,
84 | principalTable: "AspNetRoles",
85 | principalColumn: "Id",
86 | onDelete: ReferentialAction.Cascade);
87 | });
88 |
89 | migrationBuilder.CreateTable(
90 | name: "AspNetUserClaims",
91 | columns: table => new
92 | {
93 | Id = table.Column(nullable: false)
94 | .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn),
95 | ClaimType = table.Column(nullable: true),
96 | ClaimValue = table.Column(nullable: true),
97 | UserId = table.Column(nullable: false)
98 | },
99 | constraints: table =>
100 | {
101 | table.PrimaryKey("PK_AspNetUserClaims", x => x.Id);
102 | table.ForeignKey(
103 | name: "FK_AspNetUserClaims_AspNetUsers_UserId",
104 | column: x => x.UserId,
105 | principalTable: "AspNetUsers",
106 | principalColumn: "Id",
107 | onDelete: ReferentialAction.Cascade);
108 | });
109 |
110 | migrationBuilder.CreateTable(
111 | name: "AspNetUserLogins",
112 | columns: table => new
113 | {
114 | LoginProvider = table.Column(nullable: false),
115 | ProviderKey = table.Column(nullable: false),
116 | ProviderDisplayName = table.Column(nullable: true),
117 | UserId = table.Column(nullable: false)
118 | },
119 | constraints: table =>
120 | {
121 | table.PrimaryKey("PK_AspNetUserLogins", x => new { x.LoginProvider, x.ProviderKey });
122 | table.ForeignKey(
123 | name: "FK_AspNetUserLogins_AspNetUsers_UserId",
124 | column: x => x.UserId,
125 | principalTable: "AspNetUsers",
126 | principalColumn: "Id",
127 | onDelete: ReferentialAction.Cascade);
128 | });
129 |
130 | migrationBuilder.CreateTable(
131 | name: "AspNetUserRoles",
132 | columns: table => new
133 | {
134 | UserId = table.Column(nullable: false),
135 | RoleId = table.Column(nullable: false)
136 | },
137 | constraints: table =>
138 | {
139 | table.PrimaryKey("PK_AspNetUserRoles", x => new { x.UserId, x.RoleId });
140 | table.ForeignKey(
141 | name: "FK_AspNetUserRoles_AspNetRoles_RoleId",
142 | column: x => x.RoleId,
143 | principalTable: "AspNetRoles",
144 | principalColumn: "Id",
145 | onDelete: ReferentialAction.Cascade);
146 | table.ForeignKey(
147 | name: "FK_AspNetUserRoles_AspNetUsers_UserId",
148 | column: x => x.UserId,
149 | principalTable: "AspNetUsers",
150 | principalColumn: "Id",
151 | onDelete: ReferentialAction.Cascade);
152 | });
153 |
154 | migrationBuilder.CreateIndex(
155 | name: "RoleNameIndex",
156 | table: "AspNetRoles",
157 | column: "NormalizedName");
158 |
159 | migrationBuilder.CreateIndex(
160 | name: "IX_AspNetRoleClaims_RoleId",
161 | table: "AspNetRoleClaims",
162 | column: "RoleId");
163 |
164 | migrationBuilder.CreateIndex(
165 | name: "IX_AspNetUserClaims_UserId",
166 | table: "AspNetUserClaims",
167 | column: "UserId");
168 |
169 | migrationBuilder.CreateIndex(
170 | name: "IX_AspNetUserLogins_UserId",
171 | table: "AspNetUserLogins",
172 | column: "UserId");
173 |
174 | migrationBuilder.CreateIndex(
175 | name: "IX_AspNetUserRoles_RoleId",
176 | table: "AspNetUserRoles",
177 | column: "RoleId");
178 |
179 | migrationBuilder.CreateIndex(
180 | name: "IX_AspNetUserRoles_UserId",
181 | table: "AspNetUserRoles",
182 | column: "UserId");
183 |
184 | migrationBuilder.CreateIndex(
185 | name: "EmailIndex",
186 | table: "AspNetUsers",
187 | column: "NormalizedEmail");
188 |
189 | migrationBuilder.CreateIndex(
190 | name: "UserNameIndex",
191 | table: "AspNetUsers",
192 | column: "NormalizedUserName",
193 | unique: true);
194 | }
195 |
196 | protected override void Down(MigrationBuilder migrationBuilder)
197 | {
198 | migrationBuilder.DropTable(
199 | name: "AspNetRoleClaims");
200 |
201 | migrationBuilder.DropTable(
202 | name: "AspNetUserClaims");
203 |
204 | migrationBuilder.DropTable(
205 | name: "AspNetUserLogins");
206 |
207 | migrationBuilder.DropTable(
208 | name: "AspNetUserRoles");
209 |
210 | migrationBuilder.DropTable(
211 | name: "AspNetUserTokens");
212 |
213 | migrationBuilder.DropTable(
214 | name: "AspNetRoles");
215 |
216 | migrationBuilder.DropTable(
217 | name: "AspNetUsers");
218 | }
219 | }
220 | }
221 |
--------------------------------------------------------------------------------
/DosFactores/wwwroot/images/banner3.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/DosFactores/wwwroot/images/banner4.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Google.Authenticator/TwoFactorAuthentication.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Security.Cryptography;
5 | using System.Text;
6 |
7 | namespace Google.Authenticator
8 | {
9 | public class TwoFactorAuthenticator
10 | {
11 | public static DateTime _epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
12 | public TimeSpan DefaultClockDriftTolerance { get; set; }
13 | public bool UseManagedSha1Algorithm { get; set; }
14 | public bool TryUnmanagedAlgorithmOnFailure { get; set; }
15 |
16 | public TwoFactorAuthenticator() : this(true, true) { }
17 |
18 | public TwoFactorAuthenticator(bool useManagedSha1, bool useUnmanagedOnFail)
19 | {
20 | DefaultClockDriftTolerance = TimeSpan.FromMinutes(5);
21 | UseManagedSha1Algorithm = useManagedSha1;
22 | TryUnmanagedAlgorithmOnFailure = useUnmanagedOnFail;
23 | }
24 |
25 | ///
26 | /// Generate a setup code for a Google Authenticator user to scan.
27 | ///
28 | /// Account Title (no spaces)
29 | /// Account Secret Key
30 | /// QR Code Width
31 | /// QR Code Height
32 | /// SetupCode object
33 | public SetupCode GenerateSetupCode(string accountTitleNoSpaces, string accountSecretKey, int qrCodeWidth, int qrCodeHeight)
34 | {
35 | return GenerateSetupCode(null, accountTitleNoSpaces, accountSecretKey, qrCodeWidth, qrCodeHeight);
36 | }
37 |
38 | ///
39 | /// Generate a setup code for a Google Authenticator user to scan (with issuer ID).
40 | ///
41 | /// Issuer ID (the name of the system, i.e. 'MyApp')
42 | /// Account Title (no spaces)
43 | /// Account Secret Key
44 | /// QR Code Width
45 | /// QR Code Height
46 | /// SetupCode object
47 | public SetupCode GenerateSetupCode(string issuer, string accountTitleNoSpaces, string accountSecretKey, int qrCodeWidth, int qrCodeHeight)
48 | {
49 | return GenerateSetupCode(issuer, accountTitleNoSpaces, accountSecretKey, qrCodeWidth, qrCodeHeight, false);
50 | }
51 |
52 | ///
53 | /// Generate a setup code for a Google Authenticator user to scan (with issuer ID).
54 | ///
55 | /// Issuer ID (the name of the system, i.e. 'MyApp')
56 | /// Account Title (no spaces)
57 | /// Account Secret Key
58 | /// QR Code Width
59 | /// QR Code Height
60 | /// Use HTTPS instead of HTTP
61 | /// SetupCode object
62 | public SetupCode GenerateSetupCode(string issuer, string accountTitleNoSpaces, string accountSecretKey, int qrCodeWidth, int qrCodeHeight, bool useHttps)
63 | {
64 | if (accountTitleNoSpaces == null) { throw new NullReferenceException("Account Title is null"); }
65 |
66 | accountTitleNoSpaces = accountTitleNoSpaces.Replace(" ", "");
67 |
68 | SetupCode sC = new SetupCode();
69 | sC.Account = accountTitleNoSpaces;
70 | sC.AccountSecretKey = accountSecretKey;
71 |
72 | string encodedSecretKey = EncodeAccountSecretKey(accountSecretKey);
73 | sC.ManualEntryKey = encodedSecretKey;
74 |
75 | string provisionUrl = null;
76 |
77 | if (string.IsNullOrEmpty(issuer))
78 | {
79 | provisionUrl = UrlEncode(String.Format("otpauth://totp/{0}?secret={1}", accountTitleNoSpaces, encodedSecretKey));
80 | }
81 | else
82 | {
83 | provisionUrl = UrlEncode(String.Format("otpauth://totp/{0}?secret={1}&issuer={2}", accountTitleNoSpaces, encodedSecretKey, UrlEncode(issuer)));
84 | }
85 |
86 | string protocol = useHttps ? "https" : "http";
87 | string url = String.Format("{0}://chart.googleapis.com/chart?cht=qr&chs={1}x{2}&chl={3}", protocol, qrCodeWidth, qrCodeHeight, provisionUrl);
88 |
89 | sC.QrCodeSetupImageUrl = url;
90 |
91 | return sC;
92 | }
93 |
94 | private string UrlEncode(string value)
95 | {
96 | StringBuilder result = new StringBuilder();
97 | string validChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.~";
98 |
99 | foreach (char symbol in value)
100 | {
101 | if (validChars.IndexOf(symbol) != -1)
102 | {
103 | result.Append(symbol);
104 | }
105 | else
106 | {
107 | result.Append('%' + String.Format("{0:X2}", (int)symbol));
108 | }
109 | }
110 |
111 | return result.ToString().Replace(" ", "%20");
112 | }
113 |
114 | private string EncodeAccountSecretKey(string accountSecretKey)
115 | {
116 | //if (accountSecretKey.Length < 10)
117 | //{
118 | // accountSecretKey = accountSecretKey.PadRight(10, '0');
119 | //}
120 |
121 | //if (accountSecretKey.Length > 12)
122 | //{
123 | // accountSecretKey = accountSecretKey.Substring(0, 12);
124 | //}
125 |
126 | return Base32Encode(Encoding.UTF8.GetBytes(accountSecretKey));
127 | }
128 |
129 | private string Base32Encode(byte[] data)
130 | {
131 | int inByteSize = 8;
132 | int outByteSize = 5;
133 | char[] alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567".ToCharArray();
134 |
135 | int i = 0, index = 0, digit = 0;
136 | int current_byte, next_byte;
137 | StringBuilder result = new StringBuilder((data.Length + 7) * inByteSize / outByteSize);
138 |
139 | while (i < data.Length)
140 | {
141 | current_byte = (data[i] >= 0) ? data[i] : (data[i] + 256); // Unsign
142 |
143 | /* Is the current digit going to span a byte boundary? */
144 | if (index > (inByteSize - outByteSize))
145 | {
146 | if ((i + 1) < data.Length)
147 | next_byte = (data[i + 1] >= 0) ? data[i + 1] : (data[i + 1] + 256);
148 | else
149 | next_byte = 0;
150 |
151 | digit = current_byte & (0xFF >> index);
152 | index = (index + outByteSize) % inByteSize;
153 | digit <<= index;
154 | digit |= next_byte >> (inByteSize - index);
155 | i++;
156 | }
157 | else
158 | {
159 | digit = (current_byte >> (inByteSize - (index + outByteSize))) & 0x1F;
160 | index = (index + outByteSize) % inByteSize;
161 | if (index == 0)
162 | i++;
163 | }
164 | result.Append(alphabet[digit]);
165 | }
166 |
167 | return result.ToString();
168 | }
169 |
170 | public string GeneratePINAtInterval(string accountSecretKey, long counter, int digits = 6)
171 | {
172 | return GenerateHashedCode(accountSecretKey, counter, digits);
173 | }
174 |
175 | internal string GenerateHashedCode(string secret, long iterationNumber, int digits = 6)
176 | {
177 | byte[] key = Encoding.UTF8.GetBytes(secret);
178 | return GenerateHashedCode(key, iterationNumber, digits);
179 | }
180 |
181 | internal string GenerateHashedCode(byte[] key, long iterationNumber, int digits = 6)
182 | {
183 | byte[] counter = BitConverter.GetBytes(iterationNumber);
184 |
185 | if (BitConverter.IsLittleEndian)
186 | {
187 | Array.Reverse(counter);
188 | }
189 |
190 | HMACSHA1 hmac = getHMACSha1Algorithm(key);
191 |
192 | byte[] hash = hmac.ComputeHash(counter);
193 |
194 | int offset = hash[hash.Length - 1] & 0xf;
195 |
196 | // Convert the 4 bytes into an integer, ignoring the sign.
197 | int binary =
198 | ((hash[offset] & 0x7f) << 24)
199 | | (hash[offset + 1] << 16)
200 | | (hash[offset + 2] << 8)
201 | | (hash[offset + 3]);
202 |
203 | int password = binary % (int)Math.Pow(10, digits);
204 | return password.ToString(new string('0', digits));
205 | }
206 |
207 | private long GetCurrentCounter()
208 | {
209 | return GetCurrentCounter(DateTime.UtcNow, _epoch, 30);
210 | }
211 |
212 | private long GetCurrentCounter(DateTime now, DateTime epoch, int timeStep)
213 | {
214 | return (long)(now - epoch).TotalSeconds / timeStep;
215 | }
216 |
217 | ///
218 | /// Creates a HMACSHA1 algorithm to use to hash the counter bytes. By default, this will attempt to use
219 | /// the managed SHA1 class (SHA1Manager) and on exception (FIPS-compliant machine policy, etc) will attempt
220 | /// to use the unmanaged SHA1 class (SHA1CryptoServiceProvider).
221 | ///
222 | /// User's secret key, in bytes
223 | /// HMACSHA1 cryptographic algorithm
224 | private HMACSHA1 getHMACSha1Algorithm(byte[] key)
225 | {
226 | HMACSHA1 hmac;
227 |
228 | try
229 | {
230 | hmac = new HMACSHA1(key);//, UseManagedSha1Algorithm);
231 | }
232 | catch (InvalidOperationException ioe)
233 | {
234 | if (UseManagedSha1Algorithm && TryUnmanagedAlgorithmOnFailure)
235 | {
236 | try
237 | {
238 | hmac = new HMACSHA1(key);
239 | }
240 | catch (InvalidOperationException ioe2)
241 | {
242 | throw ioe2;
243 | }
244 | }
245 | else
246 | {
247 | throw ioe;
248 | }
249 | }
250 |
251 | return hmac;
252 | }
253 |
254 | public bool ValidateTwoFactorPIN(string accountSecretKey, string twoFactorCodeFromClient)
255 | {
256 | return ValidateTwoFactorPIN(accountSecretKey, twoFactorCodeFromClient, DefaultClockDriftTolerance);
257 | }
258 |
259 | public bool ValidateTwoFactorPIN(string accountSecretKey, string twoFactorCodeFromClient, TimeSpan timeTolerance)
260 | {
261 | var codes = GetCurrentPINs(accountSecretKey, timeTolerance);
262 | return codes.Any(c => c == twoFactorCodeFromClient);
263 | }
264 |
265 | public string GetCurrentPIN(string accountSecretKey)
266 | {
267 | return GeneratePINAtInterval(accountSecretKey, GetCurrentCounter());
268 | }
269 |
270 | public string GetCurrentPIN(string accountSecretKey, DateTime now)
271 | {
272 | return GeneratePINAtInterval(accountSecretKey, GetCurrentCounter(now, _epoch, 30));
273 | }
274 |
275 | public string[] GetCurrentPINs(string accountSecretKey)
276 | {
277 | return GetCurrentPINs(accountSecretKey, DefaultClockDriftTolerance);
278 | }
279 |
280 | public string[] GetCurrentPINs(string accountSecretKey, TimeSpan timeTolerance)
281 | {
282 | List codes = new List();
283 | long iterationCounter = GetCurrentCounter();
284 | int iterationOffset = 0;
285 |
286 | if (timeTolerance.TotalSeconds > 30)
287 | {
288 | iterationOffset = Convert.ToInt32(timeTolerance.TotalSeconds / 30.00);
289 | }
290 |
291 | long iterationStart = iterationCounter - iterationOffset;
292 | long iterationEnd = iterationCounter + iterationOffset;
293 |
294 | for (long counter = iterationStart; counter <= iterationEnd; counter++)
295 | {
296 | codes.Add(GeneratePINAtInterval(accountSecretKey, counter));
297 | }
298 |
299 | return codes.ToArray();
300 | }
301 | }
302 | }
303 |
--------------------------------------------------------------------------------
/DosFactores/wwwroot/lib/jquery-validation/dist/additional-methods.min.js:
--------------------------------------------------------------------------------
1 | /*! jQuery Validation Plugin - v1.14.0 - 6/30/2015
2 | * http://jqueryvalidation.org/
3 | * Copyright (c) 2015 Jörn Zaefferer; Licensed MIT */
4 | !function(a){"function"==typeof define&&define.amd?define(["jquery","./jquery.validate.min"],a):a(jQuery)}(function(a){!function(){function b(a){return a.replace(/<.[^<>]*?>/g," ").replace(/ | /gi," ").replace(/[.(),;:!?%#$'\"_+=\/\-“”’]*/g,"")}a.validator.addMethod("maxWords",function(a,c,d){return this.optional(c)||b(a).match(/\b\w+\b/g).length<=d},a.validator.format("Please enter {0} words or less.")),a.validator.addMethod("minWords",function(a,c,d){return this.optional(c)||b(a).match(/\b\w+\b/g).length>=d},a.validator.format("Please enter at least {0} words.")),a.validator.addMethod("rangeWords",function(a,c,d){var e=b(a),f=/\b\w+\b/g;return this.optional(c)||e.match(f).length>=d[0]&&e.match(f).length<=d[1]},a.validator.format("Please enter between {0} and {1} words."))}(),a.validator.addMethod("accept",function(b,c,d){var e,f,g="string"==typeof d?d.replace(/\s/g,"").replace(/,/g,"|"):"image/*",h=this.optional(c);if(h)return h;if("file"===a(c).attr("type")&&(g=g.replace(/\*/g,".*"),c.files&&c.files.length))for(e=0;ec;c++)d=h-c,e=f.substring(c,c+1),g+=d*e;return g%11===0},"Please specify a valid bank account number"),a.validator.addMethod("bankorgiroaccountNL",function(b,c){return this.optional(c)||a.validator.methods.bankaccountNL.call(this,b,c)||a.validator.methods.giroaccountNL.call(this,b,c)},"Please specify a valid bank or giro account number"),a.validator.addMethod("bic",function(a,b){return this.optional(b)||/^([A-Z]{6}[A-Z2-9][A-NP-Z1-2])(X{3}|[A-WY-Z0-9][A-Z0-9]{2})?$/.test(a)},"Please specify a valid BIC code"),a.validator.addMethod("cifES",function(a){"use strict";var b,c,d,e,f,g,h=[];if(a=a.toUpperCase(),!a.match("((^[A-Z]{1}[0-9]{7}[A-Z0-9]{1}$|^[T]{1}[A-Z0-9]{8}$)|^[0-9]{8}[A-Z]{1}$)"))return!1;for(d=0;9>d;d++)h[d]=parseInt(a.charAt(d),10);for(c=h[2]+h[4]+h[6],e=1;8>e;e+=2)f=(2*h[e]).toString(),g=f.charAt(1),c+=parseInt(f.charAt(0),10)+(""===g?0:parseInt(g,10));return/^[ABCDEFGHJNPQRSUVW]{1}/.test(a)?(c+="",b=10-parseInt(c.charAt(c.length-1),10),a+=b,h[8].toString()===String.fromCharCode(64+b)||h[8].toString()===a.charAt(a.length-1)):!1},"Please specify a valid CIF number."),a.validator.addMethod("cpfBR",function(a){if(a=a.replace(/([~!@#$%^&*()_+=`{}\[\]\-|\\:;'<>,.\/? ])+/g,""),11!==a.length)return!1;var b,c,d,e,f=0;if(b=parseInt(a.substring(9,10),10),c=parseInt(a.substring(10,11),10),d=function(a,b){var c=10*a%11;return(10===c||11===c)&&(c=0),c===b},""===a||"00000000000"===a||"11111111111"===a||"22222222222"===a||"33333333333"===a||"44444444444"===a||"55555555555"===a||"66666666666"===a||"77777777777"===a||"88888888888"===a||"99999999999"===a)return!1;for(e=1;9>=e;e++)f+=parseInt(a.substring(e-1,e),10)*(11-e);if(d(f,b)){for(f=0,e=1;10>=e;e++)f+=parseInt(a.substring(e-1,e),10)*(12-e);return d(f,c)}return!1},"Please specify a valid CPF number"),a.validator.addMethod("creditcardtypes",function(a,b,c){if(/[^0-9\-]+/.test(a))return!1;a=a.replace(/\D/g,"");var d=0;return c.mastercard&&(d|=1),c.visa&&(d|=2),c.amex&&(d|=4),c.dinersclub&&(d|=8),c.enroute&&(d|=16),c.discover&&(d|=32),c.jcb&&(d|=64),c.unknown&&(d|=128),c.all&&(d=255),1&d&&/^(5[12345])/.test(a)?16===a.length:2&d&&/^(4)/.test(a)?16===a.length:4&d&&/^(3[47])/.test(a)?15===a.length:8&d&&/^(3(0[012345]|[68]))/.test(a)?14===a.length:16&d&&/^(2(014|149))/.test(a)?15===a.length:32&d&&/^(6011)/.test(a)?16===a.length:64&d&&/^(3)/.test(a)?16===a.length:64&d&&/^(2131|1800)/.test(a)?15===a.length:128&d?!0:!1},"Please enter a valid credit card number."),a.validator.addMethod("currency",function(a,b,c){var d,e="string"==typeof c,f=e?c:c[0],g=e?!0:c[1];return f=f.replace(/,/g,""),f=g?f+"]":f+"]?",d="^["+f+"([1-9]{1}[0-9]{0,2}(\\,[0-9]{3})*(\\.[0-9]{0,2})?|[1-9]{1}[0-9]{0,}(\\.[0-9]{0,2})?|0(\\.[0-9]{0,2})?|(\\.[0-9]{1,2})?)$",d=new RegExp(d),this.optional(b)||d.test(a)},"Please specify a valid currency"),a.validator.addMethod("dateFA",function(a,b){return this.optional(b)||/^[1-4]\d{3}\/((0?[1-6]\/((3[0-1])|([1-2][0-9])|(0?[1-9])))|((1[0-2]|(0?[7-9]))\/(30|([1-2][0-9])|(0?[1-9]))))$/.test(a)},a.validator.messages.date),a.validator.addMethod("dateITA",function(a,b){var c,d,e,f,g,h=!1,i=/^\d{1,2}\/\d{1,2}\/\d{4}$/;return i.test(a)?(c=a.split("/"),d=parseInt(c[0],10),e=parseInt(c[1],10),f=parseInt(c[2],10),g=new Date(Date.UTC(f,e-1,d,12,0,0,0)),h=g.getUTCFullYear()===f&&g.getUTCMonth()===e-1&&g.getUTCDate()===d?!0:!1):h=!1,this.optional(b)||h},a.validator.messages.date),a.validator.addMethod("dateNL",function(a,b){return this.optional(b)||/^(0?[1-9]|[12]\d|3[01])[\.\/\-](0?[1-9]|1[012])[\.\/\-]([12]\d)?(\d\d)$/.test(a)},a.validator.messages.date),a.validator.addMethod("extension",function(a,b,c){return c="string"==typeof c?c.replace(/,/g,"|"):"png|jpe?g|gif",this.optional(b)||a.match(new RegExp("\\.("+c+")$","i"))},a.validator.format("Please enter a value with a valid extension.")),a.validator.addMethod("giroaccountNL",function(a,b){return this.optional(b)||/^[0-9]{1,7}$/.test(a)},"Please specify a valid giro account number"),a.validator.addMethod("iban",function(a,b){if(this.optional(b))return!0;var c,d,e,f,g,h,i,j,k,l=a.replace(/ /g,"").toUpperCase(),m="",n=!0,o="",p="";if(c=l.substring(0,2),h={AL:"\\d{8}[\\dA-Z]{16}",AD:"\\d{8}[\\dA-Z]{12}",AT:"\\d{16}",AZ:"[\\dA-Z]{4}\\d{20}",BE:"\\d{12}",BH:"[A-Z]{4}[\\dA-Z]{14}",BA:"\\d{16}",BR:"\\d{23}[A-Z][\\dA-Z]",BG:"[A-Z]{4}\\d{6}[\\dA-Z]{8}",CR:"\\d{17}",HR:"\\d{17}",CY:"\\d{8}[\\dA-Z]{16}",CZ:"\\d{20}",DK:"\\d{14}",DO:"[A-Z]{4}\\d{20}",EE:"\\d{16}",FO:"\\d{14}",FI:"\\d{14}",FR:"\\d{10}[\\dA-Z]{11}\\d{2}",GE:"[\\dA-Z]{2}\\d{16}",DE:"\\d{18}",GI:"[A-Z]{4}[\\dA-Z]{15}",GR:"\\d{7}[\\dA-Z]{16}",GL:"\\d{14}",GT:"[\\dA-Z]{4}[\\dA-Z]{20}",HU:"\\d{24}",IS:"\\d{22}",IE:"[\\dA-Z]{4}\\d{14}",IL:"\\d{19}",IT:"[A-Z]\\d{10}[\\dA-Z]{12}",KZ:"\\d{3}[\\dA-Z]{13}",KW:"[A-Z]{4}[\\dA-Z]{22}",LV:"[A-Z]{4}[\\dA-Z]{13}",LB:"\\d{4}[\\dA-Z]{20}",LI:"\\d{5}[\\dA-Z]{12}",LT:"\\d{16}",LU:"\\d{3}[\\dA-Z]{13}",MK:"\\d{3}[\\dA-Z]{10}\\d{2}",MT:"[A-Z]{4}\\d{5}[\\dA-Z]{18}",MR:"\\d{23}",MU:"[A-Z]{4}\\d{19}[A-Z]{3}",MC:"\\d{10}[\\dA-Z]{11}\\d{2}",MD:"[\\dA-Z]{2}\\d{18}",ME:"\\d{18}",NL:"[A-Z]{4}\\d{10}",NO:"\\d{11}",PK:"[\\dA-Z]{4}\\d{16}",PS:"[\\dA-Z]{4}\\d{21}",PL:"\\d{24}",PT:"\\d{21}",RO:"[A-Z]{4}[\\dA-Z]{16}",SM:"[A-Z]\\d{10}[\\dA-Z]{12}",SA:"\\d{2}[\\dA-Z]{18}",RS:"\\d{18}",SK:"\\d{20}",SI:"\\d{15}",ES:"\\d{20}",SE:"\\d{20}",CH:"\\d{5}[\\dA-Z]{12}",TN:"\\d{20}",TR:"\\d{5}[\\dA-Z]{17}",AE:"\\d{3}\\d{16}",GB:"[A-Z]{4}\\d{14}",VG:"[\\dA-Z]{4}\\d{16}"},g=h[c],"undefined"!=typeof g&&(i=new RegExp("^[A-Z]{2}\\d{2}"+g+"$",""),!i.test(l)))return!1;for(d=l.substring(4,l.length)+l.substring(0,4),j=0;j9&&a.match(/^(?:(?:(?:00\s?|\+)44\s?|0)7(?:[1345789]\d{2}|624)\s?\d{3}\s?\d{3})$/)},"Please specify a valid mobile number"),a.validator.addMethod("nieES",function(a){"use strict";return a=a.toUpperCase(),a.match("((^[A-Z]{1}[0-9]{7}[A-Z0-9]{1}$|^[T]{1}[A-Z0-9]{8}$)|^[0-9]{8}[A-Z]{1}$)")?/^[T]{1}/.test(a)?a[8]===/^[T]{1}[A-Z0-9]{8}$/.test(a):/^[XYZ]{1}/.test(a)?a[8]==="TRWAGMYFPDXBNJZSQVHLCKE".charAt(a.replace("X","0").replace("Y","1").replace("Z","2").substring(0,8)%23):!1:!1},"Please specify a valid NIE number."),a.validator.addMethod("nifES",function(a){"use strict";return a=a.toUpperCase(),a.match("((^[A-Z]{1}[0-9]{7}[A-Z0-9]{1}$|^[T]{1}[A-Z0-9]{8}$)|^[0-9]{8}[A-Z]{1}$)")?/^[0-9]{8}[A-Z]{1}$/.test(a)?"TRWAGMYFPDXBNJZSQVHLCKE".charAt(a.substring(8,0)%23)===a.charAt(8):/^[KLM]{1}/.test(a)?a[8]===String.fromCharCode(64):!1:!1},"Please specify a valid NIF number."),jQuery.validator.addMethod("notEqualTo",function(b,c,d){return this.optional(c)||!a.validator.methods.equalTo.call(this,b,c,d)},"Please enter a different value, values must not be the same."),a.validator.addMethod("nowhitespace",function(a,b){return this.optional(b)||/^\S+$/i.test(a)},"No white space please"),a.validator.addMethod("pattern",function(a,b,c){return this.optional(b)?!0:("string"==typeof c&&(c=new RegExp("^(?:"+c+")$")),c.test(a))},"Invalid format."),a.validator.addMethod("phoneNL",function(a,b){return this.optional(b)||/^((\+|00(\s|\s?\-\s?)?)31(\s|\s?\-\s?)?(\(0\)[\-\s]?)?|0)[1-9]((\s|\s?\-\s?)?[0-9]){8}$/.test(a)},"Please specify a valid phone number."),a.validator.addMethod("phoneUK",function(a,b){return a=a.replace(/\(|\)|\s+|-/g,""),this.optional(b)||a.length>9&&a.match(/^(?:(?:(?:00\s?|\+)44\s?)|(?:\(?0))(?:\d{2}\)?\s?\d{4}\s?\d{4}|\d{3}\)?\s?\d{3}\s?\d{3,4}|\d{4}\)?\s?(?:\d{5}|\d{3}\s?\d{3})|\d{5}\)?\s?\d{4,5})$/)},"Please specify a valid phone number"),a.validator.addMethod("phoneUS",function(a,b){return a=a.replace(/\s+/g,""),this.optional(b)||a.length>9&&a.match(/^(\+?1-?)?(\([2-9]([02-9]\d|1[02-9])\)|[2-9]([02-9]\d|1[02-9]))-?[2-9]([02-9]\d|1[02-9])-?\d{4}$/)},"Please specify a valid phone number"),a.validator.addMethod("phonesUK",function(a,b){return a=a.replace(/\(|\)|\s+|-/g,""),this.optional(b)||a.length>9&&a.match(/^(?:(?:(?:00\s?|\+)44\s?|0)(?:1\d{8,9}|[23]\d{9}|7(?:[1345789]\d{8}|624\d{6})))$/)},"Please specify a valid uk phone number"),a.validator.addMethod("postalCodeCA",function(a,b){return this.optional(b)||/^[ABCEGHJKLMNPRSTVXY]\d[A-Z] \d[A-Z]\d$/.test(a)},"Please specify a valid postal code"),a.validator.addMethod("postalcodeBR",function(a,b){return this.optional(b)||/^\d{2}.\d{3}-\d{3}?$|^\d{5}-?\d{3}?$/.test(a)},"Informe um CEP válido."),a.validator.addMethod("postalcodeIT",function(a,b){return this.optional(b)||/^\d{5}$/.test(a)},"Please specify a valid postal code"),a.validator.addMethod("postalcodeNL",function(a,b){return this.optional(b)||/^[1-9][0-9]{3}\s?[a-zA-Z]{2}$/.test(a)},"Please specify a valid postal code"),a.validator.addMethod("postcodeUK",function(a,b){return this.optional(b)||/^((([A-PR-UWYZ][0-9])|([A-PR-UWYZ][0-9][0-9])|([A-PR-UWYZ][A-HK-Y][0-9])|([A-PR-UWYZ][A-HK-Y][0-9][0-9])|([A-PR-UWYZ][0-9][A-HJKSTUW])|([A-PR-UWYZ][A-HK-Y][0-9][ABEHMNPRVWXY]))\s?([0-9][ABD-HJLNP-UW-Z]{2})|(GIR)\s?(0AA))$/i.test(a)},"Please specify a valid UK postcode"),a.validator.addMethod("require_from_group",function(b,c,d){var e=a(d[1],c.form),f=e.eq(0),g=f.data("valid_req_grp")?f.data("valid_req_grp"):a.extend({},this),h=e.filter(function(){return g.elementValue(this)}).length>=d[0];return f.data("valid_req_grp",g),a(c).data("being_validated")||(e.data("being_validated",!0),e.each(function(){g.element(this)}),e.data("being_validated",!1)),h},a.validator.format("Please fill at least {0} of these fields.")),a.validator.addMethod("skip_or_fill_minimum",function(b,c,d){var e=a(d[1],c.form),f=e.eq(0),g=f.data("valid_skip")?f.data("valid_skip"):a.extend({},this),h=e.filter(function(){return g.elementValue(this)}).length,i=0===h||h>=d[0];return f.data("valid_skip",g),a(c).data("being_validated")||(e.data("being_validated",!0),e.each(function(){g.element(this)}),e.data("being_validated",!1)),i},a.validator.format("Please either skip these fields or fill at least {0} of them.")),a.validator.addMethod("stateUS",function(a,b,c){var d,e="undefined"==typeof c,f=e||"undefined"==typeof c.caseSensitive?!1:c.caseSensitive,g=e||"undefined"==typeof c.includeTerritories?!1:c.includeTerritories,h=e||"undefined"==typeof c.includeMilitary?!1:c.includeMilitary;return d=g||h?g&&h?"^(A[AEKLPRSZ]|C[AOT]|D[CE]|FL|G[AU]|HI|I[ADLN]|K[SY]|LA|M[ADEINOPST]|N[CDEHJMVY]|O[HKR]|P[AR]|RI|S[CD]|T[NX]|UT|V[AIT]|W[AIVY])$":g?"^(A[KLRSZ]|C[AOT]|D[CE]|FL|G[AU]|HI|I[ADLN]|K[SY]|LA|M[ADEINOPST]|N[CDEHJMVY]|O[HKR]|P[AR]|RI|S[CD]|T[NX]|UT|V[AIT]|W[AIVY])$":"^(A[AEKLPRZ]|C[AOT]|D[CE]|FL|GA|HI|I[ADLN]|K[SY]|LA|M[ADEINOST]|N[CDEHJMVY]|O[HKR]|PA|RI|S[CD]|T[NX]|UT|V[AT]|W[AIVY])$":"^(A[KLRZ]|C[AOT]|D[CE]|FL|GA|HI|I[ADLN]|K[SY]|LA|M[ADEINOST]|N[CDEHJMVY]|O[HKR]|PA|RI|S[CD]|T[NX]|UT|V[AT]|W[AIVY])$",d=f?new RegExp(d):new RegExp(d,"i"),this.optional(b)||d.test(a)},"Please specify a valid state"),a.validator.addMethod("strippedminlength",function(b,c,d){return a(b).text().length>=d},a.validator.format("Please enter at least {0} characters")),a.validator.addMethod("time",function(a,b){return this.optional(b)||/^([01]\d|2[0-3]|[0-9])(:[0-5]\d){1,2}$/.test(a)},"Please enter a valid time, between 00:00 and 23:59"),a.validator.addMethod("time12h",function(a,b){return this.optional(b)||/^((0?[1-9]|1[012])(:[0-5]\d){1,2}(\ ?[AP]M))$/i.test(a)},"Please enter a valid time in 12-hour am/pm format"),a.validator.addMethod("url2",function(a,b){return this.optional(b)||/^(https?|ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)*(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i.test(a)},a.validator.messages.url),a.validator.addMethod("vinUS",function(a){if(17!==a.length)return!1;var b,c,d,e,f,g,h=["A","B","C","D","E","F","G","H","J","K","L","M","N","P","R","S","T","U","V","W","X","Y","Z"],i=[1,2,3,4,5,6,7,8,1,2,3,4,5,7,9,2,3,4,5,6,7,8,9],j=[8,7,6,5,4,3,2,10,0,9,8,7,6,5,4,3,2],k=0;for(b=0;17>b;b++){if(e=j[b],d=a.slice(b,b+1),8===b&&(g=d),isNaN(d)){for(c=0;c _userManager;
21 | private readonly SignInManager _signInManager;
22 | private readonly string _externalCookieScheme;
23 | private readonly IEmailSender _emailSender;
24 | private readonly ISmsSender _smsSender;
25 | private readonly ILogger _logger;
26 |
27 | public ManageController(
28 | UserManager userManager,
29 | SignInManager signInManager,
30 | IOptions identityCookieOptions,
31 | IEmailSender emailSender,
32 | ISmsSender smsSender,
33 | ILoggerFactory loggerFactory)
34 | {
35 | _userManager = userManager;
36 | _signInManager = signInManager;
37 | _externalCookieScheme = identityCookieOptions.Value.ExternalCookieAuthenticationScheme;
38 | _emailSender = emailSender;
39 | _smsSender = smsSender;
40 | _logger = loggerFactory.CreateLogger();
41 | }
42 |
43 | //
44 | // GET: /Manage/Index
45 | [HttpGet]
46 | public async Task Index(ManageMessageId? message = null)
47 | {
48 | ViewData["StatusMessage"] =
49 | message == ManageMessageId.ChangePasswordSuccess ? "Your password has been changed."
50 | : message == ManageMessageId.SetPasswordSuccess ? "Your password has been set."
51 | : message == ManageMessageId.SetTwoFactorSuccess ? "Your two-factor authentication provider has been set."
52 | : message == ManageMessageId.Error ? "An error has occurred."
53 | : message == ManageMessageId.AddPhoneSuccess ? "Your phone number was added."
54 | : message == ManageMessageId.RemovePhoneSuccess ? "Your phone number was removed."
55 | : "";
56 |
57 | var user = await GetCurrentUserAsync();
58 | if (user == null)
59 | {
60 | return View("Error");
61 | }
62 | var model = new IndexViewModel
63 | {
64 | TwoFactorAuthenticatorQrCode = TempData["AuthenticatorQr"]?.ToString(),
65 | HasPassword = await _userManager.HasPasswordAsync(user),
66 | PhoneNumber = await _userManager.GetPhoneNumberAsync(user),
67 | TwoFactor = await _userManager.GetTwoFactorEnabledAsync(user),
68 | Logins = await _userManager.GetLoginsAsync(user),
69 | BrowserRemembered = await _signInManager.IsTwoFactorClientRememberedAsync(user)
70 | };
71 | return View(model);
72 | }
73 |
74 | //
75 | // POST: /Manage/RemoveLogin
76 | [HttpPost]
77 | [ValidateAntiForgeryToken]
78 | public async Task RemoveLogin(RemoveLoginViewModel account)
79 | {
80 | ManageMessageId? message = ManageMessageId.Error;
81 | var user = await GetCurrentUserAsync();
82 | if (user != null)
83 | {
84 | var result = await _userManager.RemoveLoginAsync(user, account.LoginProvider, account.ProviderKey);
85 | if (result.Succeeded)
86 | {
87 | await _signInManager.SignInAsync(user, isPersistent: false);
88 | message = ManageMessageId.RemoveLoginSuccess;
89 | }
90 | }
91 | return RedirectToAction(nameof(ManageLogins), new { Message = message });
92 | }
93 |
94 | //
95 | // GET: /Manage/AddPhoneNumber
96 | public IActionResult AddPhoneNumber()
97 | {
98 | return View();
99 | }
100 |
101 | //
102 | // POST: /Manage/AddPhoneNumber
103 | [HttpPost]
104 | [ValidateAntiForgeryToken]
105 | public async Task AddPhoneNumber(AddPhoneNumberViewModel model)
106 | {
107 | if (!ModelState.IsValid)
108 | {
109 | return View(model);
110 | }
111 | // Generate the token and send it
112 | var user = await GetCurrentUserAsync();
113 | if (user == null)
114 | {
115 | return View("Error");
116 | }
117 | var code = await _userManager.GenerateChangePhoneNumberTokenAsync(user, model.PhoneNumber);
118 | await _smsSender.SendSmsAsync(model.PhoneNumber, "Your security code is: " + code);
119 | return RedirectToAction(nameof(VerifyPhoneNumber), new { PhoneNumber = model.PhoneNumber });
120 | }
121 |
122 | //
123 | // POST: /Manage/RequestTwoFactorAuthentication
124 | [HttpPost]
125 | [ValidateAntiForgeryToken]
126 | public async Task RequestTwoFactorAuthentication()
127 | {
128 | var user = await GetCurrentUserAsync();
129 | if (user != null)
130 | {
131 | var tfaKey = Guid.NewGuid().ToString("N");
132 | user.TfaKey = tfaKey;
133 | await _userManager.UpdateAsync(user);
134 | var authenticator = new TwoFactorAuthenticator();
135 | var code = authenticator.GenerateSetupCode($"DosFactores ({user.UserName})", tfaKey, 300, 300);
136 | TempData["AuthenticatorQr"] = code.QrCodeSetupImageUrl;
137 | _logger.LogInformation(1, "User enabled two-factor authentication.");
138 | }
139 | return RedirectToAction(nameof(Index), "Manage");
140 | }
141 |
142 | //
143 | // POST: /Manage/EnableTwoFactorAuthentication
144 | [HttpPost]
145 | [ValidateAntiForgeryToken]
146 | public async Task EnableTwoFactorAuthentication()
147 | {
148 | var user = await GetCurrentUserAsync();
149 | if (user != null)
150 | {
151 | await _userManager.SetTwoFactorEnabledAsync(user, true);
152 | await _signInManager.SignInAsync(user, isPersistent: false);
153 | _logger.LogInformation(1, "User enabled two-factor authentication.");
154 | }
155 | return RedirectToAction(nameof(Index), "Manage");
156 | }
157 |
158 | //
159 | // POST: /Manage/DisableTwoFactorAuthentication
160 | [HttpPost]
161 | [ValidateAntiForgeryToken]
162 | public async Task DisableTwoFactorAuthentication()
163 | {
164 | var user = await GetCurrentUserAsync();
165 | if (user != null)
166 | {
167 | await _userManager.SetTwoFactorEnabledAsync(user, false);
168 | await _signInManager.SignInAsync(user, isPersistent: false);
169 | _logger.LogInformation(2, "User disabled two-factor authentication.");
170 | }
171 | return RedirectToAction(nameof(Index), "Manage");
172 | }
173 |
174 | //
175 | // GET: /Manage/VerifyPhoneNumber
176 | [HttpGet]
177 | public async Task VerifyPhoneNumber(string phoneNumber)
178 | {
179 | var user = await GetCurrentUserAsync();
180 | if (user == null)
181 | {
182 | return View("Error");
183 | }
184 | var code = await _userManager.GenerateChangePhoneNumberTokenAsync(user, phoneNumber);
185 | // Send an SMS to verify the phone number
186 | return phoneNumber == null ? View("Error") : View(new VerifyPhoneNumberViewModel { PhoneNumber = phoneNumber });
187 | }
188 |
189 | //
190 | // POST: /Manage/VerifyPhoneNumber
191 | [HttpPost]
192 | [ValidateAntiForgeryToken]
193 | public async Task VerifyPhoneNumber(VerifyPhoneNumberViewModel model)
194 | {
195 | if (!ModelState.IsValid)
196 | {
197 | return View(model);
198 | }
199 | var user = await GetCurrentUserAsync();
200 | if (user != null)
201 | {
202 | var result = await _userManager.ChangePhoneNumberAsync(user, model.PhoneNumber, model.Code);
203 | if (result.Succeeded)
204 | {
205 | await _signInManager.SignInAsync(user, isPersistent: false);
206 | return RedirectToAction(nameof(Index), new { Message = ManageMessageId.AddPhoneSuccess });
207 | }
208 | }
209 | // If we got this far, something failed, redisplay the form
210 | ModelState.AddModelError(string.Empty, "Failed to verify phone number");
211 | return View(model);
212 | }
213 |
214 | //
215 | // POST: /Manage/RemovePhoneNumber
216 | [HttpPost]
217 | [ValidateAntiForgeryToken]
218 | public async Task RemovePhoneNumber()
219 | {
220 | var user = await GetCurrentUserAsync();
221 | if (user != null)
222 | {
223 | var result = await _userManager.SetPhoneNumberAsync(user, null);
224 | if (result.Succeeded)
225 | {
226 | await _signInManager.SignInAsync(user, isPersistent: false);
227 | return RedirectToAction(nameof(Index), new { Message = ManageMessageId.RemovePhoneSuccess });
228 | }
229 | }
230 | return RedirectToAction(nameof(Index), new { Message = ManageMessageId.Error });
231 | }
232 |
233 | //
234 | // GET: /Manage/ChangePassword
235 | [HttpGet]
236 | public IActionResult ChangePassword()
237 | {
238 | return View();
239 | }
240 |
241 | //
242 | // POST: /Manage/ChangePassword
243 | [HttpPost]
244 | [ValidateAntiForgeryToken]
245 | public async Task ChangePassword(ChangePasswordViewModel model)
246 | {
247 | if (!ModelState.IsValid)
248 | {
249 | return View(model);
250 | }
251 | var user = await GetCurrentUserAsync();
252 | if (user != null)
253 | {
254 | var result = await _userManager.ChangePasswordAsync(user, model.OldPassword, model.NewPassword);
255 | if (result.Succeeded)
256 | {
257 | await _signInManager.SignInAsync(user, isPersistent: false);
258 | _logger.LogInformation(3, "User changed their password successfully.");
259 | return RedirectToAction(nameof(Index), new { Message = ManageMessageId.ChangePasswordSuccess });
260 | }
261 | AddErrors(result);
262 | return View(model);
263 | }
264 | return RedirectToAction(nameof(Index), new { Message = ManageMessageId.Error });
265 | }
266 |
267 | //
268 | // GET: /Manage/SetPassword
269 | [HttpGet]
270 | public IActionResult SetPassword()
271 | {
272 | return View();
273 | }
274 |
275 | //
276 | // POST: /Manage/SetPassword
277 | [HttpPost]
278 | [ValidateAntiForgeryToken]
279 | public async Task SetPassword(SetPasswordViewModel model)
280 | {
281 | if (!ModelState.IsValid)
282 | {
283 | return View(model);
284 | }
285 |
286 | var user = await GetCurrentUserAsync();
287 | if (user != null)
288 | {
289 | var result = await _userManager.AddPasswordAsync(user, model.NewPassword);
290 | if (result.Succeeded)
291 | {
292 | await _signInManager.SignInAsync(user, isPersistent: false);
293 | return RedirectToAction(nameof(Index), new { Message = ManageMessageId.SetPasswordSuccess });
294 | }
295 | AddErrors(result);
296 | return View(model);
297 | }
298 | return RedirectToAction(nameof(Index), new { Message = ManageMessageId.Error });
299 | }
300 |
301 | //GET: /Manage/ManageLogins
302 | [HttpGet]
303 | public async Task ManageLogins(ManageMessageId? message = null)
304 | {
305 | ViewData["StatusMessage"] =
306 | message == ManageMessageId.RemoveLoginSuccess ? "The external login was removed."
307 | : message == ManageMessageId.AddLoginSuccess ? "The external login was added."
308 | : message == ManageMessageId.Error ? "An error has occurred."
309 | : "";
310 | var user = await GetCurrentUserAsync();
311 | if (user == null)
312 | {
313 | return View("Error");
314 | }
315 | var userLogins = await _userManager.GetLoginsAsync(user);
316 | var otherLogins = _signInManager.GetExternalAuthenticationSchemes().Where(auth => userLogins.All(ul => auth.AuthenticationScheme != ul.LoginProvider)).ToList();
317 | ViewData["ShowRemoveButton"] = user.PasswordHash != null || userLogins.Count > 1;
318 | return View(new ManageLoginsViewModel
319 | {
320 | CurrentLogins = userLogins,
321 | OtherLogins = otherLogins
322 | });
323 | }
324 |
325 | //
326 | // POST: /Manage/LinkLogin
327 | [HttpPost]
328 | [ValidateAntiForgeryToken]
329 | public async Task LinkLogin(string provider)
330 | {
331 | // Clear the existing external cookie to ensure a clean login process
332 | await HttpContext.Authentication.SignOutAsync(_externalCookieScheme);
333 |
334 | // Request a redirect to the external login provider to link a login for the current user
335 | var redirectUrl = Url.Action(nameof(LinkLoginCallback), "Manage");
336 | var properties = _signInManager.ConfigureExternalAuthenticationProperties(provider, redirectUrl, _userManager.GetUserId(User));
337 | return Challenge(properties, provider);
338 | }
339 |
340 | //
341 | // GET: /Manage/LinkLoginCallback
342 | [HttpGet]
343 | public async Task LinkLoginCallback()
344 | {
345 | var user = await GetCurrentUserAsync();
346 | if (user == null)
347 | {
348 | return View("Error");
349 | }
350 | var info = await _signInManager.GetExternalLoginInfoAsync(await _userManager.GetUserIdAsync(user));
351 | if (info == null)
352 | {
353 | return RedirectToAction(nameof(ManageLogins), new { Message = ManageMessageId.Error });
354 | }
355 | var result = await _userManager.AddLoginAsync(user, info);
356 | var message = ManageMessageId.Error;
357 | if (result.Succeeded)
358 | {
359 | message = ManageMessageId.AddLoginSuccess;
360 | // Clear the existing external cookie to ensure a clean login process
361 | await HttpContext.Authentication.SignOutAsync(_externalCookieScheme);
362 | }
363 | return RedirectToAction(nameof(ManageLogins), new { Message = message });
364 | }
365 |
366 | #region Helpers
367 |
368 | private void AddErrors(IdentityResult result)
369 | {
370 | foreach (var error in result.Errors)
371 | {
372 | ModelState.AddModelError(string.Empty, error.Description);
373 | }
374 | }
375 |
376 | public enum ManageMessageId
377 | {
378 | AddPhoneSuccess,
379 | AddLoginSuccess,
380 | ChangePasswordSuccess,
381 | SetTwoFactorSuccess,
382 | SetPasswordSuccess,
383 | RemoveLoginSuccess,
384 | RemovePhoneSuccess,
385 | Error
386 | }
387 |
388 | private Task GetCurrentUserAsync()
389 | {
390 | return _userManager.GetUserAsync(HttpContext.User);
391 | }
392 |
393 | #endregion
394 | }
395 | }
396 |
--------------------------------------------------------------------------------