Skip to content

Commit 1cc8f82

Browse files
committed
Token permission stuffs
1 parent 22a2e26 commit 1cc8f82

File tree

5 files changed

+97
-17
lines changed

5 files changed

+97
-17
lines changed

Desktop/Constants.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.Net.Mime;
33
using System.Reflection;
44
using OpenShock.Desktop.Ui.Utils;
5+
using OpenShock.SDK.CSharp.Models;
56
using Semver;
67

78
namespace OpenShock.Desktop;
@@ -17,6 +18,11 @@ public static class Constants
1718

1819
public static readonly SemVersion Version = SemVersion.Parse(typeof(Constants).Assembly.GetCustomAttribute<AssemblyInformationalVersionAttribute>()!.InformationalVersion, SemVersionStyles.Strict);
1920
public static readonly SemVersion VersionWithoutMetadata = Version.WithoutMetadata();
21+
22+
public static readonly ImmutableArray<PermissionType> BasePermissions = [
23+
PermissionType.Shockers_Use,
24+
PermissionType.Shockers_Pause
25+
];
2026

2127
public static readonly ImmutableArray<Uri> BuiltInModuleRepositories = [
2228
..new List<Uri>

Desktop/Services/AuthService.cs

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,16 @@ public sealed class AuthService
1616
private readonly LiveControlManager _liveControlManager;
1717
private readonly OpenShockApi _apiClient;
1818
private readonly ConfigManager _configManager;
19+
private readonly ModuleManager.ModuleManager _moduleManager;
1920
public SelfResponse? SelfResponse { get; private set; }
2021
public TokenResponse? TokenSelf { get; private set; }
2122

2223
// NotAuthed
2324
// FailedAuth
2425
// Authed
2526

26-
27+
public bool MissingPermissions { get; private set; }
28+
2729
public IObservableVariable<AuthStateType> AuthState => _authState;
2830
private readonly ObservableVariable<AuthStateType> _authState = new(AuthStateType.NotAuthed);
2931

@@ -32,14 +34,16 @@ public AuthService(ILogger<AuthService> logger,
3234
OpenShockHubClient hubClient,
3335
LiveControlManager liveControlManager,
3436
OpenShockApi apiClient,
35-
ConfigManager configManager)
37+
ConfigManager configManager,
38+
ModuleManager.ModuleManager moduleManager)
3639
{
3740
_logger = logger;
3841
_backendHubManager = backendHubManager;
3942
_hubClient = hubClient;
4043
_liveControlManager = liveControlManager;
4144
_apiClient = apiClient;
4245
_configManager = configManager;
46+
_moduleManager = moduleManager;
4347
}
4448

4549
private readonly SemaphoreSlim _authLock = new(1, 1);
@@ -73,11 +77,21 @@ public async Task Authenticate()
7377
if (!tokenSelf.IsT0) throw new Exception("Failed to get token self response");
7478
TokenSelf = tokenSelf.AsT0.Value;
7579

76-
7780
_authState.Value = AuthStateType.Authed;
81+
82+
MissingPermissions = !_moduleManager.RequiredPermissions.Concat(Constants.BasePermissions).All(x => TokenSelf.Permissions.Contains(x));
83+
if (MissingPermissions)
84+
{
85+
_logger.LogWarning("Missing permissions for modules: {MissingPermissions}",
86+
string.Join(", ", _moduleManager.RequiredPermissions
87+
.Concat(Constants.BasePermissions)
88+
.Where(x => !TokenSelf.Permissions.Contains(x))
89+
.Select(x => PermissionTypeBindings.PermissionTypeToName[x].Name)));
90+
}
7891
}
79-
catch (Exception)
92+
catch (Exception ex)
8093
{
94+
_logger.LogError(ex, "Failed to authenticate");
8195
_authState.Value = AuthStateType.FailedAuth;
8296
}
8397
finally
@@ -102,6 +116,8 @@ public async Task Logout()
102116
_apiClient.Logout();
103117
await _liveControlManager.RefreshConnections();
104118

119+
TokenSelf = null;
120+
105121
_logger.LogInformation("Logged out");
106122
}
107123
finally

Desktop/Services/StartupService.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,6 @@ public async Task StartupApp()
148148
catch (Exception e)
149149
{
150150
_logger.LogError(e, "Error while starting module {Module}", moduleManagerModule.Key);
151-
;
152151
}
153152
}
154153

