If the owner of an object is taking a copy from the scene (e.g. via the "take copy" option on a viewer) then only require owner copy perms, not copy and transfer.

This matches Linden Lab behaviour and what was already possible via shift-copy.
Transfer would not apply here as the owner and copier are the same.
This is the only functional change, all other current take copy logic remains the same.
Adds regression tests around relevant take copy cases.
inv-download
Justin Clark-Casey (justincc) 2015-02-03 23:40:32 +00:00
parent 39754b2dca
commit 1d2616e7a2
7 changed files with 389 additions and 20 deletions

View File

@ -614,6 +614,10 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
protected InventoryItemBase CreateItemForObject(
DeRezAction action, IClientAPI remoteClient, SceneObjectGroup so, UUID folderID)
{
// m_log.DebugFormat(
// "[BASIC INVENTORY ACCESS MODULE]: Creating item for object {0} {1} for folder {2}, action {3}",
// so.Name, so.UUID, folderID, action);
//
// Get the user info of the item destination
//
UUID userID = UUID.Zero;

View File

@ -801,8 +801,10 @@ namespace OpenSim.Region.CoreModules.World.Permissions
// Friends with benefits should be able to edit the objects too
if (IsFriendWithPerms(currentUser, objectOwner))
{
// Return immediately, so that the administrator can share objects with friends
return true;
}
// Users should be able to edit what is over their land.
ILandObject parcel = m_scene.LandChannel.GetLandObject(group.AbsolutePosition.X, group.AbsolutePosition.Y);
@ -1522,6 +1524,9 @@ namespace OpenSim.Region.CoreModules.World.Permissions
if (m_bypassPermissions) return m_bypassPermissionsValue;
bool permission = GenericObjectPermission(userID, objectID, false);
SceneObjectGroup so = (SceneObjectGroup)m_scene.Entities[objectID];
if (!permission)
{
if (!m_scene.Entities.ContainsKey(objectID))
@ -1535,31 +1540,23 @@ namespace OpenSim.Region.CoreModules.World.Permissions
return false;
}
SceneObjectGroup task = (SceneObjectGroup)m_scene.Entities[objectID];
// UUID taskOwner = null;
// Added this because at this point in time it wouldn't be wise for
// the administrator object permissions to take effect.
// UUID objectOwner = task.OwnerID;
if ((task.RootPart.EveryoneMask & PERM_COPY) != 0)
if ((so.RootPart.EveryoneMask & PERM_COPY) != 0)
permission = true;
}
if (task.OwnerID != userID)
if (so.OwnerID != userID)
{
if ((task.GetEffectivePermissions() & (PERM_COPY | PERM_TRANS)) != (PERM_COPY | PERM_TRANS))
if ((so.GetEffectivePermissions() & (PERM_COPY | PERM_TRANS)) != (PERM_COPY | PERM_TRANS))
permission = false;
}
else
{
if ((task.GetEffectivePermissions() & PERM_COPY) != PERM_COPY)
permission = false;
}
}
else
{
SceneObjectGroup task = (SceneObjectGroup)m_scene.Entities[objectID];
if ((task.GetEffectivePermissions() & (PERM_COPY | PERM_TRANS)) != (PERM_COPY | PERM_TRANS))
if ((so.GetEffectivePermissions() & PERM_COPY) != PERM_COPY)
permission = false;
}

View File

@ -265,6 +265,7 @@ namespace OpenSim.Region.Framework.Scenes
for (int i = 0; i < parts.Length; i++)
{
SceneObjectPart part = parts[i];
// m_log.DebugFormat("[SCENE OBJECT GROUP INVENTORY]: Effective perms of {0} are {1}", part.Name, (OpenMetaverse.PermissionMask)part.OwnerMask);
ownerMask &= part.OwnerMask;
perms &= part.Inventory.MaskEffectivePermissions();
}

View File

@ -2943,6 +2943,11 @@ namespace OpenSim.Region.Framework.Scenes
uint lockMask = ~(uint)(PermissionMask.Move | PermissionMask.Modify);
uint lockBit = RootPart.OwnerMask & (uint)(PermissionMask.Move | PermissionMask.Modify);
RootPart.OwnerMask = (RootPart.OwnerMask & lockBit) | ((newOwnerMask | foldedPerms) & lockMask);
// m_log.DebugFormat(
// "[SCENE OBJECT GROUP]: RootPart.OwnerMask now {0} for {1} in {2}",
// (OpenMetaverse.PermissionMask)RootPart.OwnerMask, Name, Scene.Name);
RootPart.ScheduleFullUpdate();
}

View File

