/// <summary> /// Treats this object as an action question and matches it against the list of /// permissions given as a parameter. /// </summary> /// <remarks>This may throw if things aren't right (permissions attribute isn't Perm[], etc)</remarks> /// <returns>True if it's allowed.</returns> public bool check( Mob target ) { // Make sure we have everything we need for a proper question. if( (this.perms & PermBits.Verb) || (this.perms & PermBits.Attr) ) if( String.IsNullOrEmpty( this.specific ) ) throw new ArgumentException( "Permission question has verb or attribute, but no specific name." ); if( this.perms == 0 ) throw new ArgumentException( "Permission question has no bits set." ); if( (this.perms.mask & (this.perms.mask - 1)) != 0 ) throw new ArgumentException( "Permission question has more than one bit." ); if( this.perms & PermBits.AO ) throw new ArgumentException( "Permission question can't specify AO." ); // Post-condition: We have a proper single bit permission question with a specific if appropriate. // Team members can do anything they please. The find may fail here if it's an anonymous player. Mob actor = target.world.findObject( this.actorId ); if( actor != null && actor.teamMember ) return true; // If we're editing the permissions attribute itself, only team members can do that. if( (this.perms & PermBits.AW) && this.specific == Mob.Attributes.Permissions ) return false; // Get the permissions assertions, starting with the specific target mob and working up the inheritance chain. var permissions = new List<KeyValuePair<Mob, Perm[]>>(); for( Mob m = target; m != null; m = m.parent ) { var permattr = m.attrGet( Mob.Attributes.Permissions ); if( permattr != null ) { Perm[] tp; object tpcontents = permattr.contents; if( tpcontents is object[] ) tp = ((object[])tpcontents).Select( p => (Perm)p ).ToArray(); else tp = (Perm[])permattr.contents; permissions.Add( new KeyValuePair<Mob, Perm[]>( m, tp ) ); } } // Are we dealing with an attribute? If so, look for a sticky bit starting at the bottom. if( this.perms & PermBits.Attr ) { // This is not so efficient, but it should be okay for the small numbers we're working with. for( int i = permissions.Count - 1; i > 0; --i ) { var kvp = permissions[i]; if( kvp.Value.Any( (p) => p.specific == this.specific && p.perms & PermBits.AO ) ) { // We really want to do this check with this other object's permissions. return check( kvp.Key ); } } } // If it's not an AO attribute, then the owner is allowed to do anything. if( target.ownerId == this.actorId ) return true; // Find all the mob IDs in the inheritance chain for this question's actor ID. We // stop before #1 because it probably has all sorts of powers. var actors = new List<int>(); if( this.actorId == 1 ) actors.Add( 1 ); else if( actor == null ) { // This can come about from anonymous users. actors.Add( this.actorId ); } else { for( Mob m = actor; m != null && m.id != 1; m = m.parent ) actors.Add( m.id ); } // If we find nothing, we have to fall back to looking for an "opaque" attribute // to determine what the base permissions are. So we'll just do that now and tack the defaults // onto the end. if( target.findAttribute( Mob.Attributes.Opaque ) == null ) { // Not opaque: give a set of default permissions that lets people read most of it. var clearPerms = new Perm[] { new Perm() { actorId = Mob.Any.id, perms = PermBits.AR | PermBits.OR | PermBits.OF | PermBits.VR, specific = null } }; permissions.Add( new KeyValuePair<Mob,Perm[]>( target, clearPerms ) ); } // Go through until we find a permission that matches what we're looking for. foreach( var kvp in permissions ) { foreach( var p in kvp.Value ) { // This permission applies if: // - The actor is Any, and the caller is not Anon. (Permissions must be granted to Anon.) // - The actor is a set value, and that value is in the caller's inheritance chain. if( (this.actorId != Mob.Anon.id && p.actorId == Mob.Any.id) || actors.Any( a => a == p.actorId ) ) { // Make sure we're talking about the same subject. if( matches( p ) ) return p.type == Type.Allow; } } } // Didn't find anything: denied. return false; }
/// <summary> /// Treats us as an action and matches us against the specified permission. /// Returns true if the permission matches. /// </summary> public bool matches( Perm other ) { // Specifics might be null, but they must still match. Any bits that are shared // make the permission relevant. return (this.perms & other.perms) && (string.IsNullOrEmpty( other.specific ) || this.specific == other.specific); }
public void Permissions() { createBasicWorld(); // Make a chain to test inheritance. _testObj.permissions = new Perm[] { new Perm() { actorId = _player.id, type = Perm.Type.Allow, perms = PermBits.AW, specific = "test" }, new Perm() { actorId = Mob.Any.id, type = Perm.Type.Deny, perms = PermBits.VW, specific = null }, new Perm() { actorId = 1, type = Perm.Type.Allow, perms = PermBits.AO | PermBits.AW, specific = "test2" } }; _testObj.ownerId = _god.id; _testObj.attrSet( "test", "test" ); _testObj.attrSet( "test2", "test" ); var test2 = Mob.Wrap( _sw.createObject() ); test2.ownerId = _god.id; test2.parentId = _testObj.id; test2.locationId = _god.id; test2.permissions = new Perm[] { new Perm() { actorId = _player.id, type = Perm.Type.Deny, perms = PermBits.AW, specific = "test" }, new Perm() // This is invalid { actorId = _player.id, type = Perm.Type.Allow, perms = PermBits.AW, specific = "test2" } }; test2.ownerId = _testObj.id; var test3 = Mob.Wrap( _sw.createObject() ); test3.parentId = test2.id; test3.locationId = _god.id; test3.ownerId = _player.id; // Now try some questions against it all. Perm q = new Perm() { actorId = _player.id, perms = PermBits.VW, specific = "bob" }; bool success = q.check( test2 ); Assert.IsFalse( success ); success = q.check( test3 ); Assert.IsTrue( success ); q = new Perm() { actorId = _player.id, perms = PermBits.AW, specific = "test2" }; success = q.check( test3 ); Assert.IsFalse( success ); }