Implemented OIDC
This commit is contained in:
		
							parent
							
								
									116dd93da2
								
							
						
					
					
						commit
						a9269ece30
					
				|  | @ -8,7 +8,7 @@ internal sealed class IdentityUserAccessor( | |||
|     IdentityRedirectManager redirectManager) { | ||||
|     public async Task<ApplicationUser> GetRequiredUserAsync(HttpContext context) { | ||||
|         var user = await userManager.GetUserAsync(context.User); | ||||
| 
 | ||||
|          | ||||
|         if (user is null) { | ||||
|             redirectManager.RedirectToWithStatus("Account/InvalidUser", | ||||
|                 $"Error: Unable to load user with ID '{userManager.GetUserId(context.User)}'.", context); | ||||
|  |  | |||
|  | @ -18,7 +18,8 @@ | |||
| 
 | ||||
| <BoardComponent CenterContent="true"> | ||||
|     <BoardCardComponent Heading="@Localizer["Title"]"> | ||||
|         <StatusMessage Message="@Message" /> | ||||
| 	    <StatusMessage Message="@Message" /> | ||||
|         <a class="btn btn-primary w-full mt-3" href="/Account/Login">@Localizer["Login_Label"]</a> | ||||
|     </BoardCardComponent> | ||||
| </BoardComponent> | ||||
| 
 | ||||
|  |  | |||
|  | @ -4,192 +4,197 @@ | |||
| @using System.Security.Claims | ||||
| @using System.Text | ||||
| @using System.Text.Encodings.Web | ||||
| @using Humanizer | ||||
| @using Microsoft.AspNetCore.Identity | ||||
| @using Microsoft.AspNetCore.WebUtilities | ||||
| @using Wave.Data | ||||
| 
 | ||||
| @inject SignInManager<ApplicationUser> SignInManager | ||||
| @inject UserManager<ApplicationUser> UserManager | ||||
| @inject RoleManager<IdentityRole> RoleManager | ||||
| @inject IUserStore<ApplicationUser> UserStore | ||||
| @inject IEmailSender<ApplicationUser> EmailSender | ||||
| @inject NavigationManager NavigationManager | ||||
| @inject IdentityRedirectManager RedirectManager | ||||
| @inject ILogger<ExternalLogin> Logger | ||||
| @inject IStringLocalizer<ExternalLogin> Localizer | ||||
| 
 | ||||
| <PageTitle>Register</PageTitle> | ||||
| <PageTitle>@Localizer["Title"]</PageTitle> | ||||
| 
 | ||||
| <StatusMessage Message="@message" /> | ||||
| <h1>Register</h1> | ||||
| <h2>Associate your @ProviderDisplayName account.</h2> | ||||
| <hr /> | ||||
| 
 | ||||
| <div  class="alert alert-info"> | ||||
|     You've successfully authenticated with <strong>@ProviderDisplayName</strong>. | ||||
|     Please enter an email address for this site below and click the Register button to finish | ||||
|     logging in. | ||||
| </div> | ||||
| <BoardComponent CenterContent="true"> | ||||
| 	<BoardCardComponent Heading="@Localizer["Title"]"> | ||||
| 		<Alert CanRemove="false" Type="Alert.MessageType.Information"> | ||||
| 			<p> | ||||
| 				@string.Format(Localizer["Message"], ProviderDisplayName) | ||||
| 			</p> | ||||
| 		</Alert> | ||||
| 		<EditForm Model="Input" OnValidSubmit="OnValidSubmitAsync" FormName="confirmation" method="post"> | ||||
| 			<DataAnnotationsValidator/> | ||||
| 			<InputLabelComponent LabelText="@Localizer["Email_Label"]" For="() => Input.Email"> | ||||
| 				<InputText @bind-Value="Input.Email" class="input input-bordered w-full" | ||||
| 				           autocomplete="email" placeholder="@Localizer["Email_Placeholder"]" /> | ||||
| 			</InputLabelComponent> | ||||
| 
 | ||||
| <div class="row"> | ||||
|     <div class="col-md-4"> | ||||
|         <EditForm Model="Input" OnValidSubmit="OnValidSubmitAsync" FormName="confirmation" method="post"> | ||||
|             <DataAnnotationsValidator /> | ||||
|             <ValidationSummary class="text-danger" role="alert" /> | ||||
|             <div class="form-floating mb-3"> | ||||
|                 <InputText @bind-Value="Input.Email" class="form-control" autocomplete="email" placeholder="Please enter your email." /> | ||||
|                 <label for="email" class="form-label">Email</label> | ||||
|                 <ValidationMessage For="() => Input.Email" /> | ||||
|             </div> | ||||
|             <button type="submit" class="w-100 btn btn-lg btn-primary">Register</button> | ||||
|         </EditForm> | ||||
|     </div> | ||||
| </div> | ||||
| 			<button type="submit" class="btn btn-primary w-full"> | ||||
| 				@Localizer["Submit"] | ||||
| 			</button> | ||||
| 		</EditForm> | ||||
| 	</BoardCardComponent> | ||||
| </BoardComponent> | ||||
| 
 | ||||
| @code { | ||||
|     public const string LoginCallbackAction = "LoginCallback"; | ||||
| 	public const string LoginCallbackAction = "LoginCallback"; | ||||
| 
 | ||||
|     private string? message; | ||||
|     private ExternalLoginInfo externalLoginInfo = default!; | ||||
| 	private string? message; | ||||
| 	private ExternalLoginInfo externalLoginInfo = default!; | ||||
| 
 | ||||
|     [CascadingParameter] | ||||
|     private HttpContext HttpContext { get; set; } = default!; | ||||
| 	[CascadingParameter]  | ||||
| 	private HttpContext HttpContext { get; set; } = default!; | ||||
| 
 | ||||
|     [SupplyParameterFromForm] | ||||
|     private InputModel Input { get; set; } = new(); | ||||
| 	[SupplyParameterFromForm]  | ||||
| 	private InputModel Input { get; set; } = new(); | ||||
| 
 | ||||
|     [SupplyParameterFromQuery] | ||||
|     private string? RemoteError { get; set; } | ||||
| 	[SupplyParameterFromQuery]  | ||||
| 	private string? RemoteError { get; set; } | ||||
| 
 | ||||
|     [SupplyParameterFromQuery] | ||||
|     private string? ReturnUrl { get; set; } | ||||
| 	[SupplyParameterFromQuery]  | ||||
| 	private string? ReturnUrl { get; set; } | ||||
| 
 | ||||
|     [SupplyParameterFromQuery] | ||||
|     private string? Action { get; set; } | ||||
| 	[SupplyParameterFromQuery]  | ||||
| 	private string? Action { get; set; } | ||||
| 
 | ||||
|     private string? ProviderDisplayName => externalLoginInfo.ProviderDisplayName; | ||||
| 	private string? ProviderDisplayName => externalLoginInfo.ProviderDisplayName; | ||||
| 
 | ||||
|     protected override async Task OnInitializedAsync() | ||||
|     { | ||||
|         if (RemoteError is not null) | ||||
|         { | ||||
|             RedirectManager.RedirectToWithStatus("Account/Login", $"Error from external provider: {RemoteError}", HttpContext); | ||||
|         } | ||||
| 	protected override async Task OnInitializedAsync() { | ||||
| 		if (RemoteError is not null) { | ||||
| 			RedirectManager.RedirectToWithStatus("Account/Login", $"Error from external provider: {RemoteError}", HttpContext); | ||||
| 		} | ||||
| 
 | ||||
|         var info = await SignInManager.GetExternalLoginInfoAsync(); | ||||
|         if (info is null) | ||||
|         { | ||||
|             RedirectManager.RedirectToWithStatus("Account/Login", "Error loading external login information.", HttpContext); | ||||
|         } | ||||
| 		var info = await SignInManager.GetExternalLoginInfoAsync(); | ||||
| 		if (info is null) { | ||||
| 			RedirectManager.RedirectToWithStatus("Account/Login", "Error loading external login information.", HttpContext); | ||||
| 		} | ||||
| 
 | ||||
|         externalLoginInfo = info; | ||||
| 		externalLoginInfo = info; | ||||
| 
 | ||||
|         if (HttpMethods.IsGet(HttpContext.Request.Method)) | ||||
|         { | ||||
|             if (Action == LoginCallbackAction) | ||||
|             { | ||||
|                 await OnLoginCallbackAsync(); | ||||
|                 return; | ||||
|             } | ||||
| 		if (HttpMethods.IsGet(HttpContext.Request.Method)) { | ||||
| 			if (Action == LoginCallbackAction) { | ||||
| 				await OnLoginCallbackAsync(); | ||||
| 				return; | ||||
| 			} | ||||
| 
 | ||||
|             // We should only reach this page via the login callback, so redirect back to | ||||
|             // the login page if we get here some other way. | ||||
|             RedirectManager.RedirectTo("Account/Login"); | ||||
|         } | ||||
|     } | ||||
| 			// We should only reach this page via the login callback, so redirect back to | ||||
| 			// the login page if we get here some other way. | ||||
| 			RedirectManager.RedirectTo("Account/Login"); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
|     private async Task OnLoginCallbackAsync() | ||||
|     { | ||||
|         // Sign in the user with this external login provider if the user already has a login. | ||||
|         var result = await SignInManager.ExternalLoginSignInAsync( | ||||
|             externalLoginInfo.LoginProvider, | ||||
|             externalLoginInfo.ProviderKey, | ||||
|             isPersistent: false, | ||||
|             bypassTwoFactor: true); | ||||
| 	private async Task OnLoginCallbackAsync() { | ||||
| 		// Sign in the user with this external login provider if the user already has a login. | ||||
| 		var result = await SignInManager.ExternalLoginSignInAsync( | ||||
| 			externalLoginInfo.LoginProvider, | ||||
| 			externalLoginInfo.ProviderKey, | ||||
| 			isPersistent: false, | ||||
| 			bypassTwoFactor: true); | ||||
| 
 | ||||
|         if (result.Succeeded) | ||||
|         { | ||||
|             Logger.LogInformation( | ||||
|                 "{Name} logged in with {LoginProvider} provider.", | ||||
|                 externalLoginInfo.Principal.Identity?.Name, | ||||
|                 externalLoginInfo.LoginProvider); | ||||
|             RedirectManager.RedirectTo(ReturnUrl); | ||||
|         } | ||||
|         else if (result.IsLockedOut) | ||||
|         { | ||||
|             RedirectManager.RedirectTo("Account/Lockout"); | ||||
|         } | ||||
| 		if (result.Succeeded) { | ||||
| 			Logger.LogInformation( | ||||
| 				"{Name} logged in with {LoginProvider} provider.", | ||||
| 				externalLoginInfo.Principal.Identity?.Name, | ||||
| 				externalLoginInfo.LoginProvider); | ||||
| 			RedirectManager.RedirectTo(ReturnUrl); | ||||
| 		} else if (result.IsLockedOut) { | ||||
| 			RedirectManager.RedirectTo("Account/Lockout"); | ||||
| 		} | ||||
| 
 | ||||
|         // If the user does not have an account, then ask the user to create an account. | ||||
|         if (externalLoginInfo.Principal.HasClaim(c => c.Type == ClaimTypes.Email)) | ||||
|         { | ||||
|             Input.Email = externalLoginInfo.Principal.FindFirstValue(ClaimTypes.Email) ?? ""; | ||||
|         } | ||||
|     } | ||||
| 		// If the user does not have an account, then ask the user to create an account. | ||||
| 		if (externalLoginInfo.Principal.Claims.FirstOrDefault(c => c.Type is ClaimTypes.Email or "email") is {} claim) { | ||||
| 			Input.Email = claim.Value; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
|     private async Task OnValidSubmitAsync() | ||||
|     { | ||||
|         var emailStore = GetEmailStore(); | ||||
|         var user = CreateUser(); | ||||
| 	private async Task OnValidSubmitAsync() { | ||||
| 		var emailStore = GetEmailStore(); | ||||
| 		var user = CreateUser(); | ||||
| 
 | ||||
|         await UserStore.SetUserNameAsync(user, Input.Email, CancellationToken.None); | ||||
|         await emailStore.SetEmailAsync(user, Input.Email, CancellationToken.None); | ||||
| 		await UserStore.SetUserNameAsync(user, Input.Email, CancellationToken.None); | ||||
| 		await emailStore.SetEmailAsync(user, Input.Email, CancellationToken.None); | ||||
| 
 | ||||
|         var result = await UserManager.CreateAsync(user); | ||||
|         if (result.Succeeded) | ||||
|         { | ||||
|             result = await UserManager.AddLoginAsync(user, externalLoginInfo); | ||||
|             if (result.Succeeded) | ||||
|             { | ||||
|                 Logger.LogInformation("User created an account using {Name} provider.", externalLoginInfo.LoginProvider); | ||||
| 		var info = await SignInManager.GetExternalLoginInfoAsync(); | ||||
| 		if (info?.Principal.Claims.FirstOrDefault(c => c.Type is ClaimTypes.Name or ClaimTypes.GivenName or "name") is {} nameClaim) { | ||||
| 			user.FullName = nameClaim.Value; | ||||
| 		} | ||||
| 
 | ||||
|                 var userId = await UserManager.GetUserIdAsync(user); | ||||
|                 var code = await UserManager.GenerateEmailConfirmationTokenAsync(user); | ||||
|                 code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code)); | ||||
| 		var result = await UserManager.CreateAsync(user); | ||||
| 		if (result.Succeeded) { | ||||
| 			result = await UserManager.AddLoginAsync(user, externalLoginInfo); | ||||
| 			if (result.Succeeded) { | ||||
| 				Logger.LogInformation("User created an account using {Name} provider.", externalLoginInfo.LoginProvider); | ||||
| 
 | ||||
|                 var callbackUrl = NavigationManager.GetUriWithQueryParameters( | ||||
|                     NavigationManager.ToAbsoluteUri("Account/ConfirmEmail").AbsoluteUri, | ||||
|                     new Dictionary<string, object?> { ["userId"] = userId, ["code"] = code }); | ||||
|                 await EmailSender.SendConfirmationLinkAsync(user, Input.Email, HtmlEncoder.Default.Encode(callbackUrl)); | ||||
| 				string userId = await UserManager.GetUserIdAsync(user); | ||||
| 				string code = await UserManager.GenerateEmailConfirmationTokenAsync(user); | ||||
| 				code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code)); | ||||
| 
 | ||||
|                 // If account confirmation is required, we need to show the link if we don't have a real email sender | ||||
|                 if (UserManager.Options.SignIn.RequireConfirmedAccount) | ||||
|                 { | ||||
|                     RedirectManager.RedirectTo("Account/RegisterConfirmation", new() { ["email"] = Input.Email }); | ||||
|                 } | ||||
| 				string callbackUrl = NavigationManager.GetUriWithQueryParameters( | ||||
| 					NavigationManager.ToAbsoluteUri("Account/ConfirmEmail").AbsoluteUri, | ||||
| 					new Dictionary<string, object?> {["userId"] = userId, ["code"] = code}); | ||||
| 				await EmailSender.SendConfirmationLinkAsync(user, Input.Email, HtmlEncoder.Default.Encode(callbackUrl)); | ||||
| 
 | ||||
|                 await SignInManager.SignInAsync(user, isPersistent: false, externalLoginInfo.LoginProvider); | ||||
|                 RedirectManager.RedirectTo(ReturnUrl); | ||||
|             } | ||||
|         } | ||||
| 				if (info?.Principal.Claims.FirstOrDefault(c => c.Type is ClaimTypes.Role or "roles") is { } roleClaim) { | ||||
| 					var roles = roleClaim.Value.Split(",").Select(s => s.Trim()); | ||||
| 
 | ||||
|         message = $"Error: {string.Join(",", result.Errors.Select(error => error.Description))}"; | ||||
|     } | ||||
| 					foreach (string role in roles) { | ||||
| 						try { | ||||
| 							string r = role.Titleize(); | ||||
| 							if (r is "Author" or "Reviewer" or "Moderator" or "Admin" &&  | ||||
| 							    !await RoleManager.RoleExistsAsync(r) &&  | ||||
| 							    !(await RoleManager.CreateAsync(new IdentityRole(r))).Succeeded) { | ||||
| 								Logger.LogError("Failed to create role {role}. Failed to assign it to user {name}.", r, user.UserName); | ||||
| 								continue; | ||||
| 							} | ||||
| 
 | ||||
|     private ApplicationUser CreateUser() | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             return Activator.CreateInstance<ApplicationUser>(); | ||||
|         } | ||||
|         catch | ||||
|         { | ||||
|             throw new InvalidOperationException($"Can't create an instance of '{nameof(ApplicationUser)}'. " + | ||||
|                 $"Ensure that '{nameof(ApplicationUser)}' is not an abstract class and has a parameterless constructor"); | ||||
|         } | ||||
|     } | ||||
| 							await UserManager.AddToRoleAsync(user, r); | ||||
| 						} catch (Exception ex) { | ||||
| 							Logger.LogWarning(ex, "Failed to add newly created user {name} to role {role}.", user.UserName, role); | ||||
| 						} | ||||
| 					} | ||||
| 				} | ||||
| 
 | ||||
|     private IUserEmailStore<ApplicationUser> GetEmailStore() | ||||
|     { | ||||
|         if (!UserManager.SupportsUserEmail) | ||||
|         { | ||||
|             throw new NotSupportedException("The default UI requires a user store with email support."); | ||||
|         } | ||||
|         return (IUserEmailStore<ApplicationUser>)UserStore; | ||||
|     } | ||||
| 				// If account confirmation is required, we need to show the link if we don't have a real email sender | ||||
| 				if (UserManager.Options.SignIn.RequireConfirmedAccount) { | ||||
| 					RedirectManager.RedirectTo("Account/RegisterConfirmation", new() { ["email"] = Input.Email }); | ||||
| 				} | ||||
| 
 | ||||
|     private sealed class InputModel | ||||
|     { | ||||
|         [Required] | ||||
|         [EmailAddress] | ||||
|         public string Email { get; set; } = ""; | ||||
|     } | ||||
| } | ||||
| 				await SignInManager.SignInAsync(user, isPersistent: false, externalLoginInfo.LoginProvider); | ||||
| 				RedirectManager.RedirectTo(ReturnUrl); | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		message = $"Error: {string.Join(",", result.Errors.Select(error => error.Description))}"; | ||||
| 	} | ||||
| 
 | ||||
| 	private ApplicationUser CreateUser() { | ||||
| 		try { | ||||
| 			return Activator.CreateInstance<ApplicationUser>(); | ||||
| 		} catch { | ||||
| 			throw new InvalidOperationException($"Can't create an instance of '{nameof(ApplicationUser)}'. " + | ||||
| 			                                    $"Ensure that '{nameof(ApplicationUser)}' is not an abstract class and has a parameterless constructor"); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	private IUserEmailStore<ApplicationUser> GetEmailStore() { | ||||
| 		if (!UserManager.SupportsUserEmail) { | ||||
| 			throw new NotSupportedException("The default UI requires a user store with email support."); | ||||
| 		} | ||||
| 
 | ||||
| 		return (IUserEmailStore<ApplicationUser>) UserStore; | ||||
| 	} | ||||
| 
 | ||||
| 	private sealed class InputModel { | ||||
| 		[Required] [EmailAddress]  | ||||
| 		public string Email { get; set; } = ""; | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
|  | @ -20,54 +20,49 @@ | |||
| <StatusMessage Message="@_errorMessage" /> | ||||
| 
 | ||||
| <BoardComponent CenterContent="true"> | ||||
|     <BoardCardComponent Heading="@Localizer["Title"]"> | ||||
|         <EditForm Model="Input" method="post" OnValidSubmit="LoginUser" FormName="login" class="w-full"> | ||||
|             <DataAnnotationsValidator /> | ||||
| 	<BoardCardComponent Heading="@Localizer["Title"]"> | ||||
| 		<EditForm Model="Input" method="post" OnValidSubmit="LoginUser" FormName="login" class="w-full"> | ||||
| 			<DataAnnotationsValidator /> | ||||
| 
 | ||||
|             <InputLabelComponent LabelText="@Localizer["Email_Label"]" For="() => Input.Email"> | ||||
|                 <InputText @bind-Value="Input.Email" class="input input-bordered w-full" autocomplete="username" | ||||
|                            required aria-required="true" placeholder="@Localizer["Email_Placeholder"]" /> | ||||
|             </InputLabelComponent> | ||||
|             <InputLabelComponent LabelText="@Localizer["Password_Label"]" For="() => Input.Password"> | ||||
|                 <InputText @bind-Value="Input.Password" class="input input-bordered w-full" autocomplete="current-password" type="password" | ||||
|                            required aria-required="true" placeholder="@Localizer["Password_Placeholder"]" /> | ||||
|             </InputLabelComponent> | ||||
|             <div class="form-control"> | ||||
|                 <label class="label cursor-pointer"> | ||||
|                     <span class="label-text">@Localizer["RememberMe_Label"]</span> | ||||
|                     <InputCheckbox @bind-Value="Input.RememberMe" class="checkbox" /> | ||||
|                 </label> | ||||
|             </div> | ||||
| 			<InputLabelComponent LabelText="@Localizer["Email_Label"]" For="() => Input.Email"> | ||||
| 				<InputText @bind-Value="Input.Email" class="input input-bordered w-full" autocomplete="username" | ||||
| 				           required aria-required="true" placeholder="@Localizer["Email_Placeholder"]" /> | ||||
| 			</InputLabelComponent> | ||||
| 			<InputLabelComponent LabelText="@Localizer["Password_Label"]" For="() => Input.Password"> | ||||
| 				<InputText @bind-Value="Input.Password" class="input input-bordered w-full" autocomplete="current-password" type="password" | ||||
| 				           required aria-required="true" placeholder="@Localizer["Password_Placeholder"]" /> | ||||
| 			</InputLabelComponent> | ||||
| 			<div class="form-control"> | ||||
| 				<label class="label cursor-pointer"> | ||||
| 					<span class="label-text">@Localizer["RememberMe_Label"]</span> | ||||
| 					<InputCheckbox @bind-Value="Input.RememberMe" class="checkbox" /> | ||||
| 				</label> | ||||
| 			</div> | ||||
| 
 | ||||
|             <button type="submit" class="btn btn-primary w-full"> | ||||
|                 @Localizer["Submit"] | ||||
|             </button> | ||||
|         </EditForm> | ||||
|         <ul class="mt-3 flex flex-col gap-1 text-center"> | ||||
|             <li> | ||||
|                 <a class="hover:link" href="Account/ForgotPassword"> | ||||
|                     @Localizer["ResetPassword_Label"] | ||||
|                 </a> | ||||
|             </li> | ||||
|             <li> | ||||
|                 <a class="hover:link" href="@(NavigationManager.GetUriWithQueryParameters("Account/Register", new Dictionary<string, object?> { ["ReturnUrl"] = ReturnUrl }))"> | ||||
|                     @Localizer["Register_Label"] | ||||
|                 </a> | ||||
|             </li> | ||||
|             <li> | ||||
|                 <a class="hover:link" href="Account/ResendEmailConfirmation"> | ||||
|                     @Localizer["ResendMailConfirmation_Label"] | ||||
|                 </a> | ||||
|             </li> | ||||
|         </ul> | ||||
|     </BoardCardComponent> | ||||
|     <!-- | ||||
|     <section class="w-80 max-w-xs"> | ||||
|         <h2 class="text-2xl lg:text-4xl mb-3">Use another service to log in.</h2> | ||||
|         <hr /> | ||||
|         <ExternalLoginPicker /> | ||||
|     </section> | ||||
|     --> | ||||
| 			<button type="submit" class="btn btn-primary w-full"> | ||||
| 				@Localizer["Submit"] | ||||
| 			</button> | ||||
| 		</EditForm> | ||||
| 		<ul class="mt-3 flex flex-col gap-1 text-center"> | ||||
| 			<li> | ||||
| 				<a class="hover:link" href="Account/ForgotPassword"> | ||||
| 					@Localizer["ResetPassword_Label"] | ||||
| 				</a> | ||||
| 			</li> | ||||
| 			<li> | ||||
| 				<a class="hover:link" href="@(NavigationManager.GetUriWithQueryParameters("Account/Register", new Dictionary<string, object?> { ["ReturnUrl"] = ReturnUrl }))"> | ||||
| 					@Localizer["Register_Label"] | ||||
| 				</a> | ||||
| 			</li> | ||||
| 			<li> | ||||
| 				<a class="hover:link" href="Account/ResendEmailConfirmation"> | ||||
| 					@Localizer["ResendMailConfirmation_Label"] | ||||
| 				</a> | ||||
| 			</li> | ||||
| 		</ul> | ||||
| 	</BoardCardComponent> | ||||
|      | ||||
| 	<ExternalLoginPicker /> | ||||
| </BoardComponent> | ||||
| 
 | ||||
| @code { | ||||
|  |  | |||
|  | @ -3,6 +3,7 @@ | |||
| @using System.ComponentModel.DataAnnotations | ||||
| @using Microsoft.AspNetCore.Identity | ||||
| @using Wave.Data | ||||
| @using Wave.Utilities | ||||
| 
 | ||||
| @inject UserManager<ApplicationUser> UserManager | ||||
| @inject SignInManager<ApplicationUser> SignInManager | ||||
|  | @ -10,66 +11,69 @@ | |||
| @inject IdentityRedirectManager RedirectManager | ||||
| @inject ILogger<DeletePersonalData> Logger | ||||
| @inject IStringLocalizer<DeletePersonalData> Localizer | ||||
| @inject IMessageDisplay Message | ||||
| 
 | ||||
| <PageTitle>@Localizer["Title"]</PageTitle> | ||||
| 
 | ||||
| <StatusMessage Message="@message" /> | ||||
| 
 | ||||
| <BoardComponent> | ||||
|     <BoardCardComponent Heading="@Localizer["Title"]"> | ||||
|         <Alert Type="Alert.MessageType.Warning" CanRemove="false"> | ||||
|             <strong class="font-bold">@Localizer["Delete_FinalWarning"]</strong> | ||||
|         </Alert> | ||||
|          | ||||
|         <EditForm Model="Input" FormName="delete-user" OnValidSubmit="OnValidSubmitAsync" method="post" class="w-full"> | ||||
|             <DataAnnotationsValidator /> | ||||
|             <ValidationSummary class="text-error" role="alert" /> | ||||
|             @if (requirePassword) { | ||||
|                 <InputLabelComponent LabelText="@Localizer["Delete_Password_Label"]" For="() => Input.Password"> | ||||
|                     <InputText type="password" @bind-Value="Input.Password" class="input input-bordered w-full" required | ||||
|                                autocomplete="current-password" placeholder="@Localizer["Delete_Password_Placeholder"]" /> | ||||
|                 </InputLabelComponent> | ||||
|             } | ||||
|             <button class="btn btn-lg btn-error w-full" type="submit">@Localizer["Delete_FinalSubmit"]</button> | ||||
|         </EditForm> | ||||
|     </BoardCardComponent> | ||||
| 	<BoardCardComponent Heading="@Localizer["Title"]"> | ||||
| 		<Alert Type="Alert.MessageType.Warning" CanRemove="false"> | ||||
| 			<strong class="font-bold">@Localizer["Delete_FinalWarning"]</strong> | ||||
| 		</Alert> | ||||
| 
 | ||||
| 		<EditForm Model="Input" FormName="delete-user" OnValidSubmit="OnValidSubmitAsync" method="post" class="w-full mt-3"> | ||||
| 			<DataAnnotationsValidator/> | ||||
| 			@if (RequirePassword) { | ||||
| 				<InputLabelComponent LabelText="@Localizer["Delete_Password_Label"]" For="() => Input.Password"> | ||||
| 					<InputText type="password" @bind-Value="Input.Password" class="input input-bordered w-full" required | ||||
| 					           autocomplete="current-password" placeholder="@Localizer["Delete_Password_Placeholder"]"/> | ||||
| 				</InputLabelComponent> | ||||
| 			} else { | ||||
| 				<!-- our model binding fails without zero bound properties --> | ||||
| 				<InputText type="hidden" @bind-Value="Input.Password" /> | ||||
| 			} | ||||
| 			<button class="btn btn-lg btn-error w-full" type="submit">@Localizer["Delete_FinalSubmit"]</button> | ||||
| 		</EditForm> | ||||
| 	</BoardCardComponent> | ||||
| </BoardComponent> | ||||
| 
 | ||||
| @code { | ||||
|     private string? message; | ||||
|     private ApplicationUser user = default!; | ||||
|     private bool requirePassword; | ||||
| 	private ApplicationUser User { get; set; } = default!; | ||||
| 	private bool RequirePassword { get; set; } | ||||
| 
 | ||||
|     [CascadingParameter]  | ||||
|     private HttpContext HttpContext { get; set; } = default!; | ||||
|     [SupplyParameterFromForm]  | ||||
|     private InputModel Input { get; set; } = new(); | ||||
| 	[CascadingParameter] private HttpContext HttpContext { get; set; } = default!; | ||||
| 
 | ||||
|     protected override async Task OnInitializedAsync() { | ||||
|         user = await UserAccessor.GetRequiredUserAsync(HttpContext); | ||||
|         requirePassword = await UserManager.HasPasswordAsync(user); | ||||
|     } | ||||
| 	[SupplyParameterFromForm(FormName = "delete-user")] | ||||
| 	private InputModel Input { get; set; } = new(); | ||||
| 
 | ||||
|     private async Task OnValidSubmitAsync() { | ||||
|         if (requirePassword && !await UserManager.CheckPasswordAsync(user, Input.Password)) { | ||||
|             message = Localizer["Delete_ErrorWrongPassword"]; | ||||
|             return; | ||||
|         } | ||||
| 	protected override async Task OnInitializedAsync() { | ||||
| 		User = await UserAccessor.GetRequiredUserAsync(HttpContext); | ||||
| 		RequirePassword = await UserManager.HasPasswordAsync(User); | ||||
| 	} | ||||
| 
 | ||||
|         var result = await UserManager.DeleteAsync(user); | ||||
|         if (!result.Succeeded) { | ||||
|             throw new InvalidOperationException(Localizer["Delete_ErrorUnknown"]); | ||||
|         } | ||||
| 	private async Task OnValidSubmitAsync() { | ||||
| 		if (RequirePassword && !await UserManager.CheckPasswordAsync(User, Input.Password)) { | ||||
| 			Message.ShowError(Localizer["Delete_ErrorWrongPassword"]); | ||||
| 			return; | ||||
| 		} | ||||
| 
 | ||||
|         await SignInManager.SignOutAsync(); | ||||
| 		var result = await UserManager.DeleteAsync(User); | ||||
| 		if (!result.Succeeded) { | ||||
| 			throw new InvalidOperationException(Localizer["Delete_ErrorUnknown"]); | ||||
| 		} | ||||
| 
 | ||||
|         string userId = await UserManager.GetUserIdAsync(user); | ||||
|         Logger.LogInformation("User with ID '{UserId}' deleted themselves.", userId); | ||||
| 		await SignInManager.SignOutAsync(); | ||||
| 
 | ||||
|         RedirectManager.RedirectToWithStatus("/", Localizer["Delete_Success"], HttpContext); | ||||
|     } | ||||
| 		string userId = await UserManager.GetUserIdAsync(User); | ||||
| 		Logger.LogInformation("User with ID '{UserId}' deleted themselves.", userId); | ||||
| 
 | ||||
|     private sealed class InputModel { | ||||
|         [DataType(DataType.Password)] public string Password { get; set; } = ""; | ||||
|     } | ||||
| } | ||||
| 		Message.ShowSuccess(Localizer["Delete_Success"]); | ||||
| 		RedirectManager.RedirectTo("/"); | ||||
| 	} | ||||
| 
 | ||||
| 	private sealed class InputModel { | ||||
| 		[DataType(DataType.Password)]  | ||||
| 		public string Password { get; set; } = ""; | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
|  | @ -9,132 +9,129 @@ | |||
| @inject IdentityUserAccessor UserAccessor | ||||
| @inject IUserStore<ApplicationUser> UserStore | ||||
| @inject IdentityRedirectManager RedirectManager | ||||
| @inject IStringLocalizer<ExternalLogin> Localizer | ||||
| 
 | ||||
| <PageTitle>Manage your external logins</PageTitle> | ||||
| <PageTitle>@Localizer["Title"]</PageTitle> | ||||
| 
 | ||||
| <StatusMessage /> | ||||
| @if (currentLogins?.Count > 0) | ||||
| { | ||||
|     <h3>Registered Logins</h3> | ||||
|     <table class="table"> | ||||
|         <tbody> | ||||
|             @foreach (var login in currentLogins) | ||||
|             { | ||||
|                 <tr> | ||||
|                     <td>@login.ProviderDisplayName</td> | ||||
|                     <td> | ||||
|                         @if (showRemoveButton) | ||||
|                         { | ||||
|                             <form @formname="@($"remove-login-{login.LoginProvider}")" @onsubmit="OnSubmitAsync" method="post"> | ||||
|                                 <AntiforgeryToken /> | ||||
|                                 <div> | ||||
|                                     <input type="hidden" name="@nameof(LoginProvider)" value="@login.LoginProvider" /> | ||||
|                                     <input type="hidden" name="@nameof(ProviderKey)" value="@login.ProviderKey" /> | ||||
|                                     <button type="submit" class="btn btn-primary" title="Remove this @login.ProviderDisplayName login from your account">Remove</button> | ||||
|                                 </div> | ||||
|                             </form> | ||||
|                         } | ||||
|                         else | ||||
|                         { | ||||
|                             @:   | ||||
|                         } | ||||
|                     </td> | ||||
|                 </tr> | ||||
|             } | ||||
|         </tbody> | ||||
|     </table> | ||||
| } | ||||
| @if (otherLogins?.Count > 0) | ||||
| { | ||||
|     <h4>Add another service to log in.</h4> | ||||
|     <hr /> | ||||
|     <form class="form-horizontal" action="Account/Manage/LinkExternalLogin" method="post"> | ||||
|         <AntiforgeryToken /> | ||||
|         <div> | ||||
|             <p> | ||||
|                 @foreach (var provider in otherLogins) | ||||
|                 { | ||||
|                     <button type="submit" class="btn btn-primary" name="Provider" value="@provider.Name" title="Log in using your @provider.DisplayName account"> | ||||
|                         @provider.DisplayName | ||||
|                     </button> | ||||
|                 } | ||||
|             </p> | ||||
|         </div> | ||||
|     </form> | ||||
| <StatusMessage/> | ||||
| 
 | ||||
| @if (CurrentLogins?.Count > 0) { | ||||
| 	<BoardComponent> | ||||
| 		<BoardCardComponent Heading="@Localizer["Title"]"> | ||||
| 			<div class="overflow-x-auto"> | ||||
| 				<table class="table"> | ||||
| 					<thead> | ||||
| 					<tr> | ||||
| 						<th>Provider</th> | ||||
| 						<th></th> | ||||
| 					</tr> | ||||
| 					</thead> | ||||
| 					<tbody> | ||||
| 					@foreach (var login in CurrentLogins) { | ||||
| 						<tr> | ||||
| 							<td>@login.ProviderDisplayName</td> | ||||
| 							<td> | ||||
| 								@if (ShowRemoveButton) { | ||||
| 									<form @formname="@($"remove-login-{login.LoginProvider}")" @onsubmit="OnSubmitAsync" method="post"> | ||||
| 										<AntiforgeryToken/> | ||||
| 										<div> | ||||
| 											<input type="hidden" name="@nameof(LoginProvider)" value="@login.LoginProvider"/> | ||||
| 											<input type="hidden" name="@nameof(ProviderKey)" value="@login.ProviderKey"/> | ||||
| 											<button type="submit" class="btn btn-primary" title="Remove this @login.ProviderDisplayName login from your account">Remove</button> | ||||
| 										</div> | ||||
| 									</form> | ||||
| 								} else { | ||||
| 									@:   | ||||
| 								} | ||||
| 							</td> | ||||
| 						</tr> | ||||
| 					} | ||||
| 					</tbody> | ||||
| 				</table> | ||||
| 			</div> | ||||
| 		</BoardCardComponent> | ||||
| 		@if (OtherLogins?.Count > 0) { | ||||
| 			<BoardCardComponent Heading="Add another service to log in."> | ||||
| 				<form class="form-horizontal" action="Account/Manage/LinkExternalLogin" method="post"> | ||||
| 					<AntiforgeryToken/> | ||||
| 					<div> | ||||
| 						<p> | ||||
| 							@foreach (var provider in OtherLogins) { | ||||
| 								<button type="submit" class="btn btn-primary" name="Provider" value="@provider.Name" title="Log in using your @provider.DisplayName account"> | ||||
| 									@provider.DisplayName | ||||
| 								</button> | ||||
| 							} | ||||
| 						</p> | ||||
| 					</div> | ||||
| 				</form> | ||||
| 			</BoardCardComponent> | ||||
| 		} | ||||
| 	</BoardComponent> | ||||
| } | ||||
| 
 | ||||
| @code { | ||||
|     public const string LinkLoginCallbackAction = "LinkLoginCallback"; | ||||
| 	public const string LinkLoginCallbackAction = "LinkLoginCallback"; | ||||
| 
 | ||||
|     private ApplicationUser user = default!; | ||||
|     private IList<UserLoginInfo>? currentLogins; | ||||
|     private IList<AuthenticationScheme>? otherLogins; | ||||
|     private bool showRemoveButton; | ||||
| 	private ApplicationUser User { get; set; } = default!; | ||||
| 	private IList<UserLoginInfo>? CurrentLogins { get; set; } | ||||
| 	private IList<AuthenticationScheme>? OtherLogins { get; set; } | ||||
| 	private bool ShowRemoveButton { get; set; } | ||||
| 
 | ||||
|     [CascadingParameter] | ||||
| 	[CascadingParameter]  | ||||
|     private HttpContext HttpContext { get; set; } = default!; | ||||
| 
 | ||||
|     [SupplyParameterFromForm] | ||||
| 	[SupplyParameterFromForm]  | ||||
|     private string? LoginProvider { get; set; } | ||||
| 
 | ||||
|     [SupplyParameterFromForm] | ||||
| 	[SupplyParameterFromForm]  | ||||
|     private string? ProviderKey { get; set; } | ||||
| 
 | ||||
|     [SupplyParameterFromQuery] | ||||
| 	[SupplyParameterFromQuery]  | ||||
|     private string? Action { get; set; } | ||||
| 
 | ||||
|     protected override async Task OnInitializedAsync() | ||||
|     { | ||||
|         user = await UserAccessor.GetRequiredUserAsync(HttpContext); | ||||
|         currentLogins = await UserManager.GetLoginsAsync(user); | ||||
|         otherLogins = (await SignInManager.GetExternalAuthenticationSchemesAsync()) | ||||
|             .Where(auth => currentLogins.All(ul => auth.Name != ul.LoginProvider)) | ||||
|             .ToList(); | ||||
| 	protected override async Task OnInitializedAsync() { | ||||
| 		User = await UserAccessor.GetRequiredUserAsync(HttpContext); | ||||
| 		CurrentLogins = await UserManager.GetLoginsAsync(User); | ||||
| 		OtherLogins = (await SignInManager.GetExternalAuthenticationSchemesAsync()) | ||||
| 			.Where(auth => CurrentLogins.All(ul => auth.Name != ul.LoginProvider)) | ||||
| 			.ToList(); | ||||
| 
 | ||||
|         string? passwordHash = null; | ||||
|         if (UserStore is IUserPasswordStore<ApplicationUser> userPasswordStore) | ||||
|         { | ||||
|             passwordHash = await userPasswordStore.GetPasswordHashAsync(user, HttpContext.RequestAborted); | ||||
|         } | ||||
| 		string? passwordHash = null; | ||||
| 		if (UserStore is IUserPasswordStore<ApplicationUser> userPasswordStore) { | ||||
| 			passwordHash = await userPasswordStore.GetPasswordHashAsync(User, HttpContext.RequestAborted); | ||||
| 		} | ||||
| 
 | ||||
|         showRemoveButton = passwordHash is not null || currentLogins.Count > 1; | ||||
| 		ShowRemoveButton = passwordHash is not null || CurrentLogins.Count > 1; | ||||
| 
 | ||||
|         if (HttpMethods.IsGet(HttpContext.Request.Method) && Action == LinkLoginCallbackAction) | ||||
|         { | ||||
|             await OnGetLinkLoginCallbackAsync(); | ||||
|         } | ||||
|     } | ||||
| 		if (HttpMethods.IsGet(HttpContext.Request.Method) && Action == LinkLoginCallbackAction) { | ||||
| 			await OnGetLinkLoginCallbackAsync(); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
|     private async Task OnSubmitAsync() | ||||
|     { | ||||
|         var result = await UserManager.RemoveLoginAsync(user, LoginProvider!, ProviderKey!); | ||||
|         if (!result.Succeeded) | ||||
|         { | ||||
|             RedirectManager.RedirectToCurrentPageWithStatus("Error: The external login was not removed.", HttpContext); | ||||
|         } | ||||
| 	private async Task OnSubmitAsync() { | ||||
| 		var result = await UserManager.RemoveLoginAsync(User, LoginProvider!, ProviderKey!); | ||||
| 		if (!result.Succeeded) { | ||||
| 			RedirectManager.RedirectToCurrentPageWithStatus("Error: The external login was not removed.", HttpContext); | ||||
| 		} | ||||
| 
 | ||||
|         await SignInManager.RefreshSignInAsync(user); | ||||
|         RedirectManager.RedirectToCurrentPageWithStatus("The external login was removed.", HttpContext); | ||||
|     } | ||||
| 		await SignInManager.RefreshSignInAsync(User); | ||||
| 		RedirectManager.RedirectToCurrentPageWithStatus("The external login was removed.", HttpContext); | ||||
| 	} | ||||
| 
 | ||||
|     private async Task OnGetLinkLoginCallbackAsync() | ||||
|     { | ||||
|         var userId = await UserManager.GetUserIdAsync(user); | ||||
|         var info = await SignInManager.GetExternalLoginInfoAsync(userId); | ||||
|         if (info is null) | ||||
|         { | ||||
|             RedirectManager.RedirectToCurrentPageWithStatus("Error: Could not load external login info.", HttpContext); | ||||
|         } | ||||
| 	private async Task OnGetLinkLoginCallbackAsync() { | ||||
| 		var userId = await UserManager.GetUserIdAsync(User); | ||||
| 		var info = await SignInManager.GetExternalLoginInfoAsync(userId); | ||||
| 		if (info is null) { | ||||
| 			RedirectManager.RedirectToCurrentPageWithStatus("Error: Could not load external login info.", HttpContext); | ||||
| 		} | ||||
| 
 | ||||
|         var result = await UserManager.AddLoginAsync(user, info); | ||||
|         if (!result.Succeeded) | ||||
|         { | ||||
|             RedirectManager.RedirectToCurrentPageWithStatus("Error: The external login was not added. External logins can only be associated with one account.", HttpContext); | ||||
|         } | ||||
| 		var result = await UserManager.AddLoginAsync(User, info); | ||||
| 		if (!result.Succeeded) { | ||||
| 			RedirectManager.RedirectToCurrentPageWithStatus("Error: The external login was not added. External logins can only be associated with one account.", HttpContext); | ||||
| 		} | ||||
| 
 | ||||
|         // Clear the existing external cookie to ensure a clean login process | ||||
|         await HttpContext.SignOutAsync(IdentityConstants.ExternalScheme); | ||||
| 		// Clear the existing external cookie to ensure a clean login process | ||||
| 		await HttpContext.SignOutAsync(IdentityConstants.ExternalScheme); | ||||
| 
 | ||||
|         RedirectManager.RedirectToCurrentPageWithStatus("The external login was added.", HttpContext); | ||||
|     } | ||||
| } | ||||
| 		RedirectManager.RedirectToCurrentPageWithStatus("The external login was added.", HttpContext); | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
|  | @ -8,80 +8,72 @@ | |||
| @inject SignInManager<ApplicationUser> SignInManager | ||||
| @inject IdentityUserAccessor UserAccessor | ||||
| @inject IdentityRedirectManager RedirectManager | ||||
| @inject IStringLocalizer<SetPassword> Localizer | ||||
| 
 | ||||
| <PageTitle>Set password</PageTitle> | ||||
| <PageTitle>@Localizer["Title"]</PageTitle> | ||||
| 
 | ||||
| <h3>Set your password</h3> | ||||
| <StatusMessage Message="@message" /> | ||||
| <p class="text-info"> | ||||
|     You do not have a local username/password for this site. Add a local | ||||
|     account so you can log in without an external login. | ||||
| </p> | ||||
| <div class="row"> | ||||
|     <div class="col-md-6"> | ||||
|         <EditForm Model="Input" FormName="set-password" OnValidSubmit="OnValidSubmitAsync" method="post"> | ||||
|             <DataAnnotationsValidator /> | ||||
|             <ValidationSummary class="text-danger" role="alert" /> | ||||
|             <div class="form-floating mb-3"> | ||||
|                 <InputText type="password" @bind-Value="Input.NewPassword" class="form-control" autocomplete="new-password" placeholder="Please enter your new password." /> | ||||
|                 <label for="new-password" class="form-label">New password</label> | ||||
|                 <ValidationMessage For="() => Input.NewPassword" class="text-danger" /> | ||||
|             </div> | ||||
|             <div class="form-floating mb-3"> | ||||
|                 <InputText type="password" @bind-Value="Input.ConfirmPassword" class="form-control" autocomplete="new-password" placeholder="Please confirm your new password." /> | ||||
|                 <label for="confirm-password" class="form-label">Confirm password</label> | ||||
|                 <ValidationMessage For="() => Input.ConfirmPassword" class="text-danger" /> | ||||
|             </div> | ||||
|             <button type="submit" class="w-100 btn btn-lg btn-primary">Set password</button> | ||||
|         </EditForm> | ||||
|      </div> | ||||
| </div> | ||||
| <StatusMessage Message="@Message"/> | ||||
| <BoardComponent> | ||||
| 	<BoardCardComponent Heading="@Localizer["Title"]"> | ||||
| 		<Alert CanRemove="false" Type="Alert.MessageType.Information"> | ||||
| 			<p>@Localizer["Message"]</p> | ||||
| 		</Alert> | ||||
| 		<EditForm Model="Input" FormName="set-password" OnValidSubmit="OnValidSubmitAsync" method="post"> | ||||
| 			<DataAnnotationsValidator/> | ||||
| 			<InputLabelComponent LabelText="@Localizer["NewPassword_Label"]" For="() => Input.NewPassword"> | ||||
| 				<InputText type="password" @bind-Value="Input.NewPassword" class="input input-bordered w-full" autocomplete="new-password" | ||||
| 				           required aria-required="true" placeholder="@Localizer["NewPassword_Placeholder"]"/> | ||||
| 			</InputLabelComponent> | ||||
| 			<InputLabelComponent LabelText="@Localizer["ConfirmPassword_Label"]" For="() => Input.ConfirmPassword"> | ||||
| 				<InputText type="password" @bind-Value="Input.ConfirmPassword" class="input input-bordered w-full" autocomplete="new-password" | ||||
| 				           required aria-required="true" placeholder="@Localizer["ConfirmPassword_Placeholder"]"/> | ||||
| 			</InputLabelComponent> | ||||
| 			<button type="submit" class="btn btn-primary w-full"> | ||||
| 				@Localizer["ChangePassword_Submit"] | ||||
| 			</button> | ||||
| 		</EditForm> | ||||
| 	</BoardCardComponent> | ||||
| </BoardComponent> | ||||
| 
 | ||||
| @code { | ||||
|     private string? message; | ||||
|     private ApplicationUser user = default!; | ||||
| 	private string? Message { get; set; } | ||||
| 	private ApplicationUser User { get; set; } = default!; | ||||
| 
 | ||||
|     [CascadingParameter] | ||||
|     private HttpContext HttpContext { get; set; } = default!; | ||||
| 	[CascadingParameter] private HttpContext HttpContext { get; set; } = default!; | ||||
| 
 | ||||
|     [SupplyParameterFromForm] | ||||
|     private InputModel Input { get; set; } = new(); | ||||
| 	[SupplyParameterFromForm] private InputModel Input { get; set; } = new(); | ||||
| 
 | ||||
|     protected override async Task OnInitializedAsync() | ||||
|     { | ||||
|         user = await UserAccessor.GetRequiredUserAsync(HttpContext); | ||||
| 	protected override async Task OnInitializedAsync() { | ||||
| 		User = await UserAccessor.GetRequiredUserAsync(HttpContext); | ||||
| 
 | ||||
|         var hasPassword = await UserManager.HasPasswordAsync(user); | ||||
|         if (hasPassword) | ||||
|         { | ||||
|             RedirectManager.RedirectTo("Account/Manage/ChangePassword"); | ||||
|         } | ||||
|     } | ||||
| 		bool hasPassword = await UserManager.HasPasswordAsync(User); | ||||
| 		if (hasPassword) { | ||||
| 			RedirectManager.RedirectTo("Account/Manage/ChangePassword"); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
|     private async Task OnValidSubmitAsync() | ||||
|     { | ||||
|         var addPasswordResult = await UserManager.AddPasswordAsync(user, Input.NewPassword!); | ||||
|         if (!addPasswordResult.Succeeded) | ||||
|         { | ||||
|             message = $"Error: {string.Join(",", addPasswordResult.Errors.Select(error => error.Description))}"; | ||||
|             return; | ||||
|         } | ||||
| 	private async Task OnValidSubmitAsync() { | ||||
| 		var addPasswordResult = await UserManager.AddPasswordAsync(User, Input.NewPassword!); | ||||
| 		if (!addPasswordResult.Succeeded) { | ||||
| 			Message = $"Error: {string.Join(",", addPasswordResult.Errors.Select(error => error.Description))}"; | ||||
| 			return; | ||||
| 		} | ||||
| 
 | ||||
|         await SignInManager.RefreshSignInAsync(user); | ||||
|         RedirectManager.RedirectToCurrentPageWithStatus("Your password has been set.", HttpContext); | ||||
|     } | ||||
| 		await SignInManager.RefreshSignInAsync(User); | ||||
| 		RedirectManager.RedirectToCurrentPageWithStatus("Your password has been set.", HttpContext); | ||||
| 	} | ||||
| 
 | ||||
|     private sealed class InputModel | ||||
|     { | ||||
|         [Required] | ||||
|         [StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)] | ||||
|         [DataType(DataType.Password)] | ||||
|         [Display(Name = "New password")] | ||||
|         public string? NewPassword { get; set; } | ||||
| 	private sealed class InputModel { | ||||
| 		[Required] | ||||
| 		[StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)] | ||||
| 		[DataType(DataType.Password)] | ||||
| 		[Display(Name = "New password")] | ||||
| 		public string? NewPassword { get; set; } | ||||
| 
 | ||||
|         [DataType(DataType.Password)] | ||||
|         [Display(Name = "Confirm new password")] | ||||
|         [Compare("NewPassword", ErrorMessage = "The new password and confirmation password do not match.")] | ||||
|         public string? ConfirmPassword { get; set; } | ||||
|     } | ||||
| } | ||||
| 		[DataType(DataType.Password)] | ||||
| 		[Display(Name = "Confirm new password")] | ||||
| 		[Compare("NewPassword", ErrorMessage = "The new password and confirmation password do not match.")] | ||||
| 		public string? ConfirmPassword { get; set; } | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
|  | @ -9,64 +9,59 @@ | |||
| @inject IEmailSender<ApplicationUser> EmailSender | ||||
| @inject NavigationManager NavigationManager | ||||
| @inject IdentityRedirectManager RedirectManager | ||||
| @inject IStringLocalizer<RegisterConfirmation> Localizer | ||||
| 
 | ||||
| <HeadContent> | ||||
|     <meta name="robots" content="noindex,nofollow"> | ||||
| 	<meta name="robots" content="noindex,nofollow"> | ||||
| </HeadContent> | ||||
| 
 | ||||
| <PageTitle>Register confirmation</PageTitle> | ||||
| <PageTitle>@Localizer["Title"] </PageTitle> | ||||
| 
 | ||||
| <h1>Register confirmation</h1> | ||||
| <StatusMessage Message="@statusMessage"/> | ||||
| 
 | ||||
| <StatusMessage Message="@statusMessage" /> | ||||
| 
 | ||||
| @if (emailConfirmationLink is not null) | ||||
| { | ||||
|     <p> | ||||
|         This app does not currently have a real email sender registered, see <a href="https://aka.ms/aspaccountconf">these docs</a> for how to configure a real email sender. | ||||
|         Normally this would be emailed: <a href="@emailConfirmationLink">Click here to confirm your account</a> | ||||
|     </p> | ||||
| } | ||||
| else | ||||
| { | ||||
|     <p>Please check your email to confirm your account.</p> | ||||
| } | ||||
| <BoardComponent CenterContent="true"> | ||||
| 	<BoardCardComponent Heading="@Localizer["Title"]"> | ||||
| 		<Alert CanRemove="false" Type="Alert.MessageType.Success"> | ||||
| 			@if (emailConfirmationLink is not null) { | ||||
| 				<p> | ||||
| 					This app does not currently have a real email sender registered, see <a href="https://aka.ms/aspaccountconf">these docs</a> for how to configure a real email sender. | ||||
| 					Normally this would be emailed: <a href="@emailConfirmationLink">Click here to confirm your account</a> | ||||
| 				</p> | ||||
| 			} else { | ||||
| 				<p>@Localizer["Message"]</p> | ||||
| 			} | ||||
| 		</Alert> | ||||
| 	</BoardCardComponent> | ||||
| </BoardComponent> | ||||
| 
 | ||||
| @code { | ||||
|     private string? emailConfirmationLink; | ||||
|     private string? statusMessage; | ||||
| 	private string? emailConfirmationLink; | ||||
| 	private string? statusMessage; | ||||
| 
 | ||||
|     [CascadingParameter] | ||||
|     private HttpContext HttpContext { get; set; } = default!; | ||||
| 	[CascadingParameter] private HttpContext HttpContext { get; set; } = default!; | ||||
| 
 | ||||
|     [SupplyParameterFromQuery] | ||||
|     private string? Email { get; set; } | ||||
| 	[SupplyParameterFromQuery] private string? Email { get; set; } | ||||
| 
 | ||||
|     [SupplyParameterFromQuery] | ||||
|     private string? ReturnUrl { get; set; } | ||||
| 	[SupplyParameterFromQuery] private string? ReturnUrl { get; set; } | ||||
| 
 | ||||
|     protected override async Task OnInitializedAsync() | ||||
|     { | ||||
|         if (Email is null) | ||||
|         { | ||||
|             RedirectManager.RedirectTo(""); | ||||
|         } | ||||
| 	protected override async Task OnInitializedAsync() { | ||||
| 		if (Email is null) { | ||||
| 			RedirectManager.RedirectTo(""); | ||||
| 		} | ||||
| 
 | ||||
|         var user = await UserManager.FindByEmailAsync(Email); | ||||
|         if (user is null) | ||||
|         { | ||||
|             HttpContext.Response.StatusCode = StatusCodes.Status404NotFound; | ||||
|             statusMessage = "Error finding user for unspecified email"; | ||||
|         } | ||||
|         else if (EmailSender is IdentityNoOpEmailSender) | ||||
|         { | ||||
|             // Once you add a real email sender, you should remove this code that lets you confirm the account | ||||
|             var userId = await UserManager.GetUserIdAsync(user); | ||||
|             var code = await UserManager.GenerateEmailConfirmationTokenAsync(user); | ||||
|             code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code)); | ||||
|             emailConfirmationLink = NavigationManager.GetUriWithQueryParameters( | ||||
|                 NavigationManager.ToAbsoluteUri("Account/ConfirmEmail").AbsoluteUri, | ||||
|                 new Dictionary<string, object?> { ["userId"] = userId, ["code"] = code, ["returnUrl"] = ReturnUrl }); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 		var user = await UserManager.FindByEmailAsync(Email); | ||||
| 		if (user is null) { | ||||
| 			HttpContext.Response.StatusCode = StatusCodes.Status404NotFound; | ||||
| 			statusMessage = "Error finding user for unspecified email"; | ||||
| 		} else if (EmailSender is IdentityNoOpEmailSender) { | ||||
| 			// Once you add a real email sender, you should remove this code that lets you confirm the account | ||||
| 			var userId = await UserManager.GetUserIdAsync(user); | ||||
| 			var code = await UserManager.GenerateEmailConfirmationTokenAsync(user); | ||||
| 			code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code)); | ||||
| 			emailConfirmationLink = NavigationManager.GetUriWithQueryParameters( | ||||
| 				NavigationManager.ToAbsoluteUri("Account/ConfirmEmail").AbsoluteUri, | ||||
| 				new Dictionary<string, object?> {["userId"] = userId, ["code"] = code, ["returnUrl"] = ReturnUrl}); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
|  | @ -4,40 +4,42 @@ | |||
| 
 | ||||
| @inject SignInManager<ApplicationUser> SignInManager | ||||
| @inject IdentityRedirectManager RedirectManager | ||||
| @inject IStringLocalizer<ExternalLoginPicker> Localizer | ||||
| 
 | ||||
| @if (externalLogins.Length == 0) | ||||
| { | ||||
|     <div> | ||||
|         <p> | ||||
|             There are no external authentication services configured. See this <a href="https://go.microsoft.com/fwlink/?LinkID=532715">article | ||||
|             about setting up this ASP.NET application to support logging in via external services</a>. | ||||
|         </p> | ||||
|     </div> | ||||
| } | ||||
| else | ||||
| { | ||||
|     <form class="form-horizontal" action="Account/PerformExternalLogin" method="post"> | ||||
|         <div> | ||||
|             <AntiforgeryToken /> | ||||
|             <input type="hidden" name="ReturnUrl" value="@ReturnUrl" /> | ||||
|             <p> | ||||
|                 @foreach (var provider in externalLogins) | ||||
|                 { | ||||
|                     <button type="submit" class="btn btn-primary" name="provider" value="@provider.Name" title="Log in using your @provider.DisplayName account">@provider.DisplayName</button> | ||||
|                 } | ||||
|             </p> | ||||
|         </div> | ||||
|     </form> | ||||
| @if (externalLogins.Length > 0) { | ||||
| 	<BoardCardComponent Heading="@Localizer["Title"]"> | ||||
| 		<form class="form-horizontal" action="Account/PerformExternalLogin" method="post"> | ||||
| 			<div class="flex flex-col space-y-3"> | ||||
| 				<AntiforgeryToken/> | ||||
| 				<input type="hidden" name="ReturnUrl" value="@ReturnUrl"/> | ||||
| 				<p> | ||||
| 					@foreach (var provider in externalLogins) { | ||||
| 						if (provider.Name is "OpenIdConnect") { | ||||
| 							<button type="submit" class="btn btn-wide btn-primary" name="provider" value="@provider.Name" title="@Localizer["OpenId_Tooltip"]"> | ||||
| 								@Localizer["OpenId_Label"] | ||||
| 								<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6"> | ||||
| 									<path stroke-linecap="round" stroke-linejoin="round" d="M15.75 9V5.25A2.25 2.25 0 0 0 13.5 3h-6a2.25 2.25 0 0 0-2.25 2.25v13.5A2.25 2.25 0 0 0 7.5 21h6a2.25 2.25 0 0 0 2.25-2.25V15m3 0 3-3m0 0-3-3m3 3H9" /> | ||||
| 								</svg> | ||||
| 							</button> | ||||
| 						} else { | ||||
| 							<button type="submit" class="btn btn-wide btn-primary" name="provider" value="@provider.Name" title="Log in using your @provider.DisplayName account"> | ||||
| 								@provider.DisplayName | ||||
| 							</button> | ||||
| 						} | ||||
| 					} | ||||
| 				</p> | ||||
| 			</div> | ||||
| 		</form> | ||||
| 	</BoardCardComponent> | ||||
| } | ||||
| 
 | ||||
| @code { | ||||
|     private AuthenticationScheme[] externalLogins = []; | ||||
| 	private AuthenticationScheme[] externalLogins = []; | ||||
| 
 | ||||
|     [SupplyParameterFromQuery] | ||||
|     private string? ReturnUrl { get; set; } | ||||
| 	[SupplyParameterFromQuery] private string? ReturnUrl { get; set; } | ||||
| 
 | ||||
|     protected override async Task OnInitializedAsync() | ||||
|     { | ||||
|         externalLogins = (await SignInManager.GetExternalAuthenticationSchemesAsync()).ToArray(); | ||||
|     } | ||||
| } | ||||
| 	protected override async Task OnInitializedAsync() { | ||||
| 		externalLogins = (await SignInManager.GetExternalAuthenticationSchemesAsync()).ToArray(); | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										7
									
								
								Wave/Data/OidcConfiguration.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								Wave/Data/OidcConfiguration.cs
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,7 @@ | |||
| namespace Wave.Data; | ||||
| 
 | ||||
| public class OidcConfiguration { | ||||
| 	public string Authority { get; set; } = string.Empty; | ||||
| 	public string ClientId { get; set; } = string.Empty; | ||||
| 	public string ClientSecret { get; set; } = string.Empty; | ||||
| } | ||||
|  | @ -11,7 +11,7 @@ public class UserClaimsFactory( | |||
| 	: UserClaimsPrincipalFactory<ApplicationUser, IdentityRole>(userManager, roleManager, options) { | ||||
| 	protected override async Task<ClaimsIdentity> GenerateClaimsAsync(ApplicationUser user) { | ||||
| 		var principal = await base.GenerateClaimsAsync(user); | ||||
| 		principal.AddClaim(new Claim("Id", user.Id)); | ||||
| 		// principal.AddClaim(new Claim("Id", user.Id)); | ||||
| 		principal.AddClaim(new Claim("FullName", user.Name)); | ||||
| 		return principal; | ||||
| 	} | ||||
|  |  | |||
|  | @ -5,7 +5,6 @@ | |||
| using Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption; | ||||
| using Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel; | ||||
| using Microsoft.AspNetCore.Identity; | ||||
| using Microsoft.AspNetCore.Identity.UI.Services; | ||||
| using Microsoft.AspNetCore.StaticFiles; | ||||
| using Microsoft.EntityFrameworkCore; | ||||
| using Microsoft.Extensions.Caching.Distributed; | ||||
|  | @ -19,6 +18,7 @@ | |||
| using Wave.Data; | ||||
| using Wave.Services; | ||||
| using Wave.Utilities; | ||||
| using Microsoft.IdentityModel.Protocols.OpenIdConnect; | ||||
| 
 | ||||
| string humanReadableVersion = Assembly.GetEntryAssembly()? | ||||
| 	.GetCustomAttribute<AssemblyInformationalVersionAttribute>()? | ||||
|  | @ -94,7 +94,7 @@ | |||
| 	.AddPolicy("ArticleEditOrReviewPermissions", p => p.RequireRole("Author", "Reviewer", "Admin")) | ||||
| 	 | ||||
| 	.AddPolicy("EmailApi", p => p.RequireClaim("EmailApi") | ||||
| 		.AddAuthenticationSchemes(ApiKeyDefaults.AuthenticationScheme)); | ||||
| 	.AddAuthenticationSchemes(ApiKeyDefaults.AuthenticationScheme)); | ||||
| builder.Services.AddAuthentication(options => { | ||||
| 		options.DefaultScheme = IdentityConstants.ApplicationScheme; | ||||
| 		options.DefaultSignInScheme = IdentityConstants.ExternalScheme; | ||||
|  | @ -103,6 +103,30 @@ | |||
| 		options.Realm = "Wave API"; | ||||
| 	}) | ||||
| 	.AddIdentityCookies(); | ||||
| if (builder.Configuration.GetSection("Oidc").Get<OidcConfiguration>() is {} oidc && !string.IsNullOrWhiteSpace(oidc.Authority)) { | ||||
| 	builder.Services.AddAuthentication(options => { | ||||
| 		options.DefaultScheme = IdentityConstants.ApplicationScheme; | ||||
| 		options.DefaultSignInScheme = IdentityConstants.ExternalScheme; | ||||
| 	}).AddOpenIdConnect(options => { | ||||
| 		options.SignInScheme = IdentityConstants.ExternalScheme; | ||||
| 
 | ||||
| 		options.Scope.Add(OpenIdConnectScope.OpenIdProfile); | ||||
| 		options.Scope.Add(OpenIdConnectScope.OfflineAccess); | ||||
| 		options.Authority = oidc.Authority; | ||||
| 
 | ||||
| 		options.ClientId = oidc.ClientId; | ||||
| 		options.ClientSecret = oidc.ClientSecret; | ||||
| 		options.ResponseType = OpenIdConnectResponseType.Code; | ||||
| 
 | ||||
| 		options.MapInboundClaims = false; | ||||
| 		options.TokenValidationParameters.NameClaimType = "name"; | ||||
| 		options.TokenValidationParameters.RoleClaimType = "role"; | ||||
| 
 | ||||
| 		options.CallbackPath = new PathString("/signin-oidc"); | ||||
| 		options.SignedOutCallbackPath = new PathString("/signout-callback-oidc"); | ||||
| 		options.RemoteSignOutPath = new PathString("/signout-oidc"); | ||||
| 	}); | ||||
| } | ||||
| 
 | ||||
| #endregion | ||||
| 
 | ||||
|  | @ -114,7 +138,10 @@ | |||
| 	options.UseNpgsql(connectionString)); | ||||
| builder.Services.AddDatabaseDeveloperPageExceptionFilter(); | ||||
| 
 | ||||
| builder.Services.AddIdentityCore<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = true) | ||||
| builder.Services.AddIdentityCore<ApplicationUser>(options => { | ||||
| 		options.SignIn.RequireConfirmedAccount = true; | ||||
| 		options.ClaimsIdentity.UserIdClaimType = "Id"; | ||||
| 	}) | ||||
| 	.AddRoles<IdentityRole>() | ||||
| 	.AddEntityFrameworkStores<ApplicationDbContext>() | ||||
| 	.AddSignInManager() | ||||
|  |  | |||
|  | @ -110,4 +110,7 @@ | |||
|   <data name="Success" xml:space="preserve"> | ||||
|     <value>Vielen Dank fürs Bestätigen ihrer E-Mail Adresse.</value> | ||||
|   </data> | ||||
|     <data name="Login_Label" xml:space="preserve"> | ||||
|         <value>Anmelden</value> | ||||
|     </data> | ||||
| </root> | ||||
|  | @ -110,4 +110,7 @@ | |||
|   <data name="Success" xml:space="preserve"> | ||||
|     <value>Thank you for confirming your email.</value> | ||||
|   </data> | ||||
|     <data name="Login_Label" xml:space="preserve"> | ||||
|         <value>Log In</value> | ||||
|     </data> | ||||
| </root> | ||||
							
								
								
									
										117
									
								
								Wave/Resources/Components/Account/Pages/ExternalLogin.de-DE.resx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										117
									
								
								Wave/Resources/Components/Account/Pages/ExternalLogin.de-DE.resx
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,117 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <root> | ||||
| 	<!--  | ||||
| 		Microsoft ResX Schema | ||||
| 
 | ||||
| 		Version 1.3 | ||||
| 
 | ||||
| 		The primary goals of this format is to allow a simple XML format  | ||||
| 		that is mostly human readable. The generation and parsing of the  | ||||
| 		various data types are done through the TypeConverter classes  | ||||
| 		associated with the data types. | ||||
| 
 | ||||
| 		Example: | ||||
| 
 | ||||
| 		... ado.net/XML headers & schema ... | ||||
| 		<resheader name="resmimetype">text/microsoft-resx</resheader> | ||||
| 		<resheader name="version">1.3</resheader> | ||||
| 		<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader> | ||||
| 		<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader> | ||||
| 		<data name="Name1">this is my long string</data> | ||||
| 		<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data> | ||||
| 		<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64"> | ||||
| 			[base64 mime encoded serialized .NET Framework object] | ||||
| 		</data> | ||||
| 		<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> | ||||
| 			[base64 mime encoded string representing a byte array form of the .NET Framework object] | ||||
| 		</data> | ||||
| 
 | ||||
| 		There are any number of "resheader" rows that contain simple  | ||||
| 		name/value pairs. | ||||
| 
 | ||||
| 		Each data row contains a name, and value. The row also contains a  | ||||
| 		type or mimetype. Type corresponds to a .NET class that support  | ||||
| 		text/value conversion through the TypeConverter architecture.  | ||||
| 		Classes that don't support this are serialized and stored with the  | ||||
| 		mimetype set. | ||||
| 
 | ||||
| 		The mimetype is used for serialized objects, and tells the  | ||||
| 		ResXResourceReader how to depersist the object. This is currently not  | ||||
| 		extensible. For a given mimetype the value must be set accordingly: | ||||
| 
 | ||||
| 		Note - application/x-microsoft.net.object.binary.base64 is the format  | ||||
| 		that the ResXResourceWriter will generate, however the reader can  | ||||
| 		read any of the formats listed below. | ||||
| 
 | ||||
| 		mimetype: application/x-microsoft.net.object.binary.base64 | ||||
| 		value   : The object must be serialized with  | ||||
| 			: System.Serialization.Formatters.Binary.BinaryFormatter | ||||
| 			: and then encoded with base64 encoding. | ||||
| 
 | ||||
| 		mimetype: application/x-microsoft.net.object.soap.base64 | ||||
| 		value   : The object must be serialized with  | ||||
| 			: System.Runtime.Serialization.Formatters.Soap.SoapFormatter | ||||
| 			: and then encoded with base64 encoding. | ||||
| 
 | ||||
| 		mimetype: application/x-microsoft.net.object.bytearray.base64 | ||||
| 		value   : The object must be serialized into a byte array  | ||||
| 			: using a System.ComponentModel.TypeConverter | ||||
| 			: and then encoded with base64 encoding. | ||||
| 	--> | ||||
| 	 | ||||
| 	<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> | ||||
| 		<xsd:element name="root" msdata:IsDataSet="true"> | ||||
| 			<xsd:complexType> | ||||
| 				<xsd:choice maxOccurs="unbounded"> | ||||
| 					<xsd:element name="data"> | ||||
| 						<xsd:complexType> | ||||
| 							<xsd:sequence> | ||||
| 								<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> | ||||
| 								<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" /> | ||||
| 							</xsd:sequence> | ||||
| 							<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" /> | ||||
| 							<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" /> | ||||
| 							<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" /> | ||||
| 						</xsd:complexType> | ||||
| 					</xsd:element> | ||||
| 					<xsd:element name="resheader"> | ||||
| 						<xsd:complexType> | ||||
| 							<xsd:sequence> | ||||
| 								<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> | ||||
| 							</xsd:sequence> | ||||
| 							<xsd:attribute name="name" type="xsd:string" use="required" /> | ||||
| 						</xsd:complexType> | ||||
| 					</xsd:element> | ||||
| 				</xsd:choice> | ||||
| 			</xsd:complexType> | ||||
| 		</xsd:element> | ||||
| 	</xsd:schema> | ||||
| 	<resheader name="resmimetype"> | ||||
| 		<value>text/microsoft-resx</value> | ||||
| 	</resheader> | ||||
| 	<resheader name="version"> | ||||
| 		<value>1.3</value> | ||||
| 	</resheader> | ||||
| 	<resheader name="reader"> | ||||
| 		<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> | ||||
| 	</resheader> | ||||
| 	<resheader name="writer"> | ||||
| 		<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> | ||||
| 	</resheader> | ||||
|     <data name="Message" xml:space="preserve"> | ||||
|         <value>Sie haben sich erfolgreich mit {0} angemeldet. | ||||
| Bitte geben Sie nun eine E-Mail Addresse für diese Webseite ein.</value> | ||||
|     </data> | ||||
|     <data name="Email_Label" xml:space="preserve"> | ||||
|         <value>E-Mail</value> | ||||
|     </data> | ||||
|     <data name="Email_Placeholder" xml:space="preserve"> | ||||
|         <value>name@example.de</value> | ||||
|     </data> | ||||
|     <data name="Submit" xml:space="preserve"> | ||||
|         <value>Registrieren</value> | ||||
|     </data> | ||||
|     <data name="Title" xml:space="preserve"> | ||||
|         <value>Benutzerkonto Erstellen</value> | ||||
|     </data> | ||||
| </root> | ||||
							
								
								
									
										101
									
								
								Wave/Resources/Components/Account/Pages/ExternalLogin.en-GB.resx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								Wave/Resources/Components/Account/Pages/ExternalLogin.en-GB.resx
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,101 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <root> | ||||
| 	<!--  | ||||
| 		Microsoft ResX Schema | ||||
| 
 | ||||
| 		Version 1.3 | ||||
| 
 | ||||
| 		The primary goals of this format is to allow a simple XML format  | ||||
| 		that is mostly human readable. The generation and parsing of the  | ||||
| 		various data types are done through the TypeConverter classes  | ||||
| 		associated with the data types. | ||||
| 
 | ||||
| 		Example: | ||||
| 
 | ||||
| 		... ado.net/XML headers & schema ... | ||||
| 		<resheader name="resmimetype">text/microsoft-resx</resheader> | ||||
| 		<resheader name="version">1.3</resheader> | ||||
| 		<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader> | ||||
| 		<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader> | ||||
| 		<data name="Name1">this is my long string</data> | ||||
| 		<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data> | ||||
| 		<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64"> | ||||
| 			[base64 mime encoded serialized .NET Framework object] | ||||
| 		</data> | ||||
| 		<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> | ||||
| 			[base64 mime encoded string representing a byte array form of the .NET Framework object] | ||||
| 		</data> | ||||
| 
 | ||||
| 		There are any number of "resheader" rows that contain simple  | ||||
| 		name/value pairs. | ||||
| 
 | ||||
| 		Each data row contains a name, and value. The row also contains a  | ||||
| 		type or mimetype. Type corresponds to a .NET class that support  | ||||
| 		text/value conversion through the TypeConverter architecture.  | ||||
| 		Classes that don't support this are serialized and stored with the  | ||||
| 		mimetype set. | ||||
| 
 | ||||
| 		The mimetype is used for serialized objects, and tells the  | ||||
| 		ResXResourceReader how to depersist the object. This is currently not  | ||||
| 		extensible. For a given mimetype the value must be set accordingly: | ||||
| 
 | ||||
| 		Note - application/x-microsoft.net.object.binary.base64 is the format  | ||||
| 		that the ResXResourceWriter will generate, however the reader can  | ||||
| 		read any of the formats listed below. | ||||
| 
 | ||||
| 		mimetype: application/x-microsoft.net.object.binary.base64 | ||||
| 		value   : The object must be serialized with  | ||||
| 			: System.Serialization.Formatters.Binary.BinaryFormatter | ||||
| 			: and then encoded with base64 encoding. | ||||
| 
 | ||||
| 		mimetype: application/x-microsoft.net.object.soap.base64 | ||||
| 		value   : The object must be serialized with  | ||||
| 			: System.Runtime.Serialization.Formatters.Soap.SoapFormatter | ||||
| 			: and then encoded with base64 encoding. | ||||
| 
 | ||||
| 		mimetype: application/x-microsoft.net.object.bytearray.base64 | ||||
| 		value   : The object must be serialized into a byte array  | ||||
| 			: using a System.ComponentModel.TypeConverter | ||||
| 			: and then encoded with base64 encoding. | ||||
| 	--> | ||||
| 	 | ||||
| 	<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> | ||||
| 		<xsd:element name="root" msdata:IsDataSet="true"> | ||||
| 			<xsd:complexType> | ||||
| 				<xsd:choice maxOccurs="unbounded"> | ||||
| 					<xsd:element name="data"> | ||||
| 						<xsd:complexType> | ||||
| 							<xsd:sequence> | ||||
| 								<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> | ||||
| 								<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" /> | ||||
| 							</xsd:sequence> | ||||
| 							<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" /> | ||||
| 							<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" /> | ||||
| 							<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" /> | ||||
| 						</xsd:complexType> | ||||
| 					</xsd:element> | ||||
| 					<xsd:element name="resheader"> | ||||
| 						<xsd:complexType> | ||||
| 							<xsd:sequence> | ||||
| 								<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> | ||||
| 							</xsd:sequence> | ||||
| 							<xsd:attribute name="name" type="xsd:string" use="required" /> | ||||
| 						</xsd:complexType> | ||||
| 					</xsd:element> | ||||
| 				</xsd:choice> | ||||
| 			</xsd:complexType> | ||||
| 		</xsd:element> | ||||
| 	</xsd:schema> | ||||
| 	<resheader name="resmimetype"> | ||||
| 		<value>text/microsoft-resx</value> | ||||
| 	</resheader> | ||||
| 	<resheader name="version"> | ||||
| 		<value>1.3</value> | ||||
| 	</resheader> | ||||
| 	<resheader name="reader"> | ||||
| 		<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> | ||||
| 	</resheader> | ||||
| 	<resheader name="writer"> | ||||
| 		<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> | ||||
| 	</resheader> | ||||
| </root> | ||||
							
								
								
									
										117
									
								
								Wave/Resources/Components/Account/Pages/ExternalLogin.resx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										117
									
								
								Wave/Resources/Components/Account/Pages/ExternalLogin.resx
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,117 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <root> | ||||
| 	<!--  | ||||
| 		Microsoft ResX Schema | ||||
| 
 | ||||
| 		Version 1.3 | ||||
| 
 | ||||
| 		The primary goals of this format is to allow a simple XML format  | ||||
| 		that is mostly human readable. The generation and parsing of the  | ||||
| 		various data types are done through the TypeConverter classes  | ||||
| 		associated with the data types. | ||||
| 
 | ||||
| 		Example: | ||||
| 
 | ||||
| 		... ado.net/XML headers & schema ... | ||||
| 		<resheader name="resmimetype">text/microsoft-resx</resheader> | ||||
| 		<resheader name="version">1.3</resheader> | ||||
| 		<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader> | ||||
| 		<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader> | ||||
| 		<data name="Name1">this is my long string</data> | ||||
| 		<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data> | ||||
| 		<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64"> | ||||
| 			[base64 mime encoded serialized .NET Framework object] | ||||
| 		</data> | ||||
| 		<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> | ||||
| 			[base64 mime encoded string representing a byte array form of the .NET Framework object] | ||||
| 		</data> | ||||
| 
 | ||||
| 		There are any number of "resheader" rows that contain simple  | ||||
| 		name/value pairs. | ||||
| 
 | ||||
| 		Each data row contains a name, and value. The row also contains a  | ||||
| 		type or mimetype. Type corresponds to a .NET class that support  | ||||
| 		text/value conversion through the TypeConverter architecture.  | ||||
| 		Classes that don't support this are serialized and stored with the  | ||||
| 		mimetype set. | ||||
| 
 | ||||
| 		The mimetype is used for serialized objects, and tells the  | ||||
| 		ResXResourceReader how to depersist the object. This is currently not  | ||||
| 		extensible. For a given mimetype the value must be set accordingly: | ||||
| 
 | ||||
| 		Note - application/x-microsoft.net.object.binary.base64 is the format  | ||||
| 		that the ResXResourceWriter will generate, however the reader can  | ||||
| 		read any of the formats listed below. | ||||
| 
 | ||||
| 		mimetype: application/x-microsoft.net.object.binary.base64 | ||||
| 		value   : The object must be serialized with  | ||||
| 			: System.Serialization.Formatters.Binary.BinaryFormatter | ||||
| 			: and then encoded with base64 encoding. | ||||
| 
 | ||||
| 		mimetype: application/x-microsoft.net.object.soap.base64 | ||||
| 		value   : The object must be serialized with  | ||||
| 			: System.Runtime.Serialization.Formatters.Soap.SoapFormatter | ||||
| 			: and then encoded with base64 encoding. | ||||
| 
 | ||||
| 		mimetype: application/x-microsoft.net.object.bytearray.base64 | ||||
| 		value   : The object must be serialized into a byte array  | ||||
| 			: using a System.ComponentModel.TypeConverter | ||||
| 			: and then encoded with base64 encoding. | ||||
| 	--> | ||||
| 	 | ||||
| 	<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> | ||||
| 		<xsd:element name="root" msdata:IsDataSet="true"> | ||||
| 			<xsd:complexType> | ||||
| 				<xsd:choice maxOccurs="unbounded"> | ||||
| 					<xsd:element name="data"> | ||||
| 						<xsd:complexType> | ||||
| 							<xsd:sequence> | ||||
| 								<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> | ||||
| 								<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" /> | ||||
| 							</xsd:sequence> | ||||
| 							<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" /> | ||||
| 							<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" /> | ||||
| 							<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" /> | ||||
| 						</xsd:complexType> | ||||
| 					</xsd:element> | ||||
| 					<xsd:element name="resheader"> | ||||
| 						<xsd:complexType> | ||||
| 							<xsd:sequence> | ||||
| 								<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> | ||||
| 							</xsd:sequence> | ||||
| 							<xsd:attribute name="name" type="xsd:string" use="required" /> | ||||
| 						</xsd:complexType> | ||||
| 					</xsd:element> | ||||
| 				</xsd:choice> | ||||
| 			</xsd:complexType> | ||||
| 		</xsd:element> | ||||
| 	</xsd:schema> | ||||
| 	<resheader name="resmimetype"> | ||||
| 		<value>text/microsoft-resx</value> | ||||
| 	</resheader> | ||||
| 	<resheader name="version"> | ||||
| 		<value>1.3</value> | ||||
| 	</resheader> | ||||
| 	<resheader name="reader"> | ||||
| 		<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> | ||||
| 	</resheader> | ||||
| 	<resheader name="writer"> | ||||
| 		<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> | ||||
| 	</resheader> | ||||
|     <data name="Title" xml:space="preserve"> | ||||
|         <value>Create Account</value> | ||||
|     </data> | ||||
|     <data name="Message" xml:space="preserve"> | ||||
|         <value>You've successfully authenticated with {0}. | ||||
| Please enter an email address for this site below.</value> | ||||
|     </data> | ||||
|     <data name="Email_Label" xml:space="preserve"> | ||||
|         <value>Email</value> | ||||
|     </data> | ||||
|     <data name="Email_Placeholder" xml:space="preserve"> | ||||
|         <value>name@example.com</value> | ||||
|     </data> | ||||
|     <data name="Submit" xml:space="preserve"> | ||||
|         <value>Register</value> | ||||
|     </data> | ||||
| </root> | ||||
|  | @ -0,0 +1,122 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <root> | ||||
| 	<!--  | ||||
| 		Microsoft ResX Schema | ||||
| 
 | ||||
| 		Version 1.3 | ||||
| 
 | ||||
| 		The primary goals of this format is to allow a simple XML format  | ||||
| 		that is mostly human readable. The generation and parsing of the  | ||||
| 		various data types are done through the TypeConverter classes  | ||||
| 		associated with the data types. | ||||
| 
 | ||||
| 		Example: | ||||
| 
 | ||||
| 		... ado.net/XML headers & schema ... | ||||
| 		<resheader name="resmimetype">text/microsoft-resx</resheader> | ||||
| 		<resheader name="version">1.3</resheader> | ||||
| 		<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader> | ||||
| 		<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader> | ||||
| 		<data name="Name1">this is my long string</data> | ||||
| 		<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data> | ||||
| 		<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64"> | ||||
| 			[base64 mime encoded serialized .NET Framework object] | ||||
| 		</data> | ||||
| 		<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> | ||||
| 			[base64 mime encoded string representing a byte array form of the .NET Framework object] | ||||
| 		</data> | ||||
| 
 | ||||
| 		There are any number of "resheader" rows that contain simple  | ||||
| 		name/value pairs. | ||||
| 
 | ||||
| 		Each data row contains a name, and value. The row also contains a  | ||||
| 		type or mimetype. Type corresponds to a .NET class that support  | ||||
| 		text/value conversion through the TypeConverter architecture.  | ||||
| 		Classes that don't support this are serialized and stored with the  | ||||
| 		mimetype set. | ||||
| 
 | ||||
| 		The mimetype is used for serialized objects, and tells the  | ||||
| 		ResXResourceReader how to depersist the object. This is currently not  | ||||
| 		extensible. For a given mimetype the value must be set accordingly: | ||||
| 
 | ||||
| 		Note - application/x-microsoft.net.object.binary.base64 is the format  | ||||
| 		that the ResXResourceWriter will generate, however the reader can  | ||||
| 		read any of the formats listed below. | ||||
| 
 | ||||
| 		mimetype: application/x-microsoft.net.object.binary.base64 | ||||
| 		value   : The object must be serialized with  | ||||
| 			: System.Serialization.Formatters.Binary.BinaryFormatter | ||||
| 			: and then encoded with base64 encoding. | ||||
| 
 | ||||
| 		mimetype: application/x-microsoft.net.object.soap.base64 | ||||
| 		value   : The object must be serialized with  | ||||
| 			: System.Runtime.Serialization.Formatters.Soap.SoapFormatter | ||||
| 			: and then encoded with base64 encoding. | ||||
| 
 | ||||
| 		mimetype: application/x-microsoft.net.object.bytearray.base64 | ||||
| 		value   : The object must be serialized into a byte array  | ||||
| 			: using a System.ComponentModel.TypeConverter | ||||
| 			: and then encoded with base64 encoding. | ||||
| 	--> | ||||
| 	 | ||||
| 	<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> | ||||
| 		<xsd:element name="root" msdata:IsDataSet="true"> | ||||
| 			<xsd:complexType> | ||||
| 				<xsd:choice maxOccurs="unbounded"> | ||||
| 					<xsd:element name="data"> | ||||
| 						<xsd:complexType> | ||||
| 							<xsd:sequence> | ||||
| 								<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> | ||||
| 								<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" /> | ||||
| 							</xsd:sequence> | ||||
| 							<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" /> | ||||
| 							<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" /> | ||||
| 							<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" /> | ||||
| 						</xsd:complexType> | ||||
| 					</xsd:element> | ||||
| 					<xsd:element name="resheader"> | ||||
| 						<xsd:complexType> | ||||
| 							<xsd:sequence> | ||||
| 								<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> | ||||
| 							</xsd:sequence> | ||||
| 							<xsd:attribute name="name" type="xsd:string" use="required" /> | ||||
| 						</xsd:complexType> | ||||
| 					</xsd:element> | ||||
| 				</xsd:choice> | ||||
| 			</xsd:complexType> | ||||
| 		</xsd:element> | ||||
| 	</xsd:schema> | ||||
| 	<resheader name="resmimetype"> | ||||
| 		<value>text/microsoft-resx</value> | ||||
| 	</resheader> | ||||
| 	<resheader name="version"> | ||||
| 		<value>1.3</value> | ||||
| 	</resheader> | ||||
| 	<resheader name="reader"> | ||||
| 		<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> | ||||
| 	</resheader> | ||||
| 	<resheader name="writer"> | ||||
| 		<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> | ||||
| 	</resheader> | ||||
|     <data name="Title" xml:space="preserve"> | ||||
|         <value>Passwort Erstellen</value> | ||||
|     </data> | ||||
|     <data name="Message" xml:space="preserve"> | ||||
|         <value>Sie haben momentan kein lokales Benutzerkonto/Passwort für diese Seite. Fügen Sie ein lokales Konto hinzu um sich ohne externen Dienst anmelden zu können.</value> | ||||
|     </data> | ||||
|     <data name="ConfirmPassword_Label" xml:space="preserve"> | ||||
|         <value>Neues Passwort wiederholen</value> | ||||
|     </data> | ||||
|     <data name="ConfirmPassword_Placeholder" xml:space="preserve"> | ||||
|         <value>Bestätigen Sie ihr neues Passwort</value> | ||||
|     </data> | ||||
|     <data name="NewPassword_Label" xml:space="preserve"> | ||||
|         <value>Neues Passwort</value> | ||||
|     </data> | ||||
|     <data name="NewPassword_Placeholder" xml:space="preserve"> | ||||
|         <value>Geben Sie ihr neues Passwort ein</value> | ||||
|     </data> | ||||
|     <data name="ChangePassword_Submit" xml:space="preserve"> | ||||
|         <value>Passwort Ändern</value> | ||||
|     </data> | ||||
| </root> | ||||
|  | @ -0,0 +1,101 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <root> | ||||
| 	<!--  | ||||
| 		Microsoft ResX Schema | ||||
| 
 | ||||
| 		Version 1.3 | ||||
| 
 | ||||
| 		The primary goals of this format is to allow a simple XML format  | ||||
| 		that is mostly human readable. The generation and parsing of the  | ||||
| 		various data types are done through the TypeConverter classes  | ||||
| 		associated with the data types. | ||||
| 
 | ||||
| 		Example: | ||||
| 
 | ||||
| 		... ado.net/XML headers & schema ... | ||||
| 		<resheader name="resmimetype">text/microsoft-resx</resheader> | ||||
| 		<resheader name="version">1.3</resheader> | ||||
| 		<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader> | ||||
| 		<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader> | ||||
| 		<data name="Name1">this is my long string</data> | ||||
| 		<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data> | ||||
| 		<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64"> | ||||
| 			[base64 mime encoded serialized .NET Framework object] | ||||
| 		</data> | ||||
| 		<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> | ||||
| 			[base64 mime encoded string representing a byte array form of the .NET Framework object] | ||||
| 		</data> | ||||
| 
 | ||||
| 		There are any number of "resheader" rows that contain simple  | ||||
| 		name/value pairs. | ||||
| 
 | ||||
| 		Each data row contains a name, and value. The row also contains a  | ||||
| 		type or mimetype. Type corresponds to a .NET class that support  | ||||
| 		text/value conversion through the TypeConverter architecture.  | ||||
| 		Classes that don't support this are serialized and stored with the  | ||||
| 		mimetype set. | ||||
| 
 | ||||
| 		The mimetype is used for serialized objects, and tells the  | ||||
| 		ResXResourceReader how to depersist the object. This is currently not  | ||||
| 		extensible. For a given mimetype the value must be set accordingly: | ||||
| 
 | ||||
| 		Note - application/x-microsoft.net.object.binary.base64 is the format  | ||||
| 		that the ResXResourceWriter will generate, however the reader can  | ||||
| 		read any of the formats listed below. | ||||
| 
 | ||||
| 		mimetype: application/x-microsoft.net.object.binary.base64 | ||||
| 		value   : The object must be serialized with  | ||||
| 			: System.Serialization.Formatters.Binary.BinaryFormatter | ||||
| 			: and then encoded with base64 encoding. | ||||
| 
 | ||||
| 		mimetype: application/x-microsoft.net.object.soap.base64 | ||||
| 		value   : The object must be serialized with  | ||||
| 			: System.Runtime.Serialization.Formatters.Soap.SoapFormatter | ||||
| 			: and then encoded with base64 encoding. | ||||
| 
 | ||||
| 		mimetype: application/x-microsoft.net.object.bytearray.base64 | ||||
| 		value   : The object must be serialized into a byte array  | ||||
| 			: using a System.ComponentModel.TypeConverter | ||||
| 			: and then encoded with base64 encoding. | ||||
| 	--> | ||||
| 	 | ||||
| 	<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> | ||||
| 		<xsd:element name="root" msdata:IsDataSet="true"> | ||||
| 			<xsd:complexType> | ||||
| 				<xsd:choice maxOccurs="unbounded"> | ||||
| 					<xsd:element name="data"> | ||||
| 						<xsd:complexType> | ||||
| 							<xsd:sequence> | ||||
| 								<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> | ||||
| 								<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" /> | ||||
| 							</xsd:sequence> | ||||
| 							<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" /> | ||||
| 							<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" /> | ||||
| 							<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" /> | ||||
| 						</xsd:complexType> | ||||
| 					</xsd:element> | ||||
| 					<xsd:element name="resheader"> | ||||
| 						<xsd:complexType> | ||||
| 							<xsd:sequence> | ||||
| 								<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> | ||||
| 							</xsd:sequence> | ||||
| 							<xsd:attribute name="name" type="xsd:string" use="required" /> | ||||
| 						</xsd:complexType> | ||||
| 					</xsd:element> | ||||
| 				</xsd:choice> | ||||
| 			</xsd:complexType> | ||||
| 		</xsd:element> | ||||
| 	</xsd:schema> | ||||
| 	<resheader name="resmimetype"> | ||||
| 		<value>text/microsoft-resx</value> | ||||
| 	</resheader> | ||||
| 	<resheader name="version"> | ||||
| 		<value>1.3</value> | ||||
| 	</resheader> | ||||
| 	<resheader name="reader"> | ||||
| 		<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> | ||||
| 	</resheader> | ||||
| 	<resheader name="writer"> | ||||
| 		<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> | ||||
| 	</resheader> | ||||
| </root> | ||||
							
								
								
									
										122
									
								
								Wave/Resources/Components/Account/Pages/Manage/SetPassword.resx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										122
									
								
								Wave/Resources/Components/Account/Pages/Manage/SetPassword.resx
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,122 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <root> | ||||
| 	<!--  | ||||
| 		Microsoft ResX Schema | ||||
| 
 | ||||
| 		Version 1.3 | ||||
| 
 | ||||
| 		The primary goals of this format is to allow a simple XML format  | ||||
| 		that is mostly human readable. The generation and parsing of the  | ||||
| 		various data types are done through the TypeConverter classes  | ||||
| 		associated with the data types. | ||||
| 
 | ||||
| 		Example: | ||||
| 
 | ||||
| 		... ado.net/XML headers & schema ... | ||||
| 		<resheader name="resmimetype">text/microsoft-resx</resheader> | ||||
| 		<resheader name="version">1.3</resheader> | ||||
| 		<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader> | ||||
| 		<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader> | ||||
| 		<data name="Name1">this is my long string</data> | ||||
| 		<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data> | ||||
| 		<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64"> | ||||
| 			[base64 mime encoded serialized .NET Framework object] | ||||
| 		</data> | ||||
| 		<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> | ||||
| 			[base64 mime encoded string representing a byte array form of the .NET Framework object] | ||||
| 		</data> | ||||
| 
 | ||||
| 		There are any number of "resheader" rows that contain simple  | ||||
| 		name/value pairs. | ||||
| 
 | ||||
| 		Each data row contains a name, and value. The row also contains a  | ||||
| 		type or mimetype. Type corresponds to a .NET class that support  | ||||
| 		text/value conversion through the TypeConverter architecture.  | ||||
| 		Classes that don't support this are serialized and stored with the  | ||||
| 		mimetype set. | ||||
| 
 | ||||
| 		The mimetype is used for serialized objects, and tells the  | ||||
| 		ResXResourceReader how to depersist the object. This is currently not  | ||||
| 		extensible. For a given mimetype the value must be set accordingly: | ||||
| 
 | ||||
| 		Note - application/x-microsoft.net.object.binary.base64 is the format  | ||||
| 		that the ResXResourceWriter will generate, however the reader can  | ||||
| 		read any of the formats listed below. | ||||
| 
 | ||||
| 		mimetype: application/x-microsoft.net.object.binary.base64 | ||||
| 		value   : The object must be serialized with  | ||||
| 			: System.Serialization.Formatters.Binary.BinaryFormatter | ||||
| 			: and then encoded with base64 encoding. | ||||
| 
 | ||||
| 		mimetype: application/x-microsoft.net.object.soap.base64 | ||||
| 		value   : The object must be serialized with  | ||||
| 			: System.Runtime.Serialization.Formatters.Soap.SoapFormatter | ||||
| 			: and then encoded with base64 encoding. | ||||
| 
 | ||||
| 		mimetype: application/x-microsoft.net.object.bytearray.base64 | ||||
| 		value   : The object must be serialized into a byte array  | ||||
| 			: using a System.ComponentModel.TypeConverter | ||||
| 			: and then encoded with base64 encoding. | ||||
| 	--> | ||||
| 	 | ||||
| 	<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> | ||||
| 		<xsd:element name="root" msdata:IsDataSet="true"> | ||||
| 			<xsd:complexType> | ||||
| 				<xsd:choice maxOccurs="unbounded"> | ||||
| 					<xsd:element name="data"> | ||||
| 						<xsd:complexType> | ||||
| 							<xsd:sequence> | ||||
| 								<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> | ||||
| 								<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" /> | ||||
| 							</xsd:sequence> | ||||
| 							<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" /> | ||||
| 							<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" /> | ||||
| 							<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" /> | ||||
| 						</xsd:complexType> | ||||
| 					</xsd:element> | ||||
| 					<xsd:element name="resheader"> | ||||
| 						<xsd:complexType> | ||||
| 							<xsd:sequence> | ||||
| 								<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> | ||||
| 							</xsd:sequence> | ||||
| 							<xsd:attribute name="name" type="xsd:string" use="required" /> | ||||
| 						</xsd:complexType> | ||||
| 					</xsd:element> | ||||
| 				</xsd:choice> | ||||
| 			</xsd:complexType> | ||||
| 		</xsd:element> | ||||
| 	</xsd:schema> | ||||
| 	<resheader name="resmimetype"> | ||||
| 		<value>text/microsoft-resx</value> | ||||
| 	</resheader> | ||||
| 	<resheader name="version"> | ||||
| 		<value>1.3</value> | ||||
| 	</resheader> | ||||
| 	<resheader name="reader"> | ||||
| 		<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> | ||||
| 	</resheader> | ||||
| 	<resheader name="writer"> | ||||
| 		<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> | ||||
| 	</resheader> | ||||
|     <data name="Title" xml:space="preserve"> | ||||
|         <value>Create Password</value> | ||||
|     </data> | ||||
|     <data name="Message" xml:space="preserve"> | ||||
|         <value>You do not have a local username/password for this site. Add a local account, so you can log in without an external login.</value> | ||||
|     </data> | ||||
|     <data name="NewPassword_Label" xml:space="preserve"> | ||||
|         <value>New password</value> | ||||
|     </data> | ||||
|     <data name="NewPassword_Placeholder" xml:space="preserve"> | ||||
|         <value>Enter your new password</value> | ||||
|     </data> | ||||
|     <data name="ConfirmPassword_Label" xml:space="preserve"> | ||||
|         <value>Confirm new password</value> | ||||
|     </data> | ||||
|     <data name="ConfirmPassword_Placeholder" xml:space="preserve"> | ||||
|         <value>Confirm your new Password</value> | ||||
|     </data> | ||||
|     <data name="ChangePassword_Submit" xml:space="preserve"> | ||||
|         <value>Change Password</value> | ||||
|     </data> | ||||
| </root> | ||||
|  | @ -0,0 +1,107 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <root> | ||||
| 	<!--  | ||||
| 		Microsoft ResX Schema | ||||
| 
 | ||||
| 		Version 1.3 | ||||
| 
 | ||||
| 		The primary goals of this format is to allow a simple XML format  | ||||
| 		that is mostly human readable. The generation and parsing of the  | ||||
| 		various data types are done through the TypeConverter classes  | ||||
| 		associated with the data types. | ||||
| 
 | ||||
| 		Example: | ||||
| 
 | ||||
| 		... ado.net/XML headers & schema ... | ||||
| 		<resheader name="resmimetype">text/microsoft-resx</resheader> | ||||
| 		<resheader name="version">1.3</resheader> | ||||
| 		<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader> | ||||
| 		<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader> | ||||
| 		<data name="Name1">this is my long string</data> | ||||
| 		<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data> | ||||
| 		<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64"> | ||||
| 			[base64 mime encoded serialized .NET Framework object] | ||||
| 		</data> | ||||
| 		<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> | ||||
| 			[base64 mime encoded string representing a byte array form of the .NET Framework object] | ||||
| 		</data> | ||||
| 
 | ||||
| 		There are any number of "resheader" rows that contain simple  | ||||
| 		name/value pairs. | ||||
| 
 | ||||
| 		Each data row contains a name, and value. The row also contains a  | ||||
| 		type or mimetype. Type corresponds to a .NET class that support  | ||||
| 		text/value conversion through the TypeConverter architecture.  | ||||
| 		Classes that don't support this are serialized and stored with the  | ||||
| 		mimetype set. | ||||
| 
 | ||||
| 		The mimetype is used for serialized objects, and tells the  | ||||
| 		ResXResourceReader how to depersist the object. This is currently not  | ||||
| 		extensible. For a given mimetype the value must be set accordingly: | ||||
| 
 | ||||
| 		Note - application/x-microsoft.net.object.binary.base64 is the format  | ||||
| 		that the ResXResourceWriter will generate, however the reader can  | ||||
| 		read any of the formats listed below. | ||||
| 
 | ||||
| 		mimetype: application/x-microsoft.net.object.binary.base64 | ||||
| 		value   : The object must be serialized with  | ||||
| 			: System.Serialization.Formatters.Binary.BinaryFormatter | ||||
| 			: and then encoded with base64 encoding. | ||||
| 
 | ||||
| 		mimetype: application/x-microsoft.net.object.soap.base64 | ||||
| 		value   : The object must be serialized with  | ||||
| 			: System.Runtime.Serialization.Formatters.Soap.SoapFormatter | ||||
| 			: and then encoded with base64 encoding. | ||||
| 
 | ||||
| 		mimetype: application/x-microsoft.net.object.bytearray.base64 | ||||
| 		value   : The object must be serialized into a byte array  | ||||
| 			: using a System.ComponentModel.TypeConverter | ||||
| 			: and then encoded with base64 encoding. | ||||
| 	--> | ||||
| 	 | ||||
| 	<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> | ||||
| 		<xsd:element name="root" msdata:IsDataSet="true"> | ||||
| 			<xsd:complexType> | ||||
| 				<xsd:choice maxOccurs="unbounded"> | ||||
| 					<xsd:element name="data"> | ||||
| 						<xsd:complexType> | ||||
| 							<xsd:sequence> | ||||
| 								<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> | ||||
| 								<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" /> | ||||
| 							</xsd:sequence> | ||||
| 							<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" /> | ||||
| 							<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" /> | ||||
| 							<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" /> | ||||
| 						</xsd:complexType> | ||||
| 					</xsd:element> | ||||
| 					<xsd:element name="resheader"> | ||||
| 						<xsd:complexType> | ||||
| 							<xsd:sequence> | ||||
| 								<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> | ||||
| 							</xsd:sequence> | ||||
| 							<xsd:attribute name="name" type="xsd:string" use="required" /> | ||||
| 						</xsd:complexType> | ||||
| 					</xsd:element> | ||||
| 				</xsd:choice> | ||||
| 			</xsd:complexType> | ||||
| 		</xsd:element> | ||||
| 	</xsd:schema> | ||||
| 	<resheader name="resmimetype"> | ||||
| 		<value>text/microsoft-resx</value> | ||||
| 	</resheader> | ||||
| 	<resheader name="version"> | ||||
| 		<value>1.3</value> | ||||
| 	</resheader> | ||||
| 	<resheader name="reader"> | ||||
| 		<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> | ||||
| 	</resheader> | ||||
| 	<resheader name="writer"> | ||||
| 		<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> | ||||
| 	</resheader> | ||||
|     <data name="Title" xml:space="preserve"> | ||||
|         <value>Registrierung Bestätigen</value> | ||||
|     </data> | ||||
|     <data name="Message" xml:space="preserve"> | ||||
|         <value>Bitte öffnen Sie Ihre E-Mails und bestätigen Sie ihr Benutzerkonto. Sie können sich nicht Anmelden bevor Ihr Konto bestätigt wurde.</value> | ||||
|     </data> | ||||
| </root> | ||||
|  | @ -0,0 +1,101 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <root> | ||||
| 	<!--  | ||||
| 		Microsoft ResX Schema | ||||
| 
 | ||||
| 		Version 1.3 | ||||
| 
 | ||||
| 		The primary goals of this format is to allow a simple XML format  | ||||
| 		that is mostly human readable. The generation and parsing of the  | ||||
| 		various data types are done through the TypeConverter classes  | ||||
| 		associated with the data types. | ||||
| 
 | ||||
| 		Example: | ||||
| 
 | ||||
| 		... ado.net/XML headers & schema ... | ||||
| 		<resheader name="resmimetype">text/microsoft-resx</resheader> | ||||
| 		<resheader name="version">1.3</resheader> | ||||
| 		<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader> | ||||
| 		<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader> | ||||
| 		<data name="Name1">this is my long string</data> | ||||
| 		<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data> | ||||
| 		<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64"> | ||||
| 			[base64 mime encoded serialized .NET Framework object] | ||||
| 		</data> | ||||
| 		<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> | ||||
| 			[base64 mime encoded string representing a byte array form of the .NET Framework object] | ||||
| 		</data> | ||||
| 
 | ||||
| 		There are any number of "resheader" rows that contain simple  | ||||
| 		name/value pairs. | ||||
| 
 | ||||
| 		Each data row contains a name, and value. The row also contains a  | ||||
| 		type or mimetype. Type corresponds to a .NET class that support  | ||||
| 		text/value conversion through the TypeConverter architecture.  | ||||
| 		Classes that don't support this are serialized and stored with the  | ||||
| 		mimetype set. | ||||
| 
 | ||||
| 		The mimetype is used for serialized objects, and tells the  | ||||
| 		ResXResourceReader how to depersist the object. This is currently not  | ||||
| 		extensible. For a given mimetype the value must be set accordingly: | ||||
| 
 | ||||
| 		Note - application/x-microsoft.net.object.binary.base64 is the format  | ||||
| 		that the ResXResourceWriter will generate, however the reader can  | ||||
| 		read any of the formats listed below. | ||||
| 
 | ||||
| 		mimetype: application/x-microsoft.net.object.binary.base64 | ||||
| 		value   : The object must be serialized with  | ||||
| 			: System.Serialization.Formatters.Binary.BinaryFormatter | ||||
| 			: and then encoded with base64 encoding. | ||||
| 
 | ||||
| 		mimetype: application/x-microsoft.net.object.soap.base64 | ||||
| 		value   : The object must be serialized with  | ||||
| 			: System.Runtime.Serialization.Formatters.Soap.SoapFormatter | ||||
| 			: and then encoded with base64 encoding. | ||||
| 
 | ||||
| 		mimetype: application/x-microsoft.net.object.bytearray.base64 | ||||
| 		value   : The object must be serialized into a byte array  | ||||
| 			: using a System.ComponentModel.TypeConverter | ||||
| 			: and then encoded with base64 encoding. | ||||
| 	--> | ||||
| 	 | ||||
| 	<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> | ||||
| 		<xsd:element name="root" msdata:IsDataSet="true"> | ||||
| 			<xsd:complexType> | ||||
| 				<xsd:choice maxOccurs="unbounded"> | ||||
| 					<xsd:element name="data"> | ||||
| 						<xsd:complexType> | ||||
| 							<xsd:sequence> | ||||
| 								<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> | ||||
| 								<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" /> | ||||
| 							</xsd:sequence> | ||||
| 							<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" /> | ||||
| 							<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" /> | ||||
| 							<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" /> | ||||
| 						</xsd:complexType> | ||||
| 					</xsd:element> | ||||
| 					<xsd:element name="resheader"> | ||||
| 						<xsd:complexType> | ||||
| 							<xsd:sequence> | ||||
| 								<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> | ||||
| 							</xsd:sequence> | ||||
| 							<xsd:attribute name="name" type="xsd:string" use="required" /> | ||||
| 						</xsd:complexType> | ||||
| 					</xsd:element> | ||||
| 				</xsd:choice> | ||||
| 			</xsd:complexType> | ||||
| 		</xsd:element> | ||||
| 	</xsd:schema> | ||||
| 	<resheader name="resmimetype"> | ||||
| 		<value>text/microsoft-resx</value> | ||||
| 	</resheader> | ||||
| 	<resheader name="version"> | ||||
| 		<value>1.3</value> | ||||
| 	</resheader> | ||||
| 	<resheader name="reader"> | ||||
| 		<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> | ||||
| 	</resheader> | ||||
| 	<resheader name="writer"> | ||||
| 		<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> | ||||
| 	</resheader> | ||||
| </root> | ||||
|  | @ -0,0 +1,107 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <root> | ||||
| 	<!--  | ||||
| 		Microsoft ResX Schema | ||||
| 
 | ||||
| 		Version 1.3 | ||||
| 
 | ||||
| 		The primary goals of this format is to allow a simple XML format  | ||||
| 		that is mostly human readable. The generation and parsing of the  | ||||
| 		various data types are done through the TypeConverter classes  | ||||
| 		associated with the data types. | ||||
| 
 | ||||
| 		Example: | ||||
| 
 | ||||
| 		... ado.net/XML headers & schema ... | ||||
| 		<resheader name="resmimetype">text/microsoft-resx</resheader> | ||||
| 		<resheader name="version">1.3</resheader> | ||||
| 		<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader> | ||||
| 		<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader> | ||||
| 		<data name="Name1">this is my long string</data> | ||||
| 		<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data> | ||||
| 		<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64"> | ||||
| 			[base64 mime encoded serialized .NET Framework object] | ||||
| 		</data> | ||||
| 		<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> | ||||
| 			[base64 mime encoded string representing a byte array form of the .NET Framework object] | ||||
| 		</data> | ||||
| 
 | ||||
| 		There are any number of "resheader" rows that contain simple  | ||||
| 		name/value pairs. | ||||
| 
 | ||||
| 		Each data row contains a name, and value. The row also contains a  | ||||
| 		type or mimetype. Type corresponds to a .NET class that support  | ||||
| 		text/value conversion through the TypeConverter architecture.  | ||||
| 		Classes that don't support this are serialized and stored with the  | ||||
| 		mimetype set. | ||||
| 
 | ||||
| 		The mimetype is used for serialized objects, and tells the  | ||||
| 		ResXResourceReader how to depersist the object. This is currently not  | ||||
| 		extensible. For a given mimetype the value must be set accordingly: | ||||
| 
 | ||||
| 		Note - application/x-microsoft.net.object.binary.base64 is the format  | ||||
| 		that the ResXResourceWriter will generate, however the reader can  | ||||
| 		read any of the formats listed below. | ||||
| 
 | ||||
| 		mimetype: application/x-microsoft.net.object.binary.base64 | ||||
| 		value   : The object must be serialized with  | ||||
| 			: System.Serialization.Formatters.Binary.BinaryFormatter | ||||
| 			: and then encoded with base64 encoding. | ||||
| 
 | ||||
| 		mimetype: application/x-microsoft.net.object.soap.base64 | ||||
| 		value   : The object must be serialized with  | ||||
| 			: System.Runtime.Serialization.Formatters.Soap.SoapFormatter | ||||
| 			: and then encoded with base64 encoding. | ||||
| 
 | ||||
| 		mimetype: application/x-microsoft.net.object.bytearray.base64 | ||||
| 		value   : The object must be serialized into a byte array  | ||||
| 			: using a System.ComponentModel.TypeConverter | ||||
| 			: and then encoded with base64 encoding. | ||||
| 	--> | ||||
| 	 | ||||
| 	<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> | ||||
| 		<xsd:element name="root" msdata:IsDataSet="true"> | ||||
| 			<xsd:complexType> | ||||
| 				<xsd:choice maxOccurs="unbounded"> | ||||
| 					<xsd:element name="data"> | ||||
| 						<xsd:complexType> | ||||
| 							<xsd:sequence> | ||||
| 								<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> | ||||
| 								<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" /> | ||||
| 							</xsd:sequence> | ||||
| 							<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" /> | ||||
| 							<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" /> | ||||
| 							<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" /> | ||||
| 						</xsd:complexType> | ||||
| 					</xsd:element> | ||||
| 					<xsd:element name="resheader"> | ||||
| 						<xsd:complexType> | ||||
| 							<xsd:sequence> | ||||
| 								<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> | ||||
| 							</xsd:sequence> | ||||
| 							<xsd:attribute name="name" type="xsd:string" use="required" /> | ||||
| 						</xsd:complexType> | ||||
| 					</xsd:element> | ||||
| 				</xsd:choice> | ||||
| 			</xsd:complexType> | ||||
| 		</xsd:element> | ||||
| 	</xsd:schema> | ||||
| 	<resheader name="resmimetype"> | ||||
| 		<value>text/microsoft-resx</value> | ||||
| 	</resheader> | ||||
| 	<resheader name="version"> | ||||
| 		<value>1.3</value> | ||||
| 	</resheader> | ||||
| 	<resheader name="reader"> | ||||
| 		<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> | ||||
| 	</resheader> | ||||
| 	<resheader name="writer"> | ||||
| 		<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> | ||||
| 	</resheader> | ||||
|     <data name="Title" xml:space="preserve"> | ||||
|         <value>Confirm Registration</value> | ||||
|     </data> | ||||
|     <data name="Message" xml:space="preserve"> | ||||
|         <value>Please check your email to confirm your account. You cannot log in before your account has been confirmed.</value> | ||||
|     </data> | ||||
| </root> | ||||
|  | @ -0,0 +1,107 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <root> | ||||
| 	<!--  | ||||
| 		Microsoft ResX Schema | ||||
| 
 | ||||
| 		Version 1.3 | ||||
| 
 | ||||
| 		The primary goals of this format is to allow a simple XML format  | ||||
| 		that is mostly human readable. The generation and parsing of the  | ||||
| 		various data types are done through the TypeConverter classes  | ||||
| 		associated with the data types. | ||||
| 
 | ||||
| 		Example: | ||||
| 
 | ||||
| 		... ado.net/XML headers & schema ... | ||||
| 		<resheader name="resmimetype">text/microsoft-resx</resheader> | ||||
| 		<resheader name="version">1.3</resheader> | ||||
| 		<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader> | ||||
| 		<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader> | ||||
| 		<data name="Name1">this is my long string</data> | ||||
| 		<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data> | ||||
| 		<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64"> | ||||
| 			[base64 mime encoded serialized .NET Framework object] | ||||
| 		</data> | ||||
| 		<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> | ||||
| 			[base64 mime encoded string representing a byte array form of the .NET Framework object] | ||||
| 		</data> | ||||
| 
 | ||||
| 		There are any number of "resheader" rows that contain simple  | ||||
| 		name/value pairs. | ||||
| 
 | ||||
| 		Each data row contains a name, and value. The row also contains a  | ||||
| 		type or mimetype. Type corresponds to a .NET class that support  | ||||
| 		text/value conversion through the TypeConverter architecture.  | ||||
| 		Classes that don't support this are serialized and stored with the  | ||||
| 		mimetype set. | ||||
| 
 | ||||
| 		The mimetype is used for serialized objects, and tells the  | ||||
| 		ResXResourceReader how to depersist the object. This is currently not  | ||||
| 		extensible. For a given mimetype the value must be set accordingly: | ||||
| 
 | ||||
| 		Note - application/x-microsoft.net.object.binary.base64 is the format  | ||||
| 		that the ResXResourceWriter will generate, however the reader can  | ||||
| 		read any of the formats listed below. | ||||
| 
 | ||||
| 		mimetype: application/x-microsoft.net.object.binary.base64 | ||||
| 		value   : The object must be serialized with  | ||||
| 			: System.Serialization.Formatters.Binary.BinaryFormatter | ||||
| 			: and then encoded with base64 encoding. | ||||
| 
 | ||||
| 		mimetype: application/x-microsoft.net.object.soap.base64 | ||||
| 		value   : The object must be serialized with  | ||||
| 			: System.Runtime.Serialization.Formatters.Soap.SoapFormatter | ||||
| 			: and then encoded with base64 encoding. | ||||
| 
 | ||||
| 		mimetype: application/x-microsoft.net.object.bytearray.base64 | ||||
| 		value   : The object must be serialized into a byte array  | ||||
| 			: using a System.ComponentModel.TypeConverter | ||||
| 			: and then encoded with base64 encoding. | ||||
| 	--> | ||||
| 	 | ||||
| 	<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> | ||||
| 		<xsd:element name="root" msdata:IsDataSet="true"> | ||||
| 			<xsd:complexType> | ||||
| 				<xsd:choice maxOccurs="unbounded"> | ||||
| 					<xsd:element name="data"> | ||||
| 						<xsd:complexType> | ||||
| 							<xsd:sequence> | ||||
| 								<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> | ||||
| 								<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" /> | ||||
| 							</xsd:sequence> | ||||
| 							<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" /> | ||||
| 							<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" /> | ||||
| 							<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" /> | ||||
| 						</xsd:complexType> | ||||
| 					</xsd:element> | ||||
| 					<xsd:element name="resheader"> | ||||
| 						<xsd:complexType> | ||||
| 							<xsd:sequence> | ||||
| 								<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> | ||||
| 							</xsd:sequence> | ||||
| 							<xsd:attribute name="name" type="xsd:string" use="required" /> | ||||
| 						</xsd:complexType> | ||||
| 					</xsd:element> | ||||
| 				</xsd:choice> | ||||
| 			</xsd:complexType> | ||||
| 		</xsd:element> | ||||
| 	</xsd:schema> | ||||
| 	<resheader name="resmimetype"> | ||||
| 		<value>text/microsoft-resx</value> | ||||
| 	</resheader> | ||||
| 	<resheader name="version"> | ||||
| 		<value>1.3</value> | ||||
| 	</resheader> | ||||
| 	<resheader name="reader"> | ||||
| 		<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> | ||||
| 	</resheader> | ||||
| 	<resheader name="writer"> | ||||
| 		<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> | ||||
| 	</resheader> | ||||
|     <data name="Title" xml:space="preserve"> | ||||
|         <value>Anmelden über externen Dienst</value> | ||||
|     </data> | ||||
|     <data name="OpenId_Tooltip" xml:space="preserve"> | ||||
|         <value>Melden Sie sich über ihren OpenID Connect Dienst an</value> | ||||
|     </data> | ||||
| </root> | ||||
|  | @ -0,0 +1,101 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <root> | ||||
| 	<!--  | ||||
| 		Microsoft ResX Schema | ||||
| 
 | ||||
| 		Version 1.3 | ||||
| 
 | ||||
| 		The primary goals of this format is to allow a simple XML format  | ||||
| 		that is mostly human readable. The generation and parsing of the  | ||||
| 		various data types are done through the TypeConverter classes  | ||||
| 		associated with the data types. | ||||
| 
 | ||||
| 		Example: | ||||
| 
 | ||||
| 		... ado.net/XML headers & schema ... | ||||
| 		<resheader name="resmimetype">text/microsoft-resx</resheader> | ||||
| 		<resheader name="version">1.3</resheader> | ||||
| 		<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader> | ||||
| 		<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader> | ||||
| 		<data name="Name1">this is my long string</data> | ||||
| 		<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data> | ||||
| 		<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64"> | ||||
| 			[base64 mime encoded serialized .NET Framework object] | ||||
| 		</data> | ||||
| 		<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> | ||||
| 			[base64 mime encoded string representing a byte array form of the .NET Framework object] | ||||
| 		</data> | ||||
| 
 | ||||
| 		There are any number of "resheader" rows that contain simple  | ||||
| 		name/value pairs. | ||||
| 
 | ||||
| 		Each data row contains a name, and value. The row also contains a  | ||||
| 		type or mimetype. Type corresponds to a .NET class that support  | ||||
| 		text/value conversion through the TypeConverter architecture.  | ||||
| 		Classes that don't support this are serialized and stored with the  | ||||
| 		mimetype set. | ||||
| 
 | ||||
| 		The mimetype is used for serialized objects, and tells the  | ||||
| 		ResXResourceReader how to depersist the object. This is currently not  | ||||
| 		extensible. For a given mimetype the value must be set accordingly: | ||||
| 
 | ||||
| 		Note - application/x-microsoft.net.object.binary.base64 is the format  | ||||
| 		that the ResXResourceWriter will generate, however the reader can  | ||||
| 		read any of the formats listed below. | ||||
| 
 | ||||
| 		mimetype: application/x-microsoft.net.object.binary.base64 | ||||
| 		value   : The object must be serialized with  | ||||
| 			: System.Serialization.Formatters.Binary.BinaryFormatter | ||||
| 			: and then encoded with base64 encoding. | ||||
| 
 | ||||
| 		mimetype: application/x-microsoft.net.object.soap.base64 | ||||
| 		value   : The object must be serialized with  | ||||
| 			: System.Runtime.Serialization.Formatters.Soap.SoapFormatter | ||||
| 			: and then encoded with base64 encoding. | ||||
| 
 | ||||
| 		mimetype: application/x-microsoft.net.object.bytearray.base64 | ||||
| 		value   : The object must be serialized into a byte array  | ||||
| 			: using a System.ComponentModel.TypeConverter | ||||
| 			: and then encoded with base64 encoding. | ||||
| 	--> | ||||
| 	 | ||||
| 	<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> | ||||
| 		<xsd:element name="root" msdata:IsDataSet="true"> | ||||
| 			<xsd:complexType> | ||||
| 				<xsd:choice maxOccurs="unbounded"> | ||||
| 					<xsd:element name="data"> | ||||
| 						<xsd:complexType> | ||||
| 							<xsd:sequence> | ||||
| 								<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> | ||||
| 								<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" /> | ||||
| 							</xsd:sequence> | ||||
| 							<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" /> | ||||
| 							<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" /> | ||||
| 							<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" /> | ||||
| 						</xsd:complexType> | ||||
| 					</xsd:element> | ||||
| 					<xsd:element name="resheader"> | ||||
| 						<xsd:complexType> | ||||
| 							<xsd:sequence> | ||||
| 								<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> | ||||
| 							</xsd:sequence> | ||||
| 							<xsd:attribute name="name" type="xsd:string" use="required" /> | ||||
| 						</xsd:complexType> | ||||
| 					</xsd:element> | ||||
| 				</xsd:choice> | ||||
| 			</xsd:complexType> | ||||
| 		</xsd:element> | ||||
| 	</xsd:schema> | ||||
| 	<resheader name="resmimetype"> | ||||
| 		<value>text/microsoft-resx</value> | ||||
| 	</resheader> | ||||
| 	<resheader name="version"> | ||||
| 		<value>1.3</value> | ||||
| 	</resheader> | ||||
| 	<resheader name="reader"> | ||||
| 		<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> | ||||
| 	</resheader> | ||||
| 	<resheader name="writer"> | ||||
| 		<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> | ||||
| 	</resheader> | ||||
| </root> | ||||
|  | @ -0,0 +1,110 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <root> | ||||
| 	<!--  | ||||
| 		Microsoft ResX Schema | ||||
| 
 | ||||
| 		Version 1.3 | ||||
| 
 | ||||
| 		The primary goals of this format is to allow a simple XML format  | ||||
| 		that is mostly human readable. The generation and parsing of the  | ||||
| 		various data types are done through the TypeConverter classes  | ||||
| 		associated with the data types. | ||||
| 
 | ||||
| 		Example: | ||||
| 
 | ||||
| 		... ado.net/XML headers & schema ... | ||||
| 		<resheader name="resmimetype">text/microsoft-resx</resheader> | ||||
| 		<resheader name="version">1.3</resheader> | ||||
| 		<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader> | ||||
| 		<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader> | ||||
| 		<data name="Name1">this is my long string</data> | ||||
| 		<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data> | ||||
| 		<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64"> | ||||
| 			[base64 mime encoded serialized .NET Framework object] | ||||
| 		</data> | ||||
| 		<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> | ||||
| 			[base64 mime encoded string representing a byte array form of the .NET Framework object] | ||||
| 		</data> | ||||
| 
 | ||||
| 		There are any number of "resheader" rows that contain simple  | ||||
| 		name/value pairs. | ||||
| 
 | ||||
| 		Each data row contains a name, and value. The row also contains a  | ||||
| 		type or mimetype. Type corresponds to a .NET class that support  | ||||
| 		text/value conversion through the TypeConverter architecture.  | ||||
| 		Classes that don't support this are serialized and stored with the  | ||||
| 		mimetype set. | ||||
| 
 | ||||
| 		The mimetype is used for serialized objects, and tells the  | ||||
| 		ResXResourceReader how to depersist the object. This is currently not  | ||||
| 		extensible. For a given mimetype the value must be set accordingly: | ||||
| 
 | ||||
| 		Note - application/x-microsoft.net.object.binary.base64 is the format  | ||||
| 		that the ResXResourceWriter will generate, however the reader can  | ||||
| 		read any of the formats listed below. | ||||
| 
 | ||||
| 		mimetype: application/x-microsoft.net.object.binary.base64 | ||||
| 		value   : The object must be serialized with  | ||||
| 			: System.Serialization.Formatters.Binary.BinaryFormatter | ||||
| 			: and then encoded with base64 encoding. | ||||
| 
 | ||||
| 		mimetype: application/x-microsoft.net.object.soap.base64 | ||||
| 		value   : The object must be serialized with  | ||||
| 			: System.Runtime.Serialization.Formatters.Soap.SoapFormatter | ||||
| 			: and then encoded with base64 encoding. | ||||
| 
 | ||||
| 		mimetype: application/x-microsoft.net.object.bytearray.base64 | ||||
| 		value   : The object must be serialized into a byte array  | ||||
| 			: using a System.ComponentModel.TypeConverter | ||||
| 			: and then encoded with base64 encoding. | ||||
| 	--> | ||||
| 	 | ||||
| 	<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> | ||||
| 		<xsd:element name="root" msdata:IsDataSet="true"> | ||||
| 			<xsd:complexType> | ||||
| 				<xsd:choice maxOccurs="unbounded"> | ||||
| 					<xsd:element name="data"> | ||||
| 						<xsd:complexType> | ||||
| 							<xsd:sequence> | ||||
| 								<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> | ||||
| 								<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" /> | ||||
| 							</xsd:sequence> | ||||
| 							<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" /> | ||||
| 							<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" /> | ||||
| 							<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" /> | ||||
| 						</xsd:complexType> | ||||
| 					</xsd:element> | ||||
| 					<xsd:element name="resheader"> | ||||
| 						<xsd:complexType> | ||||
| 							<xsd:sequence> | ||||
| 								<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> | ||||
| 							</xsd:sequence> | ||||
| 							<xsd:attribute name="name" type="xsd:string" use="required" /> | ||||
| 						</xsd:complexType> | ||||
| 					</xsd:element> | ||||
| 				</xsd:choice> | ||||
| 			</xsd:complexType> | ||||
| 		</xsd:element> | ||||
| 	</xsd:schema> | ||||
| 	<resheader name="resmimetype"> | ||||
| 		<value>text/microsoft-resx</value> | ||||
| 	</resheader> | ||||
| 	<resheader name="version"> | ||||
| 		<value>1.3</value> | ||||
| 	</resheader> | ||||
| 	<resheader name="reader"> | ||||
| 		<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> | ||||
| 	</resheader> | ||||
| 	<resheader name="writer"> | ||||
| 		<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> | ||||
| 	</resheader> | ||||
|     <data name="Title" xml:space="preserve"> | ||||
|         <value>Log In using external service</value> | ||||
|     </data> | ||||
|     <data name="OpenId_Label" xml:space="preserve"> | ||||
|         <value>OpenID Connect</value> | ||||
|     </data> | ||||
|     <data name="OpenId_Tooltip" xml:space="preserve"> | ||||
|         <value>Log In using OpenID Connect provider</value> | ||||
|     </data> | ||||
| </root> | ||||
|  | @ -17,6 +17,7 @@ | |||
|     <PackageReference Include="Magick.NET-Q8-AnyCPU" Version="13.5.0" /> | ||||
|     <PackageReference Include="MailKit" Version="4.3.0" /> | ||||
|     <PackageReference Include="Markdig" Version="0.34.0" /> | ||||
|     <PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="8.0.2" /> | ||||
|     <PackageReference Include="Microsoft.AspNetCore.DataProtection.StackExchangeRedis" Version="8.0.1" /> | ||||
|     <PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="8.0.0" /> | ||||
|     <PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="8.0.0" /> | ||||
|  |  | |||
							
								
								
									
										2
									
								
								Wave/wwwroot/css/main.min.css
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								Wave/wwwroot/css/main.min.css
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
		Loading…
	
		Reference in a new issue