using System; using System.Collections.Generic; using System.Linq; using MoralisUnity.Platform.Abstractions; using Newtonsoft.Json; namespace MoralisUnity.Platform.Objects { class MoralisAclJsonConvertor : JsonConverter { public override bool CanConvert(Type objectType) { return true; } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { //MyCustomType myCustomType = new MyCustomType();//for null values Dictionary acl = new Dictionary(); string key = String.Empty; while (reader.Read()) { var tokenType = reader.TokenType; if (reader.TokenType == JsonToken.PropertyName) { key = (reader.Value as string) ?? string.Empty; } else if (reader.TokenType == JsonToken.StartObject) { Dictionary cntlDict = new Dictionary(); var cntlKey = string.Empty; while (reader.Read()) { if (reader.TokenType == JsonToken.PropertyName) { cntlKey = (reader.Value as string) ?? string.Empty; } else if (reader.TokenType == JsonToken.Boolean) { bool? b = reader.Value as bool?; cntlDict.Add(cntlKey, b.Value); } if (reader.TokenType == JsonToken.EndObject) { acl.Add(key, cntlDict); break; } } } else if (reader.TokenType == JsonToken.EndObject) { break; } } return new MoralisAcl(acl); } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { if (value == null || !(value is MoralisAcl)) { serializer.Serialize(writer, null); return; } Dictionary acl = ((MoralisAcl)value).ToParameterDictionary(); serializer.Serialize(writer, acl); } } [JsonConverter(typeof(MoralisAclJsonConvertor))] public class MoralisAcl { private enum AccessKind { Read, Write } private const string publicName = "*"; private readonly ICollection readers = new HashSet(); private readonly ICollection writers = new HashSet(); internal MoralisAcl(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 MoralisAcl() { } /// /// Creates an ACL where only the provided user has access. /// /// The only user that can read or write objects governed by this ACL. public MoralisAcl(MoralisUser owner) { SetReadAccess(owner, true); SetWriteAccess(owner, true); } public Dictionary ToParameterDictionary() { Dictionary result = new Dictionary(); foreach (string user in readers.Union(writers)) { Dictionary 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 => 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 => 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(MoralisUser 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(MoralisUser 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) => 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(MoralisUser user) => 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) => 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(MoralisUser user) => 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(MoralisRole 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) => 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(MoralisRole role) => 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(MoralisRole 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) => 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(MoralisRole role) => GetRoleWriteAccess(role.name); } }