├── README.md ├── 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 ├── Controllers │ ├── HomeController.cs │ └── ManageController.cs ├── Data │ ├── ApplicationDbContext.cs │ └── Migrations │ │ ├── ApplicationDbContextModelSnapshot.cs │ │ ├── 00000000000000_CreateIdentitySchema.Designer.cs │ │ └── 00000000000000_CreateIdentitySchema.cs ├── GoogleAuthenticatorProvider.cs ├── DosFactores.csproj └── Startup.cs ├── Google.Authenticator ├── Google.Authenticator.csproj ├── SetupCode.cs └── TwoFactorAuthenticator.cs ├── DosFactores.sln └── .gitignore /README.md: -------------------------------------------------------------------------------- 1 | # DosFactores -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /DosFactores/wwwroot/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thatcsharpguy/Dos_Factores/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/Dos_Factores/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/Dos_Factores/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/Dos_Factores/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/Dos_Factores/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 |
6 |

@ViewData["Title"].

7 |

Unsuccessful login with service.

8 |
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 |
6 |

Access Denied.

7 |

You do not have access to this resource.

8 |
9 | -------------------------------------------------------------------------------- /DosFactores/Views/Account/Lockout.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewData["Title"] = "Locked out"; 3 | } 4 | 5 |
6 |

Locked out.

7 |

This account has been locked out, please try again later.

8 |
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 |
7 |

8 | Thank you for confirming your email. Please Click here to Log in. 9 |

10 |
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-c2604328-7fd4-4ec1-bfad-0807bbc87745;Trusted_Connection=True;MultipleActiveResultSets=true" 4 | }, 5 | "Logging": { 6 | "IncludeScopes": false, 7 | "LogLevel": { 8 | "Default": "Warning" 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /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}} -------------------------------------------------------------------------------- /Google.Authenticator/SetupCode.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace Google.Authenticator 6 | { 7 | public class SetupCode 8 | { 9 | public string Account { get; internal set; } 10 | public string AccountSecretKey { get; internal set; } 11 | public string ManualEntryKey { get; internal set; } 12 | public string QrCodeSetupImageUrl { get; internal set; } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /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/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 |
9 | 10 |
11 |
12 | Select Two-Factor Authentication Provider: 13 | 14 | 15 |
16 |
17 |
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 |
8 |

Add a phone number.

9 |
10 |
11 |
12 | 13 |
14 | 15 | 16 |
17 |
18 |
19 |
20 | 21 |
22 |
23 |
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 |
9 | 10 |

Add a phone number.

11 |
@ViewData["Status"]
12 |
13 |
14 |
15 | 16 |
17 | 18 | 19 |
20 |
21 |
22 |
23 | 24 |
25 |
26 |
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 | @*
12 |

Enter your email.

13 |
14 |
15 |
16 | 17 |
18 | 19 | 20 |
21 |
22 |
23 |
24 | 25 |
26 |
27 |
*@ 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 |
10 |

Association Form

11 |
12 |
13 | 14 |

15 | You've successfully authenticated with @ViewData["LoginProvider"]. 16 | Please enter an email address for this site below and click the Register button to finish 17 | logging in. 18 |

19 |
20 | 21 |
22 | 23 | 24 |
25 |
26 |
27 |
28 | 29 |
30 |
31 |
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 |
9 |
10 | 11 | 12 |

@ViewData["Status"]

13 |
14 |
15 | 16 |
17 | 18 | 19 |
20 |
21 |
22 |
23 |
24 | 25 | 26 |
27 |
28 |
29 |
30 |
31 | 32 |
33 |
34 |
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 |
12 |

Set your password

