HGInventoryAccessModule.cs 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574
  1. /*
  2. * Copyright (c) Contributors, http://opensimulator.org/
  3. * See CONTRIBUTORS.TXT for a full list of copyright holders.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. * * Redistributions of source code must retain the above copyright
  8. * notice, this list of conditions and the following disclaimer.
  9. * * Redistributions in binary form must reproduce the above copyright
  10. * notice, this list of conditions and the following disclaimer in the
  11. * documentation and/or other materials provided with the distribution.
  12. * * Neither the name of the OpenSimulator Project nor the
  13. * names of its contributors may be used to endorse or promote products
  14. * derived from this software without specific prior written permission.
  15. *
  16. * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
  17. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  18. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  19. * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
  20. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  21. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  22. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  23. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  24. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  25. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26. */
  27. using System;
  28. using System.Collections.Generic;
  29. using System.Reflection;
  30. using OpenSim.Framework;
  31. using OpenSim.Framework.Client;
  32. using OpenSim.Region.Framework.Interfaces;
  33. using OpenSim.Region.Framework.Scenes;
  34. using OpenSim.Services.Connectors.Hypergrid;
  35. using OpenSim.Services.Interfaces;
  36. using OpenSim.Server.Base;
  37. using GridRegion = OpenSim.Services.Interfaces.GridRegion;
  38. using OpenMetaverse;
  39. using log4net;
  40. using Nini.Config;
  41. using Mono.Addins;
  42. namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
  43. {
  44. [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "HGInventoryAccessModule")]
  45. public class HGInventoryAccessModule : BasicInventoryAccessModule, INonSharedRegionModule, IInventoryAccessModule
  46. {
  47. private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
  48. private static HGAssetMapper m_assMapper;
  49. public static HGAssetMapper AssetMapper
  50. {
  51. get { return m_assMapper; }
  52. }
  53. private string m_HomeURI;
  54. private bool m_OutboundPermission;
  55. private string m_ThisGatekeeper;
  56. private bool m_RestrictInventoryAccessAbroad;
  57. private bool m_bypassPermissions = true;
  58. // This simple check makes it possible to support grids in which all the simulators
  59. // share all central services of the Robust server EXCEPT assets. In other words,
  60. // grids where the simulators' assets are kept in one DB and the users' inventory assets
  61. // are kept on another. When users rez items from inventory or take objects from world,
  62. // an HG-like asset copy takes place between the 2 servers, the world asset server and
  63. // the user's asset server.
  64. private bool m_CheckSeparateAssets = false;
  65. private string m_LocalAssetsURL = string.Empty;
  66. // private bool m_Initialized = false;
  67. #region INonSharedRegionModule
  68. public override string Name
  69. {
  70. get { return "HGInventoryAccessModule"; }
  71. }
  72. public override void Initialise(IConfigSource source)
  73. {
  74. IConfig moduleConfig = source.Configs["Modules"];
  75. if (moduleConfig != null)
  76. {
  77. string name = moduleConfig.GetString("InventoryAccessModule", "");
  78. if (name == Name)
  79. {
  80. m_Enabled = true;
  81. InitialiseCommon(source);
  82. m_log.InfoFormat("[HG INVENTORY ACCESS MODULE]: {0} enabled.", Name);
  83. IConfig thisModuleConfig = source.Configs["HGInventoryAccessModule"];
  84. if (thisModuleConfig != null)
  85. {
  86. m_HomeURI = Util.GetConfigVarFromSections<string>(source, "HomeURI",
  87. new string[] { "Startup", "Hypergrid", "HGInventoryAccessModule" }, String.Empty);
  88. m_ThisGatekeeper = Util.GetConfigVarFromSections<string>(source, "GatekeeperURI",
  89. new string[] { "Startup", "Hypergrid", "HGInventoryAccessModule" }, String.Empty);
  90. // Legacy. Renove soon!
  91. m_ThisGatekeeper = thisModuleConfig.GetString("Gatekeeper", m_ThisGatekeeper);
  92. m_OutboundPermission = thisModuleConfig.GetBoolean("OutboundPermission", true);
  93. m_RestrictInventoryAccessAbroad = thisModuleConfig.GetBoolean("RestrictInventoryAccessAbroad", true);
  94. m_CheckSeparateAssets = thisModuleConfig.GetBoolean("CheckSeparateAssets", false);
  95. m_LocalAssetsURL = thisModuleConfig.GetString("RegionHGAssetServerURI", string.Empty);
  96. m_LocalAssetsURL = m_LocalAssetsURL.Trim(new char[] { '/' });
  97. }
  98. else
  99. m_log.Warn("[HG INVENTORY ACCESS MODULE]: HGInventoryAccessModule configs not found. ProfileServerURI not set!");
  100. m_bypassPermissions = !Util.GetConfigVarFromSections<bool>(source, "serverside_object_permissions",
  101. new string[] { "Startup", "Permissions" }, true);
  102. }
  103. }
  104. }
  105. public override void AddRegion(Scene scene)
  106. {
  107. if (!m_Enabled)
  108. return;
  109. base.AddRegion(scene);
  110. m_assMapper = new HGAssetMapper(scene, m_HomeURI);
  111. scene.EventManager.OnNewInventoryItemUploadComplete += PostInventoryAsset;
  112. scene.EventManager.OnTeleportStart += TeleportStart;
  113. scene.EventManager.OnTeleportFail += TeleportFail;
  114. // We're fgoing to enforce some stricter permissions if Outbound is false
  115. scene.Permissions.OnTakeObject += CanTakeObject;
  116. scene.Permissions.OnTakeCopyObject += CanTakeObject;
  117. scene.Permissions.OnTransferUserInventory += OnTransferUserInventory;
  118. }
  119. #endregion
  120. #region Event handlers
  121. protected override void OnNewClient(IClientAPI client)
  122. {
  123. base.OnNewClient(client);
  124. client.OnCompleteMovementToRegion += new Action<IClientAPI, bool>(OnCompleteMovementToRegion);
  125. }
  126. protected void OnCompleteMovementToRegion(IClientAPI client, bool arg2)
  127. {
  128. //m_log.DebugFormat("[HG INVENTORY ACCESS MODULE]: OnCompleteMovementToRegion of user {0}", client.Name);
  129. object sp = null;
  130. if (client.Scene.TryGetScenePresence(client.AgentId, out sp))
  131. {
  132. if (sp is ScenePresence)
  133. {
  134. AgentCircuitData aCircuit = ((ScenePresence)sp).Scene.AuthenticateHandler.GetAgentCircuitData(client.AgentId);
  135. if (aCircuit != null && (aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaHGLogin) != 0)
  136. {
  137. if (m_RestrictInventoryAccessAbroad)
  138. {
  139. IUserManagement uMan = m_Scene.RequestModuleInterface<IUserManagement>();
  140. if (uMan.IsLocalGridUser(client.AgentId))
  141. ProcessInventoryForComingHome(client);
  142. else
  143. ProcessInventoryForArriving(client);
  144. }
  145. }
  146. }
  147. }
  148. }
  149. protected void TeleportStart(IClientAPI client, GridRegion destination, GridRegion finalDestination, uint teleportFlags, bool gridLogout)
  150. {
  151. if (gridLogout && m_RestrictInventoryAccessAbroad)
  152. {
  153. IUserManagement uMan = m_Scene.RequestModuleInterface<IUserManagement>();
  154. if (uMan != null && uMan.IsLocalGridUser(client.AgentId))
  155. {
  156. // local grid user
  157. ProcessInventoryForHypergriding(client);
  158. }
  159. else
  160. {
  161. // Foreigner
  162. ProcessInventoryForLeaving(client);
  163. }
  164. }
  165. }
  166. protected void TeleportFail(IClientAPI client, bool gridLogout)
  167. {
  168. if (gridLogout && m_RestrictInventoryAccessAbroad)
  169. {
  170. IUserManagement uMan = m_Scene.RequestModuleInterface<IUserManagement>();
  171. if (uMan.IsLocalGridUser(client.AgentId))
  172. {
  173. ProcessInventoryForComingHome(client);
  174. }
  175. else
  176. {
  177. ProcessInventoryForArriving(client);
  178. }
  179. }
  180. }
  181. private void PostInventoryAsset(InventoryItemBase item, int userlevel)
  182. {
  183. InventoryFolderBase f = m_Scene.InventoryService.GetFolderForType(item.Owner, FolderType.Trash);
  184. if (f == null || (f != null && item.Folder != f.ID))
  185. PostInventoryAsset(item.Owner, (AssetType)item.AssetType, item.AssetID, item.Name, userlevel);
  186. }
  187. private void PostInventoryAsset(UUID avatarID, AssetType type, UUID assetID, string name, int userlevel)
  188. {
  189. if (type == AssetType.Link)
  190. return;
  191. string userAssetServer = string.Empty;
  192. if (IsForeignUser(avatarID, out userAssetServer) && userAssetServer != string.Empty && m_OutboundPermission)
  193. {
  194. m_assMapper.Post(assetID, avatarID, userAssetServer);
  195. }
  196. }
  197. #endregion
  198. #region Overrides of Basic Inventory Access methods
  199. protected override string GenerateLandmark(ScenePresence presence, out string prefix, out string suffix)
  200. {
  201. if (UserManagementModule != null && !UserManagementModule.IsLocalGridUser(presence.UUID))
  202. prefix = "HG ";
  203. else
  204. prefix = string.Empty;
  205. suffix = " @ " + m_ThisGatekeeper;
  206. Vector3 pos = presence.AbsolutePosition;
  207. return String.Format("Landmark version 2\nregion_id {0}\nlocal_pos {1} {2} {3}\nregion_handle {4}\ngatekeeper {5}\n",
  208. presence.Scene.RegionInfo.RegionID,
  209. pos.X, pos.Y, pos.Z,
  210. presence.RegionHandle,
  211. m_ThisGatekeeper);
  212. }
  213. ///
  214. /// CapsUpdateInventoryItemAsset
  215. ///
  216. public override UUID CapsUpdateInventoryItemAsset(IClientAPI remoteClient, UUID itemID, byte[] data)
  217. {
  218. UUID newAssetID = base.CapsUpdateInventoryItemAsset(remoteClient, itemID, data);
  219. // We need to construct this here to satisfy the calling convention.
  220. // Better this in two places than five formal params in all others.
  221. InventoryItemBase item = new InventoryItemBase();
  222. item.Owner = remoteClient.AgentId;
  223. item.AssetType = (int)AssetType.Unknown;
  224. item.AssetID = newAssetID;
  225. item.Name = String.Empty;
  226. PostInventoryAsset(item, 0);
  227. return newAssetID;
  228. }
  229. ///
  230. /// UpdateInventoryItemAsset
  231. ///
  232. public override bool UpdateInventoryItemAsset(UUID ownerID, InventoryItemBase item, AssetBase asset)
  233. {
  234. if (base.UpdateInventoryItemAsset(ownerID, item, asset))
  235. {
  236. PostInventoryAsset(item, 0);
  237. return true;
  238. }
  239. return false;
  240. }
  241. ///
  242. /// Used in DeleteToInventory
  243. ///
  244. protected override void ExportAsset(UUID agentID, UUID assetID)
  245. {
  246. if (!assetID.Equals(UUID.Zero))
  247. {
  248. InventoryItemBase item = new InventoryItemBase();
  249. item.Owner = agentID;
  250. item.AssetType = (int)AssetType.Unknown;
  251. item.AssetID = assetID;
  252. item.Name = String.Empty;
  253. PostInventoryAsset(item, 0);
  254. }
  255. else
  256. {
  257. m_log.Debug("[HGScene]: Scene.Inventory did not create asset");
  258. }
  259. }
  260. ///
  261. /// RezObject
  262. ///
  263. // compatibility do not use
  264. public override SceneObjectGroup RezObject(
  265. IClientAPI remoteClient, UUID itemID, Vector3 RayEnd, Vector3 RayStart,
  266. UUID RayTargetID, byte BypassRayCast, bool RayEndIsIntersection,
  267. bool RezSelected, bool RemoveItem, UUID fromTaskID, bool attachment)
  268. {
  269. return RezObject(remoteClient, itemID, UUID.Zero, RayEnd, RayStart,
  270. RayTargetID, BypassRayCast, RayEndIsIntersection,
  271. RezSelected, RemoveItem, fromTaskID, attachment);
  272. }
  273. public override SceneObjectGroup RezObject(IClientAPI remoteClient, UUID itemID,
  274. UUID groupID, Vector3 RayEnd, Vector3 RayStart,
  275. UUID RayTargetID, byte BypassRayCast, bool RayEndIsIntersection,
  276. bool RezSelected, bool RemoveItem, UUID fromTaskID, bool attachment)
  277. {
  278. //m_log.DebugFormat("[HGScene]: RezObject itemID={0} fromTaskID={1}", itemID, fromTaskID);
  279. //if (fromTaskID.Equals(UUID.Zero))
  280. //{
  281. InventoryItemBase item = m_Scene.InventoryService.GetItem(remoteClient.AgentId, itemID);
  282. //if (item == null)
  283. //{ // Fetch the item
  284. // item = new InventoryItemBase();
  285. // item.Owner = remoteClient.AgentId;
  286. // item.ID = itemID;
  287. // item = m_assMapper.Get(item, userInfo.RootFolder.ID, userInfo);
  288. //}
  289. string userAssetServer = string.Empty;
  290. if (item != null && IsForeignUser(remoteClient.AgentId, out userAssetServer))
  291. {
  292. m_assMapper.Get(item.AssetID, remoteClient.AgentId, userAssetServer);
  293. }
  294. //}
  295. // OK, we're done fetching. Pass it up to the default RezObject
  296. SceneObjectGroup sog = base.RezObject(remoteClient, itemID, groupID, RayEnd, RayStart, RayTargetID, BypassRayCast, RayEndIsIntersection,
  297. RezSelected, RemoveItem, fromTaskID, attachment);
  298. return sog;
  299. }
  300. public override void TransferInventoryAssets(InventoryItemBase item, UUID sender, UUID receiver)
  301. {
  302. string senderAssetServer = string.Empty;
  303. string receiverAssetServer = string.Empty;
  304. bool isForeignSender, isForeignReceiver;
  305. isForeignSender = IsForeignUser(sender, out senderAssetServer);
  306. isForeignReceiver = IsForeignUser(receiver, out receiverAssetServer);
  307. // They're both local. Nothing to do.
  308. if (!isForeignSender && !isForeignReceiver)
  309. return;
  310. // At least one of them is foreign.
  311. // If both users have the same asset server, no need to transfer the asset
  312. if (senderAssetServer.Equals(receiverAssetServer))
  313. {
  314. m_log.DebugFormat("[HGScene]: Asset transfer between foreign users, but they have the same server. No transfer.");
  315. return;
  316. }
  317. if (isForeignSender && senderAssetServer != string.Empty)
  318. m_assMapper.Get(item.AssetID, sender, senderAssetServer);
  319. if (isForeignReceiver && receiverAssetServer != string.Empty && m_OutboundPermission)
  320. m_assMapper.Post(item.AssetID, receiver, receiverAssetServer);
  321. }
  322. public override bool IsForeignUser(UUID userID, out string assetServerURL)
  323. {
  324. assetServerURL = string.Empty;
  325. if (UserManagementModule != null)
  326. {
  327. if (!m_CheckSeparateAssets)
  328. {
  329. if (!UserManagementModule.IsLocalGridUser(userID))
  330. { // foreign
  331. ScenePresence sp = null;
  332. if (m_Scene.TryGetScenePresence(userID, out sp))
  333. {
  334. AgentCircuitData aCircuit = m_Scene.AuthenticateHandler.GetAgentCircuitData(sp.ControllingClient.CircuitCode);
  335. if (aCircuit != null && aCircuit.ServiceURLs != null && aCircuit.ServiceURLs.ContainsKey("AssetServerURI"))
  336. {
  337. assetServerURL = aCircuit.ServiceURLs["AssetServerURI"].ToString();
  338. assetServerURL = assetServerURL.Trim(new char[] { '/' });
  339. }
  340. }
  341. else
  342. {
  343. assetServerURL = UserManagementModule.GetUserServerURL(userID, "AssetServerURI");
  344. assetServerURL = assetServerURL.Trim(new char[] { '/' });
  345. }
  346. return true;
  347. }
  348. }
  349. else
  350. {
  351. if (IsLocalInventoryAssetsUser(userID, out assetServerURL))
  352. {
  353. m_log.DebugFormat("[HGScene]: user {0} has local assets {1}", userID, assetServerURL);
  354. return false;
  355. }
  356. else
  357. {
  358. m_log.DebugFormat("[HGScene]: user {0} has foreign assets {1}", userID, assetServerURL);
  359. return true;
  360. }
  361. }
  362. }
  363. return false;
  364. }
  365. private bool IsLocalInventoryAssetsUser(UUID uuid, out string assetsURL)
  366. {
  367. assetsURL = UserManagementModule.GetUserServerURL(uuid, "AssetServerURI");
  368. if (assetsURL == string.Empty)
  369. {
  370. AgentCircuitData agent = m_Scene.AuthenticateHandler.GetAgentCircuitData(uuid);
  371. if (agent != null)
  372. {
  373. assetsURL = agent.ServiceURLs["AssetServerURI"].ToString();
  374. assetsURL = assetsURL.Trim(new char[] { '/' });
  375. }
  376. }
  377. return m_LocalAssetsURL.Equals(assetsURL);
  378. }
  379. protected override InventoryItemBase GetItem(UUID agentID, UUID itemID)
  380. {
  381. InventoryItemBase item = base.GetItem(agentID, itemID);
  382. if (item == null)
  383. return null;
  384. string userAssetServer = string.Empty;
  385. if (IsForeignUser(agentID, out userAssetServer))
  386. m_assMapper.Get(item.AssetID, agentID, userAssetServer);
  387. return item;
  388. }
  389. #endregion
  390. #region Inventory manipulation upon arriving/leaving
  391. //
  392. // These 2 are for local and foreign users coming back, respectively
  393. //
  394. private void ProcessInventoryForComingHome(IClientAPI client)
  395. {
  396. m_log.DebugFormat("[HG INVENTORY ACCESS MODULE]: Restoring root folder for local user {0}", client.Name);
  397. if (client is IClientCore)
  398. {
  399. IClientCore core = (IClientCore)client;
  400. IClientInventory inv;
  401. if (core.TryGet<IClientInventory>(out inv))
  402. {
  403. InventoryFolderBase root = m_Scene.InventoryService.GetRootFolder(client.AgentId);
  404. InventoryCollection content = m_Scene.InventoryService.GetFolderContent(client.AgentId, root.ID);
  405. List<InventoryFolderBase> keep = new List<InventoryFolderBase>();
  406. foreach (InventoryFolderBase f in content.Folders)
  407. {
  408. if (f.Name != "My Suitcase" && f.Name != "Current Outfit")
  409. keep.Add(f);
  410. }
  411. inv.SendBulkUpdateInventory(keep.ToArray(), content.Items.ToArray());
  412. }
  413. }
  414. }
  415. private void ProcessInventoryForArriving(IClientAPI client)
  416. {
  417. // No-op for now, but we may need to do something for freign users inventory
  418. }
  419. //
  420. // These 2 are for local and foreign users going away respectively
  421. //
  422. private void ProcessInventoryForHypergriding(IClientAPI client)
  423. {
  424. if (client is IClientCore)
  425. {
  426. IClientCore core = (IClientCore)client;
  427. IClientInventory inv;
  428. if (core.TryGet<IClientInventory>(out inv))
  429. {
  430. InventoryFolderBase root = m_Scene.InventoryService.GetRootFolder(client.AgentId);
  431. if (root != null)
  432. {
  433. m_log.DebugFormat("[HG INVENTORY ACCESS MODULE]: Changing root inventory for user {0}", client.Name);
  434. InventoryCollection content = m_Scene.InventoryService.GetFolderContent(client.AgentId, root.ID);
  435. List<InventoryFolderBase> keep = new List<InventoryFolderBase>();
  436. foreach (InventoryFolderBase f in content.Folders)
  437. {
  438. if (f.Name != "My Suitcase" && f.Name != "Current Outfit")
  439. {
  440. f.Name = f.Name + " (Unavailable)";
  441. keep.Add(f);
  442. }
  443. }
  444. // items directly under the root folder
  445. foreach (InventoryItemBase it in content.Items)
  446. it.Name = it.Name + " (Unavailable)"; ;
  447. // Send the new names
  448. inv.SendBulkUpdateInventory(keep.ToArray(), content.Items.ToArray());
  449. }
  450. }
  451. }
  452. }
  453. private void ProcessInventoryForLeaving(IClientAPI client)
  454. {
  455. // No-op for now
  456. }
  457. #endregion
  458. #region Permissions
  459. private bool CanTakeObject(SceneObjectGroup sog, ScenePresence sp)
  460. {
  461. if (m_bypassPermissions) return true;
  462. if(sp == null || sog == null)
  463. return false;
  464. if (!m_OutboundPermission && !UserManagementModule.IsLocalGridUser(sp.UUID))
  465. {
  466. if (sog.OwnerID == sp.UUID)
  467. return true;
  468. return false;
  469. }
  470. return true;
  471. }
  472. private bool OnTransferUserInventory(UUID itemID, UUID userID, UUID recipientID)
  473. {
  474. if (m_bypassPermissions) return true;
  475. if (!m_OutboundPermission && !UserManagementModule.IsLocalGridUser(recipientID))
  476. return false;
  477. return true;
  478. }
  479. #endregion
  480. }
  481. }