using System; using System.Collections.Generic; using System.Linq; using LeanCloud.Storage.Internal; namespace LeanCloud { /// /// A AVACL is used to control which users and roles can access or modify a particular object. Each /// can have its own AVACL. You can grant read and write permissions /// separately to specific users, to groups of users that belong to roles, or you can grant permissions /// to "the public" so that, for example, any user could read a particular object but only a particular /// set of users could write to that object. /// public class AVACL : IJsonConvertible { private enum AccessKind { Read, Write } private const string publicName = "*"; private readonly ICollection readers = new HashSet(); private readonly ICollection writers = new HashSet(); internal AVACL(IDictionary jsonObject) { readers = new HashSet(from pair in jsonObject where ((IDictionary)pair.Value).ContainsKey("read") select pair.Key); writers = new HashSet(from pair in jsonObject where ((IDictionary)pair.Value).ContainsKey("write") select pair.Key); } /// /// Creates an ACL with no permissions granted. /// public AVACL() { } /// /// Creates an ACL where only the provided user has access. /// /// The only user that can read or write objects governed by this ACL. public AVACL(AVUser owner) { SetReadAccess(owner, true); SetWriteAccess(owner, true); } IDictionary IJsonConvertible.ToJSON() { var result = new Dictionary(); foreach (var user in readers.Union(writers)) { var userPermissions = new Dictionary(); if (readers.Contains(user)) { userPermissions["read"] = true; } if (writers.Contains(user)) { userPermissions["write"] = true; } result[user] = userPermissions; } return result; } private void SetAccess(AccessKind kind, string userId, bool allowed) { if (userId == null) { throw new ArgumentException("Cannot set access for an unsaved user or role."); } ICollection target = null; switch (kind) { case AccessKind.Read: target = readers; break; case AccessKind.Write: target = writers; break; default: throw new NotImplementedException("Unknown AccessKind"); } if (allowed) { target.Add(userId); } else { target.Remove(userId); } } private bool GetAccess(AccessKind kind, string userId) { if (userId == null) { throw new ArgumentException("Cannot get access for an unsaved user or role."); } switch (kind) { case AccessKind.Read: return readers.Contains(userId); case AccessKind.Write: return writers.Contains(userId); default: throw new NotImplementedException("Unknown AccessKind"); } } /// /// Gets or sets whether the public is allowed to read this object. /// public bool PublicReadAccess { get { return GetAccess(AccessKind.Read, publicName); } set { SetAccess(AccessKind.Read, publicName, value); } } /// /// Gets or sets whether the public is allowed to write this object. /// public bool PublicWriteAccess { get { return GetAccess(AccessKind.Write, publicName); } set { SetAccess(AccessKind.Write, publicName, value); } } /// /// Sets whether the given user id is allowed to read this object. /// /// The objectId of the user. /// Whether the user has permission. public void SetReadAccess(string userId, bool allowed) { SetAccess(AccessKind.Read, userId, allowed); } /// /// Sets whether the given user is allowed to read this object. /// /// The user. /// Whether the user has permission. public void SetReadAccess(AVUser user, bool allowed) { SetReadAccess(user.ObjectId, allowed); } /// /// Sets whether the given user id is allowed to write this object. /// /// The objectId of the user. /// Whether the user has permission. public void SetWriteAccess(string userId, bool allowed) { SetAccess(AccessKind.Write, userId, allowed); } /// /// Sets whether the given user is allowed to write this object. /// /// The user. /// Whether the user has permission. public void SetWriteAccess(AVUser user, bool allowed) { SetWriteAccess(user.ObjectId, allowed); } /// /// Gets whether the given user id is *explicitly* allowed to read this object. /// Even if this returns false, the user may still be able to read it if /// PublicReadAccess is true or a role that the user belongs to has read access. /// /// The user objectId to check. /// Whether the user has access. public bool GetReadAccess(string userId) { return GetAccess(AccessKind.Read, userId); } /// /// Gets whether the given user is *explicitly* allowed to read this object. /// Even if this returns false, the user may still be able to read it if /// PublicReadAccess is true or a role that the user belongs to has read access. /// /// The user to check. /// Whether the user has access. public bool GetReadAccess(AVUser user) { return GetReadAccess(user.ObjectId); } /// /// Gets whether the given user id is *explicitly* allowed to write this object. /// Even if this returns false, the user may still be able to write it if /// PublicReadAccess is true or a role that the user belongs to has write access. /// /// The user objectId to check. /// Whether the user has access. public bool GetWriteAccess(string userId) { return GetAccess(AccessKind.Write, userId); } /// /// Gets whether the given user is *explicitly* allowed to write this object. /// Even if this returns false, the user may still be able to write it if /// PublicReadAccess is true or a role that the user belongs to has write access. /// /// The user to check. /// Whether the user has access. public bool GetWriteAccess(AVUser user) { return GetWriteAccess(user.ObjectId); } /// /// Sets whether users belonging to the role with the given /// are allowed to read this object. /// /// The name of the role. /// Whether the role has access. public void SetRoleReadAccess(string roleName, bool allowed) { SetAccess(AccessKind.Read, "role:" + roleName, allowed); } /// /// Sets whether users belonging to the given role are allowed to read this object. /// /// The role. /// Whether the role has access. public void SetRoleReadAccess(AVRole role, bool allowed) { SetRoleReadAccess(role.Name, allowed); } /// /// Gets whether users belonging to the role with the given /// are allowed to read this object. Even if this returns false, the role may still be /// able to read it if a parent role has read access. /// /// The name of the role. /// Whether the role has access. public bool GetRoleReadAccess(string roleName) { return GetAccess(AccessKind.Read, "role:" + roleName); } /// /// Gets whether users belonging to the role are allowed to read this object. /// Even if this returns false, the role may still be able to read it if a /// parent role has read access. /// /// The name of the role. /// Whether the role has access. public bool GetRoleReadAccess(AVRole role) { return GetRoleReadAccess(role.Name); } /// /// Sets whether users belonging to the role with the given /// are allowed to write this object. /// /// The name of the role. /// Whether the role has access. public void SetRoleWriteAccess(string roleName, bool allowed) { SetAccess(AccessKind.Write, "role:" + roleName, allowed); } /// /// Sets whether users belonging to the given role are allowed to write this object. /// /// The role. /// Whether the role has access. public void SetRoleWriteAccess(AVRole role, bool allowed) { SetRoleWriteAccess(role.Name, allowed); } /// /// Gets whether users belonging to the role with the given /// are allowed to write this object. Even if this returns false, the role may still be /// able to write it if a parent role has write access. /// /// The name of the role. /// Whether the role has access. public bool GetRoleWriteAccess(string roleName) { return GetAccess(AccessKind.Write, "role:" + roleName); } /// /// Gets whether users belonging to the role are allowed to write this object. /// Even if this returns false, the role may still be able to write it if a /// parent role has write access. /// /// The name of the role. /// Whether the role has access. public bool GetRoleWriteAccess(AVRole role) { return GetRoleWriteAccess(role.Name); } } }