Add a dedicated action and permission for granting instance user permissions on an instance

This commit is contained in:
Jordan Brown
2020-06-13 23:16:39 -04:00
parent 17b9aa5131
commit 4db03eab75
7 changed files with 86 additions and 28 deletions
@@ -61,6 +61,11 @@ namespace Tgstation.Server.Api.Rights
/// <summary>
/// User can change <see cref="Models.Instance.ChatBotLimit"/>.
/// </summary>
SetChatBotLimit = 512
SetChatBotLimit = 512,
/// <summary>
/// User can give themselves full <see cref="Models.InstanceUser"/> rights on instances.
/// </summary>
GrantPermissions = 1024,
}
}
+3
View File
@@ -235,6 +235,9 @@ namespace Tgstation.Server.Client
/// <inheritdoc />
public Task<TResult> Update<TBody, TResult>(string route, TBody body, CancellationToken cancellationToken) => RunRequest<TResult>(route, body, HttpMethod.Post, null, false, cancellationToken);
/// <inheritdoc />
public Task Patch(string route, CancellationToken cancellationToken) => RunRequest<object>(route, null, HttpMethod.Patch, null, false, cancellationToken);
/// <inheritdoc />
public Task Update<TBody>(string route, TBody body, CancellationToken cancellationToken) => RunRequest<object>(route, body, HttpMethod.Post, null, false, cancellationToken);
@@ -90,6 +90,14 @@ namespace Tgstation.Server.Client
/// <returns>A <see cref="Task"/> representing the running operation</returns>
Task Update<TBody>(string route, TBody body, CancellationToken cancellationToken);
/// <summary>
/// Run an HTTP PATCH request.
/// </summary>
/// <param name="route">The server route to make the request to.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation.</param>
/// <returns>A <see cref="Task"/> representing the running operation.</returns>
Task Patch(string route, CancellationToken cancellationToken);
/// <summary>
/// Run an HTTP DELETE request
/// </summary>
@@ -50,6 +50,14 @@ namespace Tgstation.Server.Client
/// <returns>A <see cref="Task"/> representing the running operation</returns>
Task Detach(Instance instance, CancellationToken cancellationToken);
/// <summary>
/// Gives the user full permissions on an <paramref name="instance"/>.
/// </summary>
/// <param name="instance">The <see cref="Instance"/> to grant permissions on.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation.</param>
/// <returns>A <see cref="Task"/> representing the running operation.</returns>
Task GrantPermissions(Instance instance, CancellationToken cancellationToken);
/// <summary>
/// Create an <see cref="IInstanceClient"/> for a given <see cref="Instance"/>
/// </summary>
@@ -47,6 +47,9 @@ namespace Tgstation.Server.Client
/// <inheritdoc />
public Task<Instance> GetId(Instance instance, CancellationToken cancellationToken) => apiClient.Read<Instance>(Routes.SetID(Routes.InstanceManager, instance?.Id ?? throw new ArgumentNullException(nameof(instance))), cancellationToken);
/// <inheritdoc />
public Task GrantPermissions(Instance instance, CancellationToken cancellationToken) => apiClient.Patch(Routes.SetID(Routes.InstanceManager, instance?.Id ?? throw new ArgumentNullException(nameof(instance))), cancellationToken);
/// <inheritdoc />
public IInstanceClient CreateClient(Instance instance)
{
@@ -114,17 +114,22 @@ namespace Tgstation.Server.Host.Controllers
return path;
}
Models.InstanceUser InstanceAdminUser() => new Models.InstanceUser
Models.InstanceUser InstanceAdminUser(Models.InstanceUser userToModify)
{
ByondRights = (ByondRights)~0U,
ChatBotRights = (ChatBotRights)~0U,
ConfigurationRights = (ConfigurationRights)~0U,
DreamDaemonRights = (DreamDaemonRights)~0U,
DreamMakerRights = (DreamMakerRights)~0U,
RepositoryRights = (RepositoryRights)~0U,
InstanceUserRights = (InstanceUserRights)~0U,
UserId = AuthenticationContext.User.Id
};
if (userToModify == null)
userToModify = new Models.InstanceUser()
{
UserId = AuthenticationContext.User.Id
};
userToModify.ByondRights = RightsHelper.AllRights<ByondRights>();
userToModify.ChatBotRights = RightsHelper.AllRights<ChatBotRights>();
userToModify.ConfigurationRights = RightsHelper.AllRights<ConfigurationRights>();
userToModify.DreamDaemonRights = RightsHelper.AllRights<DreamDaemonRights>();
userToModify.DreamMakerRights = RightsHelper.AllRights<DreamMakerRights>();
userToModify.RepositoryRights = RightsHelper.AllRights<RepositoryRights>();
userToModify.InstanceUserRights = RightsHelper.AllRights<InstanceUserRights>();
return userToModify;
}
/// <summary>
/// Create or attach an <see cref="Api.Models.Instance"/>.
@@ -267,7 +272,7 @@ namespace Tgstation.Server.Host.Controllers
},
InstanceUsers = new List<Models.InstanceUser> // give this user full privileges on the instance
{
InstanceAdminUser()
InstanceAdminUser(null)
}
};
@@ -458,21 +463,6 @@ namespace Tgstation.Server.Host.Controllers
return Conflict(new ErrorMessage(ErrorCode.ChatBotMax));
}
// ensure the current user has write privilege on the instance
var usersInstanceUser = await InstanceQuery()
.SelectMany(x => x.InstanceUsers)
.Where(x => x.UserId == AuthenticationContext.User.Id)
.FirstOrDefaultAsync(cancellationToken)
.ConfigureAwait(false);
if (usersInstanceUser == default)
{
var instanceAdminUser = InstanceAdminUser();
instanceAdminUser.InstanceId = originalModel.Id;
DatabaseContext.InstanceUsers.Add(instanceAdminUser);
}
else
usersInstanceUser.InstanceUserRights |= InstanceUserRights.WriteUsers;
await DatabaseContext.Save(cancellationToken).ConfigureAwait(false);
if (renamed)
@@ -634,5 +624,40 @@ namespace Tgstation.Server.Host.Controllers
api.MoveJob = moveJob?.ToApi();
return Json(api);
}
/// <summary>
/// Gives the current user full permissions on a given instance <paramref name="id"/>.
/// </summary>
/// <param name="id">The instance <see cref="EntityId.Id"/> to give permissions on.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation.</param>
/// <returns>A <see cref="Task{TResult}"/> resulting in the <see cref="IActionResult"/> of the request.</returns>
/// <response code="204">Granted permissions successfully.</response>
[HttpPatch("{id}")]
[TgsAuthorize(InstanceManagerRights.GrantPermissions)]
[ProducesResponseType(204)]
public async Task<IActionResult> GrantPermissions(long id, CancellationToken cancellationToken)
{
// ensure the current user has write privilege on the instance
var usersInstanceUser = await DatabaseContext
.Instances
.AsQueryable()
.Where(x => x.Id == id)
.SelectMany(x => x.InstanceUsers)
.Where(x => x.UserId == AuthenticationContext.User.Id)
.FirstOrDefaultAsync(cancellationToken)
.ConfigureAwait(false);
if (usersInstanceUser == default)
{
var instanceAdminUser = InstanceAdminUser(null);
instanceAdminUser.InstanceId = id;
DatabaseContext.InstanceUsers.Add(instanceAdminUser);
}
else
InstanceAdminUser(usersInstanceUser);
await DatabaseContext.Save(cancellationToken).ConfigureAwait(false);
return NoContent();
}
}
}
+7 -1
View File
@@ -1,6 +1,5 @@
{
"General": {
"ApiPort": 5000,
"MinimumPasswordLength": 15,
"GitHubAccessToken": null,
"SetupWizardMode": "AutoDetect",
@@ -33,6 +32,13 @@
}
}
},
"Kestrel": {
"EndPoints": {
"Http": {
"Url": "http://0.0.0.0:80"
}
}
},
"ControlPanel": {
"Enable": false,
"AllowAnyOrigin": false,