summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AclEnum.cs4
-rw-r--r--Pages/Component/AclDialog.razor127
-rw-r--r--Pages/Component/AclDialog.razor.css14
-rw-r--r--SecurityIdentifier.cs18
4 files changed, 129 insertions, 34 deletions
diff --git a/AclEnum.cs b/AclEnum.cs
index ac07bf6..fba509c 100644
--- a/AclEnum.cs
+++ b/AclEnum.cs
@@ -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:;">&#x1F589</a>
- <a title="Delete" href="javascript:;">&#x2716</a>
+ <a title="Edit" href="javascript:;" @onclick=@(() => EditRule(rule))>&#x1F589</a>
+ <a title="Delete" href="javascript:;" @onclick=@(() => RemoveRule(rule))>&#x2716</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;