Desktop/Ui/Pages/Authentication/LoginPart.razor

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,13 @@
55
@using OneOf.Types
66
@using OpenShock.Desktop.Backend
77
@using OpenShock.Desktop.Config
8+
@using OpenShock.Desktop.ModuleManager
89
@using OpenShock.Desktop.Utils
910
@using OpenShock.SDK.CSharp.Models
1011
@using OpenShock.SDK.CSharp.Utils
1112

1213
@inject ConfigManager ConfigManager
14+
@inject ModuleManager ModuleManager
1315
@inject ISnackbar Snackbar
1416
@inject ILogger<LoginPart> Logger
1517

@@ -182,7 +184,10 @@
182184

183185
Logger.LogTrace("Open browser for token");
184186

185-
var requestUri = new Uri(root.Data!.ShortLinkUrl, "/t/?name=OpenShock%20Desktop&redirect_uri=openshock:token/%&permissions=shockers.use,shockers.pause");
187+
188+
var permissionString = string.Join(',', Constants.BasePermissions.Concat(ModuleManager.RequiredPermissions).Select(x => PermissionTypeBindings.PermissionTypeToName[x].Name));
189+
190+
var requestUri = new Uri(root.Data!.ShortLinkUrl, $"/t/?name=OpenShock%20Desktop&redirect_uri=openshock:token/%&permissions={permissionString}");
186191
UiUtils.OpenUrl(requestUri.ToString());
187192
}
188193

Desktop/Ui/Pages/Dash/SideBar.razor

Lines changed: 65 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,20 @@
11
@using Microsoft.AspNetCore.SignalR.Client
22
@using OpenShock.Desktop.Backend
3+
@using OpenShock.Desktop.ModuleBase.Models
34
@using OpenShock.Desktop.ModuleManager
45
@using OpenShock.Desktop.Services
56
@using OpenShock.Desktop.Ui.Utils
67
@using OpenShock.SDK.CSharp.Hub
78
@using OpenShock.Desktop.Ui.Pages.Dash.Components
9+
@using OpenShock.SDK.CSharp.Models
810
@using StatePart = OpenShock.Desktop.Ui.Pages.Dash.Components.StatePart
911
@inject OpenShockApi Api
1012
@inject OpenShockHubClient ApiHubClient
1113
@inject ISnackbar Snackbar
1214
@inject LiveControlManager LiveControlManager
1315
@inject StatusHandler StatusHandler
1416
@inject ModuleManager ModuleManager
17+
@inject AuthService AuthService
1518
@implements IAsyncDisposable
1619

1720
<MudPaper Width="250px" Height="100%" Elevation="0" Class="flex-none">
@@ -22,36 +25,69 @@
2225
<div class="d-flex" style="align-items: center">
2326
@* ReSharper disable once Html.PathError *@
2427
<a href="/dash/dashboard">
25-
<MudImage Src="images/NavbarLogoSpin.svg" Alt="Logo" Height="45" Width="218" Class="mx-4 my-2" Style="vertical-align: bottom;"/>
28+
<MudImage Src="images/NavbarLogoSpin.svg" Alt="Logo" Height="45" Width="218" Class="mx-4 my-2"
29+
Style="vertical-align: bottom;"/>
2630
</a>
2731
</div>
2832
<MudDivider Style="margin-bottom: 5px" DividerType="DividerType.Middle"/>
2933
</div>
3034

3135

32-
<MudNavMenu style="align-self: flex-start; overflow-y: auto" Class="flex-auto flex-grow-1" Margin="Margin.Dense" Color="Color.Primary" Bordered="true">
36+
<MudNavMenu style="align-self: flex-start; overflow-y: auto" Class="flex-auto flex-grow-1" Margin="Margin.Dense"
37+
Color="Color.Primary" Bordered="true">
3338

3439
<MudNavLink Icon="@Icons.Material.Filled.ViewModule" Href="/dash/modules">Manage Modules</MudNavLink>
35-
40+
3641
<MudDivider Style="margin-bottom: 5px; margin-top: 5px;" DividerType="DividerType.Middle"/>
37-
42+
3843
@foreach (var modules in ModuleManager.Modules)
3944
{
4045
<ModuleNavComponent LoadedModule="@modules.Value"></ModuleNavComponent>
4146
}
4247
</MudNavMenu>
4348

