diff options
| author | Jake Mannens <jake@asger.xyz> | 2023-10-06 16:18:30 +1100 |
|---|---|---|
| committer | Jake Mannens <jake@asger.xyz> | 2023-10-06 16:18:30 +1100 |
| commit | 2c30354c4af308bf9856a3651d9ba3a686eed936 (patch) | |
| tree | 74fe8ee40fb519feb5a865622fc32531b94220f7 | |
| parent | 3d5f6e47bd74ce77d5ec253f51b7cef1b42099ef (diff) | |
More work on AclDialog
| -rw-r--r-- | AclEnum.cs | 4 | ||||
| -rw-r--r-- | Pages/Component/AclDialog.razor | 127 | ||||
| -rw-r--r-- | Pages/Component/AclDialog.razor.css | 14 | ||||
| -rw-r--r-- | SecurityIdentifier.cs | 18 |
4 files changed, 129 insertions, 34 deletions
@@ -21,7 +21,9 @@ public enum MediaPermissions : ulong { [AclPermission("Set tags")] SetTags = 0x10, [AclPermission("View permissions")] GetAcl = 0x20, [AclPermission("Set permissions")] SetAcl = 0x40, - [AclPermission("Full control")] FullControl = 0x7F + [AclPermission("Download media")] Save = 0x80, + [AclPermission("Full read")] FullRead = 0xA9, + [AclPermission("Full control")] FullControl = 0xFF } [Flags] diff --git a/Pages/Component/AclDialog.razor b/Pages/Component/AclDialog.razor index 6df9320..0d24530 100644 --- a/Pages/Component/AclDialog.razor +++ b/Pages/Component/AclDialog.razor @@ -7,10 +7,19 @@ <div class="hcontainer"> <div> @if(obj?.Acl is not null) { - <label> - Owner - <input type="text" autocomplete="off"/> - </label> + <div class="principal-select"> + @if(editOwner is not null) { + <label>Owner</label> + <input type="text" autocomplete="off" @bind=editOwner/> + <button class="secondary" @onclick=@(() => editOwner = null)>Cancel</button> + <button @onclick=@(() => editOwner = null)>OK</button> + } else { + <label>Owner:</label> + <a href="javascript:;" @onclick=@(() => editOwner = obj.Owner.ToString())> + @obj.Owner.ToString() + </a> + } + </div> <table class="data-table"> <tr> <th>Action</th> @@ -21,42 +30,54 @@ <tr> <td><div><AclActionSwitch InitialValue=@(rule.Action == AclRuleAction.Allow)/></div></td> <td> - @(WellKnownSid.TranslateSid(rule.Principal) ?? rule.Principal.ToString()) + @rule.Principal.ToString() </td> <td>@GetActivePermissions(rule)</td> <td> - <a title="Edit" href="javascript:;">🖉</a> - <a title="Delete" href="javascript:;">✖</a> + <a title="Edit" href="javascript:;" @onclick=@(() => EditRule(rule))>🖉</a> + <a title="Delete" href="javascript:;" @onclick=@(() => RemoveRule(rule))>✖</a> </td> </tr> } </table> <br/> - <center><a href="javascript:;">Add new</a></center> + <center><a href="javascript:;" @onclick=AddRule>Add new</a></center> } else { <p><i>This item does not have any permissions set!</i></p> } </div> <div> - @if(obj?.Acl is not null) { + @if(ruleToEdit is not null && permissionCheckboxes is not null) { <div class="principal-select"> - <label> - Subject - <input type="text" autocomplete="off"/> - </label> - <button>Submit</button> + @if(editSubject is not null) { + <label>Subject</label> + <input type="text" autocomplete="off" @bind=editSubject/> + <button class="secondary" @onclick=@(() => editSubject = null)>Cancel</button> + <button @onclick=@(() => editSubject = null)>OK</button> + } else { + <label>Subject:</label> + <a href="javascript:;" @onclick=@(() => editSubject = ruleToEdit.Principal.ToString())> + @if(ruleToEdit.Principal == WellKnownSid.NullSid) { + <i>Select a user or group</i> + } else { + @ruleToEdit.Principal.ToString() + } + </a> + } </div> - var permissions = Acl.GetPermissionDescriptions(obj) + var permissions = Acl.GetPermissionDescriptions(obj!) .OrderByDescending(kv => BitOperations.PopCount(kv.Value)) .ThenBy(kv => kv.Value); - foreach(var kv in permissions) { + foreach(var perm in permissionCheckboxes) { <label> - <input type="checkbox"/> - @kv.Key + <input + type="checkbox" + @bind=perm.Value/> + @perm.Description </label> } } else { - <p><i>Click Edit next to an ACL to edit it's permissions</i></p> + <p><i>Click 'Edit' next to a rule to edit it's permissions</i></p> } </div> </div> @@ -79,7 +100,12 @@ } } - private HBObject? obj; + private HBObject? obj; + private AclRule? ruleToEdit; + private PermissionCheckbox[]? permissionCheckboxes; + + private string? editOwner; + private string? editSubject; private Dialog dialog; @@ -94,6 +120,9 @@ public HBObject? Object { get => obj; set { + editOwner = null; + CancelEditRule(); + if(value is null) { obj = null; return; @@ -110,7 +139,7 @@ } } - public string GetActivePermissions(AclRule rule) { + private string GetActivePermissions(AclRule rule) { var perms = Acl.GetPermissionDescriptions(obj!) .Where(kv => (rule.Permissions & kv.Value) == kv.Value) .ToList(); @@ -125,6 +154,7 @@ if(i != j) if((perms[i].Value & perms[j].Value) == perms[i].Value) toRemove.Add(i); + toRemove = toRemove.Order().Distinct().ToList(); for(int i = toRemove.Count() - 1; i >= 0; i--) perms.RemoveAt(toRemove[i]); @@ -133,4 +163,59 @@ .ThenBy(kv => kv.Value) .Select(kv => kv.Key)); } + + private void AddRule() { + var rule = new AclRule() { + Principal = WellKnownSid.NullSid, + Action = AclRuleAction.Allow, + Permissions = 0 + }; + + obj!.Acl!.Rules.Add(rule); + EditRule(rule); + } + + private void RemoveRule(AclRule rule) { + if(rule == ruleToEdit) + CancelEditRule(); + obj!.Acl!.Rules.Remove(rule); + } + + private void EditRule(AclRule rule) { + ruleToEdit = rule; + editSubject = null; + permissionCheckboxes = Acl.GetPermissionDescriptions(obj!) + .OrderByDescending(kv => BitOperations.PopCount(kv.Value)) + .ThenBy(kv => kv.Value) + .Select(kv => new PermissionCheckbox(rule, kv)) + .ToArray(); + } + + private void CancelEditRule() { + ruleToEdit = null; + permissionCheckboxes = null; + } + + private class PermissionCheckbox { + public string Description { get; private init; } + + private AclRule rule; + private ulong mask; + + public PermissionCheckbox(AclRule rule, KeyValuePair<string, ulong> kv) { + this.rule = rule; + this.mask = kv.Value; + Description = kv.Key; + } + + public bool Value { + get => (rule.Permissions & mask) == mask; + set { + if(value) + rule.Permissions |= mask; + else + rule.Permissions &= ~mask; + } + } + } }
\ No newline at end of file diff --git a/Pages/Component/AclDialog.razor.css b/Pages/Component/AclDialog.razor.css index 74e405f..c9ac518 100644 --- a/Pages/Component/AclDialog.razor.css +++ b/Pages/Component/AclDialog.razor.css @@ -34,6 +34,7 @@ div.principal-select { align-items: center; display: flex; flex-direction: row; + margin-bottom: 16px; } div.principal-select * { @@ -61,16 +62,11 @@ table tr { } table td { - white-space: nowrap; text-overflow: ellipsis; font-size: 8pt; font-family: 'Lucida Console'; } -table td:last-child { - font-size: 12pt; -} - table td:nth-last-child(2) { border-right: none !important; } @@ -79,9 +75,15 @@ table tr:nth-child(2n+1) td:not(:first-child) { background: rgba(255, 255, 255, 0.1); } -table td:nth-child(2n) { +table td:first-child { + width: 1px; +} + +table td:last-child { width: 1px; white-space: nowrap; + text-align: right; + font-size: 12pt; } table td > div { diff --git a/SecurityIdentifier.cs b/SecurityIdentifier.cs index 075788d..8ffaa1b 100644 --- a/SecurityIdentifier.cs +++ b/SecurityIdentifier.cs @@ -15,6 +15,7 @@ public static class WellKnownSid { public static readonly SecurityIdentifier CreatorGroupSid = new("S-1-3-1"); private static readonly (string name, SecurityIdentifier sid)[] nameMap = new[] { + ( "Nobody", NullSid ), ( "Everyone", WorldSid ), ( "LOCAL", LocalSid ), ( "CREATOR OWNER", CreatorGroupSid ), @@ -106,14 +107,19 @@ public class SecurityIdentifier { } } - public override string ToString() { - var identifierAuthority = new BigInteger(SidStruct.IdentifierAuthority, true, true); - var subAuthorities = string.Join('-',SidStruct.SubAuthorities.Select(sa => sa.ToString())); - if(!string.IsNullOrEmpty(subAuthorities)) - subAuthorities = "-" + subAuthorities; - return $"S-{SidStruct.Revision}-{identifierAuthority}{subAuthorities}"; + public string SddlForm { + get { + var identifierAuthority = new BigInteger(SidStruct.IdentifierAuthority, true, true); + var subAuthorities = string.Join('-',SidStruct.SubAuthorities.Select(sa => sa.ToString())); + if(!string.IsNullOrEmpty(subAuthorities)) + subAuthorities = "-" + subAuthorities; + return $"S-{SidStruct.Revision}-{identifierAuthority}{subAuthorities}"; + } } + public override string ToString() => + WellKnownSid.TranslateSid(this) ?? SddlForm; + public static bool operator ==(SecurityIdentifier? x, SecurityIdentifier? y) => x?.SidStruct.Equals(y?.SidStruct) ?? false; |
