Initial commit

This commit is contained in:
Marek Lesko
2025-08-19 16:58:51 +02:00
commit a2f7e2285a
908 changed files with 160315 additions and 0 deletions

View File

@@ -0,0 +1,69 @@
@using SimpleIdp.Resources
@model SimpleIdServer.IdServer.UI.ViewModels.AccountsIndexViewModel
@{
ViewBag.Title = AccountsResource.select_session;
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h1>@AccountsResource.active_sessions</h1>
@if (!string.IsNullOrWhiteSpace(ViewBag.IsUserAccountSwitched))
{
<div class="alert alert-success">@AccountsResource.useraccount_switched</div>
}
@if (!string.IsNullOrWhiteSpace(ViewBag.IsSessionRejected))
{
<div class="alert alert-success">@AccountsResource.useraccount_rejected</div>
}
<div class="row">
@{
int i = 0;
foreach (var account in Model.Accounts)
{
i++;
string rejectFormId = "reject-" + i;
<div class="col-md-4">
@using (Html.BeginForm("Index", "Accounts", FormMethod.Post))
{
@Html.AntiForgeryToken()
<div class="card">
<input type="hidden" name="AccountName" value="@account.Name" />
<input type="hidden" name="ReturnUrl" value="@Model.ReturnUrl" />
<input type="hidden" name="Action" value="Choose" />
<div class="card-header">@account.Name</div>
<div class="card-body">
@if (account.IssuedUtc != null)
{
<p>
@string.Format(AccountsResource.authentication_time, account.IssuedUtc.Value.ToString("s"))
</p>
}
@if (account.ExpiresUct != null)
{
<p>
@string.Format(AccountsResource.expiration_time, account.ExpiresUct.Value.ToString("s"))
</p>
}
</div>
<div class="card-footer d-flex justify-content-between">
<input type="submit" class="btn btn-primary" value="@AccountsResource.choose_session" />
<input type="submit" class="btn btn-danger" form="@rejectFormId" value="@AccountsResource.reject" />
</div>
</div>
}
@using (Html.BeginForm("Index", "Accounts", FormMethod.Post, new { id = rejectFormId }))
{
@Html.AntiForgeryToken()
<input type="hidden" name="AccountName" value="@account.Name" />
<input type="hidden" name="ReturnUrl" value="@Model.ReturnUrl" />
<input type="hidden" name="Action" value="Reject" />
}
</div>
}
}
</div>

View File

@@ -0,0 +1,74 @@
@using SimpleIdp.Resources
@using SimpleIdServer.IdServer.UI.ViewModels
@model SimpleIdServer.IdServer.UI.ViewModels.BCConsentsIndexViewModel
@{
ViewBag.Title = LayoutResource.consents;
Layout = "~/Views/Shared/_CommonLayout.cshtml";
}
<div class="consentContainer">
<div class="card consent">
<div class="card-body">
@if(Model.IsConfirmed)
{
<div class="alert alert-success">
@(Model.ConfirmationStatus == ConfirmationStatus.CONFIRMED ? BCConsentsResource.consent_confirmed : BCConsentsResource.consent_rejected)
</div>
}
else
{
<form method="post" action="@Url.Action("Reject", "BackChannelConsents")" id="rejectForm">
@Html.AntiForgeryToken()
<input name="ReturnUrl" type="hidden" value="@Model.ReturnUrl" />
<input name="IsRejected" type="hidden" value="true" />
</form>
@using (Html.BeginForm("Index", "BackChannelConsents", FormMethod.Post))
{
@Html.AntiForgeryToken()
@if (!ViewData.ModelState.IsValid)
{
<ul class="list-group">
@foreach (var modelState in ViewData.ModelState.Values)
{
foreach (var error in modelState.Errors)
{
<li class="list-group-item list-group-item-danger">@BCConsentsResource.ResourceManager.GetString(error.ErrorMessage)</li>
}
}
</ul>
}
<input type="hidden" value="@Model.ReturnUrl" name="ReturnUrl" />
<input name="IsRejected" type="hidden" value="false" />
<h5>@string.Format(BCConsentsResource.consent_client_access, Model.ClientName)</h5>
<ul class="list-group">
@if (!string.IsNullOrWhiteSpace(Model.BindingMessage))
{
<li class="list-group-item"><b>@BCConsentsResource.message</b> : @Model.BindingMessage</li>
}
@if(Model.Scopes == null || !Model.Scopes.Any())
{
<li class="list-group-item"><b>@BCConsentsResource.scopes</b> : @string.Join(",", Model.Scopes)</li>
}
@if(Model.AuthorizationDetails != null && Model.AuthorizationDetails.Any())
{
foreach(var authDetail in Model.AuthorizationDetails)
{
<li class="list-group-item"><b>@authDetail.Type</b> : @string.Join(",", authDetail.Actions)</li>
}
}
</ul>
<div>
<button type="submit" class="btn btn-success card-link">@BCConsentsResource.confirm</button>
<button type="submit" form="rejectForm" class="btn btn-danger">@BCConsentsResource.reject</button>
</div>
}
}
</div>
</div>
</div>

View File

@@ -0,0 +1,41 @@
@using Microsoft.Extensions.Options;
@using SimpleIdServer.IdServer.Options;
@using SimpleIdp.Resources
@model SimpleIdServer.IdServer.UI.ViewModels.RevokeSessionViewModel
@inject IOptions<IdServerHostOptions> options
@{
ViewBag.Title = CheckSessionResource.revoke_session_title;
Layout = "~/Views/Shared/_Layout.cshtml";
}
@foreach (var frontChannelLogout in Model.FrontChannelLogouts)
{
<iframe src="@frontChannelLogout" style="display: none"></iframe>
}
@if(Model.RedirectToRevokeSessionUI)
{
<a href="@Model.RevokeSessionCallbackUrl" class="btn btn-danger">@CheckSessionResource.revoke_session_title</a>
}
else
{
<div class="alert alert-info">
<p>@string.Format(CheckSessionResource.session_being_revoked, (options.Value.EndSessionRedirectionTimeInMS / 1000))</p>
</div>
}
@section Scripts {
<script type="text/javascript">
$(document).ready(function() {
var isRedirected = '@Model.RedirectToRevokeSessionUI.ToString().ToLowerInvariant()' == 'false';
var callback = '@Html.Raw(Model.RevokeSessionCallbackUrl)';
var timeMS = parseInt('@options.Value.EndSessionRedirectionTimeInMS');
if(isRedirected) {
setTimeout(() => {
window.location.replace(callback);
}, timeMS);
}
})
</script>
}

View File

@@ -0,0 +1,92 @@
@using SimpleIdServer.IdServer.DTOs
@using SimpleIdServer.IdServer.Domains;
@using SimpleIdp.Resources
@model SimpleIdServer.IdServer.UI.ViewModels.ConsentsIndexViewModel
@{
ViewBag.Title = LayoutResource.consents;
Layout = "~/Views/Shared/_CommonLayout.cshtml";
}
<div class="consentContainer">
<div class="card consent">
<div class="card-body">
<!-- Rejection form -->
<form method="post" action="@Url.Action("Reject", "Consents")" id="rejectForm">
@Html.AntiForgeryToken()
<input name="ReturnUrl" type="hidden" value="@Model.ReturnUrl" />
</form>
<div class="consentinfo">
<div class="img">
@Html.UserPicture(User)
</div>
<div class="separator"></div>
<div class="img">
@Html.ClientPicture(Model.PictureUri)
</div>
</div>
<!-- Confirmation form -->
@using (Html.BeginForm("Index", "Consents", FormMethod.Post))
{
@Html.AntiForgeryToken()
@if (!ViewData.ModelState.IsValid)
{
<ul class="list-group">
@foreach (var modelState in ViewData.ModelState.Values)
{
foreach (var error in modelState.Errors)
{
<li class="list-group-item list-group-item-danger">@ConsentsResource.ResourceManager.GetString(error.ErrorMessage)</li>
}
}
</ul>
}
<input type="hidden" name="ReturnUrl" value="@Model.ReturnUrl" />
<h5>@string.Format(ConsentsResource.consent_client_access, Model.ClientName)</h5>
<ul class="list-group">
@if(Model.ScopeNames != null && Model.ScopeNames.Any())
{
<li class="list-group-item"><b>@ConsentsResource.scopes</b> : @string.Join(",", Model.ScopeNames)</li>
}
@if(Model.ClaimNames != null && Model.ClaimNames.Any())
{
<li class="list-group-item"><b>@ConsentsResource.claims</b> : @string.Join(",", Model.ClaimNames)</li>
}
@if (Model.AuthorizationDetails != null && Model.AuthorizationDetails.Any())
{
foreach (var authDetail in Model.AuthorizationDetails)
{
if (authDetail.Type == AuthorizationDetailsNames.OpenIdCredential)
{
}
else
{
<li class="list-group-item">
<b>@authDetail.Type</b> : @string.Join(",", authDetail.Actions)
@if (authDetail.Locations != null && authDetail.Locations.Any())
{
<ul class="list-group">
@foreach (var location in authDetail.Locations)
{
<li class="list-group-item">@location</li>
}
</ul>
}
</li>
}
}
}
</ul>
<div>
<button type="submit" class="btn btn-success card-link">@ConsentsResource.confirm</button>
<button type="submit" form="rejectForm" class="btn btn-danger">@ConsentsResource.reject</button>
</div>
}
</div>
</div>
</div>

66
Views/Device/Index.cshtml Normal file
View File

@@ -0,0 +1,66 @@
@using SimpleIdServer.IdServer.Domains;
@using SimpleIdp.Resources
@model SimpleIdServer.IdServer.UI.ViewModels.DeviceCodeViewModel
@{
ViewBag.Title = LayoutResource.deviceauth;
Layout = "~/Views/Shared/_CommonLayout.cshtml";
}
<div class="consentContainer">
<div class="card consent">
<div class="card-body">
@if(Model.IsConfirmed)
{
<div class="alert alert-success">
@DeviceCodeResource.confirmed
</div>
}
else
{
<div class="consentinfo">
<div class="img">
@Html.UserPicture(User)
</div>
<div class="separator"></div>
<div class="img">
@Html.ClientPicture(Model.PictureUri)
</div>
</div>
<!-- Confirmation form -->
@using (Html.BeginForm("Index", "Device", FormMethod.Post))
{
@Html.AntiForgeryToken()
@if (!ViewData.ModelState.IsValid)
{
<ul class="list-group">
@foreach (var modelState in ViewData.ModelState.Values)
{
foreach (var error in modelState.Errors)
{
<li class="list-group-item list-group-item-danger">@DeviceCodeResource.ResourceManager.GetString(error.ErrorMessage)</li>
}
}
</ul>
}
<h5>@string.Format(DeviceCodeResource.consent_client_access, Model.ClientName)</h5>
<ul class="list-group">
@if (Model.Scopes != null && Model.Scopes.Any())
{
<li class="list-group-item"><b>@DeviceCodeResource.scopes</b> : @string.Join(",", Model.Scopes)</li>
}
</ul>
<div class="input-group mb-3 mt-3">
<input type="text" value="@Model.UserCode" name="UserCode" class="form-control" placeholder="@DeviceCodeResource.usercode">
</div>
<div>
<button type="submit" class="btn btn-success card-link">@DeviceCodeResource.confirm</button>
</div>
}
}
</div>
</div>
</div>

11
Views/Errors/Index.cshtml Normal file
View File

@@ -0,0 +1,11 @@
@using SimpleIdp.Resources
@model SimpleIdServer.IdServer.UI.ViewModels.ErrorViewModel
@{
ViewBag.Title = "Error";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<div class="alert alert-danger" role="alert">
@Model.Message
</div>

View File

@@ -0,0 +1,10 @@
@using SimpleIdp.Resources
@{
ViewBag.Title = "Error";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<div class="alert alert-danger" role="alert">
@LayoutResource.UnexpectedError
</div>

View File

@@ -0,0 +1,17 @@
@using Microsoft.AspNetCore.Mvc.ApiExplorer;
@using SimpleIdp.Resources
@model SimpleIdServer.IdServer.UI.ViewModels.DisconnectViewModel
@{
ViewBag.Title = LayoutResource.Disconnected;
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h6>@LayoutResource.YouAreDisconnected</h6>
@foreach (var frontChannelLogout in Model.FrontChannelLogoutUrls)
{
<iframe src="@frontChannelLogout" style="display: none"></iframe>
}
<a href="@Url.Action("Index", "Home")" class="btn btn-primary mt-1">@LayoutResource.back</a>

7
Views/Home/Index.cshtml Normal file
View File

@@ -0,0 +1,7 @@
@using Microsoft.AspNetCore.Mvc.ApiExplorer;
@using SimpleIdp.Resources
@{
ViewBag.Title = HomeResource.home;
Layout = "~/Views/Shared/_Layout.cshtml";
}

287
Views/Home/Profile.cshtml Normal file
View File

@@ -0,0 +1,287 @@
@using Microsoft.AspNetCore.Http;
@using SimpleIdServer.IdServer.Domains;
@using SimpleIdp.Resources
@using System.Security.Claims;
@model SimpleIdServer.IdServer.UI.ViewModels.ProfileViewModel
@{
ViewBag.Title = ProfileResource.title;
Layout = "~/Views/Shared/_Layout.cshtml";
Func<string, string> getClaim = (str) =>
{
var cl = User.Claims.FirstOrDefault(c => c.Type == str);
if (cl == null) return "-";
return cl.Value;
};
var basePath = Context.Request.GetAbsoluteUriWithVirtualPath();
var returnUrl = $"{basePath}{Url.Action("Profile", "Home")}";
}
<div class="row profile gy-4">
<!-- User Information -->
<div class="col-md-3">
<div class="card shadow-sm">
<div class="card-body info">
<div class="picture">
@Html.UserPicture(User, Model.Picture, true)
<form id="pictureForm" action="@Url.Action("UpdatePicture", "Home")" method="post">
<input type="file" id="pictureFile" name="File" style="display: none" accept="image/*" />
</form>
</div>
<ul>
<!-- Name identifier -->
<li>
<h6>@ProfileResource.subject</h6>
<span class="text-muted">@getClaim(ClaimTypes.NameIdentifier)</span>
</li>
<!-- Name -->
<li>
<h6>@ProfileResource.name</h6>
<span class="text-muted">@User.Identity.Name</span>
</li>
<!-- OTP Key -->
<li>
<h6>@ProfileResource.qrcode_otp</h6>
@if (!Model.HasOtpKey)
{
<div class="alert alert-warning">@ProfileResource.no_otp</div>
}
else
{
<div>
<img src="@Url.Action("GetOTP", "Home")" width="200px" />
</div>
}
</li>
</ul>
</div>
</div>
</div>
<div class="col">
<div class="row gy-4">
<!-- OPENID Consents -->
<div class="col-md-6">
<div class="card shadow-sm">
<div class="card-body">
<h5>@ProfileResource.approved_apps_title</h5>
<p>@ProfileResource.approved_apps_description</p>
<table class="table table-striped">
<thead>
<tr>
<th></th>
<th>@ProfileResource.client</th>
<th>@ProfileResource.scopes</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var consent in Model.Consents.OrderBy(c => c.ClientName))
{
<tr>
<td>@Html.ClientPicture(consent.ClientUri)</td>
<td class="align-middle">@(string.IsNullOrWhiteSpace(consent.ClientName) ? '-' : consent.ClientName)</td>
<td class="align-middle">
@if(consent.ScopeNames != null && consent.ScopeNames.Any())
{
foreach(var scopeName in consent.ScopeNames)
{
<span class="badge bg-secondary">@scopeName</span>
}
}
else
{
<span>-</span>
}
</td>
<td class="align-middle">
<a href="@Url.Action("RejectConsent", "Home", new { consentId = consent.ConsentId })" class="btn btn-danger">@ProfileResource.revoke_access</a>
</td>
</tr>
}
</tbody>
</table>
</div>
</div>
</div>
<!-- Pending requests -->
<div class="col-md-6">
<div class="card shadow-sm">
<div class="card-body">
<h5>@ProfileResource.pending_request_title</h5>
<p>@ProfileResource.pending_request_description</p>
@if(Model.PendingRequests != null && Model.PendingRequests.Any())
{
<table class="table table-striped">
<thead>
<tr>
<th>@ProfileResource.resource</th>
<th>@ProfileResource.scopes</th>
<th>@ProfileResource.requester</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var consent in Model.PendingRequests.Where(p => p.Owner == getClaim(ClaimTypes.NameIdentifier) && p.Status == UMAPendingRequestStatus.TOBECONFIRMED).OrderByDescending(u => u.CreateDateTime))
{
<tr>
<td>@(string.IsNullOrWhiteSpace(consent.ResourceName) ? '-' : consent.ResourceName)</td>
<td>
@if(consent.Scopes != null && consent.Scopes.Any())
{
<span>-</span>
}
@foreach(var scope in consent.Scopes)
{
<span class="badge bg-secondary">@scope</span>
}
</td>
<td>@consent.Requester</td>
<td>
<a href="@Url.Action("RejectUmaPendingRequest", "Home", new { ticketId = consent.TicketId})" class="btn btn-danger">@ProfileResource.revoke_access</a>
<a href="@Url.Action("ConfirmUmaPendingRequest", "Home", new { ticketId = consent.TicketId})" class="btn btn-success">@ProfileResource.accept_access</a>
</td>
</tr>
}
</tbody>
</table>
}
else
{
<i>@ProfileResource.no_pending_request</i>
}
</div>
</div>
</div>
<!-- External accounts -->
<div class="col-md-6">
<div class="card shadow-sm">
<div class="card-body">
<h5>@ProfileResource.external_accounts_title</h5>
<p>@ProfileResource.external_accounts_description</p>
@if (Model.Profiles != null && Model.Profiles.Any())
{
<table class="table table-striped">
<thead>
<tr>
<th>@ProfileResource.account_name</th>
<th>@ProfileResource.account_login</th>
<th>@ProfileResource.created_at</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var externalAccount in Model.Profiles)
{
<tr>
<td>@externalAccount.Scheme</td>
<td>@externalAccount.Subject</td>
<td>@externalAccount.CreateDateTime.ToString("dd/M/yyyy HH:mm:ss")</td>
<td>
@using (Html.BeginForm("Unlink", "Home", FormMethod.Post))
{
@Html.AntiForgeryToken()
<input type="hidden" value="@externalAccount.Subject" name="Subject" />
<input type="hidden" value="@externalAccount.Scheme" name="Scheme" />
<button type="submit" class="btn btn-danger">@ProfileResource.unlink</button>
}
</td>
</tr>
}
</tbody>
</table>
}
else
{
<i>@ProfileResource.no_external_accounts</i>
}
<div class="mt-2">
@foreach(var extProvider in Model.ExternalIdProviders)
{
<a class="btn btn-secondary me-1" href="@Url.Action("Link", "Home", new { scheme = extProvider.AuthenticationScheme, returnUrl = returnUrl })">
@extProvider.DisplayName
</a>
}
</div>
</div>
</div>
</div>
<!-- Manage credentials -->
<div class="col-md-6">
<div class="card shadow-sm">
<div class="card-body">
<h5>@ProfileResource.credentials</h5>
<div>
@if(Model.AuthenticationMethods != null && Model.AuthenticationMethods.Any(m => m.IsCredentialExists))
{
<p>@ProfileResource.update_your_credentials</p>
foreach(var authenticationMethod in Model.AuthenticationMethods.Where(m => m.IsCredentialExists))
{
<a class="btn btn-secondary me-1" href="@Url.Action("RegisterCredential", "Home", new { name = authenticationMethod.Amr, redirectUrl = returnUrl })">
@authenticationMethod.Name
</a>
}
}
else
{
<p>@ProfileResource.no_credentials_to_update</p>
}
</div>
<div>
@if(Model.AuthenticationMethods != null && Model.AuthenticationMethods.Any(m => !m.IsCredentialExists))
{
<p>@ProfileResource.enroll_credentials</p>
foreach (var authenticationMethod in Model.AuthenticationMethods.Where(m => !m.IsCredentialExists))
{
<a class="btn btn-secondary me-1" href="@Url.Action("RegisterCredential", "Home", new { name = authenticationMethod.Amr, redirectUrl = returnUrl })">
@authenticationMethod.Name
</a>
}
}
else
{
<p>@ProfileResource.no_credentials_to_create</p>
}
</div>
</div>
</div>
</div>
</div>
</div>
</div>
@section Scripts {
<script type="text/javascript">
$(document).ready(function () {
$("#pictureFile").on("change", function (e) {
const files = e.target.files;
if (files.length != 1) return;
const action = $("#pictureForm").attr("action");
const formData = new FormData();
formData.append('file', files[0]);
$.ajax({
url: action,
type: 'POST',
data: formData,
cache: false,
contentType: false,
processData: false,
success: function() {
var reader = new FileReader();
reader.onload = function (e) {
$('#user-picture').attr('src', e.target.result);
}
reader.readAsDataURL(files[0]);
}
});
return false;
});
$("#edit-profile").on('click', function () {
$("#pictureFile").trigger('click');
return false;
});
});
</script>
}

View File

@@ -0,0 +1,50 @@
@using Microsoft.AspNetCore.Mvc.ApiExplorer;
@using SimpleIdServer.IdServer.Helpers
@using SimpleIdp.Resources
@model IEnumerable<SimpleIdServer.IdServer.UI.ViewModels.SessionViewModel>
@{
ViewBag.Title = SessionsResource.title;
Layout = "~/Views/Shared/_CommonLayout.cshtml";
}
<nav class="navbar navbar-expand-lg bg-primary">
<div class="container-fluid">
<a class="navbar-brand" href="#">
<img src="~/images/SIDLogo.svg" width="40px" />
</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent">
<span class="navbar-toggler-icon"></span>
</button>
</div>
</nav>
<div id="container">
@if(Model.Any())
{
var grp = Model.GroupBy(g => g.Realm);
foreach (var kvp in grp)
{
<div class="mb-2">
<h5>@string.Format(SessionsResource.realm, kvp.Key)</h5>
<ul class="list-group">
@foreach (var session in kvp)
{
<li class="list-group-item d-flex justify-content-between align-items-center">
<a href="@Url.Action("Index", "Home", new { prefix = kvp.Key })">@session.Name</a>
<form action="@Url.Action("Index", "Sessions", new { realm = kvp.Key, user = session.Name })" method="post">
@Html.AntiForgeryToken()
<input type="hidden" name="Realm" value="@kvp.Key" />
<input type="hidden" name="User" value="@session.Name" />
<button type="submit" class="btn btn-danger"><i class="fa-solid fa-trash" style="padding-right:5px"></i>@SessionsResource.revoke</button>
</form>
</li>
}
</ul>
</div>
}
}
else
{
<div class="alert alert-danger">@SessionsResource.no_session</div>
}
</div>

View File

@@ -0,0 +1,27 @@
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@using SimpleIdp.Resources
@using System.Globalization
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>SimpleIdServer - @ViewBag.Title</title>
<link rel="stylesheet" href="@Url.Content("~/lib/bootstrap/css/bootstrap.css")" />
<link rel="stylesheet" href="@Url.Content("~/lib/fontawesome/css/all.css")" />
<link rel="stylesheet" href="@Url.Content("~/styles/theme.css")" />
<link rel="stylesheet" href="@Url.Content("~/styles/authenticate.css")" />
<link rel="stylesheet" href="@Url.Content("~/styles/consent.css")" />
<link rel="stylesheet" href="@Url.Content("~/styles/profile.css")" />
<link rel="icon" href="@Url.Content("~/images/favicon.ico")" />
</head>
<body class="orange">
@RenderBody()
<script type="text/javascript" src="@Url.Content("~/lib/jquery/jquery.js")"></script>
<script type="text/javascript" src="@Url.Content("~/lib/popper.js/umd/popper.js")"></script>
<script type="text/javascript" src="@Url.Content("~/lib/bootstrap/js/bootstrap.js")"></script>
<script type="text/javascript" src="@Url.Content("~/lib/helpers.js")"></script>
@RenderSection("Scripts", required: false)
</body>
</html>

View File

@@ -0,0 +1,82 @@
@using Microsoft.AspNetCore.Components.Web
@using FormBuilder.Components
@using SimpleIdp.Resources
@using System.Globalization
@model SimpleIdServer.IdServer.UI.ViewModels.ILayoutViewModel
@namespace FormBuilder.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@{
var returnUrl = string.IsNullOrEmpty(Context.Request.Path) ? "~/" : $"~{Context.Request.Path.Value}{Context.Request.QueryString}";
var currentCultureInfo = CultureInfo.DefaultThreadCurrentUICulture;
string languagesLabel = LayoutResource.ResourceManager.GetString("languages");
if (currentCultureInfo != null && !string.IsNullOrWhiteSpace(currentCultureInfo.Name))
{
var str = LayoutResource.ResourceManager.GetString(currentCultureInfo.Name);
if (!string.IsNullOrWhiteSpace(str))
{
languagesLabel = string.Format(LayoutResource.ResourceManager.GetString("selected_language"), str);
}
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<base href="~/" />
<link rel="stylesheet" href="@Url.Content("~/lib/bootstrap/css/bootstrap.css")" />
<link rel="stylesheet" href="@Url.Content("~/styles/theme.css")" />
<link rel="stylesheet" href="_content/Radzen.Blazor/css/default.css">
<link rel="stylesheet" href="_content/SidFormBuilder/themes.css" />
<link rel="stylesheet" href="_content/SidFormBuilder/style.css" />
<link rel="stylesheet" href="FormBuilder.Startup.styles.css" />
@RenderSection("Header", required: false)
</head>
<body class="orange">
<nav class="navbar navbar-expand-lg bg-primary">
<div class="container-fluid">
<a class="navbar-brand" href="#">
<img src="~/images/SIDLogo.svg" width="40px" />
</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<div class="me-auto"></div>
<ul class="navbar-nav">
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" data-bs-toggle="dropdown">
@languagesLabel
</a>
<div class="dropdown-menu">
@foreach (var language in Model.Languages)
{
<form asp-controller="Home" asp-action="SwitchLanguage" asp-area="" method="post">
<input type="hidden" name="culture" value="@language.Code" />
<input type="hidden" name="returnUrl" value="@returnUrl" />
<button type="submit" class="dropdown-item" href="#">@language.Description</button>
</form>
}
</div>
</li>
</ul>
</div>
</div>
</nav>
@RenderBody()
<script src="_framework/blazor.server.js"></script>
<script type="text/javascript" src="@Url.Content("~/lib/jquery/jquery.js")"></script>
<script type="text/javascript" src="@Url.Content("~/lib/popper.js/umd/popper.js")"></script>
<script type="text/javascript" src="@Url.Content("~/lib/bootstrap/js/bootstrap.js")"></script>
<script src="_content/Radzen.Blazor/Radzen.Blazor.js"></script>
<script src="_content/SidFormBuilder/lib.js"></script>
<script src="_content/SidFormBuilder/reCaptcha.js"></script>
<script src="_content/BlazorMonaco/jsInterop.js"></script>
<script src="_content/BlazorMonaco/lib/monaco-editor/min/vs/loader.js"></script>
<script src="_content/BlazorMonaco/lib/monaco-editor/min/vs/editor/editor.main.js"></script>
<script type="text/javascript" src="@Url.Content("~/lib/helpers.js")"></script>
@RenderSection("Scripts", required: false)
</body>
</html>

View File

@@ -0,0 +1,97 @@
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@using SimpleIdServer.IdServer.Options
@using SimpleIdServer.IdServer.Resources
@using SimpleIdp.Resources
@using Microsoft.Extensions.Options
@using System.Globalization
@inject IOptions<IdServerHostOptions> options
@model SimpleIdServer.IdServer.UI.ViewModels.ILayoutViewModel
@{
var returnUrl = string.IsNullOrEmpty(Context.Request.Path) ? "~/" : $"~{Context.Request.Path.Value}{Context.Request.QueryString}";
var currentCultureInfo = CultureInfo.DefaultThreadCurrentUICulture;
string languagesLabel = LayoutResource.ResourceManager.GetString("languages");
if (currentCultureInfo != null && !string.IsNullOrWhiteSpace(currentCultureInfo.Name))
{
var str = LayoutResource.ResourceManager.GetString(currentCultureInfo.Name);
if (!string.IsNullOrWhiteSpace(str))
{
languagesLabel = string.Format(LayoutResource.ResourceManager.GetString("selected_language"), str);
}
}
Layout = "~/Views/Shared/_CommonLayout.cshtml";
}
<nav class="navbar navbar-expand-lg bg-primary">
<div class="container-fluid">
<a class="navbar-brand" href="#">
<img src="~/images/SIDLogo.svg" width="40px" />
</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav me-auto">
@if (User.Identity.IsAuthenticated)
{
<li class="nav-item">
<a class="nav-link" href="@Url.Action("Profile", "Home")">
Welcome @User.Identity.Name
</a>
</li>
}
@if (options.Value.RealmEnabled)
{
<li class="nav-item">
<a class="nav-link" href="@Url.Action("Index", "Sessions", new { prefix = string.Empty })">
@LayoutResource.Sessions
</a>
</li>
}
@RenderSection("SubMenu", required: false)
</ul>
<ul class="navbar-nav">
@if (User.Identity.IsAuthenticated)
{
<li class="nav-item">
<a class="nav-link" href="@Url.Action("Disconnect", "Home", new { area = "" })">@LayoutResource.disconnect</a>
</li>
}
else
{
<li class="nav-item">
<a class="nav-link" href="@Url.Action("Profile", "Home", new { area = "" })">@LayoutResource.authenticate</a>
</li>
}
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" data-bs-toggle="dropdown">
@languagesLabel
</a>
<div class="dropdown-menu">
@foreach (var language in Model.Languages)
{
<form asp-controller="Home" asp-action="SwitchLanguage" asp-area="" method="post">
<input type="hidden" name="culture" value="@language.Code" />
<input type="hidden" name="returnUrl" value="@returnUrl" />
<button type="submit" class="dropdown-item" href="#">@language.Description</button>
</form>
}
</div>
</li>
</ul>
</div>
</div>
</nav>
<div id="container">
<div>
@RenderSection("PageTitle", false)
</div>
<div>
@RenderBody()
</div>
</div>
@section Scripts {
@RenderSection("Scripts", required: false)
}