@ -0,0 +1,347 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Collections.Generic;
using System.Reflection;
using Nini.Config;
using NUnit.Framework;
using OpenMetaverse;
using OpenSim.Framework;
using OpenSim.Framework.Communications;
using OpenSim.Region.CoreModules.Framework.EntityTransfer;
using OpenSim.Region.CoreModules.Framework.InventoryAccess;
using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation;
using OpenSim.Region.CoreModules.World.Permissions;
using OpenSim.Region.Framework.Scenes;
using OpenSim.Services.Interfaces;
using OpenSim.Tests.Common;
namespace OpenSim.Region.Framework.Scenes.Tests
{
/// <summary>
/// Test copying of scene objects.
/// </summary>
/// <remarks>
/// This is at a level above the SceneObjectBasicTests, which act on the scene directly.
/// </remarks>
[TestFixture]
public class SceneObjectCopyTests : OpenSimTestCase
{
[TestFixtureSetUp]
public void FixtureInit()
{
// Don't allow tests to be bamboozled by asynchronous events. Execute everything on the same thread.
// This facility was added after the original async delete tests were written, so it may be possible now
// to not bother explicitly disabling their async (since everything will be running sync).
Util.FireAndForgetMethod = FireAndForgetMethod.RegressionTest;
}
[TestFixtureTearDown]
public void TearDown()
{
// We must set this back afterwards, otherwise later tests will fail since they're expecting multiple
// threads. Possibly, later tests should be rewritten so none of them require async stuff (which regression
// tests really shouldn't).
Util.FireAndForgetMethod = Util.DefaultFireAndForgetMethod;
}
[Test]
public void TestTakeCopyWhenCopierIsOwnerWithPerms()
{
TestHelpers.InMethod();
// TestHelpers.EnableLogging();
IConfigSource config = new IniConfigSource();
config.AddConfig("Modules");
config.Configs["Modules"].Set("InventoryAccessModule", "BasicInventoryAccessModule");
TestScene scene = new SceneHelpers().SetupScene("s1", TestHelpers.ParseTail(0x99), 1000, 1000, config);
SceneHelpers.SetupSceneModules(scene, config, new PermissionsModule(), new BasicInventoryAccessModule());
UserAccount ua = UserAccountHelpers.CreateUserWithInventory(scene, TestHelpers.ParseTail(0x1));
TestClient client = (TestClient)SceneHelpers.AddScenePresence(scene, ua.PrincipalID).ControllingClient;
// Turn off the timer on the async sog deleter - we'll crank it by hand for this test.
AsyncSceneObjectGroupDeleter sogd = scene.SceneObjectGroupDeleter;
sogd.Enabled = false;
SceneObjectGroup so = SceneHelpers.AddSceneObject(scene, "so1", ua.PrincipalID);
uint soLocalId = so.LocalId;
// so.UpdatePermissions(
// ua.PrincipalID, (byte)PermissionWho.Owner, so.LocalId, (uint)OpenMetaverse.PermissionMask.Copy, 1);
// so.UpdatePermissions(
// ua.PrincipalID, (byte)PermissionWho.Owner, so.LocalId, (uint)OpenMetaverse.PermissionMask.Transfer, 0);
// so.UpdatePermissions(
// ua.PrincipalID, (byte)PermissionWho.Base, so.LocalId, (uint)OpenMetaverse.PermissionMask.Transfer, 0);
// scene.HandleObjectPermissionsUpdate(client, client.AgentId, client.SessionId, (byte)PermissionWho.Owner, so.LocalId, (uint)OpenMetaverse.PermissionMask.Transfer, 0);
// Ideally we might change these via client-focussed method calls as commented out above. However, this
// becomes very convoluted so we will set only the copy perm directly.
so.RootPart.BaseMask = (uint)OpenMetaverse.PermissionMask.Copy;
// so.RootPart.OwnerMask = (uint)OpenMetaverse.PermissionMask.Copy;
List<uint> localIds = new List<uint>();
localIds.Add(so.LocalId);
// Specifying a UUID.Zero in this case will currently plop it in Lost and Found
scene.DeRezObjects(client, localIds, UUID.Zero, DeRezAction.TakeCopy, UUID.Zero);
// Check that object isn't copied until we crank the sogd handle.
SceneObjectPart retrievedPart = scene.GetSceneObjectPart(so.LocalId);
Assert.That(retrievedPart, Is.Not.Null);
Assert.That(retrievedPart.ParentGroup.IsDeleted, Is.False);
sogd.InventoryDeQueueAndDelete();
// Check that object is still there.
SceneObjectPart retrievedPart2 = scene.GetSceneObjectPart(so.LocalId);
Assert.That(retrievedPart2, Is.Not.Null);
Assert.That(client.ReceivedKills.Count, Is.EqualTo(0));
// Check that we have a copy in inventory
InventoryItemBase item
= UserInventoryHelpers.GetInventoryItem(scene.InventoryService, ua.PrincipalID, "Lost And Found/so1");
Assert.That(item, Is.Not.Null);
}
[Test]
public void TestTakeCopyWhenCopierIsOwnerWithoutPerms()
{
TestHelpers.InMethod();
// TestHelpers.EnableLogging();
IConfigSource config = new IniConfigSource();
config.AddConfig("Modules");
config.Configs["Modules"].Set("InventoryAccessModule", "BasicInventoryAccessModule");
TestScene scene = new SceneHelpers().SetupScene("s1", TestHelpers.ParseTail(0x99), 1000, 1000, config);
SceneHelpers.SetupSceneModules(scene, config, new PermissionsModule(), new BasicInventoryAccessModule());
UserAccount ua = UserAccountHelpers.CreateUserWithInventory(scene, TestHelpers.ParseTail(0x1));
TestClient client = (TestClient)SceneHelpers.AddScenePresence(scene, ua.PrincipalID).ControllingClient;
// Turn off the timer on the async sog deleter - we'll crank it by hand for this test.
AsyncSceneObjectGroupDeleter sogd = scene.SceneObjectGroupDeleter;
sogd.Enabled = false;
SceneObjectGroup so = SceneHelpers.AddSceneObject(scene, "so1", ua.PrincipalID);
uint soLocalId = so.LocalId;
so.RootPart.BaseMask = (uint)(OpenMetaverse.PermissionMask.All & ~OpenMetaverse.PermissionMask.Copy);
//so.RootPart.OwnerMask = (uint)(OpenMetaverse.PermissionMask.Copy & ~OpenMetaverse.PermissionMask.Copy);
List<uint> localIds = new List<uint>();
localIds.Add(so.LocalId);
// Specifying a UUID.Zero in this case will currently plop it in Lost and Found
scene.DeRezObjects(client, localIds, UUID.Zero, DeRezAction.TakeCopy, UUID.Zero);
// Check that object isn't copied until we crank the sogd handle.
SceneObjectPart retrievedPart = scene.GetSceneObjectPart(so.LocalId);
Assert.That(retrievedPart, Is.Not.Null);
Assert.That(retrievedPart.ParentGroup.IsDeleted, Is.False);
sogd.InventoryDeQueueAndDelete();
// Check that object is still there.
SceneObjectPart retrievedPart2 = scene.GetSceneObjectPart(so.LocalId);
Assert.That(retrievedPart2, Is.Not.Null);
Assert.That(client.ReceivedKills.Count, Is.EqualTo(0));
// Check that we do not have a copy in inventory
InventoryItemBase item
= UserInventoryHelpers.GetInventoryItem(scene.InventoryService, ua.PrincipalID, "Lost And Found/so1");
Assert.That(item, Is.Null);
}
[Test]
public void TestTakeCopyWhenCopierIsNotOwnerWithPerms()
{
TestHelpers.InMethod();
// TestHelpers.EnableLogging();
IConfigSource config = new IniConfigSource();
config.AddConfig("Modules");
config.Configs["Modules"].Set("InventoryAccessModule", "BasicInventoryAccessModule");
TestScene scene = new SceneHelpers().SetupScene("s1", TestHelpers.ParseTail(0x99), 1000, 1000, config);
SceneHelpers.SetupSceneModules(scene, config, new PermissionsModule(), new BasicInventoryAccessModule());
UserAccount ua = UserAccountHelpers.CreateUserWithInventory(scene, TestHelpers.ParseTail(0x1));
TestClient client = (TestClient)SceneHelpers.AddScenePresence(scene, ua.PrincipalID).ControllingClient;
// Turn off the timer on the async sog deleter - we'll crank it by hand for this test.
AsyncSceneObjectGroupDeleter sogd = scene.SceneObjectGroupDeleter;
sogd.Enabled = false;
SceneObjectGroup so = SceneHelpers.AddSceneObject(scene, "so1", TestHelpers.ParseTail(0x2));
uint soLocalId = so.LocalId;
// Base must allow transfer and copy
so.RootPart.BaseMask = (uint)(OpenMetaverse.PermissionMask.Copy | OpenMetaverse.PermissionMask.Transfer);
// Must be set so anyone can copy
so.RootPart.EveryoneMask = (uint)OpenMetaverse.PermissionMask.Copy;
List<uint> localIds = new List<uint>();
localIds.Add(so.LocalId);
// Specifying a UUID.Zero in this case will plop it in the Objects folder
scene.DeRezObjects(client, localIds, UUID.Zero, DeRezAction.TakeCopy, UUID.Zero);
// Check that object isn't copied until we crank the sogd handle.
SceneObjectPart retrievedPart = scene.GetSceneObjectPart(so.LocalId);
Assert.That(retrievedPart, Is.Not.Null);
Assert.That(retrievedPart.ParentGroup.IsDeleted, Is.False);
sogd.InventoryDeQueueAndDelete();
// Check that object is still there.
SceneObjectPart retrievedPart2 = scene.GetSceneObjectPart(so.LocalId);
Assert.That(retrievedPart2, Is.Not.Null);
Assert.That(client.ReceivedKills.Count, Is.EqualTo(0));
// Check that we have a copy in inventory
InventoryItemBase item
= UserInventoryHelpers.GetInventoryItem(scene.InventoryService, ua.PrincipalID, "Objects/so1");
Assert.That(item, Is.Not.Null);
}
[Test]
public void TestTakeCopyWhenCopierIsNotOwnerWithoutPerms()
{
TestHelpers.InMethod();
// TestHelpers.EnableLogging();
IConfigSource config = new IniConfigSource();
config.AddConfig("Modules");
config.Configs["Modules"].Set("InventoryAccessModule", "BasicInventoryAccessModule");
TestScene scene = new SceneHelpers().SetupScene("s1", TestHelpers.ParseTail(0x99), 1000, 1000, config);
SceneHelpers.SetupSceneModules(scene, config, new PermissionsModule(), new BasicInventoryAccessModule());
UserAccount ua = UserAccountHelpers.CreateUserWithInventory(scene, TestHelpers.ParseTail(0x1));
TestClient client = (TestClient)SceneHelpers.AddScenePresence(scene, ua.PrincipalID).ControllingClient;
// Turn off the timer on the async sog deleter - we'll crank it by hand for this test.
AsyncSceneObjectGroupDeleter sogd = scene.SceneObjectGroupDeleter;
sogd.Enabled = false;
SceneObjectGroup so = SceneHelpers.AddSceneObject(scene, "so1", TestHelpers.ParseTail(0x2));
uint soLocalId = so.LocalId;
{
// Check that object is not copied if copy base perms is missing.
// Should not allow copy if base does not have this.
so.RootPart.BaseMask = (uint)OpenMetaverse.PermissionMask.Transfer;
// Must be set so anyone can copy
so.RootPart.EveryoneMask = (uint)OpenMetaverse.PermissionMask.Copy;
// Check that object is not copied
List<uint> localIds = new List<uint>();
localIds.Add(so.LocalId);
// Specifying a UUID.Zero in this case will plop it in the Objects folder if we have perms
scene.DeRezObjects(client, localIds, UUID.Zero, DeRezAction.TakeCopy, UUID.Zero);
// Check that object isn't copied until we crank the sogd handle.
SceneObjectPart retrievedPart = scene.GetSceneObjectPart(so.LocalId);
Assert.That(retrievedPart, Is.Not.Null);
Assert.That(retrievedPart.ParentGroup.IsDeleted, Is.False);
sogd.InventoryDeQueueAndDelete();
// Check that object is still there.
SceneObjectPart retrievedPart2 = scene.GetSceneObjectPart(so.LocalId);
Assert.That(retrievedPart2, Is.Not.Null);
Assert.That(client.ReceivedKills.Count, Is.EqualTo(0));
// Check that we have a copy in inventory
InventoryItemBase item
= UserInventoryHelpers.GetInventoryItem(scene.InventoryService, ua.PrincipalID, "Objects/so1");
Assert.That(item, Is.Null);
}
{
// Check that object is not copied if copy trans perms is missing.
// Should not allow copy if base does not have this.
so.RootPart.BaseMask = (uint)OpenMetaverse.PermissionMask.Copy;
// Must be set so anyone can copy
so.RootPart.EveryoneMask = (uint)OpenMetaverse.PermissionMask.Copy;
// Check that object is not copied
List<uint> localIds = new List<uint>();
localIds.Add(so.LocalId);
// Specifying a UUID.Zero in this case will plop it in the Objects folder if we have perms
scene.DeRezObjects(client, localIds, UUID.Zero, DeRezAction.TakeCopy, UUID.Zero);
// Check that object isn't copied until we crank the sogd handle.
SceneObjectPart retrievedPart = scene.GetSceneObjectPart(so.LocalId);
Assert.That(retrievedPart, Is.Not.Null);
Assert.That(retrievedPart.ParentGroup.IsDeleted, Is.False);
sogd.InventoryDeQueueAndDelete();
// Check that object is still there.
SceneObjectPart retrievedPart2 = scene.GetSceneObjectPart(so.LocalId);
Assert.That(retrievedPart2, Is.Not.Null);
Assert.That(client.ReceivedKills.Count, Is.EqualTo(0));
// Check that we have a copy in inventory
InventoryItemBase item
= UserInventoryHelpers.GetInventoryItem(scene.InventoryService, ua.PrincipalID, "Objects/so1");
Assert.That(item, Is.Null);
}
{
// Check that object is not copied if everyone copy perms is missing.
// Should not allow copy if base does not have this.
so.RootPart.BaseMask = (uint)(OpenMetaverse.PermissionMask.Copy | OpenMetaverse.PermissionMask.Transfer);
// Make sure everyone perm does not allow copy
so.RootPart.EveryoneMask = (uint)(OpenMetaverse.PermissionMask.All & ~OpenMetaverse.PermissionMask.Copy);
// Check that object is not copied
List<uint> localIds = new List<uint>();
localIds.Add(so.LocalId);
// Specifying a UUID.Zero in this case will plop it in the Objects folder if we have perms
scene.DeRezObjects(client, localIds, UUID.Zero, DeRezAction.TakeCopy, UUID.Zero);
// Check that object isn't copied until we crank the sogd handle.
SceneObjectPart retrievedPart = scene.GetSceneObjectPart(so.LocalId);
Assert.That(retrievedPart, Is.Not.Null);
Assert.That(retrievedPart.ParentGroup.IsDeleted, Is.False);
sogd.InventoryDeQueueAndDelete();
// Check that object is still there.
SceneObjectPart retrievedPart2 = scene.GetSceneObjectPart(so.LocalId);
Assert.That(retrievedPart2, Is.Not.Null);
Assert.That(client.ReceivedKills.Count, Is.EqualTo(0));
// Check that we have a copy in inventory
InventoryItemBase item
= UserInventoryHelpers.GetInventoryItem(scene.InventoryService, ua.PrincipalID, "Objects/so1");
Assert.That(item, Is.Null);
}
}
}
}

