This commit is contained in:
2
.vscode/launch.json
vendored
2
.vscode/launch.json
vendored
@@ -53,7 +53,7 @@
|
|||||||
"AYANOVA_FOLDER_USER_FILES": "c:\\temp\\RavenTestData\\userfiles",
|
"AYANOVA_FOLDER_USER_FILES": "c:\\temp\\RavenTestData\\userfiles",
|
||||||
"AYANOVA_FOLDER_BACKUP_FILES": "c:\\temp\\RavenTestData\\backupfiles",
|
"AYANOVA_FOLDER_BACKUP_FILES": "c:\\temp\\RavenTestData\\backupfiles",
|
||||||
"AYANOVA_FOLDER_TEMPORARY_SERVER_FILES": "c:\\temp\\RavenTestData\\tempfiles",
|
"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_SEEDLEVEL": "small",
|
||||||
"AYANOVA_SERVER_TEST_MODE_TZ_OFFSET": "-7",
|
"AYANOVA_SERVER_TEST_MODE_TZ_OFFSET": "-7",
|
||||||
"AYANOVA_BACKUP_PG_DUMP_PATH": "C:\\data\\code\\postgres_13\\bin\\"
|
"AYANOVA_BACKUP_PG_DUMP_PATH": "C:\\data\\code\\postgres_13\\bin\\"
|
||||||
|
|||||||
@@ -432,7 +432,7 @@ namespace AyaNova.Api.Controllers
|
|||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="apiVersion">From route path</param>
|
/// <param name="apiVersion">From route path</param>
|
||||||
/// <returns>New TOTP secret</returns>
|
/// <returns>Authentication app activation code</returns>
|
||||||
[HttpGet("totp")]
|
[HttpGet("totp")]
|
||||||
public async Task<IActionResult> GenerateAndSendTOTP(ApiVersion apiVersion)
|
public async Task<IActionResult> GenerateAndSendTOTP(ApiVersion apiVersion)
|
||||||
{
|
{
|
||||||
@@ -454,22 +454,17 @@ namespace AyaNova.Api.Controllers
|
|||||||
u.TotpSecret = tfa.CreateSecret(160);
|
u.TotpSecret = tfa.CreateSecret(160);
|
||||||
await ct.SaveChangesAsync();
|
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()
|
QRCoder.PayloadGenerator.OneTimePassword generator = new QRCoder.PayloadGenerator.OneTimePassword()
|
||||||
{
|
{
|
||||||
Secret = u.TotpSecret,
|
Secret = u.TotpSecret,
|
||||||
Issuer = "AyaNova",
|
Issuer = "AyaNova",
|
||||||
//Label = $"AyaNova.{u.Id}",
|
Label = $"AyaNova.acct.{u.Name}",
|
||||||
Type = QRCoder.PayloadGenerator.OneTimePassword.OneTimePasswordAuthType.TOTP
|
Type = QRCoder.PayloadGenerator.OneTimePassword.OneTimePasswordAuthType.TOTP
|
||||||
};
|
};
|
||||||
string payload = generator.ToString();
|
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();
|
QRCodeGenerator qrGenerator = new QRCodeGenerator();
|
||||||
QRCodeData qrCodeData = qrGenerator.CreateQrCode(payload, QRCodeGenerator.ECCLevel.Q);
|
QRCodeData qrCodeData = qrGenerator.CreateQrCode(payload, QRCodeGenerator.ECCLevel.Q);
|
||||||
Base64QRCode qrCode = new Base64QRCode(qrCodeData);
|
Base64QRCode qrCode = new Base64QRCode(qrCodeData);
|
||||||
@@ -482,6 +477,46 @@ namespace AyaNova.Api.Controllers
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Confirm 2fa ready to use
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="pin">Auth app 6 digit passcode</param>
|
||||||
|
/// <param name="apiVersion">From route path</param>
|
||||||
|
/// <returns>OK on success</returns>
|
||||||
|
[HttpPost("totp-validate")]
|
||||||
|
public async Task<IActionResult> 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
|
public class CredentialsParam
|
||||||
@@ -514,6 +549,12 @@ namespace AyaNova.Api.Controllers
|
|||||||
public string PasswordResetCode { get; set; }
|
public string PasswordResetCode { get; set; }
|
||||||
[System.ComponentModel.DataAnnotations.Required]
|
[System.ComponentModel.DataAnnotations.Required]
|
||||||
public string Password { get; set; }
|
public string Password { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class OTPPinParam
|
||||||
|
{
|
||||||
|
[System.ComponentModel.DataAnnotations.Required]
|
||||||
|
public string Pin { get; set; }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2167,7 +2167,7 @@
|
|||||||
"AlertNotes": "Alert notes",
|
"AlertNotes": "Alert notes",
|
||||||
"AuthTwoFactor":"Two-Factor Authentication",
|
"AuthTwoFactor":"Two-Factor Authentication",
|
||||||
"AuthConnectAppTitle": "Connect your app",
|
"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:",
|
"AuthConnectAppManualEntry":"Having trouble scanning the code? Enter the following manually into your authenticator app:",
|
||||||
"AuthEnterPin":"Enter 6 digit pass code"
|
"AuthEnterPin":"Enter 6 digit pass code"
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user