Skip to content

Commit

Permalink
Store non-sensitive UI state without protection (#5434)
Browse files Browse the repository at this point in the history
  • Loading branch information
JamesNK authored Aug 26, 2024
1 parent 4251f91 commit f2bdf22
Show file tree
Hide file tree
Showing 11 changed files with 254 additions and 49 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
using System.Globalization;
using Aspire.Dashboard.Components.Resize;
using Aspire.Dashboard.Model;
using Aspire.Dashboard.Utils;
using Microsoft.AspNetCore.Components;
using Microsoft.FluentUI.AspNetCore.Components;
using Microsoft.JSInterop;
Expand Down Expand Up @@ -86,7 +85,7 @@ protected override async Task OnParametersSetAsync()
{
if (RememberOrientation)
{
var orientationResult = await LocalStore.SafeGetAsync<Orientation>(GetOrientationStorageKey());
var orientationResult = await LocalStore.GetUnprotectedAsync<Orientation>(GetOrientationStorageKey());
if (orientationResult.Success)
{
Orientation = orientationResult.Value;
Expand All @@ -95,10 +94,11 @@ protected override async Task OnParametersSetAsync()

if (RememberSize)
{
var panel1FractionResult = await LocalStore.SafeGetAsync<float>(GetSizeStorageKey());
var panel1FractionResult = await LocalStore.GetUnprotectedAsync<float>(GetSizeStorageKey());
if (panel1FractionResult.Success)
{
SetPanelSizes(panel1FractionResult.Value);
var fraction = Math.Clamp(panel1FractionResult.Value, 0, 1);
SetPanelSizes(fraction);
}
}
}
Expand Down Expand Up @@ -128,16 +128,16 @@ private async Task HandleToggleOrientation()

if (RememberOrientation)
{
await LocalStore.SetAsync(GetOrientationStorageKey(), Orientation);
await LocalStore.SetUnprotectedAsync(GetOrientationStorageKey(), Orientation);
}

if (RememberSize)
{
var panel1FractionResult = await LocalStore.SafeGetAsync<float>(GetSizeStorageKey());
var panel1FractionResult = await LocalStore.GetUnprotectedAsync<float>(GetSizeStorageKey());
if (panel1FractionResult.Success)
{
SetPanelSizes(panel1FractionResult.Value);

var fraction = Math.Clamp(panel1FractionResult.Value, 0, 1);
SetPanelSizes(fraction);
}
else
{
Expand Down Expand Up @@ -170,7 +170,7 @@ private async Task HandleSplitterResize(SplitterResizedEventArgs args)

private async Task SaveSizeToStorage(float panel1Fraction)
{
await LocalStore.SetAsync(GetSizeStorageKey(), panel1Fraction);
await LocalStore.SetUnprotectedAsync(GetSizeStorageKey(), panel1Fraction);
}

private void ResetPanelSizes()
Expand Down Expand Up @@ -293,13 +293,13 @@ static void GetPanelSizes(
private string GetSizeStorageKey()
{
var viewKey = ViewKey ?? NavigationManager.ToBaseRelativePath(NavigationManager.Uri);
return $"SplitterSize_{Orientation}_{viewKey}";
return $"Aspire_SplitterSize_{Orientation}_{viewKey}";
}

private string GetOrientationStorageKey()
{
var viewKey = ViewKey ?? NavigationManager.ToBaseRelativePath(NavigationManager.Uri);
return $"SplitterOrientation_{viewKey}";
return $"Aspire_SplitterOrientation_{viewKey}";
}

public void Dispose()
Expand Down
2 changes: 1 addition & 1 deletion src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ public sealed partial class ConsoleLogs : ComponentBase, IAsyncDisposable, IPage
public ConsoleLogsViewModel PageViewModel { get; set; } = null!;

public string BasePath => DashboardUrls.ConsoleLogBasePath;
public string SessionStorageKey => "ConsoleLogs_PageState";
public string SessionStorageKey => "Aspire_ConsoleLogs_PageState";

protected override async Task OnInitializedAsync()
{
Expand Down
2 changes: 1 addition & 1 deletion src/Aspire.Dashboard/Components/Pages/Metrics.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public partial class Metrics : IDisposable, IPageWithSessionAndUrlState<Metrics.
private Subscription? _metricsSubscription;

public string BasePath => DashboardUrls.MetricsBasePath;
public string SessionStorageKey => "Metrics_PageState";
public string SessionStorageKey => "Aspire_Metrics_PageState";
public MetricsViewModel PageViewModel { get; set; } = null!;

[Parameter]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public partial class StructuredLogs : IPageWithSessionAndUrlState<StructuredLogs
private GridColumnManager _manager = null!;

public string BasePath => DashboardUrls.StructuredLogsBasePath;
public string SessionStorageKey => "StructuredLogs_PageState";
public string SessionStorageKey => "Aspire_StructuredLogs_PageState";
public StructuredLogsPageViewModel PageViewModel { get; set; } = null!;

[Inject]
Expand Down
2 changes: 1 addition & 1 deletion src/Aspire.Dashboard/Components/Pages/Traces.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public partial class Traces : IPageWithSessionAndUrlState<TracesPageViewModel, T
private AspirePageContentLayout? _contentLayout;
private GridColumnManager _manager = null!;

public string SessionStorageKey => "Traces_PageState";
public string SessionStorageKey => "Aspire_Traces_PageState";
public string BasePath => DashboardUrls.TracesBasePath;
public TracesPageViewModel PageViewModel { get; set; } = null!;

Expand Down
11 changes: 10 additions & 1 deletion src/Aspire.Dashboard/Model/BrowserStorage/ILocalStorage.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,17 @@
// Licensed to the .NET Foundation under one or more agreements.
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace Aspire.Dashboard.Model.BrowserStorage;

public interface ILocalStorage : IBrowserStorage
{
/// <summary>
/// Get unprotected data from local storage. This must only be used with non-sensitive data.
/// </summary>
Task<StorageResult<T>> GetUnprotectedAsync<T>(string key);

/// <summary>
/// Set unprotected data to local storage. This must only be used with non-sensitive data.
/// </summary>
Task SetUnprotectedAsync<T>(string key, T value);
}
51 changes: 49 additions & 2 deletions src/Aspire.Dashboard/Model/BrowserStorage/LocalBrowserStorage.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,60 @@
// Licensed to the .NET Foundation under one or more agreements.
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Text.Json;
using Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage;
using Microsoft.JSInterop;

namespace Aspire.Dashboard.Model.BrowserStorage;

public class LocalBrowserStorage : BrowserStorageBase, ILocalStorage
{
public LocalBrowserStorage(ProtectedLocalStorage protectedLocalStorage) : base(protectedLocalStorage)
private static readonly JsonSerializerOptions s_options = new()
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
PropertyNameCaseInsensitive = true,
};

private readonly IJSRuntime _jsRuntime;
private readonly ILogger<LocalBrowserStorage> _logger;

public LocalBrowserStorage(IJSRuntime jsRuntime, ProtectedLocalStorage protectedLocalStorage, ILogger<LocalBrowserStorage> logger) : base(protectedLocalStorage)
{
_jsRuntime = jsRuntime;
_logger = logger;
}

public async Task<StorageResult<T>> GetUnprotectedAsync<T>(string key)
{
var json = await GetJsonAsync(key).ConfigureAwait(false);

if (json == null)
{
return new StorageResult<T>(false, default);
}

try
{
return new StorageResult<T>(true, JsonSerializer.Deserialize<T>(json, s_options));
}
catch (Exception ex)
{
_logger.LogWarning(ex, $"Error when reading '{key}' as {typeof(T).Name} from local browser storage.");

return new StorageResult<T>(false, default);
}
}

public async Task SetUnprotectedAsync<T>(string key, T value)
{
var json = JsonSerializer.Serialize(value, s_options);

await SetJsonAsync(key, json).ConfigureAwait(false);
}

private ValueTask SetJsonAsync(string key, string json)
=> _jsRuntime.InvokeVoidAsync("localStorage.setItem", key, json);

private ValueTask<string?> GetJsonAsync(string key)
=> _jsRuntime.InvokeAsync<string?>("localStorage.getItem", key);
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Licensed to the .NET Foundation under one or more agreements.
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage;
Expand Down
29 changes: 0 additions & 29 deletions src/Aspire.Dashboard/Utils/IBrowserStorageExtensions.cs

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,21 @@ public sealed class TestLocalStorage : ILocalStorage
{
public Task<StorageResult<T>> GetAsync<T>(string key)
{
return Task.FromResult<StorageResult<T>>(new StorageResult<T>(Success: false, Value: default));
return Task.FromResult(new StorageResult<T>(Success: false, Value: default));
}

public Task<StorageResult<T>> GetUnprotectedAsync<T>(string key)
{
return Task.FromResult(new StorageResult<T>(Success: false, Value: default));
}

public Task SetAsync<T>(string key, T value)
{
return Task.CompletedTask;
}

public Task SetUnprotectedAsync<T>(string key, T value)
{
return Task.CompletedTask;
}
}
Loading

0 comments on commit f2bdf22

Please sign in to comment.