diff --git a/Nibriboard/Nibriboard.csproj b/Nibriboard/Nibriboard.csproj
index fbbcc54..9a0b52d 100644
--- a/Nibriboard/Nibriboard.csproj
+++ b/Nibriboard/Nibriboard.csproj
@@ -54,6 +54,9 @@
..\packages\GlidingSquirrel.0.6.1-alpha\lib\net462\GlidingSquirrel.dll
+
+ ..\packages\SimpleHashing.Net.1.0.1\lib\SimpleHashing.Net.dll
+
@@ -145,6 +148,10 @@
+
+
+
+
@@ -169,6 +176,7 @@
+
diff --git a/Nibriboard/Userspace/RbacPermission.cs b/Nibriboard/Userspace/RbacPermission.cs
new file mode 100644
index 0000000..cb5b7d9
--- /dev/null
+++ b/Nibriboard/Userspace/RbacPermission.cs
@@ -0,0 +1,33 @@
+using System;
+
+namespace Nibriboard.Userspace
+{
+ public class RbacPermission
+ {
+ public readonly string Name;
+ public readonly string Description;
+
+ public RbacPermission(string inName, string inDescription)
+ {
+ Name = inName;
+ Description = inDescription;
+ }
+
+ public override bool Equals(object obj)
+ {
+ RbacPermission otherPermission = obj as RbacPermission;
+ if (obj == null)
+ return false;
+ return Name == otherPermission.Name;
+ }
+ public override int GetHashCode()
+ {
+ return ToString().GetHashCode();
+ }
+ public override string ToString()
+ {
+ return $"[RbacPermission -> {Name}: {Description}]";
+ }
+ }
+
+}
diff --git a/Nibriboard/Userspace/RbacRole.cs b/Nibriboard/Userspace/RbacRole.cs
new file mode 100644
index 0000000..c2bbb97
--- /dev/null
+++ b/Nibriboard/Userspace/RbacRole.cs
@@ -0,0 +1,32 @@
+using System;
+using System.Linq;
+using System.Collections.Generic;
+
+namespace Nibriboard.Userspace
+{
+ public class RbacRole
+ {
+ public readonly string Name;
+
+ public readonly List SubRoles = new List();
+ public readonly List Permissions = new List();
+
+ public RbacRole()
+ {
+ }
+ public RbacRole(string inRoleName, List inPermissions) : this(inRoleName, inPermissions, new List())
+ {
+ }
+ public RbacRole(string inRoleName, List inPermissions, List inSubRoles)
+ {
+ Name = inRoleName;
+ Permissions = inPermissions;
+ SubRoles = inSubRoles;
+ }
+
+ public bool HasPermission(RbacPermission permission)
+ {
+ return Permissions.Contains(permission) || SubRoles.Any((RbacRole obj) => obj.HasPermission(permission));
+ }
+ }
+}
diff --git a/Nibriboard/Userspace/User.cs b/Nibriboard/Userspace/User.cs
new file mode 100644
index 0000000..5beef87
--- /dev/null
+++ b/Nibriboard/Userspace/User.cs
@@ -0,0 +1,51 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+using SimpleHashing.Net;
+
+namespace Nibriboard.Userspace
+{
+ public class User
+ {
+ private static ISimpleHash passwordHasher = new SimpleHash();
+
+ public DateTime CreationTime { get; set; }
+ public string Username { get; set; }
+ public string HashedPassword { get; set; }
+
+ public List Roles { get; set; }
+
+ public User()
+ {
+ }
+
+ ///
+ /// Updates this user's password.
+ ///
+ /// The new (unhashed) password.
+ public void SetPassword(string newPassword)
+ {
+ HashedPassword = passwordHasher.Compute(newPassword);
+ }
+ ///
+ /// Checks whether a specified (unhashed) password matches
+ ///
+ /// The password to check.
+ /// Whether the specified password matches the stored password or not.
+ public bool CheckPassword(string providedPassword)
+ {
+ return passwordHasher.Verify(providedPassword, HashedPassword);
+ }
+
+ ///
+ /// Recursively works out whether this user has the specified permission.
+ ///
+ /// The permission to search for.
+ /// Whether this user has the specified permission through one of their roles or not.
+ public bool HasPermission(RbacPermission permission)
+ {
+ return Roles.Any((RbacRole role) => role.HasPermission(permission));
+ }
+ }
+}
diff --git a/Nibriboard/Userspace/UserManager.cs b/Nibriboard/Userspace/UserManager.cs
new file mode 100644
index 0000000..876cfe5
--- /dev/null
+++ b/Nibriboard/Userspace/UserManager.cs
@@ -0,0 +1,53 @@
+using System;
+using System.Collections.Generic;
+
+namespace Nibriboard.Userspace
+{
+ public class UserManager
+ {
+ public List Users { get; private set; } = new List();
+ public List Permissions { get; private set; } = new List();
+ public List Roles { get; private set; } = new List();
+
+ public UserManager()
+ {
+ Permissions.AddRange(new RbacPermission[] {
+ new RbacPermission("view-public-plane", "View public planes"),
+ new RbacPermission("view-own-plane", "View your own planes."),
+ new RbacPermission("view-any-plane", "View anyone's planes."),
+ new RbacPermission("create-plane", "Create a new plane."),
+ new RbacPermission("delete-own-plane", "Delete a plane."),
+ new RbacPermission("delete-any-plane", "Delete a plane."),
+ new RbacPermission("manage-own-plane-members", "Manage the users allowed to access one of your planes."),
+ new RbacPermission("manage-any-plane-members", "Manage the users allowed to access one any plane.")
+ });
+ Roles.Add(new RbacRole("Guest", new List() {
+ GetPermission("view-public-plane")
+ }));
+ Roles.Add(new RbacRole("Member", new List() {
+ GetPermission("view-own-plane"),
+ GetPermission("create-plane"),
+ GetPermission("delete-own-plane"),
+ GetPermission("manage-own-plane-members")
+ }, new List() {
+ GetRole("Guest")
+ }));
+ Roles.Add(new RbacRole("Root", new List() {
+ GetPermission("view-any-plane"),
+ GetPermission("delete-any-plane"),
+ GetPermission("manage-any-plane-members")
+ }, new List() {
+ GetRole("Member")
+ }));
+ }
+
+ public RbacPermission GetPermission(string permissionName)
+ {
+ return Permissions.Find((RbacPermission permission) => permission.Name == permissionName);
+ }
+ public RbacRole GetRole(string roleName)
+ {
+ return Roles.Find((RbacRole role) => role.Name == roleName);
+ }
+ }
+}
diff --git a/Nibriboard/packages.config b/Nibriboard/packages.config
index 60ff3fc..4019e74 100644
--- a/Nibriboard/packages.config
+++ b/Nibriboard/packages.config
@@ -5,5 +5,6 @@
+
\ No newline at end of file