Files
2025-08-19 16:58:51 +02:00

166 lines
6.7 KiB
Plaintext

@using FormBuilder
@using FormBuilder.Components.Workflow
@using FormBuilder.Helpers
@using Microsoft.AspNetCore.Http
@using Microsoft.Extensions.Options
@using System.Text.Json
@model SimpleIdServer.IdServer.UI.ViewModels.SidWorkflowViewModel
@inject IOptions<FormBuilderOptions> options
@inject IUriProvider uriProvider
@inject IHttpContextAccessor HttpContextAccessor;
@{
Layout = "~/Views/Shared/_FormBuilderLayout.cshtml";
var antiforgeryToken = HttpContextAccessor.HttpContext.Request.Cookies[options.Value.AntiforgeryCookieName];
Model.AntiforgeryToken.CookieValue = antiforgeryToken;
var step = Model.Workflow?.Steps?.SingleOrDefault(s => s.Id == Model.CurrentStepId);
var makeAssertionsOptionsUrl = Url.Action("MakeAssertionOptions", "Authenticate", new { area = "webauthn" });
var authenticateUrl = Url.Action("Index", "Authenticate", new { area = "webauthn" });
var beginLoginUrl = Model.Input["BeginLoginUrl"].ToString();
var endLoginUrl = Model.Input["EndLoginUrl"].ToString();
}
<component type="typeof(WorkflowViewer)"
render-mode="ServerPrerendered"
param-Input="@Model.Input"
param-Workflow="@Model.Workflow"
param-FormRecords="@Model.FormRecords"
param-CurrentStepId="@Model.CurrentStepId"
param-ErrorMessages="@Model.ErrorMessages"
param-SuccessMessages="@Model.SuccessMessages"
param-AntiforgeryToken="@Model.AntiforgeryToken"
param-SupportedLanguageCodes="@Model.SupportedLanguageCodes"
param-Template="@Model.Template" />
@section Header {
@foreach (var cssStyle in Model.Template.CssStyles)
{
<link rel="stylesheet" href="@uriProvider.GetCssUrl(Model.Template.Id, cssStyle)" />
}
@foreach (var jsStyle in Model.Template.JsStyles)
{
<script src="@uriProvider.GetJsUrl(Model.Template.Id, jsStyle)" type="text/javascript"></script>
}
}
@section Scripts {
<script type="text/javascript">
let csharpReference;
var init = function () {
var beginLoginUrl = "@beginLoginUrl";
var endLoginUrl = "@endLoginUrl";
var makeAssertionsUrl = "@makeAssertionsOptionsUrl";
var authenticateUrl = "@authenticateUrl";
var isInitialized = false;
var toggleBtn = function (isDisabled) {
$("#fido2Auth button[type='submit']").attr('disabled', isDisabled);
}
var displayError = function (errorJson) {
csharpReference.invokeMethodAsync("SetErrorMessage", errorJson["error_description"]);
}
var tryListenForm = function () {
const elt = $("#webauthForm");
if (isInitialized === true) return;
if (elt.length === 0) {
setTimeout(() => tryListenForm(), 500);
return;
}
isInitialized = true;
elt.submit(function (e) {
e.preventDefault();
makeAssertionOptions(convertFormToJSON($(e.target)));
});
}
async function makeAssertion(credential, form, sessionId) {
let authData = new Uint8Array(credential.response.authenticatorData);
let clientDataJSON = new Uint8Array(credential.response.clientDataJSON);
let rawId = new Uint8Array(credential.rawId);
let sig = new Uint8Array(credential.response.signature);
const assertion = {
id: credential.id,
rawId: coerceToBase64Url(rawId),
type: credential.type,
extensions: credential.getClientExtensionResults(),
response: {
authenticatorData: coerceToBase64Url(authData),
clientDataJSON: coerceToBase64Url(clientDataJSON),
signature: coerceToBase64Url(sig)
}
};
let response = await fetch(endLoginUrl, {
method: 'POST',
body: JSON.stringify({ login: form.Login, session_id: sessionId, assertion: assertion }),
headers: {
"Accept": "application/json",
"Content-Type": "application/json"
}
});
if (!response.ok) {
const json = await response.json();
toggleBtn(false);
displayError(json);
return;
}
$("#webauthForm").unbind("submit");
$("#webauthForm input[name='SessionId']").val(sessionId);
$("#webauthForm input[name='Login']").removeAttr('disabled');
$("#webauthForm").trigger("submit");
}
async function makeAssertionOptions(form) {
toggleBtn(true);
let response = await fetch(beginLoginUrl, {
method: 'POST',
body: JSON.stringify({ login: form.Login, credential_type: 'webauthn' }),
headers: {
"Accept": "application/json",
"Content-Type": "application/json"
}
});
const json = await response.json();
if (!response.ok) {
toggleBtn(false);
displayError(json);
return;
}
const makeAssertionOptions = json["assertion"];
const sessionId = json["session_id"];
const challenge = makeAssertionOptions.challenge.replace(/-/g, "+").replace(/_/g, "/");
makeAssertionOptions.challenge = Uint8Array.from(atob(challenge), c => c.charCodeAt(0));
makeAssertionOptions.allowCredentials.forEach(function (listItem) {
var fixedId = listItem.id.replace(/\_/g, "/").replace(/\-/g, "+");
listItem.id = Uint8Array.from(atob(fixedId), c => c.charCodeAt(0));
});
let credential;
try {
credential = await navigator.credentials.get({ publicKey: makeAssertionOptions })
} catch (err) {
console.error(err);
toggleBtn(false);
return;
}
await makeAssertion(credential, form, sessionId);
}
tryListenForm();
};
setCsharpReference = function(ref) {
console.log(ref);
csharpReference = ref;
init();
};
</script>
}