4449
<div class="flex-none" style="align-self: flex-end">
50+
@if (AuthService.MissingPermissions)
51+
{
52+
<MudTooltip
53+
Arrow="true" Placement="Placement.Right">
54+
<ChildContent>
55+
<div class="mb-2 pa-4 flex row gap-2">
56+
<MudIcon Icon="@Icons.Material.Filled.Warning" Color="Color.Warning"/>
57+
<MudText Typo="Typo.body2" Class="mt-1">Permissions Required</MudText>
58+
</div>
59+
</ChildContent>
60+
<TooltipContent>
61+
<MudText Typo="Typo.body2">Addition API Token Permissions Required</MudText>
62+
<MudText Typo="Typo.caption">for one or more installed modules.</MudText>
63+
<br/>
64+
<br/>
65+
<br/>
66+
@foreach (var perm in PermissionInfos)
67+
{
68+
@if (perm.Missing)
69+
{
70+
<MudText Typo="Typo.subtitle2" Color="Color.Warning">@perm.Permission</MudText>
71+
}
72+
else
73+
{
74+
<MudText Typo="Typo.subtitle2">@perm.Permission</MudText>
75+
}
76+
}
77+
<br/>
78+
</TooltipContent>
79+
</MudTooltip>
80+
}
81+
4582
<MudDivider DividerType="DividerType.Middle"/>
4683
<div Class="pa-4">
47-
48-
4984
<div class="d-flex gap-5" style="flex-wrap: wrap; margin-bottom: 10px;">
5085

5186
<div style="display: flex; flex-direction: column" class="child-div-align-center flex-grow-1">
5287
<MudText Style="font-size: 10pt; text-align: center">SignalR</MudText>
5388
<MudTooltip Arrow="true" Placement="Placement.Top" Text="@ApiHubClient.State.ToString()">
54-
<MudIcon Icon="@Icons.Material.Filled.Wifi" Color="@GetConnectionStateColor(ApiHubClient.State)"
89+
<MudIcon Icon="@Icons.Material.Filled.Wifi"
90+
Color="@GetConnectionStateColor(ApiHubClient.State)"
5591
Class="d-block ma-auto"/>
5692
</MudTooltip>
5793
</div>
@@ -64,10 +100,12 @@
64100
}
65101
else
66102
{
67-
<div style="display: flex; flex-direction: column" class="child-div-align-center flex-grow-1">
103+
<div style="display: flex; flex-direction: column"
104+
class="child-div-align-center flex-grow-1">
68105
<MudText Style="font-size: 10pt; text-align: center">@device.Name.Truncate(13)</MudText>
69106
<MudTooltip Arrow="true" Placement="Placement.Top" Text="Offline">
70-
<MudIcon Icon="@Icons.Material.Filled.Wifi" Color="@Color.Dark"/>
107+
<MudIcon Icon="@Icons.Material.Filled.Wifi" Color="@Color.Dark"
108+
Class="d-block ma-auto"/>
71109
</MudTooltip>
72110
</div>
73111
}
@@ -83,12 +121,27 @@
83121

84122
@code {
85123
private IAsyncDisposable _statusSubscription = null!;
124+
private IAsyncDisposable _authStateSubscription = null!;
86125

87126
protected override async Task OnInitializedAsync()
88127
{
89128
_statusSubscription = await StatusHandler.OnWebsocketStatusChanged.SubscribeAsync(() => InvokeAsync(StateHasChanged));
129+
_authStateSubscription = await AuthService.AuthState.ValueUpdated.SubscribeAsync(_ => InvokeAsync(StateHasChanged));
90130
}
91-
131+
132+
private struct PermissionInfo
133+
{
134+
public string Permission { get; set; }
135+
public bool Missing { get; set; }
136+
}
137+
138+
private IEnumerable<PermissionInfo> PermissionInfos => Constants.BasePermissions.Concat(ModuleManager.RequiredPermissions).Distinct()
139+
.Select(x => new PermissionInfo
140+
{
141+
Permission = PermissionTypeBindings.PermissionTypeToName[x].Name,
142+
Missing = !(AuthService.TokenSelf?.Permissions.Contains(x) ?? false)
143+
});
144+
92145

93146
private static Color GetConnectionStateColor(HubConnectionState state) =>
94147
state switch
@@ -101,12 +154,13 @@
101154
};
102155

103156
private bool _disposed = false;
104-
157+
105158
public async ValueTask DisposeAsync()
106159
{
107160
if (_disposed) return;
108161
_disposed = true;
109162
await _statusSubscription.DisposeAsync();
163+
await _authStateSubscription.DisposeAsync();
110164
}
111165

112166
}

0 commit comments

Comments
 (0)