13 |
14 |
15 |
16 | 17 |
18 | 19 | 20 |
21 |
22 |
23 | 24 |
25 | 26 | 27 |
28 |
29 |
30 |
31 | 32 |
33 |
34 |
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("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DosFactores", "DosFactores\DosFactores.csproj", "{3D386493-FC4F-4047-8349-B8A39E51914A}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Google.Authenticator", "Google.Authenticator\Google.Authenticator.csproj", "{156870C6-0FAD-4265-BE4F-71287F9D9B19}" 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 | {3D386493-FC4F-4047-8349-B8A39E51914A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 17 | {3D386493-FC4F-4047-8349-B8A39E51914A}.Debug|Any CPU.Build.0 = Debug|Any CPU 18 | {3D386493-FC4F-4047-8349-B8A39E51914A}.Release|Any CPU.ActiveCfg = Release|Any CPU 19 | {3D386493-FC4F-4047-8349-B8A39E51914A}.Release|Any CPU.Build.0 = Release|Any CPU 20 | {156870C6-0FAD-4265-BE4F-71287F9D9B19}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {156870C6-0FAD-4265-BE4F-71287F9D9B19}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {156870C6-0FAD-4265-BE4F-71287F9D9B19}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {156870C6-0FAD-4265-BE4F-71287F9D9B19}.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 |
9 |

Create a new account.

10 |
11 |
12 |
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 | @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 |
9 |

Change Password Form

10 |
11 |
12 |
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 | @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 |
9 |

Reset your password.

10 |
11 |
12 | 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 | @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/GoogleAuthenticatorProvider.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using DosFactores.Data; 6 | using DosFactores.Models; 7 | using Google.Authenticator; 8 | using Microsoft.AspNetCore.Identity; 9 | 10 | namespace DosFactores 11 | { 12 | public class GoogleAuthenticatorProvider : IUserTwoFactorTokenProvider 13 | { 14 | public static readonly string ProviderName = "GoogleAuthenticator"; 15 | 16 | private readonly ApplicationDbContext _dbContext; 17 | 18 | public GoogleAuthenticatorProvider(ApplicationDbContext dbContext) 19 | { 20 | _dbContext = dbContext; 21 | } 22 | 23 | public async Task GenerateAsync(string purpose, UserManager manager, ApplicationUser user) 24 | { 25 | var userName = await manager.GetUserNameAsync(user); 26 | var authenticator = new TwoFactorAuthenticator(); 27 | var code = authenticator.GenerateSetupCode(userName, userName, 100, 100); 28 | return code.ManualEntryKey; 29 | } 30 | 31 | public Task ValidateAsync(string purpose, string token, UserManager manager, ApplicationUser user) 32 | { 33 | return Task.Factory.StartNew(() => 34 | { 35 | var authenticator = new TwoFactorAuthenticator(); 36 | return authenticator.ValidateTwoFactorPIN(user.TfaKey, token); 37 | }); 38 | } 39 | 40 | public Task CanGenerateTwoFactorTokenAsync(UserManager manager, ApplicationUser user) 41 | { 42 | return Task.Factory.StartNew(() => 43 | { 44 | // Verify if the user is ellegible for 2FA 45 | return true; 46 | }); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /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 | 19 | 35 | 36 | } 37 | 38 |
@Model.CurrentLogins[index].LoginProvider 20 | @if ((bool)ViewData["ShowRemoveButton"]) 21 | { 22 |
23 |
24 | 25 | 26 | 27 |
28 |
29 | } 30 | else 31 | { 32 | @:   33 | } 34 |
39 | } 40 | @if (Model.OtherLogins.Count > 0) 41 | { 42 |

Add another service to log in.

43 |
44 |
45 |
46 |

47 | @foreach (var provider in Model.OtherLogins) 48 | { 49 | 50 | } 51 |

52 |
53 |
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-8b4894aa-022f-4f37-aade-9e476effe1b5 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 |
42 | [] 43 |
44 | } 45 | else 46 | { 47 | Add 48 | }*@ 49 |
50 | 51 |
Two-Factor Authentication:
52 |
53 | @if (Model.TwoFactorAuthenticatorQrCode != null) 54 | { 55 | 56 |
57 | Disabled 58 |
59 | } 60 | else 61 | { 62 | if (Model.TwoFactor) 63 | { 64 |
65 | Enabled 66 |
67 | } 68 | else 69 | { 70 |
71 | Disabled 72 |
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 |
47 |

© 2017 - DosFactores

48 |
49 |
50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 63 | 69 | 70 | 71 | 72 | @RenderSection("Scripts", required: false) 73 | 74 | 75 | -------------------------------------------------------------------------------- /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 |
14 |
15 |
16 |

Use a local account to log in.

17 |
18 |
19 |
20 | 21 |
22 | 23 | 24 |
25 |
26 |
27 | 28 |
29 | 30 | 31 |
32 |
33 |
34 |
35 |
36 | 40 |
41 |
42 |
43 |
44 |
45 | 46 |
47 |
48 |

49 | Register as a new user? 50 |

51 |

52 | Forgot your password? 53 |

54 |
55 |
56 |
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 |
75 |
76 |

77 | @foreach (var provider in loginProviders) 78 | { 79 | 80 | } 81 |

82 |
83 |
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.Services; 15 | using Microsoft.AspNetCore.Identity; 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 | services.AddSession(options => 62 | { 63 | // Set a short timeout for easy testing. 64 | options.IdleTimeout = TimeSpan.FromSeconds(10); 65 | options.CookieHttpOnly = true; 66 | }); 67 | 68 | // Add application services. 69 | services.AddTransient(); 70 | services.AddTransient(); 71 | } 72 | 73 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. 74 | public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) 75 | { 76 | loggerFactory.AddConsole(Configuration.GetSection("Logging")); 77 | loggerFactory.AddDebug(); 78 | 79 | // Requires using Microsoft.AspNetCore.Rewrite; 80 | var options = new RewriteOptions() 81 | .AddRedirectToHttps(); 82 | 83 | if (env.IsDevelopment()) 84 | { 85 | app.UseDeveloperExceptionPage(); 86 | app.UseDatabaseErrorPage(); 87 | app.UseBrowserLink(); 88 | } 89 | else 90 | { 91 | app.UseExceptionHandler("/Home/Error"); 92 | } 93 | 94 | app.UseStaticFiles(); 95 | 96 | app.UseIdentity(); 97 | 98 | // Add external authentication middleware below. To configure them please see https://go.microsoft.com/fwlink/?LinkID=532715 99 | app.UseSession(); 100 | app.UseMvc(routes => 101 | { 102 | routes.MapRoute( 103 | name: "default", 104 | template: "{controller=Home}/{action=Index}/{id?}"); 105 | }); 106 | } 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /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 | 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 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.suo 8 | *.user 9 | *.userosscache 10 | *.sln.docstates 11 | 12 | # User-specific files (MonoDevelop/Xamarin Studio) 13 | *.userprefs 14 | 15 | # Build results 16 | [Dd]ebug/ 17 | [Dd]ebugPublic/ 18 | [Rr]elease/ 19 | [Rr]eleases/ 20 | x64/ 21 | x86/ 22 | bld/ 23 | [Bb]in/ 24 | [Oo]bj/ 25 | [Ll]og/ 26 | 27 | # Visual Studio 2015 cache/options directory 28 | .vs/ 29 | # Uncomment if you have tasks that create the project's static files in wwwroot 30 | #wwwroot/ 31 | 32 | # MSTest test Results 33 | [Tt]est[Rr]esult*/ 34 | [Bb]uild[Ll]og.* 35 | 36 | # NUNIT 37 | *.VisualState.xml 38 | TestResult.xml 39 | 40 | # Build Results of an ATL Project 41 | [Dd]ebugPS/ 42 | [Rr]eleasePS/ 43 | dlldata.c 44 | 45 | # .NET Core 46 | project.lock.json 47 | project.fragment.lock.json 48 | artifacts/ 49 | **/Properties/launchSettings.json 50 | 51 | *_i.c 52 | *_p.c 53 | *_i.h 54 | *.ilk 55 | *.meta 56 | *.obj 57 | *.pch 58 | *.pdb 59 | *.pgc 60 | *.pgd 61 | *.rsp 62 | *.sbr 63 | *.tlb 64 | *.tli 65 | *.tlh 66 | *.tmp 67 | *.tmp_proj 68 | *.log 69 | *.vspscc 70 | *.vssscc 71 | .builds 72 | *.pidb 73 | *.svclog 74 | *.scc 75 | 76 | # Chutzpah Test files 77 | _Chutzpah* 78 | 79 | # Visual C++ cache files 80 | ipch/ 81 | *.aps 82 | *.ncb 83 | *.opendb 84 | *.opensdf 85 | *.sdf 86 | *.cachefile 87 | *.VC.db 88 | *.VC.VC.opendb 89 | 90 | # Visual Studio profiler 91 | *.psess 92 | *.vsp 93 | *.vspx 94 | *.sap 95 | 96 | # TFS 2012 Local Workspace 97 | $tf/ 98 | 99 | # Guidance Automation Toolkit 100 | *.gpState 101 | 102 | # ReSharper is a .NET coding add-in 103 | _ReSharper*/ 104 | *.[Rr]e[Ss]harper 105 | *.DotSettings.user 106 | 107 | # JustCode is a .NET coding add-in 108 | .JustCode 109 | 110 | # TeamCity is a build add-in 111 | _TeamCity* 112 | 113 | # DotCover is a Code Coverage Tool 114 | *.dotCover 115 | 116 | # Visual Studio code coverage results 117 | *.coverage 118 | *.coveragexml 119 | 120 | # NCrunch 121 | _NCrunch_* 122 | .*crunch*.local.xml 123 | nCrunchTemp_* 124 | 125 | # MightyMoose 126 | *.mm.* 127 | AutoTest.Net/ 128 | 129 | # Web workbench (sass) 130 | .sass-cache/ 131 | 132 | # Installshield output folder 133 | [Ee]xpress/ 134 | 135 | # DocProject is a documentation generator add-in 136 | DocProject/buildhelp/ 137 | DocProject/Help/*.HxT 138 | DocProject/Help/*.HxC 139 | DocProject/Help/*.hhc 140 | DocProject/Help/*.hhk 141 | DocProject/Help/*.hhp 142 | DocProject/Help/Html2 143 | DocProject/Help/html 144 | 145 | # Click-Once directory 146 | publish/ 147 | 148 | # Publish Web Output 149 | *.[Pp]ublish.xml 150 | *.azurePubxml 151 | # TODO: Comment the next line if you want to checkin your web deploy settings 152 | # but database connection strings (with potential passwords) will be unencrypted 153 | *.pubxml 154 | *.publishproj 155 | 156 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 157 | # checkin your Azure Web App publish settings, but sensitive information contained 158 | # in these scripts will be unencrypted 159 | PublishScripts/ 160 | 161 | # NuGet Packages 162 | *.nupkg 163 | # The packages folder can be ignored because of Package Restore 164 | **/packages/* 165 | # except build/, which is used as an MSBuild target. 166 | !**/packages/build/ 167 | # Uncomment if necessary however generally it will be regenerated when needed 168 | #!**/packages/repositories.config 169 | # NuGet v3's project.json files produces more ignorable files 170 | *.nuget.props 171 | *.nuget.targets 172 | 173 | # Microsoft Azure Build Output 174 | csx/ 175 | *.build.csdef 176 | 177 | # Microsoft Azure Emulator 178 | ecf/ 179 | rcf/ 180 | 181 | # Windows Store app package directories and files 182 | AppPackages/ 183 | BundleArtifacts/ 184 | Package.StoreAssociation.xml 185 | _pkginfo.txt 186 | 187 | # Visual Studio cache files 188 | # files ending in .cache can be ignored 189 | *.[Cc]ache 190 | # but keep track of directories ending in .cache 191 | !*.[Cc]ache/ 192 | 193 | # Others 194 | ClientBin/ 195 | ~$* 196 | *~ 197 | *.dbmdl 198 | *.dbproj.schemaview 199 | *.jfm 200 | *.pfx 201 | *.publishsettings 202 | orleans.codegen.cs 203 | 204 | # Since there are multiple workflows, uncomment next line to ignore bower_components 205 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 206 | #bower_components/ 207 | 208 | # RIA/Silverlight projects 209 | Generated_Code/ 210 | 211 | # Backup & report files from converting an old project file 212 | # to a newer Visual Studio version. Backup files are not needed, 213 | # because we have git ;-) 214 | _UpgradeReport_Files/ 215 | Backup*/ 216 | UpgradeLog*.XML 217 | UpgradeLog*.htm 218 | 219 | # SQL Server files 220 | *.mdf 221 | *.ldf 222 | *.ndf 223 | 224 | # Business Intelligence projects 225 | *.rdl.data 226 | *.bim.layout 227 | *.bim_*.settings 228 | 229 | # Microsoft Fakes 230 | FakesAssemblies/ 231 | 232 | # GhostDoc plugin setting file 233 | *.GhostDoc.xml 234 | 235 | # Node.js Tools for Visual Studio 236 | .ntvs_analysis.dat 237 | node_modules/ 238 | 239 | # Typescript v1 declaration files 240 | typings/ 241 | 242 | # Visual Studio 6 build log 243 | *.plg 244 | 245 | # Visual Studio 6 workspace options file 246 | *.opt 247 | 248 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 249 | *.vbw 250 | 251 | # Visual Studio LightSwitch build output 252 | **/*.HTMLClient/GeneratedArtifacts 253 | **/*.DesktopClient/GeneratedArtifacts 254 | **/*.DesktopClient/ModelManifest.xml 255 | **/*.Server/GeneratedArtifacts 256 | **/*.Server/ModelManifest.xml 257 | _Pvt_Extensions 258 | 259 | # Paket dependency manager 260 | .paket/paket.exe 261 | paket-files/ 262 | 263 | # FAKE - F# Make 264 | .fake/ 265 | 266 | # JetBrains Rider 267 | .idea/ 268 | *.sln.iml 269 | 270 | # CodeRush 271 | .cr/ 272 | 273 | # Python Tools for Visual Studio (PTVS) 274 | __pycache__/ 275 | *.pyc 276 | 277 | # Cake - Uncomment if you are using it 278 | # tools/** 279 | # !tools/packages.config 280 | 281 | # Telerik's JustMock configuration file 282 | *.jmconfig 283 | 284 | # BizTalk build output 285 | *.btp.cs 286 | *.btm.cs 287 | *.odx.cs 288 | *.xsd.cs 289 | -------------------------------------------------------------------------------- /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 | TfaKey = table.Column(nullable: true), 60 | TwoFactorEnabled = table.Column(nullable: false), 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 | banner3b -------------------------------------------------------------------------------- /DosFactores/wwwroot/images/banner4.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Google.Authenticator/TwoFactorAuthenticator.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(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 | user.TfaKey = null; 169 | await _userManager.UpdateAsync(user); 170 | await _signInManager.SignInAsync(user, isPersistent: false); 171 | _logger.LogInformation(2, "User disabled two-factor authentication."); 172 | } 173 | return RedirectToAction(nameof(Index), "Manage"); 174 | } 175 | 176 | // 177 | // GET: /Manage/VerifyPhoneNumber 178 | [HttpGet] 179 | public async Task VerifyPhoneNumber(string phoneNumber) 180 | { 181 | var user = await GetCurrentUserAsync(); 182 | if (user == null) 183 | { 184 | return View("Error"); 185 | } 186 | var code = await _userManager.GenerateChangePhoneNumberTokenAsync(user, phoneNumber); 187 | // Send an SMS to verify the phone number 188 | return phoneNumber == null ? View("Error") : View(new VerifyPhoneNumberViewModel { PhoneNumber = phoneNumber }); 189 | } 190 | 191 | // 192 | // POST: /Manage/VerifyPhoneNumber 193 | [HttpPost] 194 | [ValidateAntiForgeryToken] 195 | public async Task VerifyPhoneNumber(VerifyPhoneNumberViewModel model) 196 | { 197 | if (!ModelState.IsValid) 198 | { 199 | return View(model); 200 | } 201 | var user = await GetCurrentUserAsync(); 202 | if (user != null) 203 | { 204 | var result = await _userManager.ChangePhoneNumberAsync(user, model.PhoneNumber, model.Code); 205 | if (result.Succeeded) 206 | { 207 | await _signInManager.SignInAsync(user, isPersistent: false); 208 | return RedirectToAction(nameof(Index), new { Message = ManageMessageId.AddPhoneSuccess }); 209 | } 210 | } 211 | // If we got this far, something failed, redisplay the form 212 | ModelState.AddModelError(string.Empty, "Failed to verify phone number"); 213 | return View(model); 214 | } 215 | 216 | // 217 | // POST: /Manage/RemovePhoneNumber 218 | [HttpPost] 219 | [ValidateAntiForgeryToken] 220 | public async Task RemovePhoneNumber() 221 | { 222 | var user = await GetCurrentUserAsync(); 223 | if (user != null) 224 | { 225 | var result = await _userManager.SetPhoneNumberAsync(user, null); 226 | if (result.Succeeded) 227 | { 228 | await _signInManager.SignInAsync(user, isPersistent: false); 229 | return RedirectToAction(nameof(Index), new { Message = ManageMessageId.RemovePhoneSuccess }); 230 | } 231 | } 232 | return RedirectToAction(nameof(Index), new { Message = ManageMessageId.Error }); 233 | } 234 | 235 | // 236 | // GET: /Manage/ChangePassword 237 | [HttpGet] 238 | public IActionResult ChangePassword() 239 | { 240 | return View(); 241 | } 242 | 243 | // 244 | // POST: /Manage/ChangePassword 245 | [HttpPost] 246 | [ValidateAntiForgeryToken] 247 | public async Task ChangePassword(ChangePasswordViewModel model) 248 | { 249 | if (!ModelState.IsValid) 250 | { 251 | return View(model); 252 | } 253 | var user = await GetCurrentUserAsync(); 254 | if (user != null) 255 | { 256 | var result = await _userManager.ChangePasswordAsync(user, model.OldPassword, model.NewPassword); 257 | if (result.Succeeded) 258 | { 259 | await _signInManager.SignInAsync(user, isPersistent: false); 260 | _logger.LogInformation(3, "User changed their password successfully."); 261 | return RedirectToAction(nameof(Index), new { Message = ManageMessageId.ChangePasswordSuccess }); 262 | } 263 | AddErrors(result); 264 | return View(model); 265 | } 266 | return RedirectToAction(nameof(Index), new { Message = ManageMessageId.Error }); 267 | } 268 | 269 | // 270 | // GET: /Manage/SetPassword 271 | [HttpGet] 272 | public IActionResult SetPassword() 273 | { 274 | return View(); 275 | } 276 | 277 | // 278 | // POST: /Manage/SetPassword 279 | [HttpPost] 280 | [ValidateAntiForgeryToken] 281 | public async Task SetPassword(SetPasswordViewModel model) 282 | { 283 | if (!ModelState.IsValid) 284 | { 285 | return View(model); 286 | } 287 | 288 | var user = await GetCurrentUserAsync(); 289 | if (user != null) 290 | { 291 | var result = await _userManager.AddPasswordAsync(user, model.NewPassword); 292 | if (result.Succeeded) 293 | { 294 | await _signInManager.SignInAsync(user, isPersistent: false); 295 | return RedirectToAction(nameof(Index), new { Message = ManageMessageId.SetPasswordSuccess }); 296 | } 297 | AddErrors(result); 298 | return View(model); 299 | } 300 | return RedirectToAction(nameof(Index), new { Message = ManageMessageId.Error }); 301 | } 302 | 303 | //GET: /Manage/ManageLogins 304 | [HttpGet] 305 | public async Task ManageLogins(ManageMessageId? message = null) 306 | { 307 | ViewData["StatusMessage"] = 308 | message == ManageMessageId.RemoveLoginSuccess ? "The external login was removed." 309 | : message == ManageMessageId.AddLoginSuccess ? "The external login was added." 310 | : message == ManageMessageId.Error ? "An error has occurred." 311 | : ""; 312 | var user = await GetCurrentUserAsync(); 313 | if (user == null) 314 | { 315 | return View("Error"); 316 | } 317 | var userLogins = await _userManager.GetLoginsAsync(user); 318 | var otherLogins = _signInManager.GetExternalAuthenticationSchemes().Where(auth => userLogins.All(ul => auth.AuthenticationScheme != ul.LoginProvider)).ToList(); 319 | ViewData["ShowRemoveButton"] = user.PasswordHash != null || userLogins.Count > 1; 320 | return View(new ManageLoginsViewModel 321 | { 322 | CurrentLogins = userLogins, 323 | OtherLogins = otherLogins 324 | }); 325 | } 326 | 327 | // 328 | // POST: /Manage/LinkLogin 329 | [HttpPost] 330 | [ValidateAntiForgeryToken] 331 | public async Task LinkLogin(string provider) 332 | { 333 | // Clear the existing external cookie to ensure a clean login process 334 | await HttpContext.Authentication.SignOutAsync(_externalCookieScheme); 335 | 336 | // Request a redirect to the external login provider to link a login for the current user 337 | var redirectUrl = Url.Action(nameof(LinkLoginCallback), "Manage"); 338 | var properties = _signInManager.ConfigureExternalAuthenticationProperties(provider, redirectUrl, _userManager.GetUserId(User)); 339 | return Challenge(properties, provider); 340 | } 341 | 342 | // 343 | // GET: /Manage/LinkLoginCallback 344 | [HttpGet] 345 | public async Task LinkLoginCallback() 346 | { 347 | var user = await GetCurrentUserAsync(); 348 | if (user == null) 349 | { 350 | return View("Error"); 351 | } 352 | var info = await _signInManager.GetExternalLoginInfoAsync(await _userManager.GetUserIdAsync(user)); 353 | if (info == null) 354 | { 355 | return RedirectToAction(nameof(ManageLogins), new { Message = ManageMessageId.Error }); 356 | } 357 | var result = await _userManager.AddLoginAsync(user, info); 358 | var message = ManageMessageId.Error; 359 | if (result.Succeeded) 360 | { 361 | message = ManageMessageId.AddLoginSuccess; 362 | // Clear the existing external cookie to ensure a clean login process 363 | await HttpContext.Authentication.SignOutAsync(_externalCookieScheme); 364 | } 365 | return RedirectToAction(nameof(ManageLogins), new { Message = message }); 366 | } 367 | 368 | #region Helpers 369 | 370 | private void AddErrors(IdentityResult result) 371 | { 372 | foreach (var error in result.Errors) 373 | { 374 | ModelState.AddModelError(string.Empty, error.Description); 375 | } 376 | } 377 | 378 | public enum ManageMessageId 379 | { 380 | AddPhoneSuccess, 381 | AddLoginSuccess, 382 | ChangePasswordSuccess, 383 | SetTwoFactorSuccess, 384 | SetPasswordSuccess, 385 | RemoveLoginSuccess, 386 | RemovePhoneSuccess, 387 | Error 388 | } 389 | 390 | private Task GetCurrentUserAsync() 391 | { 392 | return _userManager.GetUserAsync(HttpContext.User); 393 | } 394 | 395 | #endregion 396 | } 397 | } 398 | --------------------------------------------------------------------------------