View File

@ -185,7 +185,7 @@ namespace OpenSim.Tests.Common
public void addInventoryItem(InventoryItemBase item)
{
// InventoryFolderBase folder = m_folders[item.Folder];
InventoryFolderBase folder = m_folders[item.Folder];
// m_log.DebugFormat(
// "[MOCK INV DB]: Adding inventory item {0} {1} in {2} {3}", item.Name, item.ID, folder.Name, folder.ID);

View File

@ -46,9 +46,17 @@ namespace OpenSim.Tests.Common
public XInventoryItem[] GetItems(string[] fields, string[] vals)
{
// Console.WriteLine(
// "Requesting items, fields {0}, vals {1}", string.Join(", ", fields), string.Join(", ", vals));
List<XInventoryItem> origItems = Get<XInventoryItem>(fields, vals, m_allItems.Values.ToList());
return origItems.Select(i => i.Clone()).ToArray();
XInventoryItem[] items = origItems.Select(i => i.Clone()).ToArray();
// Console.WriteLine("Found {0} items", items.Length);
// Array.ForEach(items, i => Console.WriteLine("Found item {0} {1}", i.inventoryName, i.inventoryID));
return items;
}
public XInventoryFolder[] GetFolders(string[] fields, string[] vals)
@ -59,7 +67,12 @@ namespace OpenSim.Tests.Common
List<XInventoryFolder> origFolders
= Get<XInventoryFolder>(fields, vals, m_allFolders.Values.ToList());
return origFolders.Select(f => f.Clone()).ToArray();
XInventoryFolder[] folders = origFolders.Select(f => f.Clone()).ToArray();
// Console.WriteLine("Found {0} folders", folders.Length);
// Array.ForEach(folders, f => Console.WriteLine("Found folder {0} {1}", f.folderName, f.folderID));
return folders;
}
public bool StoreFolder(XInventoryFolder folder)
@ -75,7 +88,9 @@ namespace OpenSim.Tests.Common
{
m_allItems[item.inventoryID] = item.Clone();
// Console.WriteLine("Added item {0} {1}, creator {2}, owner {3}", item.inventoryName, item.inventoryID, item.creatorID, item.avatarID);
// Console.WriteLine(
// "Added item {0} {1}, folder {2}, creator {3}, owner {4}",
// item.inventoryName, item.inventoryID, item.parentFolderID, item.creatorID, item.avatarID);
return true;
}