mirror of
https://github.com/immense/Remotely.git
synced 2025-10-26 11:27:15 +00:00
141 lines
4.2 KiB
Plaintext
141 lines
4.2 KiB
Plaintext
@page "/api-keys"
|
|
@attribute [Authorize]
|
|
@inherits AuthComponentBase
|
|
|
|
@inject IDataService DataService
|
|
@inject AuthenticationStateProvider AuthProvider
|
|
@inject IJsInterop JsInterop
|
|
@inject IModalService ModalService
|
|
|
|
|
|
<h3>API Keys</h3>
|
|
|
|
@if (!string.IsNullOrWhiteSpace(_alertMessage))
|
|
{
|
|
<AlertBanner Message="@_alertMessage" />
|
|
}
|
|
|
|
@if (!string.IsNullOrWhiteSpace(_newKeySecret))
|
|
{
|
|
<h5 class="text-warning font-weight-bold mb-2 mt-4">Warning: The key's secret will only be shown once. Save it now.</h5>
|
|
<h5 class="mb-4">
|
|
<label class="mr-1">Key Secret:</label>
|
|
<input class="form-control custom-control-inline" readonly value="@_newKeySecret" style="width:400px" />
|
|
</h5>
|
|
}
|
|
|
|
|
|
@if (User.IsAdministrator)
|
|
{
|
|
<div class="mb-2 mt-4">
|
|
<label class="mr-1">New Token Name:</label>
|
|
<input @bind="_createKeyName" @bind:event="oninput"
|
|
class="form-control form-control-sm custom-control-inline mr-1"
|
|
style="width:200px" />
|
|
|
|
<button class="btn btn-primary" type="button" @onclick="CreateNewKey">Create</button>
|
|
|
|
<button class="btn btn-sm btn-secondary ml-2" @onclick="ShowApiKeyHelp">
|
|
<span class="oi oi-question-mark"></span>
|
|
</button>
|
|
</div>
|
|
|
|
<table class="table table-hover table-striped">
|
|
<thead>
|
|
<tr>
|
|
<th>Name</th>
|
|
<th>ID</th>
|
|
<th>Last Used</th>
|
|
<th></th>
|
|
<th></th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
@foreach (var apiToken in _apiTokens)
|
|
{
|
|
<tr @key="apiToken.ID">
|
|
<td>@apiToken.Name</td>
|
|
<td>@apiToken.ID</td>
|
|
<td>@apiToken.LastUsed</td>
|
|
<td>
|
|
<button type="button" class="btn btn-primary" @onclick="() => RenameKey(apiToken.ID)">Rename</button>
|
|
</td>
|
|
<td>
|
|
<button type="submit" class="btn btn-danger" @onclick="() => DeleteKey(apiToken.ID)">Delete</button>
|
|
</td>
|
|
</tr>
|
|
}
|
|
</tbody>
|
|
</table>
|
|
}
|
|
else
|
|
{
|
|
<h5 class="text-muted">Only organization administrators can view this page.</h5>
|
|
}
|
|
|
|
|
|
@code {
|
|
private readonly List<ApiToken> _apiTokens = new();
|
|
private string _alertMessage;
|
|
private string _createKeyName;
|
|
private string _newKeySecret;
|
|
|
|
protected override async Task OnInitializedAsync()
|
|
{
|
|
RefreshData();
|
|
await base.OnInitializedAsync();
|
|
}
|
|
|
|
private async Task CreateNewKey()
|
|
{
|
|
var secret = PasswordGenerator.GeneratePassword(36);
|
|
var secretHash = new PasswordHasher<RemotelyUser>().HashPassword(null, secret);
|
|
|
|
await DataService.CreateApiToken(Username, _createKeyName, secret);
|
|
RefreshData();
|
|
_alertMessage = "Key created.";
|
|
_newKeySecret = secret;
|
|
}
|
|
|
|
private async Task DeleteKey(string keyId)
|
|
{
|
|
var result = await JsInterop.Confirm("Are you sure you want to delete this key?");
|
|
if (result)
|
|
{
|
|
await DataService.DeleteApiToken(Username, keyId);
|
|
RefreshData();
|
|
_alertMessage = "Key deleted.";
|
|
}
|
|
}
|
|
|
|
private void RefreshData()
|
|
{
|
|
_apiTokens.Clear();
|
|
_apiTokens.AddRange(DataService.GetAllApiTokens(User.Id));
|
|
_createKeyName = null;
|
|
_alertMessage = null;
|
|
_newKeySecret = null;
|
|
}
|
|
|
|
|
|
private async Task RenameKey(string keyId)
|
|
{
|
|
var newName = await JsInterop.Prompt("New key name");
|
|
if (!string.IsNullOrWhiteSpace(newName))
|
|
{
|
|
await DataService.RenameApiToken(Username, keyId, newName);
|
|
RefreshData();
|
|
_alertMessage = "Key renamed.";
|
|
}
|
|
}
|
|
|
|
private void ShowApiKeyHelp()
|
|
{
|
|
ModalService.ShowModal("Using API Keys", new[]
|
|
{
|
|
"API keys should be added to the request header when making API calls. The key should be \"Authorization\", and value should be \"{key-id}:{key-secret}\". Note the colon in between.",
|
|
"Example: Authorization=e5da1c09-e851-4bd4-a8c1-532144b3f894:7uY6h5zBYm4+90pZVek4lD6ewbQ83nKcDpghBfG00hhZu6Ew"
|
|
});
|
|
}
|
|
}
|