diff --git a/.vscode/launch.json b/.vscode/launch.json index 8fd97968..0e2049e9 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -53,7 +53,7 @@ "AYANOVA_FOLDER_USER_FILES": "c:\\temp\\RavenTestData\\userfiles", "AYANOVA_FOLDER_BACKUP_FILES": "c:\\temp\\RavenTestData\\backupfiles", "AYANOVA_FOLDER_TEMPORARY_SERVER_FILES": "c:\\temp\\RavenTestData\\tempfiles", - "AYANOVA_SERVER_TEST_MODE": "true", + "AYANOVA_SERVER_TEST_MODE": "false", "AYANOVA_SERVER_TEST_MODE_SEEDLEVEL": "small", "AYANOVA_SERVER_TEST_MODE_TZ_OFFSET": "-7", "AYANOVA_BACKUP_PG_DUMP_PATH": "C:\\data\\code\\postgres_13\\bin\\" diff --git a/server/AyaNova/Controllers/AuthController.cs b/server/AyaNova/Controllers/AuthController.cs index 141ed754..a0062011 100644 --- a/server/AyaNova/Controllers/AuthController.cs +++ b/server/AyaNova/Controllers/AuthController.cs @@ -432,7 +432,7 @@ namespace AyaNova.Api.Controllers /// /// /// From route path - /// New TOTP secret + /// Authentication app activation code [HttpGet("totp")] public async Task GenerateAndSendTOTP(ApiVersion apiVersion) { @@ -454,22 +454,17 @@ namespace AyaNova.Api.Controllers u.TotpSecret = tfa.CreateSecret(160); await ct.SaveChangesAsync(); -//https://github.com/google/google-authenticator/wiki/Key-Uri-Format + //https://github.com/google/google-authenticator/wiki/Key-Uri-Format QRCoder.PayloadGenerator.OneTimePassword generator = new QRCoder.PayloadGenerator.OneTimePassword() { Secret = u.TotpSecret, Issuer = "AyaNova", - //Label = $"AyaNova.{u.Id}", + Label = $"AyaNova.acct.{u.Name}", Type = QRCoder.PayloadGenerator.OneTimePassword.OneTimePasswordAuthType.TOTP }; string payload = generator.ToString(); - // QRCodeGenerator qrGenerator = new QRCodeGenerator(); - // QRCodeData qrCodeData = qrGenerator.CreateQrCode(payload, QRCodeGenerator.ECCLevel.Q); - // QRCode qrCode = new QRCode(qrCodeData); - // var qrCodeAsBitmap = qrCode.GetGraphic(20); - QRCodeGenerator qrGenerator = new QRCodeGenerator(); QRCodeData qrCodeData = qrGenerator.CreateQrCode(payload, QRCodeGenerator.ECCLevel.Q); Base64QRCode qrCode = new Base64QRCode(qrCodeData); @@ -482,6 +477,46 @@ namespace AyaNova.Api.Controllers })); } + + /// + /// Confirm 2fa ready to use + /// + /// + /// Auth app 6 digit passcode + /// From route path + /// OK on success + [HttpPost("totp-validate")] + public async Task ValidateTOTP([FromBody] OTPPinParam pin, ApiVersion apiVersion) + { + if (!serverState.IsOpen) + return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason)); + + if (!ModelState.IsValid) + return BadRequest(new ApiErrorResponse(ModelState)); + + //get user + var UserId = UserIdFromContext.Id(HttpContext.Items); + + var u = await ct.User.FirstOrDefaultAsync(z => z.Id == UserId); + if (u == null)//should never happen but ? + return StatusCode(403, new ApiNotAuthorizedResponse()); + + if (u.TwoFactorEnabled) + return BadRequest(new ApiErrorResponse(ApiErrorCode.INVALID_OPERATION, "generalerror", "2fa already enabled")); + + if (string.IsNullOrWhiteSpace(u.TotpSecret)) + return BadRequest(new ApiErrorResponse(ApiErrorCode.INVALID_OPERATION, "generalerror", "2fa activation code not requested yet (missed a step?)")); + + //ok, something to validate, let's validate it + var tfa = new TwoFactorAuth("AyaNova"); + tfa.VerifyCode(u.TotpSecret, pin.Pin); + + return Ok(ApiOkResponse.Response(new + { + ok = tfa.VerifyCode(u.TotpSecret, pin.Pin) + })); + } + //------------------------------------------------------ public class CredentialsParam @@ -514,6 +549,12 @@ namespace AyaNova.Api.Controllers public string PasswordResetCode { get; set; } [System.ComponentModel.DataAnnotations.Required] public string Password { get; set; } + } + + public class OTPPinParam + { + [System.ComponentModel.DataAnnotations.Required] + public string Pin { get; set; } } diff --git a/server/AyaNova/resource/en.json b/server/AyaNova/resource/en.json index d0e8ca53..94932186 100644 --- a/server/AyaNova/resource/en.json +++ b/server/AyaNova/resource/en.json @@ -2167,7 +2167,7 @@ "AlertNotes": "Alert notes", "AuthTwoFactor":"Two-Factor Authentication", "AuthConnectAppTitle": "Connect your app", - "AuthConnectAppSubTitle": "Using an authenticator app such as Google Authenticator, Duo, Microsoft Authenticator or Authy, scan the QR code. It will display a 6 digit pass code which you need to enter below.", + "AuthConnectAppSubTitle": "Using an authenticator app such as Google Authenticator, Duo, Microsoft Authenticator, Authy etc, scan the QR code. It will display a 6 digit pass code which you need to enter below.", "AuthConnectAppManualEntry":"Having trouble scanning the code? Enter the following manually into your authenticator app:", "AuthEnterPin":"Enter 6 digit pass code" } \ No newline at end of file