From a4b636d5b8ad0ba9c444b86b86a1cd907930df67 Mon Sep 17 00:00:00 2001 From: Waverunner Date: Wed, 10 Jun 2015 13:22:22 -0400 Subject: [PATCH] Refactored container permissions --- .../containers/ContainerPermissions.java | 71 ++++++----- .../containers/DefaultPermissions.java | 63 ++++++++++ .../containers/InventoryPermissions.java | 47 ++++++++ .../containers/WorldPermissions.java | 82 +++++++++++++ src/resources/objects/SWGObject.java | 113 +++++++++++++----- .../buildouts/TerrainBuildoutLoader.java | 4 +- src/services/player/ZoneService.java | 9 +- 7 files changed, 329 insertions(+), 60 deletions(-) create mode 100644 src/resources/containers/DefaultPermissions.java create mode 100644 src/resources/containers/InventoryPermissions.java create mode 100644 src/resources/containers/WorldPermissions.java diff --git a/src/resources/containers/ContainerPermissions.java b/src/resources/containers/ContainerPermissions.java index 5dc0dc1fc..b976f6169 100644 --- a/src/resources/containers/ContainerPermissions.java +++ b/src/resources/containers/ContainerPermissions.java @@ -27,29 +27,31 @@ package resources.containers; -import java.io.Serializable; -import java.util.EnumSet; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; +import resources.objects.SWGObject; -public final class ContainerPermissions implements Serializable { +import java.io.Serializable; +import java.util.*; + +/** + * Structure for creating permission sets that will allow the object to be viewed/modified/added/removed by a requested + * object depending on the implemented abstract methods. + * @author Waverunner + */ +public abstract class ContainerPermissions implements Serializable { private static final long serialVersionUID = 1L; - private Map permissionGroups; - private long owner; + public static WorldPermissions WORLD = new WorldPermissions(); + public static InventoryPermissions INVENTORY = new InventoryPermissions(); - public ContainerPermissions(long owner) { + private Map permissionGroups; + private List joinedGroups; + + public ContainerPermissions() { this.permissionGroups = new HashMap<>(); - this.owner = owner; - - synchronized (permissionGroups) { - permissionGroups.put("owner", Permission.valueOf(Permission.values())); - permissionGroups.put("admin", Permission.valueOf(Permission.values())); - } + this.joinedGroups = new ArrayList<>(); } - public boolean hasPermissions(String group, Permission... permissions) { + protected boolean hasPermissions(String group, Permission... permissions) { if (!hasPermissionGroup(group)) return false; @@ -63,7 +65,20 @@ public final class ContainerPermissions implements Serializable { return true; } + public boolean hasPermissions(List requesterGroups, Permission ... permission) { + for (String group : requesterGroups) { + if (hasPermissions(group, permission)); + return true; + } + return false; + } + public void addPermissions(String group, Permission... permissions) { + if (!hasPermissionGroup(group)) { + permissionGroups.put(group, Permission.valueOf(permissions)); + return; + } + EnumSet groupPermissions = Permission.getFlags(permissionGroups.get(group)); for (Permission permission : permissions) { @@ -91,12 +106,6 @@ public final class ContainerPermissions implements Serializable { } } - public void addDefaultWorldPermissions() { - synchronized (permissionGroups) { - permissionGroups.put("world", Permission.valueOf(Permission.ENTER_BUILDING, Permission.OPEN)); - } - } - public void clearPermissions(String group) { synchronized (permissionGroups) { if (permissionGroups.containsKey(group)) @@ -114,20 +123,26 @@ public final class ContainerPermissions implements Serializable { } } - public void setOwner(long owner) { - this.owner = owner; + public List getJoinedGroups() { + return joinedGroups; } - public long getOwner() { - return owner; + public void addDefaultWorldPermissions() { + addPermissions("world", Permission.VIEW, Permission.ENTER); } + public abstract boolean canView(SWGObject viewer, SWGObject container); + public abstract boolean canEnter(SWGObject requester, SWGObject container); + public abstract boolean canRemove(SWGObject requester, SWGObject container); + public abstract boolean canMove(SWGObject requester, SWGObject container); + public abstract boolean canAdd(SWGObject requester, SWGObject container); + public enum Permission { - OPEN(1), + VIEW(1), REMOVE(1<<1), ADD(1<<2), MOVE(1<<3), - ENTER_BUILDING(1<<4); + ENTER(1<<4); int bitmask; diff --git a/src/resources/containers/DefaultPermissions.java b/src/resources/containers/DefaultPermissions.java new file mode 100644 index 000000000..febce350b --- /dev/null +++ b/src/resources/containers/DefaultPermissions.java @@ -0,0 +1,63 @@ +/******************************************************************************* + * Copyright (c) 2015 /// Project SWG /// www.projectswg.com + * + * ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on + * July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. + * Our goal is to create an emulator which will provide a server for players to + * continue playing a game similar to the one they used to play. We are basing + * it on the final publish of the game prior to end-game events. + * + * This file is part of Holocore. + * + * -------------------------------------------------------------------------------- + * + * Holocore is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * Holocore is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Holocore. If not, see + ******************************************************************************/ + +package resources.containers; + +import resources.objects.SWGObject; + +/** + * Default set of permissions that allows anyone to view or enter the container. These permissions are used + * for every new object. + * @author Waverunner + */ +public class DefaultPermissions extends ContainerPermissions { + + @Override + public boolean canView(SWGObject requester, SWGObject container) { + return true; + } + + @Override + public boolean canEnter(SWGObject requester, SWGObject container) { + return true; + } + + @Override + public boolean canRemove(SWGObject requester, SWGObject container) { + return requester.getOwner() == container.getOwner(); + } + + @Override + public boolean canMove(SWGObject requester, SWGObject container) { + return requester.getOwner() == container.getOwner(); + } + + @Override + public boolean canAdd(SWGObject requester, SWGObject container) { + return requester.getOwner() == container.getOwner(); + } +} diff --git a/src/resources/containers/InventoryPermissions.java b/src/resources/containers/InventoryPermissions.java new file mode 100644 index 000000000..ba5abde24 --- /dev/null +++ b/src/resources/containers/InventoryPermissions.java @@ -0,0 +1,47 @@ +/******************************************************************************* + * Copyright (c) 2015 /// Project SWG /// www.projectswg.com + * + * ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on + * July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. + * Our goal is to create an emulator which will provide a server for players to + * continue playing a game similar to the one they used to play. We are basing + * it on the final publish of the game prior to end-game events. + * + * This file is part of Holocore. + * + * -------------------------------------------------------------------------------- + * + * Holocore is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * Holocore is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Holocore. If not, see + ******************************************************************************/ + +package resources.containers; + +import resources.objects.SWGObject; + +/** + * This set of permissions will allow only the owner to view the container. + * + * @author Waverunner + */ +public class InventoryPermissions extends DefaultPermissions { + @Override + public boolean canView(SWGObject requester, SWGObject container) { + return requester.getOwner() == container.getOwner(); + } + + @Override + public boolean canEnter(SWGObject requester, SWGObject container) { + return requester.getOwner() == container.getOwner(); + } +} diff --git a/src/resources/containers/WorldPermissions.java b/src/resources/containers/WorldPermissions.java new file mode 100644 index 000000000..e6331dca6 --- /dev/null +++ b/src/resources/containers/WorldPermissions.java @@ -0,0 +1,82 @@ +/******************************************************************************* + * Copyright (c) 2015 /// Project SWG /// www.projectswg.com + * + * ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on + * July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. + * Our goal is to create an emulator which will provide a server for players to + * continue playing a game similar to the one they used to play. We are basing + * it on the final publish of the game prior to end-game events. + * + * This file is part of Holocore. + * + * -------------------------------------------------------------------------------- + * + * Holocore is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * Holocore is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Holocore. If not, see + ******************************************************************************/ + +package resources.containers; + +import resources.objects.SWGObject; + +import java.util.List; + +/** + * This is essentially a universal "all-in-one" permission set for managing permission groups for world objects. This + * class makes use of permission groups. Every player joins the world permission group upon creation. When a specific + * group is needed, the object will have to remove the world permission set and replace it with their own group of + * permissions. + *

Example: In order to allow only certain players into an area of Jabba's palace, you would first + * create a permission group for the CellObject with a unique name. Then you need to add the named group to the + * players ContainerPermissions joinedGroups list in order for them to properly pass the checks. + *

+ * This set of permissions will allow: + *
    + *
  1. View - If the viewer has joined a group that is recognized by the container with viewing permissions
  2. + *
  3. Enter - If the viewer has joined a group that is recognized by the container with enter permissions
  4. + *
  5. Remove, Move, Add - If the container has the same owner as the requester
  6. + *
+ * @author Waverunner + */ +public class WorldPermissions extends DefaultPermissions { + @Override + public boolean canView(SWGObject viewer, SWGObject container) { + if (super.canView(viewer, container)) + return true; + + return hasPermissions(viewer.getContainerPermissions().getJoinedGroups(), Permission.VIEW); + } + + @Override + public boolean canEnter(SWGObject requester, SWGObject container) { + if (super.canView(requester, container)) + return true; + + return hasPermissions(requester.getContainerPermissions().getJoinedGroups(), Permission.ENTER); + } + + @Override + public boolean canRemove(SWGObject requester, SWGObject container) { + return super.canRemove(requester, container); + } + + @Override + public boolean canMove(SWGObject requester, SWGObject container) { + return super.canMove(requester, container); + } + + @Override + public boolean canAdd(SWGObject requester, SWGObject container) { + return super.canAdd(requester, container); + } +} diff --git a/src/resources/objects/SWGObject.java b/src/resources/objects/SWGObject.java index 61f507335..ecdbabf6e 100644 --- a/src/resources/objects/SWGObject.java +++ b/src/resources/objects/SWGObject.java @@ -44,6 +44,7 @@ import resources.Location; import resources.common.CRC; import resources.containers.ContainerPermissions; import resources.containers.ContainerResult; +import resources.containers.DefaultPermissions; import resources.encodables.Stf; import resources.network.BaselineBuilder; import resources.network.DeltaBuilder; @@ -62,8 +63,8 @@ public abstract class SWGObject implements Serializable, Comparable { private final Map containedObjects; private final Map attributes; private final Map templateAttributes; - private final ContainerPermissions containerPermissions; private final BaselineType objectType; + private ContainerPermissions containerPermissions; private transient List objectsAware; private List > arrangement; @@ -96,7 +97,7 @@ public abstract class SWGObject implements Serializable, Comparable { this.containedObjects = Collections.synchronizedMap(new HashMap()); this.attributes = new LinkedHashMap(); this.templateAttributes = new HashMap(); - this.containerPermissions = new ContainerPermissions(objectId); + this.containerPermissions = new DefaultPermissions(); this.objectType = objectType; } @@ -129,7 +130,6 @@ public abstract class SWGObject implements Serializable, Comparable { object.parent = this; object.slotArrangement = arrangementId; - object.containerPermissions.setOwner(objectId); return true; } @@ -150,11 +150,10 @@ public abstract class SWGObject implements Serializable, Comparable { object.parent = null; object.slotArrangement = -1; - object.containerPermissions.setOwner(-1); } /** - * Moves the current object to the target object + * Moves this object to the passed container if the requester has the MOVE permission for the container * @param requester Object that is requesting to move the object, used for permission checking * @param container Where this object should be moved to * @return {@link ContainerResult} @@ -194,42 +193,102 @@ public abstract class SWGObject implements Serializable, Comparable { return ContainerResult.SUCCESS; } - public boolean hasOwnerPermissions(SWGObject object) { - return (object.getObjectId() == containerPermissions.getOwner()); + /** + * Attempts to move this object to the defined container without checking for permissions + * @param container + * @return {@link ContainerResult} + */ + public ContainerResult moveToContainer(SWGObject container) { + return moveToContainer(null, container); } + /** + * Checks if the passed object has all of the passed permissions + * @param object Requester to view this container + * @param permissions Permissions to check for + * @return + */ public boolean hasPermission(SWGObject object, ContainerPermissions.Permission... permissions) { - if (object == this || hasOwnerPermissions(object)) + if (object == null || object == this || object.getOwner() == getOwner()) return true; - - if (!containerPermissions.hasPermissions(String.valueOf(object.getObjectId()), permissions)) { - // Doesn't have any owner permissions or specific permissions, check to see if this object has an - // acceptable permission group with the specified permissions available. - for (String permissionGroup : object.containerPermissions.getPermissionGroups()) { - if (containerPermissions.hasPermissions(permissionGroup, permissions)) { - //System.out.println(object + " can view " + this); - return true; - } + for (ContainerPermissions.Permission permission : permissions) { + switch(permission) { + case VIEW: + if (!containerPermissions.canView(object, this)) + return false; + break; + case MOVE: + if (!containerPermissions.canMove(object, this)) + return false; + break; + case REMOVE: + if (!containerPermissions.canRemove(object, this)) + return false; + break; + case ADD: + if (!containerPermissions.canAdd(object, this)) + return false; + break; + case ENTER: + if (!containerPermissions.canEnter(object, this)) + return false; + break; } - return false; } - else return true; + return true; } + /** + * Creates a new permission group for this object with the given permissions for that group + * @param group Name of the permission group + * @param permissions Permissions for the group + */ public void addPermissions(String group, ContainerPermissions.Permission... permissions) { containerPermissions.addPermissions(group, permissions); } + /** + * Removes the stated permissions from the group. + * @param group Name of the permission group + * @param permissions Permissions to remove + */ public void removePermissions(String group, ContainerPermissions.Permission... permissions) { containerPermissions.removePermissions(group, permissions); } + /** + * Creates a new permission group specific to the permission requester that has the defined permissions. The name of the + * new group for this object will be the objectId of this object plus the objectId of the requester. + *
This is the same as calling addPermissions(String.valueOf(permissionRequester.getObjectId() + getObjectId()), permissions) + * with the added benefit of adding the group to the permissionRequester's joined container groups + * @param permissionRequester The object that should be given unique permissions to this object + * @param permissions Permissions that the permissionRequester will have for this object + */ public void addPermissions(SWGObject permissionRequester, ContainerPermissions.Permission... permissions) { - addPermissions(String.valueOf(permissionRequester.getObjectId()), permissions); + addPermissions(String.valueOf(permissionRequester.getObjectId() + getObjectId()), permissions); + permissionRequester.joinPermissionGroup(String.valueOf(getObjectId() + permissionRequester.getObjectId())); } - public void removePermissions(SWGObject permissionRequester, ContainerPermissions.Permission... permissions) { - removePermissions(String.valueOf(permissionRequester.getObjectId()), permissions); + /** + * Removes all the unique permissions for the permissionRequester from this object. + * @param permissionRequester The object that should no longer have unique permissions to this object + */ + public void removePermissions(SWGObject permissionRequester) { + String group = String.valueOf(permissionRequester.getObjectId() + getObjectId()); + removePermissions(group); + permissionRequester.containerPermissions.getJoinedGroups().remove(group); + } + + /** + * Assigns this object to a permission group + * @param group + */ + public void joinPermissionGroup(String group) { + containerPermissions.getJoinedGroups().add(group); + } + + public void setContainerPermissions(ContainerPermissions permissions) { + this.containerPermissions = permissions; } public void addAttribute(String attribute, String value) { @@ -491,6 +550,11 @@ public abstract class SWGObject implements Serializable, Comparable { } public void createObject(Player target) { + if (!hasPermission(target.getCreatureObject(), ContainerPermissions.Permission.VIEW)) { + // Log.i("SWGObject", target.getCreatureObject() + " doesn't have permission to view " + this + " -- skipping packet sending"); + return; + } + sendSceneCreateObject(target); sendBaselines(target); createChildrenObjects(target); @@ -683,11 +747,6 @@ public abstract class SWGObject implements Serializable, Comparable { if (slots.size() == 0 && containedObjects.size() == 0) return; - if (!hasPermission(target.getCreatureObject(), ContainerPermissions.Permission.OPEN)) { - Log.i("SWGObject", target.getCreatureObject() + " doesn't have permission to view " + this + " -- skipping packet sending"); - return; - } - List sentObjects = new ArrayList<>(); // First create the objects in the slots diff --git a/src/resources/objects/buildouts/TerrainBuildoutLoader.java b/src/resources/objects/buildouts/TerrainBuildoutLoader.java index f4a5c693a..f46fc58db 100644 --- a/src/resources/objects/buildouts/TerrainBuildoutLoader.java +++ b/src/resources/objects/buildouts/TerrainBuildoutLoader.java @@ -37,6 +37,8 @@ import resources.Terrain; import resources.client_info.ClientFactory; import resources.client_info.visitors.CrcStringTableData; import resources.client_info.visitors.DatatableData; +import resources.containers.ContainerPermissions; +import resources.containers.WorldPermissions; import resources.objects.SWGObject; import resources.objects.cell.CellObject; import resources.server_info.Log; @@ -126,7 +128,7 @@ class TerrainBuildoutLoader { } private void updatePermissions(SWGObject object) { - object.getContainerPermissions().addDefaultWorldPermissions(); + object.setContainerPermissions(ContainerPermissions.WORLD); } } diff --git a/src/services/player/ZoneService.java b/src/services/player/ZoneService.java index add49b2af..cab288222 100644 --- a/src/services/player/ZoneService.java +++ b/src/services/player/ZoneService.java @@ -86,6 +86,7 @@ import resources.Terrain; import resources.client_info.ClientFactory; import resources.client_info.visitors.ProfTemplateData; import resources.config.ConfigFile; +import resources.containers.ContainerPermissions; import resources.control.Intent; import resources.control.Service; import resources.objects.SWGObject; @@ -480,7 +481,6 @@ public class ZoneService extends Service { if (hair.isEmpty()) return; TangibleObject hairObj = createTangible(objManager, ClientFactory.formatToSharedFile(hair)); - hairObj.getContainerPermissions().addDefaultWorldPermissions(); hairObj.setAppearanceData(customization); creatureObj.addObject(hairObj); // slot = hair @@ -489,8 +489,11 @@ public class ZoneService extends Service { private void setCreatureObjectValues(ObjectManager objManager, CreatureObject creatureObj, ClientCreateCharacter create) { TangibleObject inventory = createTangible(objManager, "object/tangible/inventory/shared_character_inventory.iff"); + inventory.setContainerPermissions(ContainerPermissions.INVENTORY); TangibleObject datapad = createTangible(objManager, "object/tangible/datapad/shared_character_datapad.iff"); + datapad.setContainerPermissions(ContainerPermissions.INVENTORY); TangibleObject apprncInventory = createTangible(objManager, "object/tangible/inventory/shared_appearance_inventory.iff"); + apprncInventory.setContainerPermissions(ContainerPermissions.INVENTORY); creatureObj.setRace(Race.getRaceByFile(create.getRace())); creatureObj.setAppearanceData(create.getCharCustomization()); @@ -507,15 +510,13 @@ public class ZoneService extends Service { creatureObj.addEquipment(datapad); creatureObj.addEquipment(apprncInventory); - creatureObj.getContainerPermissions().addDefaultWorldPermissions(); + creatureObj.joinPermissionGroup("world"); } private void setPlayerObjectValues(PlayerObject playerObj, ClientCreateCharacter create) { playerObj.setProfession(create.getProfession()); Calendar date = Calendar.getInstance(); playerObj.setBornDate(date.get(Calendar.YEAR), date.get(Calendar.MONTH) + 1, date.get(Calendar.DAY_OF_MONTH)); - - playerObj.getContainerPermissions().addDefaultWorldPermissions(); } private void handleGalaxyLoopTimesRequest(Player player, GalaxyLoopTimesRequest req) {