Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

10 роки тому
8 роки тому
8 роки тому
9 роки тому
8 роки тому
9 роки тому
8 роки тому
9 роки тому
8 роки тому
9 роки тому
8 роки тому
9 роки тому
8 роки тому
8 роки тому
8 роки тому
9 роки тому
8 роки тому
9 роки тому
8 роки тому
9 роки тому
10 роки тому
9 роки тому
10 роки тому
9 роки тому
10 роки тому
9 роки тому
10 роки тому
9 роки тому
10 роки тому
10 роки тому
8 роки тому
10 роки тому
10 роки тому
10 роки тому
9 роки тому
9 роки тому
10 роки тому
9 роки тому
10 роки тому
9 роки тому
10 роки тому
10 роки тому
9 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
9 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
9 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
9 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
9 роки тому
9 роки тому
9 роки тому
9 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
8 роки тому
10 роки тому
8 роки тому
10 роки тому
10 роки тому
9 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
8 роки тому
9 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
8 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
9 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
9 роки тому
10 роки тому
10 роки тому
10 роки тому
8 роки тому
8 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
8 роки тому
10 роки тому
8 роки тому
8 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
9 роки тому
9 роки тому
9 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
9 роки тому
10 роки тому
9 роки тому
10 роки тому
9 роки тому
10 роки тому
10 роки тому
10 роки тому
9 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
9 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
9 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
9 роки тому
10 роки тому
10 роки тому
10 роки тому
8 роки тому
9 роки тому
9 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
8 роки тому
9 роки тому
9 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
9 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
9 роки тому
10 роки тому
10 роки тому
10 роки тому
9 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
9 роки тому
9 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
8 роки тому
8 роки тому
8 роки тому
9 роки тому
10 роки тому
10 роки тому
10 роки тому
9 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
8 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
9 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863
  1. <?php
  2. /**
  3. * @copyright Copyright (c) 2016, ownCloud, Inc.
  4. *
  5. * @author Arthur Schiwon <blizzz@arthur-schiwon.de>
  6. * @author Bart Visscher <bartv@thisnet.nl>
  7. * @author Bernhard Reiter <ockham@raz.or.at>
  8. * @author Björn Schießle <bjoern@schiessle.org>
  9. * @author Christopher Schäpers <kondou@ts.unde.re>
  10. * @author Christoph Wurst <christoph@owncloud.com>
  11. * @author Daniel Hansson <enoch85@gmail.com>
  12. * @author Joas Schilling <coding@schilljs.com>
  13. * @author Jörn Friedrich Dreyer <jfd@butonic.de>
  14. * @author Lukas Reschke <lukas@statuscode.ch>
  15. * @author Michael Kuhn <suraia@ikkoku.de>
  16. * @author Morris Jobke <hey@morrisjobke.de>
  17. * @author Robin Appelman <robin@icewind.nl>
  18. * @author Robin McCorkell <robin@mccorkell.me.uk>
  19. * @author Roeland Jago Douma <roeland@famdouma.nl>
  20. * @author Sebastian Döll <sebastian.doell@libasys.de>
  21. * @author Stefan Weil <sw@weilnetz.de>
  22. * @author Thomas Müller <thomas.mueller@tmit.eu>
  23. * @author Torben Dannhauer <torben@dannhauer.de>
  24. * @author Vincent Petry <pvince81@owncloud.com>
  25. * @author Volkan Gezer <volkangezer@gmail.com>
  26. *
  27. * @license AGPL-3.0
  28. *
  29. * This code is free software: you can redistribute it and/or modify
  30. * it under the terms of the GNU Affero General Public License, version 3,
  31. * as published by the Free Software Foundation.
  32. *
  33. * This program is distributed in the hope that it will be useful,
  34. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  35. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  36. * GNU Affero General Public License for more details.
  37. *
  38. * You should have received a copy of the GNU Affero General Public License, version 3,
  39. * along with this program. If not, see <http://www.gnu.org/licenses/>
  40. *
  41. */
  42. namespace OC\Share;
  43. use OC\Files\Filesystem;
  44. use OCA\FederatedFileSharing\DiscoveryManager;
  45. use OCP\DB\QueryBuilder\IQueryBuilder;
  46. use OCP\ILogger;
  47. use OCP\IUserManager;
  48. use OCP\IUserSession;
  49. use OCP\IDBConnection;
  50. use OCP\IConfig;
  51. /**
  52. * This class provides the ability for apps to share their content between users.
  53. * Apps must create a backend class that implements OCP\Share_Backend and register it with this class.
  54. *
  55. * It provides the following hooks:
  56. * - post_shared
  57. */
  58. class Share extends Constants {
  59. /** CRUDS permissions (Create, Read, Update, Delete, Share) using a bitmask
  60. * Construct permissions for share() and setPermissions with Or (|) e.g.
  61. * Give user read and update permissions: PERMISSION_READ | PERMISSION_UPDATE
  62. *
  63. * Check if permission is granted with And (&) e.g. Check if delete is
  64. * granted: if ($permissions & PERMISSION_DELETE)
  65. *
  66. * Remove permissions with And (&) and Not (~) e.g. Remove the update
  67. * permission: $permissions &= ~PERMISSION_UPDATE
  68. *
  69. * Apps are required to handle permissions on their own, this class only
  70. * stores and manages the permissions of shares
  71. * @see lib/public/constants.php
  72. */
  73. /**
  74. * Register a sharing backend class that implements OCP\Share_Backend for an item type
  75. * @param string $itemType Item type
  76. * @param string $class Backend class
  77. * @param string $collectionOf (optional) Depends on item type
  78. * @param array $supportedFileExtensions (optional) List of supported file extensions if this item type depends on files
  79. * @return boolean true if backend is registered or false if error
  80. */
  81. public static function registerBackend($itemType, $class, $collectionOf = null, $supportedFileExtensions = null) {
  82. if (self::isEnabled()) {
  83. if (!isset(self::$backendTypes[$itemType])) {
  84. self::$backendTypes[$itemType] = array(
  85. 'class' => $class,
  86. 'collectionOf' => $collectionOf,
  87. 'supportedFileExtensions' => $supportedFileExtensions
  88. );
  89. if(count(self::$backendTypes) === 1) {
  90. \OC_Util::addScript('core', 'shareconfigmodel');
  91. \OC_Util::addScript('core', 'shareitemmodel');
  92. \OC_Util::addScript('core', 'sharedialogresharerinfoview');
  93. \OC_Util::addScript('core', 'sharedialoglinkshareview');
  94. \OC_Util::addScript('core', 'sharedialogexpirationview');
  95. \OC_Util::addScript('core', 'sharedialogshareelistview');
  96. \OC_Util::addScript('core', 'sharedialogview');
  97. \OC_Util::addScript('core', 'share');
  98. \OC_Util::addStyle('core', 'share');
  99. }
  100. return true;
  101. }
  102. \OCP\Util::writeLog('OCP\Share',
  103. 'Sharing backend '.$class.' not registered, '.self::$backendTypes[$itemType]['class']
  104. .' is already registered for '.$itemType,
  105. \OCP\Util::WARN);
  106. }
  107. return false;
  108. }
  109. /**
  110. * Check if the Share API is enabled
  111. * @return boolean true if enabled or false
  112. *
  113. * The Share API is enabled by default if not configured
  114. */
  115. public static function isEnabled() {
  116. if (\OC::$server->getAppConfig()->getValue('core', 'shareapi_enabled', 'yes') == 'yes') {
  117. return true;
  118. }
  119. return false;
  120. }
  121. /**
  122. * Find which users can access a shared item
  123. * @param string $path to the file
  124. * @param string $ownerUser owner of the file
  125. * @param IUserManager $userManager
  126. * @param ILogger $logger
  127. * @param boolean $includeOwner include owner to the list of users with access to the file
  128. * @param boolean $returnUserPaths Return an array with the user => path map
  129. * @param boolean $recursive take all parent folders into account (default true)
  130. * @return array
  131. * @note $path needs to be relative to user data dir, e.g. 'file.txt'
  132. * not '/admin/data/file.txt'
  133. * @throws \OC\User\NoUserException
  134. */
  135. public static function getUsersSharingFile($path,
  136. $ownerUser,
  137. IUserManager $userManager,
  138. ILogger $logger,
  139. $includeOwner = false,
  140. $returnUserPaths = false,
  141. $recursive = true) {
  142. $userObject = $userManager->get($ownerUser);
  143. if (is_null($userObject)) {
  144. $logger->error(
  145. sprintf(
  146. 'Backends provided no user object for %s',
  147. $ownerUser
  148. ),
  149. [
  150. 'app' => 'files',
  151. ]
  152. );
  153. throw new \OC\User\NoUserException('Backends provided no user object');
  154. }
  155. $ownerUser = $userObject->getUID();
  156. Filesystem::initMountPoints($ownerUser);
  157. $shares = $sharePaths = $fileTargets = array();
  158. $publicShare = false;
  159. $remoteShare = false;
  160. $source = -1;
  161. $cache = $mountPath = false;
  162. $view = new \OC\Files\View('/' . $ownerUser . '/files');
  163. $meta = $view->getFileInfo($path);
  164. if ($meta) {
  165. $path = substr($meta->getPath(), strlen('/' . $ownerUser . '/files'));
  166. } else {
  167. // if the file doesn't exists yet we start with the parent folder
  168. $meta = $view->getFileInfo(dirname($path));
  169. }
  170. if($meta !== false) {
  171. $source = $meta['fileid'];
  172. $cache = new \OC\Files\Cache\Cache($meta['storage']);
  173. $mountPath = $meta->getMountPoint()->getMountPoint();
  174. if ($mountPath !== false) {
  175. $mountPath = substr($mountPath, strlen('/' . $ownerUser . '/files'));
  176. }
  177. }
  178. $paths = [];
  179. while ($source !== -1) {
  180. // Fetch all shares with another user
  181. if (!$returnUserPaths) {
  182. $query = \OC_DB::prepare(
  183. 'SELECT `share_with`, `file_source`, `file_target`
  184. FROM
  185. `*PREFIX*share`
  186. WHERE
  187. `item_source` = ? AND `share_type` = ? AND `item_type` IN (\'file\', \'folder\')'
  188. );
  189. $result = $query->execute(array($source, self::SHARE_TYPE_USER));
  190. } else {
  191. $query = \OC_DB::prepare(
  192. 'SELECT `share_with`, `file_source`, `file_target`
  193. FROM
  194. `*PREFIX*share`
  195. WHERE
  196. `item_source` = ? AND `share_type` IN (?, ?) AND `item_type` IN (\'file\', \'folder\')'
  197. );
  198. $result = $query->execute(array($source, self::SHARE_TYPE_USER, self::$shareTypeGroupUserUnique));
  199. }
  200. if (\OCP\DB::isError($result)) {
  201. \OCP\Util::writeLog('OCP\Share', \OC_DB::getErrorMessage(), \OCP\Util::ERROR);
  202. } else {
  203. while ($row = $result->fetchRow()) {
  204. $shares[] = $row['share_with'];
  205. if ($returnUserPaths) {
  206. $fileTargets[(int) $row['file_source']][$row['share_with']] = $row;
  207. }
  208. }
  209. }
  210. // We also need to take group shares into account
  211. $query = \OC_DB::prepare(
  212. 'SELECT `share_with`, `file_source`, `file_target`
  213. FROM
  214. `*PREFIX*share`
  215. WHERE
  216. `item_source` = ? AND `share_type` = ? AND `item_type` IN (\'file\', \'folder\')'
  217. );
  218. $result = $query->execute(array($source, self::SHARE_TYPE_GROUP));
  219. if (\OCP\DB::isError($result)) {
  220. \OCP\Util::writeLog('OCP\Share', \OC_DB::getErrorMessage(), \OCP\Util::ERROR);
  221. } else {
  222. while ($row = $result->fetchRow()) {
  223. $usersInGroup = \OC_Group::usersInGroup($row['share_with']);
  224. $shares = array_merge($shares, $usersInGroup);
  225. if ($returnUserPaths) {
  226. foreach ($usersInGroup as $user) {
  227. if (!isset($fileTargets[(int) $row['file_source']][$user])) {
  228. // When the user already has an entry for this file source
  229. // the file is either shared directly with him as well, or
  230. // he has an exception entry (because of naming conflict).
  231. $fileTargets[(int) $row['file_source']][$user] = $row;
  232. }
  233. }
  234. }
  235. }
  236. }
  237. //check for public link shares
  238. if (!$publicShare) {
  239. $query = \OC_DB::prepare('
  240. SELECT `share_with`
  241. FROM `*PREFIX*share`
  242. WHERE `item_source` = ? AND `share_type` = ? AND `item_type` IN (\'file\', \'folder\')', 1
  243. );
  244. $result = $query->execute(array($source, self::SHARE_TYPE_LINK));
  245. if (\OCP\DB::isError($result)) {
  246. \OCP\Util::writeLog('OCP\Share', \OC_DB::getErrorMessage(), \OCP\Util::ERROR);
  247. } else {
  248. if ($result->fetchRow()) {
  249. $publicShare = true;
  250. }
  251. }
  252. }
  253. //check for remote share
  254. if (!$remoteShare) {
  255. $query = \OC_DB::prepare('
  256. SELECT `share_with`
  257. FROM `*PREFIX*share`
  258. WHERE `item_source` = ? AND `share_type` = ? AND `item_type` IN (\'file\', \'folder\')', 1
  259. );
  260. $result = $query->execute(array($source, self::SHARE_TYPE_REMOTE));
  261. if (\OCP\DB::isError($result)) {
  262. \OCP\Util::writeLog('OCP\Share', \OC_DB::getErrorMessage(), \OCP\Util::ERROR);
  263. } else {
  264. if ($result->fetchRow()) {
  265. $remoteShare = true;
  266. }
  267. }
  268. }
  269. // let's get the parent for the next round
  270. $meta = $cache->get((int)$source);
  271. if ($recursive === true && $meta !== false) {
  272. $paths[$source] = $meta['path'];
  273. $source = (int)$meta['parent'];
  274. } else {
  275. $source = -1;
  276. }
  277. }
  278. // Include owner in list of users, if requested
  279. if ($includeOwner) {
  280. $shares[] = $ownerUser;
  281. }
  282. if ($returnUserPaths) {
  283. $fileTargetIDs = array_keys($fileTargets);
  284. $fileTargetIDs = array_unique($fileTargetIDs);
  285. if (!empty($fileTargetIDs)) {
  286. $query = \OC_DB::prepare(
  287. 'SELECT `fileid`, `path`
  288. FROM `*PREFIX*filecache`
  289. WHERE `fileid` IN (' . implode(',', $fileTargetIDs) . ')'
  290. );
  291. $result = $query->execute();
  292. if (\OCP\DB::isError($result)) {
  293. \OCP\Util::writeLog('OCP\Share', \OC_DB::getErrorMessage(), \OCP\Util::ERROR);
  294. } else {
  295. while ($row = $result->fetchRow()) {
  296. foreach ($fileTargets[$row['fileid']] as $uid => $shareData) {
  297. if ($mountPath !== false) {
  298. $sharedPath = $shareData['file_target'];
  299. $sharedPath .= substr($path, strlen($mountPath) + strlen($paths[$row['fileid']]));
  300. $sharePaths[$uid] = $sharedPath;
  301. } else {
  302. $sharedPath = $shareData['file_target'];
  303. $sharedPath .= substr($path, strlen($row['path']) -5);
  304. $sharePaths[$uid] = $sharedPath;
  305. }
  306. }
  307. }
  308. }
  309. }
  310. if ($includeOwner) {
  311. $sharePaths[$ownerUser] = $path;
  312. } else {
  313. unset($sharePaths[$ownerUser]);
  314. }
  315. return $sharePaths;
  316. }
  317. return array('users' => array_unique($shares), 'public' => $publicShare, 'remote' => $remoteShare);
  318. }
  319. /**
  320. * Get the items of item type shared with the current user
  321. * @param string $itemType
  322. * @param int $format (optional) Format type must be defined by the backend
  323. * @param mixed $parameters (optional)
  324. * @param int $limit Number of items to return (optional) Returns all by default
  325. * @param boolean $includeCollections (optional)
  326. * @return mixed Return depends on format
  327. */
  328. public static function getItemsSharedWith($itemType, $format = self::FORMAT_NONE,
  329. $parameters = null, $limit = -1, $includeCollections = false) {
  330. return self::getItems($itemType, null, self::$shareTypeUserAndGroups, \OC_User::getUser(), null, $format,
  331. $parameters, $limit, $includeCollections);
  332. }
  333. /**
  334. * Get the items of item type shared with a user
  335. * @param string $itemType
  336. * @param string $user id for which user we want the shares
  337. * @param int $format (optional) Format type must be defined by the backend
  338. * @param mixed $parameters (optional)
  339. * @param int $limit Number of items to return (optional) Returns all by default
  340. * @param boolean $includeCollections (optional)
  341. * @return mixed Return depends on format
  342. */
  343. public static function getItemsSharedWithUser($itemType, $user, $format = self::FORMAT_NONE,
  344. $parameters = null, $limit = -1, $includeCollections = false) {
  345. return self::getItems($itemType, null, self::$shareTypeUserAndGroups, $user, null, $format,
  346. $parameters, $limit, $includeCollections);
  347. }
  348. /**
  349. * Get the item of item type shared with the current user
  350. * @param string $itemType
  351. * @param string $itemTarget
  352. * @param int $format (optional) Format type must be defined by the backend
  353. * @param mixed $parameters (optional)
  354. * @param boolean $includeCollections (optional)
  355. * @return mixed Return depends on format
  356. */
  357. public static function getItemSharedWith($itemType, $itemTarget, $format = self::FORMAT_NONE,
  358. $parameters = null, $includeCollections = false) {
  359. return self::getItems($itemType, $itemTarget, self::$shareTypeUserAndGroups, \OC_User::getUser(), null, $format,
  360. $parameters, 1, $includeCollections);
  361. }
  362. /**
  363. * Get the item of item type shared with a given user by source
  364. * @param string $itemType
  365. * @param string $itemSource
  366. * @param string $user User to whom the item was shared
  367. * @param string $owner Owner of the share
  368. * @param int $shareType only look for a specific share type
  369. * @return array Return list of items with file_target, permissions and expiration
  370. */
  371. public static function getItemSharedWithUser($itemType, $itemSource, $user, $owner = null, $shareType = null) {
  372. $shares = array();
  373. $fileDependent = false;
  374. $where = 'WHERE';
  375. $fileDependentWhere = '';
  376. if ($itemType === 'file' || $itemType === 'folder') {
  377. $fileDependent = true;
  378. $column = 'file_source';
  379. $fileDependentWhere = 'INNER JOIN `*PREFIX*filecache` ON `file_source` = `*PREFIX*filecache`.`fileid` ';
  380. $fileDependentWhere .= 'INNER JOIN `*PREFIX*storages` ON `numeric_id` = `*PREFIX*filecache`.`storage` ';
  381. } else {
  382. $column = 'item_source';
  383. }
  384. $select = self::createSelectStatement(self::FORMAT_NONE, $fileDependent);
  385. $where .= ' `' . $column . '` = ? AND `item_type` = ? ';
  386. $arguments = array($itemSource, $itemType);
  387. // for link shares $user === null
  388. if ($user !== null) {
  389. $where .= ' AND `share_with` = ? ';
  390. $arguments[] = $user;
  391. }
  392. if ($shareType !== null) {
  393. $where .= ' AND `share_type` = ? ';
  394. $arguments[] = $shareType;
  395. }
  396. if ($owner !== null) {
  397. $where .= ' AND `uid_owner` = ? ';
  398. $arguments[] = $owner;
  399. }
  400. $query = \OC_DB::prepare('SELECT ' . $select . ' FROM `*PREFIX*share` '. $fileDependentWhere . $where);
  401. $result = \OC_DB::executeAudited($query, $arguments);
  402. while ($row = $result->fetchRow()) {
  403. if ($fileDependent && !self::isFileReachable($row['path'], $row['storage_id'])) {
  404. continue;
  405. }
  406. if ($fileDependent && (int)$row['file_parent'] === -1) {
  407. // if it is a mount point we need to get the path from the mount manager
  408. $mountManager = \OC\Files\Filesystem::getMountManager();
  409. $mountPoint = $mountManager->findByStorageId($row['storage_id']);
  410. if (!empty($mountPoint)) {
  411. $path = $mountPoint[0]->getMountPoint();
  412. $path = trim($path, '/');
  413. $path = substr($path, strlen($owner) + 1); //normalize path to 'files/foo.txt`
  414. $row['path'] = $path;
  415. } else {
  416. \OC::$server->getLogger()->warning(
  417. 'Could not resolve mount point for ' . $row['storage_id'],
  418. ['app' => 'OCP\Share']
  419. );
  420. }
  421. }
  422. $shares[] = $row;
  423. }
  424. //if didn't found a result than let's look for a group share.
  425. if(empty($shares) && $user !== null) {
  426. $groups = \OC_Group::getUserGroups($user);
  427. if (!empty($groups)) {
  428. $where = $fileDependentWhere . ' WHERE `' . $column . '` = ? AND `item_type` = ? AND `share_with` in (?)';
  429. $arguments = array($itemSource, $itemType, $groups);
  430. $types = array(null, null, IQueryBuilder::PARAM_STR_ARRAY);
  431. if ($owner !== null) {
  432. $where .= ' AND `uid_owner` = ?';
  433. $arguments[] = $owner;
  434. $types[] = null;
  435. }
  436. // TODO: inject connection, hopefully one day in the future when this
  437. // class isn't static anymore...
  438. $conn = \OC::$server->getDatabaseConnection();
  439. $result = $conn->executeQuery(
  440. 'SELECT ' . $select . ' FROM `*PREFIX*share` ' . $where,
  441. $arguments,
  442. $types
  443. );
  444. while ($row = $result->fetch()) {
  445. $shares[] = $row;
  446. }
  447. }
  448. }
  449. return $shares;
  450. }
  451. /**
  452. * Get the item of item type shared with the current user by source
  453. * @param string $itemType
  454. * @param string $itemSource
  455. * @param int $format (optional) Format type must be defined by the backend
  456. * @param mixed $parameters
  457. * @param boolean $includeCollections
  458. * @param string $shareWith (optional) define against which user should be checked, default: current user
  459. * @return array
  460. */
  461. public static function getItemSharedWithBySource($itemType, $itemSource, $format = self::FORMAT_NONE,
  462. $parameters = null, $includeCollections = false, $shareWith = null) {
  463. $shareWith = ($shareWith === null) ? \OC_User::getUser() : $shareWith;
  464. return self::getItems($itemType, $itemSource, self::$shareTypeUserAndGroups, $shareWith, null, $format,
  465. $parameters, 1, $includeCollections, true);
  466. }
  467. /**
  468. * Get the item of item type shared by a link
  469. * @param string $itemType
  470. * @param string $itemSource
  471. * @param string $uidOwner Owner of link
  472. * @return array
  473. */
  474. public static function getItemSharedWithByLink($itemType, $itemSource, $uidOwner) {
  475. return self::getItems($itemType, $itemSource, self::SHARE_TYPE_LINK, null, $uidOwner, self::FORMAT_NONE,
  476. null, 1);
  477. }
  478. /**
  479. * Based on the given token the share information will be returned - password protected shares will be verified
  480. * @param string $token
  481. * @param bool $checkPasswordProtection
  482. * @return array|boolean false will be returned in case the token is unknown or unauthorized
  483. */
  484. public static function getShareByToken($token, $checkPasswordProtection = true) {
  485. $query = \OC_DB::prepare('SELECT * FROM `*PREFIX*share` WHERE `token` = ?', 1);
  486. $result = $query->execute(array($token));
  487. if ($result === false) {
  488. \OCP\Util::writeLog('OCP\Share', \OC_DB::getErrorMessage() . ', token=' . $token, \OCP\Util::ERROR);
  489. }
  490. $row = $result->fetchRow();
  491. if ($row === false) {
  492. return false;
  493. }
  494. if (is_array($row) and self::expireItem($row)) {
  495. return false;
  496. }
  497. // password protected shares need to be authenticated
  498. if ($checkPasswordProtection && !\OCP\Share::checkPasswordProtectedShare($row)) {
  499. return false;
  500. }
  501. return $row;
  502. }
  503. /**
  504. * resolves reshares down to the last real share
  505. * @param array $linkItem
  506. * @return array file owner
  507. */
  508. public static function resolveReShare($linkItem)
  509. {
  510. if (isset($linkItem['parent'])) {
  511. $parent = $linkItem['parent'];
  512. while (isset($parent)) {
  513. $query = \OC_DB::prepare('SELECT * FROM `*PREFIX*share` WHERE `id` = ?', 1);
  514. $item = $query->execute(array($parent))->fetchRow();
  515. if (isset($item['parent'])) {
  516. $parent = $item['parent'];
  517. } else {
  518. return $item;
  519. }
  520. }
  521. }
  522. return $linkItem;
  523. }
  524. /**
  525. * Get the shared items of item type owned by the current user
  526. * @param string $itemType
  527. * @param int $format (optional) Format type must be defined by the backend
  528. * @param mixed $parameters
  529. * @param int $limit Number of items to return (optional) Returns all by default
  530. * @param boolean $includeCollections
  531. * @return mixed Return depends on format
  532. */
  533. public static function getItemsShared($itemType, $format = self::FORMAT_NONE, $parameters = null,
  534. $limit = -1, $includeCollections = false) {
  535. return self::getItems($itemType, null, null, null, \OC_User::getUser(), $format,
  536. $parameters, $limit, $includeCollections);
  537. }
  538. /**
  539. * Get the shared item of item type owned by the current user
  540. * @param string $itemType
  541. * @param string $itemSource
  542. * @param int $format (optional) Format type must be defined by the backend
  543. * @param mixed $parameters
  544. * @param boolean $includeCollections
  545. * @return mixed Return depends on format
  546. */
  547. public static function getItemShared($itemType, $itemSource, $format = self::FORMAT_NONE,
  548. $parameters = null, $includeCollections = false) {
  549. return self::getItems($itemType, $itemSource, null, null, \OC_User::getUser(), $format,
  550. $parameters, -1, $includeCollections);
  551. }
  552. /**
  553. * Get all users an item is shared with
  554. * @param string $itemType
  555. * @param string $itemSource
  556. * @param string $uidOwner
  557. * @param boolean $includeCollections
  558. * @param boolean $checkExpireDate
  559. * @return array Return array of users
  560. */
  561. public static function getUsersItemShared($itemType, $itemSource, $uidOwner, $includeCollections = false, $checkExpireDate = true) {
  562. $users = array();
  563. $items = self::getItems($itemType, $itemSource, null, null, $uidOwner, self::FORMAT_NONE, null, -1, $includeCollections, false, $checkExpireDate);
  564. if ($items) {
  565. foreach ($items as $item) {
  566. if ((int)$item['share_type'] === self::SHARE_TYPE_USER) {
  567. $users[] = $item['share_with'];
  568. } else if ((int)$item['share_type'] === self::SHARE_TYPE_GROUP) {
  569. $users = array_merge($users, \OC_Group::usersInGroup($item['share_with']));
  570. }
  571. }
  572. }
  573. return $users;
  574. }
  575. /**
  576. * Share an item with a user, group, or via private link
  577. * @param string $itemType
  578. * @param string $itemSource
  579. * @param int $shareType SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK
  580. * @param string $shareWith User or group the item is being shared with
  581. * @param int $permissions CRUDS
  582. * @param string $itemSourceName
  583. * @param \DateTime $expirationDate
  584. * @param bool $passwordChanged
  585. * @return boolean|string Returns true on success or false on failure, Returns token on success for links
  586. * @throws \OC\HintException when the share type is remote and the shareWith is invalid
  587. * @throws \Exception
  588. */
  589. public static function shareItem($itemType, $itemSource, $shareType, $shareWith, $permissions, $itemSourceName = null, \DateTime $expirationDate = null, $passwordChanged = null) {
  590. $backend = self::getBackend($itemType);
  591. $l = \OC::$server->getL10N('lib');
  592. if ($backend->isShareTypeAllowed($shareType) === false) {
  593. $message = 'Sharing %s failed, because the backend does not allow shares from type %i';
  594. $message_t = $l->t('Sharing %s failed, because the backend does not allow shares from type %i', array($itemSourceName, $shareType));
  595. \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $shareType), \OCP\Util::DEBUG);
  596. throw new \Exception($message_t);
  597. }
  598. $uidOwner = \OC_User::getUser();
  599. $shareWithinGroupOnly = self::shareWithGroupMembersOnly();
  600. if (is_null($itemSourceName)) {
  601. $itemSourceName = $itemSource;
  602. }
  603. $itemName = $itemSourceName;
  604. // check if file can be shared
  605. if ($itemType === 'file' or $itemType === 'folder') {
  606. $path = \OC\Files\Filesystem::getPath($itemSource);
  607. $itemName = $path;
  608. // verify that the file exists before we try to share it
  609. if (!$path) {
  610. $message = 'Sharing %s failed, because the file does not exist';
  611. $message_t = $l->t('Sharing %s failed, because the file does not exist', array($itemSourceName));
  612. \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName), \OCP\Util::DEBUG);
  613. throw new \Exception($message_t);
  614. }
  615. // verify that the user has share permission
  616. if (!\OC\Files\Filesystem::isSharable($path) || \OCP\Util::isSharingDisabledForUser()) {
  617. $message = 'You are not allowed to share %s';
  618. $message_t = $l->t('You are not allowed to share %s', [$path]);
  619. \OCP\Util::writeLog('OCP\Share', sprintf($message, $path), \OCP\Util::DEBUG);
  620. throw new \Exception($message_t);
  621. }
  622. }
  623. //verify that we don't share a folder which already contains a share mount point
  624. if ($itemType === 'folder') {
  625. $path = '/' . $uidOwner . '/files' . \OC\Files\Filesystem::getPath($itemSource) . '/';
  626. $mountManager = \OC\Files\Filesystem::getMountManager();
  627. $mounts = $mountManager->findIn($path);
  628. foreach ($mounts as $mount) {
  629. if ($mount->getStorage()->instanceOfStorage('\OCA\Files_Sharing\ISharedStorage')) {
  630. $message = 'Sharing "' . $itemSourceName . '" failed, because it contains files shared with you!';
  631. \OCP\Util::writeLog('OCP\Share', $message, \OCP\Util::DEBUG);
  632. throw new \Exception($message);
  633. }
  634. }
  635. }
  636. // single file shares should never have delete permissions
  637. if ($itemType === 'file') {
  638. $permissions = (int)$permissions & ~\OCP\Constants::PERMISSION_DELETE;
  639. }
  640. //Validate expirationDate
  641. if ($expirationDate !== null) {
  642. try {
  643. /*
  644. * Reuse the validateExpireDate.
  645. * We have to pass time() since the second arg is the time
  646. * the file was shared, since it is not shared yet we just use
  647. * the current time.
  648. */
  649. $expirationDate = self::validateExpireDate($expirationDate->format('Y-m-d'), time(), $itemType, $itemSource);
  650. } catch (\Exception $e) {
  651. throw new \OC\HintException($e->getMessage(), $e->getMessage(), 404);
  652. }
  653. }
  654. // Verify share type and sharing conditions are met
  655. if ($shareType === self::SHARE_TYPE_USER) {
  656. if ($shareWith == $uidOwner) {
  657. $message = 'Sharing %s failed, because you can not share with yourself';
  658. $message_t = $l->t('Sharing %s failed, because you can not share with yourself', [$itemName]);
  659. \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName), \OCP\Util::DEBUG);
  660. throw new \Exception($message_t);
  661. }
  662. if (!\OC_User::userExists($shareWith)) {
  663. $message = 'Sharing %s failed, because the user %s does not exist';
  664. $message_t = $l->t('Sharing %s failed, because the user %s does not exist', array($itemSourceName, $shareWith));
  665. \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $shareWith), \OCP\Util::DEBUG);
  666. throw new \Exception($message_t);
  667. }
  668. if ($shareWithinGroupOnly) {
  669. $inGroup = array_intersect(\OC_Group::getUserGroups($uidOwner), \OC_Group::getUserGroups($shareWith));
  670. if (empty($inGroup)) {
  671. $message = 'Sharing %s failed, because the user '
  672. .'%s is not a member of any groups that %s is a member of';
  673. $message_t = $l->t('Sharing %s failed, because the user %s is not a member of any groups that %s is a member of', array($itemName, $shareWith, $uidOwner));
  674. \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemName, $shareWith, $uidOwner), \OCP\Util::DEBUG);
  675. throw new \Exception($message_t);
  676. }
  677. }
  678. // Check if the item source is already shared with the user, either from the same owner or a different user
  679. if ($checkExists = self::getItems($itemType, $itemSource, self::$shareTypeUserAndGroups,
  680. $shareWith, null, self::FORMAT_NONE, null, 1, true, true)) {
  681. // Only allow the same share to occur again if it is the same
  682. // owner and is not a user share, this use case is for increasing
  683. // permissions for a specific user
  684. if ($checkExists['uid_owner'] != $uidOwner || $checkExists['share_type'] == $shareType) {
  685. $message = 'Sharing %s failed, because this item is already shared with %s';
  686. $message_t = $l->t('Sharing %s failed, because this item is already shared with %s', array($itemSourceName, $shareWith));
  687. \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $shareWith), \OCP\Util::DEBUG);
  688. throw new \Exception($message_t);
  689. }
  690. }
  691. if ($checkExists = self::getItems($itemType, $itemSource, self::SHARE_TYPE_USER,
  692. $shareWith, null, self::FORMAT_NONE, null, 1, true, true)) {
  693. // Only allow the same share to occur again if it is the same
  694. // owner and is not a user share, this use case is for increasing
  695. // permissions for a specific user
  696. if ($checkExists['uid_owner'] != $uidOwner || $checkExists['share_type'] == $shareType) {
  697. $message = 'Sharing %s failed, because this item is already shared with user %s';
  698. $message_t = $l->t('Sharing %s failed, because this item is already shared with user %s', array($itemSourceName, $shareWith));
  699. \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $shareWith), \OCP\Util::ERROR);
  700. throw new \Exception($message_t);
  701. }
  702. }
  703. } else if ($shareType === self::SHARE_TYPE_GROUP) {
  704. if (!\OC_Group::groupExists($shareWith)) {
  705. $message = 'Sharing %s failed, because the group %s does not exist';
  706. $message_t = $l->t('Sharing %s failed, because the group %s does not exist', array($itemSourceName, $shareWith));
  707. \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $shareWith), \OCP\Util::DEBUG);
  708. throw new \Exception($message_t);
  709. }
  710. if ($shareWithinGroupOnly && !\OC_Group::inGroup($uidOwner, $shareWith)) {
  711. $message = 'Sharing %s failed, because '
  712. .'%s is not a member of the group %s';
  713. $message_t = $l->t('Sharing %s failed, because %s is not a member of the group %s', array($itemSourceName, $uidOwner, $shareWith));
  714. \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $uidOwner, $shareWith), \OCP\Util::DEBUG);
  715. throw new \Exception($message_t);
  716. }
  717. // Check if the item source is already shared with the group, either from the same owner or a different user
  718. // The check for each user in the group is done inside the put() function
  719. if ($checkExists = self::getItems($itemType, $itemSource, self::SHARE_TYPE_GROUP, $shareWith,
  720. null, self::FORMAT_NONE, null, 1, true, true)) {
  721. if ($checkExists['share_with'] === $shareWith && $checkExists['share_type'] === \OCP\Share::SHARE_TYPE_GROUP) {
  722. $message = 'Sharing %s failed, because this item is already shared with %s';
  723. $message_t = $l->t('Sharing %s failed, because this item is already shared with %s', array($itemSourceName, $shareWith));
  724. \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $shareWith), \OCP\Util::DEBUG);
  725. throw new \Exception($message_t);
  726. }
  727. }
  728. // Convert share with into an array with the keys group and users
  729. $group = $shareWith;
  730. $shareWith = array();
  731. $shareWith['group'] = $group;
  732. $shareWith['users'] = array_diff(\OC_Group::usersInGroup($group), array($uidOwner));
  733. } else if ($shareType === self::SHARE_TYPE_LINK) {
  734. $updateExistingShare = false;
  735. if (\OC::$server->getAppConfig()->getValue('core', 'shareapi_allow_links', 'yes') == 'yes') {
  736. // IF the password is changed via the old ajax endpoint verify it before deleting the old share
  737. if ($passwordChanged === true) {
  738. self::verifyPassword($shareWith);
  739. }
  740. // when updating a link share
  741. // FIXME Don't delete link if we update it
  742. if ($checkExists = self::getItems($itemType, $itemSource, self::SHARE_TYPE_LINK, null,
  743. $uidOwner, self::FORMAT_NONE, null, 1)) {
  744. // remember old token
  745. $oldToken = $checkExists['token'];
  746. $oldPermissions = $checkExists['permissions'];
  747. //delete the old share
  748. Helper::delete($checkExists['id']);
  749. $updateExistingShare = true;
  750. }
  751. if ($passwordChanged === null) {
  752. // Generate hash of password - same method as user passwords
  753. if (is_string($shareWith) && $shareWith !== '') {
  754. self::verifyPassword($shareWith);
  755. $shareWith = \OC::$server->getHasher()->hash($shareWith);
  756. } else {
  757. // reuse the already set password, but only if we change permissions
  758. // otherwise the user disabled the password protection
  759. if ($checkExists && (int)$permissions !== (int)$oldPermissions) {
  760. $shareWith = $checkExists['share_with'];
  761. }
  762. }
  763. } else {
  764. if ($passwordChanged === true) {
  765. if (is_string($shareWith) && $shareWith !== '') {
  766. self::verifyPassword($shareWith);
  767. $shareWith = \OC::$server->getHasher()->hash($shareWith);
  768. }
  769. } else if ($updateExistingShare) {
  770. $shareWith = $checkExists['share_with'];
  771. }
  772. }
  773. if (\OCP\Util::isPublicLinkPasswordRequired() && empty($shareWith)) {
  774. $message = 'You need to provide a password to create a public link, only protected links are allowed';
  775. $message_t = $l->t('You need to provide a password to create a public link, only protected links are allowed');
  776. \OCP\Util::writeLog('OCP\Share', $message, \OCP\Util::DEBUG);
  777. throw new \Exception($message_t);
  778. }
  779. if ($updateExistingShare === false &&
  780. self::isDefaultExpireDateEnabled() &&
  781. empty($expirationDate)) {
  782. $expirationDate = Helper::calcExpireDate();
  783. }
  784. // Generate token
  785. if (isset($oldToken)) {
  786. $token = $oldToken;
  787. } else {
  788. $token = \OC::$server->getSecureRandom()->generate(self::TOKEN_LENGTH,
  789. \OCP\Security\ISecureRandom::CHAR_LOWER.\OCP\Security\ISecureRandom::CHAR_UPPER.
  790. \OCP\Security\ISecureRandom::CHAR_DIGITS
  791. );
  792. }
  793. $result = self::put($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $permissions,
  794. null, $token, $itemSourceName, $expirationDate);
  795. if ($result) {
  796. return $token;
  797. } else {
  798. return false;
  799. }
  800. }
  801. $message = 'Sharing %s failed, because sharing with links is not allowed';
  802. $message_t = $l->t('Sharing %s failed, because sharing with links is not allowed', array($itemSourceName));
  803. \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName), \OCP\Util::DEBUG);
  804. throw new \Exception($message_t);
  805. } else if ($shareType === self::SHARE_TYPE_REMOTE) {
  806. /*
  807. * Check if file is not already shared with the remote user
  808. */
  809. if ($checkExists = self::getItems($itemType, $itemSource, self::SHARE_TYPE_REMOTE,
  810. $shareWith, $uidOwner, self::FORMAT_NONE, null, 1, true, true)) {
  811. $message = 'Sharing %s failed, because this item is already shared with %s';
  812. $message_t = $l->t('Sharing %s failed, because this item is already shared with %s', array($itemSourceName, $shareWith));
  813. \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $shareWith), \OCP\Util::DEBUG);
  814. throw new \Exception($message_t);
  815. }
  816. // don't allow federated shares if source and target server are the same
  817. list($user, $remote) = Helper::splitUserRemote($shareWith);
  818. $currentServer = self::removeProtocolFromUrl(\OC::$server->getURLGenerator()->getAbsoluteURL('/'));
  819. $currentUser = \OC::$server->getUserSession()->getUser()->getUID();
  820. if (Helper::isSameUserOnSameServer($user, $remote, $currentUser, $currentServer)) {
  821. $message = 'Not allowed to create a federated share with the same user.';
  822. $message_t = $l->t('Not allowed to create a federated share with the same user');
  823. \OCP\Util::writeLog('OCP\Share', $message, \OCP\Util::DEBUG);
  824. throw new \Exception($message_t);
  825. }
  826. $token = \OC::$server->getSecureRandom()->generate(self::TOKEN_LENGTH, \OCP\Security\ISecureRandom::CHAR_LOWER . \OCP\Security\ISecureRandom::CHAR_UPPER .
  827. \OCP\Security\ISecureRandom::CHAR_DIGITS);
  828. $shareWith = $user . '@' . $remote;
  829. $shareId = self::put($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $permissions, null, $token, $itemSourceName);
  830. $send = false;
  831. if ($shareId) {
  832. $send = self::sendRemoteShare($token, $shareWith, $itemSourceName, $shareId, $uidOwner);
  833. }
  834. if ($send === false) {
  835. $currentUser = \OC::$server->getUserSession()->getUser()->getUID();
  836. self::unshare($itemType, $itemSource, $shareType, $shareWith, $currentUser);
  837. $message_t = $l->t('Sharing %s failed, could not find %s, maybe the server is currently unreachable.', array($itemSourceName, $shareWith));
  838. throw new \Exception($message_t);
  839. }
  840. return $send;
  841. } else {
  842. // Future share types need to include their own conditions
  843. $message = 'Share type %s is not valid for %s';
  844. $message_t = $l->t('Share type %s is not valid for %s', array($shareType, $itemSource));
  845. \OCP\Util::writeLog('OCP\Share', sprintf($message, $shareType, $itemSource), \OCP\Util::DEBUG);
  846. throw new \Exception($message_t);
  847. }
  848. // Put the item into the database
  849. $result = self::put($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $permissions, null, null, $itemSourceName, $expirationDate);
  850. return $result ? true : false;
  851. }
  852. /**
  853. * Unshare an item from a user, group, or delete a private link
  854. * @param string $itemType
  855. * @param string $itemSource
  856. * @param int $shareType SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK
  857. * @param string $shareWith User or group the item is being shared with
  858. * @param string $owner owner of the share, if null the current user is used
  859. * @return boolean true on success or false on failure
  860. */
  861. public static function unshare($itemType, $itemSource, $shareType, $shareWith, $owner = null) {
  862. // check if it is a valid itemType
  863. self::getBackend($itemType);
  864. $items = self::getItemSharedWithUser($itemType, $itemSource, $shareWith, $owner, $shareType);
  865. $toDelete = array();
  866. $newParent = null;
  867. $currentUser = $owner ? $owner : \OC_User::getUser();
  868. foreach ($items as $item) {
  869. // delete the item with the expected share_type and owner
  870. if ((int)$item['share_type'] === (int)$shareType && $item['uid_owner'] === $currentUser) {
  871. $toDelete = $item;
  872. // if there is more then one result we don't have to delete the children
  873. // but update their parent. For group shares the new parent should always be
  874. // the original group share and not the db entry with the unique name
  875. } else if ((int)$item['share_type'] === self::$shareTypeGroupUserUnique) {
  876. $newParent = $item['parent'];
  877. } else {
  878. $newParent = $item['id'];
  879. }
  880. }
  881. if (!empty($toDelete)) {
  882. self::unshareItem($toDelete, $newParent);
  883. return true;
  884. }
  885. return false;
  886. }
  887. /**
  888. * Unshare an item from all users, groups, and remove all links
  889. * @param string $itemType
  890. * @param string $itemSource
  891. * @return boolean true on success or false on failure
  892. */
  893. public static function unshareAll($itemType, $itemSource) {
  894. // Get all of the owners of shares of this item.
  895. $query = \OC_DB::prepare( 'SELECT `uid_owner` from `*PREFIX*share` WHERE `item_type`=? AND `item_source`=?' );
  896. $result = $query->execute(array($itemType, $itemSource));
  897. $shares = array();
  898. // Add each owner's shares to the array of all shares for this item.
  899. while ($row = $result->fetchRow()) {
  900. $shares = array_merge($shares, self::getItems($itemType, $itemSource, null, null, $row['uid_owner']));
  901. }
  902. if (!empty($shares)) {
  903. // Pass all the vars we have for now, they may be useful
  904. $hookParams = array(
  905. 'itemType' => $itemType,
  906. 'itemSource' => $itemSource,
  907. 'shares' => $shares,
  908. );
  909. \OC_Hook::emit('OCP\Share', 'pre_unshareAll', $hookParams);
  910. foreach ($shares as $share) {
  911. self::unshareItem($share);
  912. }
  913. \OC_Hook::emit('OCP\Share', 'post_unshareAll', $hookParams);
  914. return true;
  915. }
  916. return false;
  917. }
  918. /**
  919. * Unshare an item shared with the current user
  920. * @param string $itemType
  921. * @param string $itemOrigin Item target or source
  922. * @param boolean $originIsSource true if $itemOrigin is the source, false if $itemOrigin is the target (optional)
  923. * @return boolean true on success or false on failure
  924. *
  925. * Unsharing from self is not allowed for items inside collections
  926. */
  927. public static function unshareFromSelf($itemType, $itemOrigin, $originIsSource = false) {
  928. $originType = ($originIsSource) ? 'source' : 'target';
  929. $uid = \OCP\User::getUser();
  930. if ($itemType === 'file' || $itemType === 'folder') {
  931. $statement = 'SELECT * FROM `*PREFIX*share` WHERE `item_type` = ? and `file_' . $originType . '` = ?';
  932. } else {
  933. $statement = 'SELECT * FROM `*PREFIX*share` WHERE `item_type` = ? and `item_' . $originType . '` = ?';
  934. }
  935. $query = \OCP\DB::prepare($statement);
  936. $result = $query->execute(array($itemType, $itemOrigin));
  937. $shares = $result->fetchAll();
  938. $listOfUnsharedItems = array();
  939. $itemUnshared = false;
  940. foreach ($shares as $share) {
  941. if ((int)$share['share_type'] === \OCP\Share::SHARE_TYPE_USER &&
  942. $share['share_with'] === $uid) {
  943. $deletedShares = Helper::delete($share['id']);
  944. $shareTmp = array(
  945. 'id' => $share['id'],
  946. 'shareWith' => $share['share_with'],
  947. 'itemTarget' => $share['item_target'],
  948. 'itemType' => $share['item_type'],
  949. 'shareType' => (int)$share['share_type'],
  950. );
  951. if (isset($share['file_target'])) {
  952. $shareTmp['fileTarget'] = $share['file_target'];
  953. }
  954. $listOfUnsharedItems = array_merge($listOfUnsharedItems, $deletedShares, array($shareTmp));
  955. $itemUnshared = true;
  956. break;
  957. } elseif ((int)$share['share_type'] === \OCP\Share::SHARE_TYPE_GROUP) {
  958. if (\OC_Group::inGroup($uid, $share['share_with'])) {
  959. $groupShare = $share;
  960. }
  961. } elseif ((int)$share['share_type'] === self::$shareTypeGroupUserUnique &&
  962. $share['share_with'] === $uid) {
  963. $uniqueGroupShare = $share;
  964. }
  965. }
  966. if (!$itemUnshared && isset($groupShare) && !isset($uniqueGroupShare)) {
  967. $query = \OC_DB::prepare('INSERT INTO `*PREFIX*share`'
  968. .' (`item_type`, `item_source`, `item_target`, `parent`, `share_type`,'
  969. .' `share_with`, `uid_owner`, `permissions`, `stime`, `file_source`, `file_target`)'
  970. .' VALUES (?,?,?,?,?,?,?,?,?,?,?)');
  971. $query->execute(array($groupShare['item_type'], $groupShare['item_source'], $groupShare['item_target'],
  972. $groupShare['id'], self::$shareTypeGroupUserUnique,
  973. \OC_User::getUser(), $groupShare['uid_owner'], 0, $groupShare['stime'], $groupShare['file_source'],
  974. $groupShare['file_target']));
  975. $shareTmp = array(
  976. 'id' => $groupShare['id'],
  977. 'shareWith' => $groupShare['share_with'],
  978. 'itemTarget' => $groupShare['item_target'],
  979. 'itemType' => $groupShare['item_type'],
  980. 'shareType' => (int)$groupShare['share_type'],
  981. );
  982. if (isset($groupShare['file_target'])) {
  983. $shareTmp['fileTarget'] = $groupShare['file_target'];
  984. }
  985. $listOfUnsharedItems = array_merge($listOfUnsharedItems, [$shareTmp]);
  986. $itemUnshared = true;
  987. } elseif (!$itemUnshared && isset($uniqueGroupShare)) {
  988. $query = \OC_DB::prepare('UPDATE `*PREFIX*share` SET `permissions` = ? WHERE `id` = ?');
  989. $query->execute(array(0, $uniqueGroupShare['id']));
  990. $shareTmp = array(
  991. 'id' => $uniqueGroupShare['id'],
  992. 'shareWith' => $uniqueGroupShare['share_with'],
  993. 'itemTarget' => $uniqueGroupShare['item_target'],
  994. 'itemType' => $uniqueGroupShare['item_type'],
  995. 'shareType' => (int)$uniqueGroupShare['share_type'],
  996. );
  997. if (isset($uniqueGroupShare['file_target'])) {
  998. $shareTmp['fileTarget'] = $uniqueGroupShare['file_target'];
  999. }
  1000. $listOfUnsharedItems = array_merge($listOfUnsharedItems, [$shareTmp]);
  1001. $itemUnshared = true;
  1002. }
  1003. if ($itemUnshared) {
  1004. \OC_Hook::emit('OCP\Share', 'post_unshareFromSelf',
  1005. array('unsharedItems' => $listOfUnsharedItems, 'itemType' => $itemType));
  1006. }
  1007. return $itemUnshared;
  1008. }
  1009. /**
  1010. * sent status if users got informed by mail about share
  1011. * @param string $itemType
  1012. * @param string $itemSource
  1013. * @param int $shareType SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK
  1014. * @param string $recipient with whom was the file shared
  1015. * @param boolean $status
  1016. */
  1017. public static function setSendMailStatus($itemType, $itemSource, $shareType, $recipient, $status) {
  1018. $status = $status ? 1 : 0;
  1019. $query = \OC_DB::prepare(
  1020. 'UPDATE `*PREFIX*share`
  1021. SET `mail_send` = ?
  1022. WHERE `item_type` = ? AND `item_source` = ? AND `share_type` = ? AND `share_with` = ?');
  1023. $result = $query->execute(array($status, $itemType, $itemSource, $shareType, $recipient));
  1024. if($result === false) {
  1025. \OCP\Util::writeLog('OCP\Share', 'Couldn\'t set send mail status', \OCP\Util::ERROR);
  1026. }
  1027. }
  1028. /**
  1029. * Set the permissions of an item for a specific user or group
  1030. * @param string $itemType
  1031. * @param string $itemSource
  1032. * @param int $shareType SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK
  1033. * @param string $shareWith User or group the item is being shared with
  1034. * @param int $permissions CRUDS permissions
  1035. * @return boolean true on success or false on failure
  1036. * @throws \Exception when trying to grant more permissions then the user has himself
  1037. */
  1038. public static function setPermissions($itemType, $itemSource, $shareType, $shareWith, $permissions) {
  1039. $l = \OC::$server->getL10N('lib');
  1040. $connection = \OC::$server->getDatabaseConnection();
  1041. $intArrayToLiteralArray = function($intArray, $eb) {
  1042. return array_map(function($int) use ($eb) {
  1043. return $eb->literal((int)$int, 'integer');
  1044. }, $intArray);
  1045. };
  1046. $sanitizeItem = function($item) {
  1047. $item['id'] = (int)$item['id'];
  1048. $item['premissions'] = (int)$item['permissions'];
  1049. return $item;
  1050. };
  1051. if ($rootItem = self::getItems($itemType, $itemSource, $shareType, $shareWith,
  1052. \OC_User::getUser(), self::FORMAT_NONE, null, 1, false)) {
  1053. // Check if this item is a reshare and verify that the permissions
  1054. // granted don't exceed the parent shared item
  1055. if (isset($rootItem['parent'])) {
  1056. $qb = $connection->getQueryBuilder();
  1057. $qb->select('permissions')
  1058. ->from('share')
  1059. ->where($qb->expr()->eq('id', $qb->createParameter('id')))
  1060. ->setParameter(':id', $rootItem['parent']);
  1061. $dbresult = $qb->execute();
  1062. $result = $dbresult->fetch();
  1063. $dbresult->closeCursor();
  1064. if (~(int)$result['permissions'] & $permissions) {
  1065. $message = 'Setting permissions for %s failed,'
  1066. .' because the permissions exceed permissions granted to %s';
  1067. $message_t = $l->t('Setting permissions for %s failed, because the permissions exceed permissions granted to %s', array($itemSource, \OC_User::getUser()));
  1068. \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSource, \OC_User::getUser()), \OCP\Util::DEBUG);
  1069. throw new \Exception($message_t);
  1070. }
  1071. }
  1072. $qb = $connection->getQueryBuilder();
  1073. $qb->update('share')
  1074. ->set('permissions', $qb->createParameter('permissions'))
  1075. ->where($qb->expr()->eq('id', $qb->createParameter('id')))
  1076. ->setParameter(':id', $rootItem['id'])
  1077. ->setParameter(':permissions', $permissions);
  1078. $qb->execute();
  1079. if ($itemType === 'file' || $itemType === 'folder') {
  1080. \OC_Hook::emit('OCP\Share', 'post_update_permissions', array(
  1081. 'itemType' => $itemType,
  1082. 'itemSource' => $itemSource,
  1083. 'shareType' => $shareType,
  1084. 'shareWith' => $shareWith,
  1085. 'uidOwner' => \OC_User::getUser(),
  1086. 'permissions' => $permissions,
  1087. 'path' => $rootItem['path'],
  1088. 'share' => $rootItem
  1089. ));
  1090. }
  1091. // Share id's to update with the new permissions
  1092. $ids = [];
  1093. $items = [];
  1094. // Check if permissions were removed
  1095. if ((int)$rootItem['permissions'] & ~$permissions) {
  1096. // If share permission is removed all reshares must be deleted
  1097. if (($rootItem['permissions'] & \OCP\Constants::PERMISSION_SHARE) && (~$permissions & \OCP\Constants::PERMISSION_SHARE)) {
  1098. // delete all shares, keep parent and group children
  1099. Helper::delete($rootItem['id'], true, null, null, true);
  1100. }
  1101. // Remove permission from all children
  1102. $parents = [$rootItem['id']];
  1103. while (!empty($parents)) {
  1104. $parents = $intArrayToLiteralArray($parents, $qb->expr());
  1105. $qb = $connection->getQueryBuilder();
  1106. $qb->select('id', 'permissions', 'item_type')
  1107. ->from('share')
  1108. ->where($qb->expr()->in('parent', $parents));
  1109. $result = $qb->execute();
  1110. // Reset parents array, only go through loop again if
  1111. // items are found that need permissions removed
  1112. $parents = [];
  1113. while ($item = $result->fetch()) {
  1114. $item = $sanitizeItem($item);
  1115. $items[] = $item;
  1116. // Check if permissions need to be removed
  1117. if ($item['permissions'] & ~$permissions) {
  1118. // Add to list of items that need permissions removed
  1119. $ids[] = $item['id'];
  1120. $parents[] = $item['id'];
  1121. }
  1122. }
  1123. $result->closeCursor();
  1124. }
  1125. // Remove the permissions for all reshares of this item
  1126. if (!empty($ids)) {
  1127. $ids = "'".implode("','", $ids)."'";
  1128. // TODO this should be done with Doctrine platform objects
  1129. if (\OC::$server->getConfig()->getSystemValue("dbtype") === 'oci') {
  1130. $andOp = 'BITAND(`permissions`, ?)';
  1131. } else {
  1132. $andOp = '`permissions` & ?';
  1133. }
  1134. $query = \OC_DB::prepare('UPDATE `*PREFIX*share` SET `permissions` = '.$andOp
  1135. .' WHERE `id` IN ('.$ids.')');
  1136. $query->execute(array($permissions));
  1137. }
  1138. }
  1139. /*
  1140. * Permissions were added
  1141. * Update all USERGROUP shares. (So group shares where the user moved their mountpoint).
  1142. */
  1143. if ($permissions & ~(int)$rootItem['permissions']) {
  1144. $qb = $connection->getQueryBuilder();
  1145. $qb->select('id', 'permissions', 'item_type')
  1146. ->from('share')
  1147. ->where($qb->expr()->eq('parent', $qb->createParameter('parent')))
  1148. ->andWhere($qb->expr()->eq('share_type', $qb->createParameter('share_type')))
  1149. ->andWhere($qb->expr()->neq('permissions', $qb->createParameter('shareDeleted')))
  1150. ->setParameter(':parent', (int)$rootItem['id'])
  1151. ->setParameter(':share_type', 2)
  1152. ->setParameter(':shareDeleted', 0);
  1153. $result = $qb->execute();
  1154. $ids = [];
  1155. while ($item = $result->fetch()) {
  1156. $item = $sanitizeItem($item);
  1157. $items[] = $item;
  1158. $ids[] = $item['id'];
  1159. }
  1160. $result->closeCursor();
  1161. // Add permssions for all USERGROUP shares of this item
  1162. if (!empty($ids)) {
  1163. $ids = $intArrayToLiteralArray($ids, $qb->expr());
  1164. $qb = $connection->getQueryBuilder();
  1165. $qb->update('share')
  1166. ->set('permissions', $qb->createParameter('permissions'))
  1167. ->where($qb->expr()->in('id', $ids))
  1168. ->setParameter(':permissions', $permissions);
  1169. $qb->execute();
  1170. }
  1171. }
  1172. foreach ($items as $item) {
  1173. \OC_Hook::emit('OCP\Share', 'post_update_permissions', ['share' => $item]);
  1174. }
  1175. return true;
  1176. }
  1177. $message = 'Setting permissions for %s failed, because the item was not found';
  1178. $message_t = $l->t('Setting permissions for %s failed, because the item was not found', array($itemSource));
  1179. \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSource), \OCP\Util::DEBUG);
  1180. throw new \Exception($message_t);
  1181. }
  1182. /**
  1183. * validate expiration date if it meets all constraints
  1184. *
  1185. * @param string $expireDate well formatted date string, e.g. "DD-MM-YYYY"
  1186. * @param string $shareTime timestamp when the file was shared
  1187. * @param string $itemType
  1188. * @param string $itemSource
  1189. * @return \DateTime validated date
  1190. * @throws \Exception when the expire date is in the past or further in the future then the enforced date
  1191. */
  1192. private static function validateExpireDate($expireDate, $shareTime, $itemType, $itemSource) {
  1193. $l = \OC::$server->getL10N('lib');
  1194. $date = new \DateTime($expireDate);
  1195. $today = new \DateTime('now');
  1196. // if the user doesn't provide a share time we need to get it from the database
  1197. // fall-back mode to keep API stable, because the $shareTime parameter was added later
  1198. $defaultExpireDateEnforced = \OCP\Util::isDefaultExpireDateEnforced();
  1199. if ($defaultExpireDateEnforced && $shareTime === null) {
  1200. $items = self::getItemShared($itemType, $itemSource);
  1201. $firstItem = reset($items);
  1202. $shareTime = (int)$firstItem['stime'];
  1203. }
  1204. if ($defaultExpireDateEnforced) {
  1205. // initialize max date with share time
  1206. $maxDate = new \DateTime();
  1207. $maxDate->setTimestamp($shareTime);
  1208. $maxDays = \OCP\Config::getAppValue('core', 'shareapi_expire_after_n_days', '7');
  1209. $maxDate->add(new \DateInterval('P' . $maxDays . 'D'));
  1210. if ($date > $maxDate) {
  1211. $warning = 'Cannot set expiration date. Shares cannot expire later than ' . $maxDays . ' after they have been shared';
  1212. $warning_t = $l->t('Cannot set expiration date. Shares cannot expire later than %s after they have been shared', array($maxDays));
  1213. \OCP\Util::writeLog('OCP\Share', $warning, \OCP\Util::WARN);
  1214. throw new \Exception($warning_t);
  1215. }
  1216. }
  1217. if ($date < $today) {
  1218. $message = 'Cannot set expiration date. Expiration date is in the past';
  1219. $message_t = $l->t('Cannot set expiration date. Expiration date is in the past');
  1220. \OCP\Util::writeLog('OCP\Share', $message, \OCP\Util::WARN);
  1221. throw new \Exception($message_t);
  1222. }
  1223. return $date;
  1224. }
  1225. /**
  1226. * Set expiration date for a share
  1227. * @param string $itemType
  1228. * @param string $itemSource
  1229. * @param string $date expiration date
  1230. * @param int $shareTime timestamp from when the file was shared
  1231. * @return boolean
  1232. * @throws \Exception when the expire date is not set, in the past or further in the future then the enforced date
  1233. */
  1234. public static function setExpirationDate($itemType, $itemSource, $date, $shareTime = null) {
  1235. $user = \OC_User::getUser();
  1236. $l = \OC::$server->getL10N('lib');
  1237. if ($date == '') {
  1238. if (\OCP\Util::isDefaultExpireDateEnforced()) {
  1239. $warning = 'Cannot clear expiration date. Shares are required to have an expiration date.';
  1240. $warning_t = $l->t('Cannot clear expiration date. Shares are required to have an expiration date.');
  1241. \OCP\Util::writeLog('OCP\Share', $warning, \OCP\Util::WARN);
  1242. throw new \Exception($warning_t);
  1243. } else {
  1244. $date = null;
  1245. }
  1246. } else {
  1247. $date = self::validateExpireDate($date, $shareTime, $itemType, $itemSource);
  1248. }
  1249. $query = \OC_DB::prepare('UPDATE `*PREFIX*share` SET `expiration` = ? WHERE `item_type` = ? AND `item_source` = ? AND `uid_owner` = ? AND `share_type` = ?');
  1250. $query->bindValue(1, $date, 'datetime');
  1251. $query->bindValue(2, $itemType);
  1252. $query->bindValue(3, $itemSource);
  1253. $query->bindValue(4, $user);
  1254. $query->bindValue(5, \OCP\Share::SHARE_TYPE_LINK);
  1255. $query->execute();
  1256. \OC_Hook::emit('OCP\Share', 'post_set_expiration_date', array(
  1257. 'itemType' => $itemType,
  1258. 'itemSource' => $itemSource,
  1259. 'date' => $date,
  1260. 'uidOwner' => $user
  1261. ));
  1262. return true;
  1263. }
  1264. /**
  1265. * Retrieve the owner of a connection
  1266. *
  1267. * @param IDBConnection $connection
  1268. * @param int $shareId
  1269. * @throws \Exception
  1270. * @return string uid of share owner
  1271. */
  1272. private static function getShareOwner(IDBConnection $connection, $shareId) {
  1273. $qb = $connection->getQueryBuilder();
  1274. $qb->select('uid_owner')
  1275. ->from('share')
  1276. ->where($qb->expr()->eq('id', $qb->createParameter('shareId')))
  1277. ->setParameter(':shareId', $shareId);
  1278. $result = $qb->execute();
  1279. $result = $result->fetch();
  1280. if (empty($result)) {
  1281. throw new \Exception('Share not found');
  1282. }
  1283. return $result['uid_owner'];
  1284. }
  1285. /**
  1286. * Set password for a public link share
  1287. *
  1288. * @param IUserSession $userSession
  1289. * @param IDBConnection $connection
  1290. * @param IConfig $config
  1291. * @param int $shareId
  1292. * @param string $password
  1293. * @throws \Exception
  1294. * @return boolean
  1295. */
  1296. public static function setPassword(IUserSession $userSession,
  1297. IDBConnection $connection,
  1298. IConfig $config,
  1299. $shareId, $password) {
  1300. $user = $userSession->getUser();
  1301. if (is_null($user)) {
  1302. throw new \Exception("User not logged in");
  1303. }
  1304. $uid = self::getShareOwner($connection, $shareId);
  1305. if ($uid !== $user->getUID()) {
  1306. throw new \Exception('Cannot update share of a different user');
  1307. }
  1308. if ($password === '') {
  1309. $password = null;
  1310. }
  1311. //If passwords are enforced the password can't be null
  1312. if (self::enforcePassword($config) && is_null($password)) {
  1313. throw new \Exception('Cannot remove password');
  1314. }
  1315. self::verifyPassword($password);
  1316. $qb = $connection->getQueryBuilder();
  1317. $qb->update('share')
  1318. ->set('share_with', $qb->createParameter('pass'))
  1319. ->where($qb->expr()->eq('id', $qb->createParameter('shareId')))
  1320. ->setParameter(':pass', is_null($password) ? null : \OC::$server->getHasher()->hash($password))
  1321. ->setParameter(':shareId', $shareId);
  1322. $qb->execute();
  1323. return true;
  1324. }
  1325. /**
  1326. * Checks whether a share has expired, calls unshareItem() if yes.
  1327. * @param array $item Share data (usually database row)
  1328. * @return boolean True if item was expired, false otherwise.
  1329. */
  1330. protected static function expireItem(array $item) {
  1331. $result = false;
  1332. // only use default expiration date for link shares
  1333. if ((int) $item['share_type'] === self::SHARE_TYPE_LINK) {
  1334. // calculate expiration date
  1335. if (!empty($item['expiration'])) {
  1336. $userDefinedExpire = new \DateTime($item['expiration']);
  1337. $expires = $userDefinedExpire->getTimestamp();
  1338. } else {
  1339. $expires = null;
  1340. }
  1341. // get default expiration settings
  1342. $defaultSettings = Helper::getDefaultExpireSetting();
  1343. $expires = Helper::calculateExpireDate($defaultSettings, $item['stime'], $expires);
  1344. if (is_int($expires)) {
  1345. $now = time();
  1346. if ($now > $expires) {
  1347. self::unshareItem($item);
  1348. $result = true;
  1349. }
  1350. }
  1351. }
  1352. return $result;
  1353. }
  1354. /**
  1355. * Unshares a share given a share data array
  1356. * @param array $item Share data (usually database row)
  1357. * @param int $newParent parent ID
  1358. * @return null
  1359. */
  1360. protected static function unshareItem(array $item, $newParent = null) {
  1361. $shareType = (int)$item['share_type'];
  1362. $shareWith = null;
  1363. if ($shareType !== \OCP\Share::SHARE_TYPE_LINK) {
  1364. $shareWith = $item['share_with'];
  1365. }
  1366. // Pass all the vars we have for now, they may be useful
  1367. $hookParams = array(
  1368. 'id' => $item['id'],
  1369. 'itemType' => $item['item_type'],
  1370. 'itemSource' => $item['item_source'],
  1371. 'shareType' => $shareType,
  1372. 'shareWith' => $shareWith,
  1373. 'itemParent' => $item['parent'],
  1374. 'uidOwner' => $item['uid_owner'],
  1375. );
  1376. if($item['item_type'] === 'file' || $item['item_type'] === 'folder') {
  1377. $hookParams['fileSource'] = $item['file_source'];
  1378. $hookParams['fileTarget'] = $item['file_target'];
  1379. }
  1380. \OC_Hook::emit('OCP\Share', 'pre_unshare', $hookParams);
  1381. $deletedShares = Helper::delete($item['id'], false, null, $newParent);
  1382. $deletedShares[] = $hookParams;
  1383. $hookParams['deletedShares'] = $deletedShares;
  1384. \OC_Hook::emit('OCP\Share', 'post_unshare', $hookParams);
  1385. if ((int)$item['share_type'] === \OCP\Share::SHARE_TYPE_REMOTE && \OC::$server->getUserSession()->getUser()) {
  1386. list(, $remote) = Helper::splitUserRemote($item['share_with']);
  1387. self::sendRemoteUnshare($remote, $item['id'], $item['token']);
  1388. }
  1389. }
  1390. /**
  1391. * Get the backend class for the specified item type
  1392. * @param string $itemType
  1393. * @throws \Exception
  1394. * @return \OCP\Share_Backend
  1395. */
  1396. public static function getBackend($itemType) {
  1397. $l = \OC::$server->getL10N('lib');
  1398. if (isset(self::$backends[$itemType])) {
  1399. return self::$backends[$itemType];
  1400. } else if (isset(self::$backendTypes[$itemType]['class'])) {
  1401. $class = self::$backendTypes[$itemType]['class'];
  1402. if (class_exists($class)) {
  1403. self::$backends[$itemType] = new $class;
  1404. if (!(self::$backends[$itemType] instanceof \OCP\Share_Backend)) {
  1405. $message = 'Sharing backend %s must implement the interface OCP\Share_Backend';
  1406. $message_t = $l->t('Sharing backend %s must implement the interface OCP\Share_Backend', array($class));
  1407. \OCP\Util::writeLog('OCP\Share', sprintf($message, $class), \OCP\Util::ERROR);
  1408. throw new \Exception($message_t);
  1409. }
  1410. return self::$backends[$itemType];
  1411. } else {
  1412. $message = 'Sharing backend %s not found';
  1413. $message_t = $l->t('Sharing backend %s not found', array($class));
  1414. \OCP\Util::writeLog('OCP\Share', sprintf($message, $class), \OCP\Util::ERROR);
  1415. throw new \Exception($message_t);
  1416. }
  1417. }
  1418. $message = 'Sharing backend for %s not found';
  1419. $message_t = $l->t('Sharing backend for %s not found', array($itemType));
  1420. \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemType), \OCP\Util::ERROR);
  1421. throw new \Exception($message_t);
  1422. }
  1423. /**
  1424. * Check if resharing is allowed
  1425. * @return boolean true if allowed or false
  1426. *
  1427. * Resharing is allowed by default if not configured
  1428. */
  1429. public static function isResharingAllowed() {
  1430. if (!isset(self::$isResharingAllowed)) {
  1431. if (\OC::$server->getAppConfig()->getValue('core', 'shareapi_allow_resharing', 'yes') == 'yes') {
  1432. self::$isResharingAllowed = true;
  1433. } else {
  1434. self::$isResharingAllowed = false;
  1435. }
  1436. }
  1437. return self::$isResharingAllowed;
  1438. }
  1439. /**
  1440. * Get a list of collection item types for the specified item type
  1441. * @param string $itemType
  1442. * @return array
  1443. */
  1444. private static function getCollectionItemTypes($itemType) {
  1445. $collectionTypes = array($itemType);
  1446. foreach (self::$backendTypes as $type => $backend) {
  1447. if (in_array($backend['collectionOf'], $collectionTypes)) {
  1448. $collectionTypes[] = $type;
  1449. }
  1450. }
  1451. // TODO Add option for collections to be collection of themselves, only 'folder' does it now...
  1452. if (isset(self::$backendTypes[$itemType]) && (!self::getBackend($itemType) instanceof \OCP\Share_Backend_Collection || $itemType != 'folder')) {
  1453. unset($collectionTypes[0]);
  1454. }
  1455. // Return array if collections were found or the item type is a
  1456. // collection itself - collections can be inside collections
  1457. if (count($collectionTypes) > 0) {
  1458. return $collectionTypes;
  1459. }
  1460. return false;
  1461. }
  1462. /**
  1463. * Get the owners of items shared with a user.
  1464. *
  1465. * @param string $user The user the items are shared with.
  1466. * @param string $type The type of the items shared with the user.
  1467. * @param boolean $includeCollections Include collection item types (optional)
  1468. * @param boolean $includeOwner include owner in the list of users the item is shared with (optional)
  1469. * @return array
  1470. */
  1471. public static function getSharedItemsOwners($user, $type, $includeCollections = false, $includeOwner = false) {
  1472. // First, we find out if $type is part of a collection (and if that collection is part of
  1473. // another one and so on).
  1474. $collectionTypes = array();
  1475. if (!$includeCollections || !$collectionTypes = self::getCollectionItemTypes($type)) {
  1476. $collectionTypes[] = $type;
  1477. }
  1478. // Of these collection types, along with our original $type, we make a
  1479. // list of the ones for which a sharing backend has been registered.
  1480. // FIXME: Ideally, we wouldn't need to nest getItemsSharedWith in this loop but just call it
  1481. // with its $includeCollections parameter set to true. Unfortunately, this fails currently.
  1482. $allMaybeSharedItems = array();
  1483. foreach ($collectionTypes as $collectionType) {
  1484. if (isset(self::$backends[$collectionType])) {
  1485. $allMaybeSharedItems[$collectionType] = self::getItemsSharedWithUser(
  1486. $collectionType,
  1487. $user,
  1488. self::FORMAT_NONE
  1489. );
  1490. }
  1491. }
  1492. $owners = array();
  1493. if ($includeOwner) {
  1494. $owners[] = $user;
  1495. }
  1496. // We take a look at all shared items of the given $type (or of the collections it is part of)
  1497. // and find out their owners. Then, we gather the tags for the original $type from all owners,
  1498. // and return them as elements of a list that look like "Tag (owner)".
  1499. foreach ($allMaybeSharedItems as $collectionType => $maybeSharedItems) {
  1500. foreach ($maybeSharedItems as $sharedItem) {
  1501. if (isset($sharedItem['id'])) { //workaround for https://github.com/owncloud/core/issues/2814
  1502. $owners[] = $sharedItem['uid_owner'];
  1503. }
  1504. }
  1505. }
  1506. return $owners;
  1507. }
  1508. /**
  1509. * Get shared items from the database
  1510. * @param string $itemType
  1511. * @param string $item Item source or target (optional)
  1512. * @param int $shareType SHARE_TYPE_USER, SHARE_TYPE_GROUP, SHARE_TYPE_LINK, $shareTypeUserAndGroups, or $shareTypeGroupUserUnique
  1513. * @param string $shareWith User or group the item is being shared with
  1514. * @param string $uidOwner User that is the owner of shared items (optional)
  1515. * @param int $format Format to convert items to with formatItems() (optional)
  1516. * @param mixed $parameters to pass to formatItems() (optional)
  1517. * @param int $limit Number of items to return, -1 to return all matches (optional)
  1518. * @param boolean $includeCollections Include collection item types (optional)
  1519. * @param boolean $itemShareWithBySource (optional)
  1520. * @param boolean $checkExpireDate
  1521. * @return array
  1522. *
  1523. * See public functions getItem(s)... for parameter usage
  1524. *
  1525. */
  1526. public static function getItems($itemType, $item = null, $shareType = null, $shareWith = null,
  1527. $uidOwner = null, $format = self::FORMAT_NONE, $parameters = null, $limit = -1,
  1528. $includeCollections = false, $itemShareWithBySource = false, $checkExpireDate = true) {
  1529. if (!self::isEnabled()) {
  1530. return array();
  1531. }
  1532. $backend = self::getBackend($itemType);
  1533. $collectionTypes = false;
  1534. // Get filesystem root to add it to the file target and remove from the
  1535. // file source, match file_source with the file cache
  1536. if ($itemType == 'file' || $itemType == 'folder') {
  1537. if(!is_null($uidOwner)) {
  1538. $root = \OC\Files\Filesystem::getRoot();
  1539. } else {
  1540. $root = '';
  1541. }
  1542. $where = 'INNER JOIN `*PREFIX*filecache` ON `file_source` = `*PREFIX*filecache`.`fileid` ';
  1543. if (!isset($item)) {
  1544. $where .= ' AND `file_target` IS NOT NULL ';
  1545. }
  1546. $where .= 'INNER JOIN `*PREFIX*storages` ON `numeric_id` = `*PREFIX*filecache`.`storage` ';
  1547. $fileDependent = true;
  1548. $queryArgs = array();
  1549. } else {
  1550. $fileDependent = false;
  1551. $root = '';
  1552. $collectionTypes = self::getCollectionItemTypes($itemType);
  1553. if ($includeCollections && !isset($item) && $collectionTypes) {
  1554. // If includeCollections is true, find collections of this item type, e.g. a music album contains songs
  1555. if (!in_array($itemType, $collectionTypes)) {
  1556. $itemTypes = array_merge(array($itemType), $collectionTypes);
  1557. } else {
  1558. $itemTypes = $collectionTypes;
  1559. }
  1560. $placeholders = join(',', array_fill(0, count($itemTypes), '?'));
  1561. $where = ' WHERE `item_type` IN ('.$placeholders.'))';
  1562. $queryArgs = $itemTypes;
  1563. } else {
  1564. $where = ' WHERE `item_type` = ?';
  1565. $queryArgs = array($itemType);
  1566. }
  1567. }
  1568. if (\OC::$server->getAppConfig()->getValue('core', 'shareapi_allow_links', 'yes') !== 'yes') {
  1569. $where .= ' AND `share_type` != ?';
  1570. $queryArgs[] = self::SHARE_TYPE_LINK;
  1571. }
  1572. if (isset($shareType)) {
  1573. // Include all user and group items
  1574. if ($shareType == self::$shareTypeUserAndGroups && isset($shareWith)) {
  1575. $where .= ' AND ((`share_type` in (?, ?) AND `share_with` = ?) ';
  1576. $queryArgs[] = self::SHARE_TYPE_USER;
  1577. $queryArgs[] = self::$shareTypeGroupUserUnique;
  1578. $queryArgs[] = $shareWith;
  1579. $groups = \OC_Group::getUserGroups($shareWith);
  1580. if (!empty($groups)) {
  1581. $placeholders = join(',', array_fill(0, count($groups), '?'));
  1582. $where .= ' OR (`share_type` = ? AND `share_with` IN ('.$placeholders.')) ';
  1583. $queryArgs[] = self::SHARE_TYPE_GROUP;
  1584. $queryArgs = array_merge($queryArgs, $groups);
  1585. }
  1586. $where .= ')';
  1587. // Don't include own group shares
  1588. $where .= ' AND `uid_owner` != ?';
  1589. $queryArgs[] = $shareWith;
  1590. } else {
  1591. $where .= ' AND `share_type` = ?';
  1592. $queryArgs[] = $shareType;
  1593. if (isset($shareWith)) {
  1594. $where .= ' AND `share_with` = ?';
  1595. $queryArgs[] = $shareWith;
  1596. }
  1597. }
  1598. }
  1599. if (isset($uidOwner)) {
  1600. $where .= ' AND `uid_owner` = ?';
  1601. $queryArgs[] = $uidOwner;
  1602. if (!isset($shareType)) {
  1603. // Prevent unique user targets for group shares from being selected
  1604. $where .= ' AND `share_type` != ?';
  1605. $queryArgs[] = self::$shareTypeGroupUserUnique;
  1606. }
  1607. if ($fileDependent) {
  1608. $column = 'file_source';
  1609. } else {
  1610. $column = 'item_source';
  1611. }
  1612. } else {
  1613. if ($fileDependent) {
  1614. $column = 'file_target';
  1615. } else {
  1616. $column = 'item_target';
  1617. }
  1618. }
  1619. if (isset($item)) {
  1620. $collectionTypes = self::getCollectionItemTypes($itemType);
  1621. if ($includeCollections && $collectionTypes && !in_array('folder', $collectionTypes)) {
  1622. $where .= ' AND (';
  1623. } else {
  1624. $where .= ' AND';
  1625. }
  1626. // If looking for own shared items, check item_source else check item_target
  1627. if (isset($uidOwner) || $itemShareWithBySource) {
  1628. // If item type is a file, file source needs to be checked in case the item was converted
  1629. if ($fileDependent) {
  1630. $where .= ' `file_source` = ?';
  1631. $column = 'file_source';
  1632. } else {
  1633. $where .= ' `item_source` = ?';
  1634. $column = 'item_source';
  1635. }
  1636. } else {
  1637. if ($fileDependent) {
  1638. $where .= ' `file_target` = ?';
  1639. $item = \OC\Files\Filesystem::normalizePath($item);
  1640. } else {
  1641. $where .= ' `item_target` = ?';
  1642. }
  1643. }
  1644. $queryArgs[] = $item;
  1645. if ($includeCollections && $collectionTypes && !in_array('folder', $collectionTypes)) {
  1646. $placeholders = join(',', array_fill(0, count($collectionTypes), '?'));
  1647. $where .= ' OR `item_type` IN ('.$placeholders.'))';
  1648. $queryArgs = array_merge($queryArgs, $collectionTypes);
  1649. }
  1650. }
  1651. if ($shareType == self::$shareTypeUserAndGroups && $limit === 1) {
  1652. // Make sure the unique user target is returned if it exists,
  1653. // unique targets should follow the group share in the database
  1654. // If the limit is not 1, the filtering can be done later
  1655. $where .= ' ORDER BY `*PREFIX*share`.`id` DESC';
  1656. } else {
  1657. $where .= ' ORDER BY `*PREFIX*share`.`id` ASC';
  1658. }
  1659. if ($limit != -1 && !$includeCollections) {
  1660. // The limit must be at least 3, because filtering needs to be done
  1661. if ($limit < 3) {
  1662. $queryLimit = 3;
  1663. } else {
  1664. $queryLimit = $limit;
  1665. }
  1666. } else {
  1667. $queryLimit = null;
  1668. }
  1669. $select = self::createSelectStatement($format, $fileDependent, $uidOwner);
  1670. $root = strlen($root);
  1671. $query = \OC_DB::prepare('SELECT '.$select.' FROM `*PREFIX*share` '.$where, $queryLimit);
  1672. $result = $query->execute($queryArgs);
  1673. if ($result === false) {
  1674. \OCP\Util::writeLog('OCP\Share',
  1675. \OC_DB::getErrorMessage() . ', select=' . $select . ' where=',
  1676. \OCP\Util::ERROR);
  1677. }
  1678. $items = array();
  1679. $targets = array();
  1680. $switchedItems = array();
  1681. $mounts = array();
  1682. while ($row = $result->fetchRow()) {
  1683. self::transformDBResults($row);
  1684. // Filter out duplicate group shares for users with unique targets
  1685. if ($fileDependent && !self::isFileReachable($row['path'], $row['storage_id'])) {
  1686. continue;
  1687. }
  1688. if ($row['share_type'] == self::$shareTypeGroupUserUnique && isset($items[$row['parent']])) {
  1689. $row['share_type'] = self::SHARE_TYPE_GROUP;
  1690. $row['unique_name'] = true; // remember that we use a unique name for this user
  1691. $row['share_with'] = $items[$row['parent']]['share_with'];
  1692. // if the group share was unshared from the user we keep the permission, otherwise
  1693. // we take the permission from the parent because this is always the up-to-date
  1694. // permission for the group share
  1695. if ($row['permissions'] > 0) {
  1696. $row['permissions'] = $items[$row['parent']]['permissions'];
  1697. }
  1698. // Remove the parent group share
  1699. unset($items[$row['parent']]);
  1700. if ($row['permissions'] == 0) {
  1701. continue;
  1702. }
  1703. } else if (!isset($uidOwner)) {
  1704. // Check if the same target already exists
  1705. if (isset($targets[$row['id']])) {
  1706. // Check if the same owner shared with the user twice
  1707. // through a group and user share - this is allowed
  1708. $id = $targets[$row['id']];
  1709. if (isset($items[$id]) && $items[$id]['uid_owner'] == $row['uid_owner']) {
  1710. // Switch to group share type to ensure resharing conditions aren't bypassed
  1711. if ($items[$id]['share_type'] != self::SHARE_TYPE_GROUP) {
  1712. $items[$id]['share_type'] = self::SHARE_TYPE_GROUP;
  1713. $items[$id]['share_with'] = $row['share_with'];
  1714. }
  1715. // Switch ids if sharing permission is granted on only
  1716. // one share to ensure correct parent is used if resharing
  1717. if (~(int)$items[$id]['permissions'] & \OCP\Constants::PERMISSION_SHARE
  1718. && (int)$row['permissions'] & \OCP\Constants::PERMISSION_SHARE) {
  1719. $items[$row['id']] = $items[$id];
  1720. $switchedItems[$id] = $row['id'];
  1721. unset($items[$id]);
  1722. $id = $row['id'];
  1723. }
  1724. $items[$id]['permissions'] |= (int)$row['permissions'];
  1725. }
  1726. continue;
  1727. } elseif (!empty($row['parent'])) {
  1728. $targets[$row['parent']] = $row['id'];
  1729. }
  1730. }
  1731. // Remove root from file source paths if retrieving own shared items
  1732. if (isset($uidOwner) && isset($row['path'])) {
  1733. if (isset($row['parent'])) {
  1734. $query = \OC_DB::prepare('SELECT `file_target` FROM `*PREFIX*share` WHERE `id` = ?');
  1735. $parentResult = $query->execute(array($row['parent']));
  1736. if ($result === false) {
  1737. \OCP\Util::writeLog('OCP\Share', 'Can\'t select parent: ' .
  1738. \OC_DB::getErrorMessage() . ', select=' . $select . ' where=' . $where,
  1739. \OCP\Util::ERROR);
  1740. } else {
  1741. $parentRow = $parentResult->fetchRow();
  1742. $tmpPath = $parentRow['file_target'];
  1743. // find the right position where the row path continues from the target path
  1744. $pos = strrpos($row['path'], $parentRow['file_target']);
  1745. $subPath = substr($row['path'], $pos);
  1746. $splitPath = explode('/', $subPath);
  1747. foreach (array_slice($splitPath, 2) as $pathPart) {
  1748. $tmpPath = $tmpPath . '/' . $pathPart;
  1749. }
  1750. $row['path'] = $tmpPath;
  1751. }
  1752. } else {
  1753. if (!isset($mounts[$row['storage']])) {
  1754. $mountPoints = \OC\Files\Filesystem::getMountByNumericId($row['storage']);
  1755. if (is_array($mountPoints) && !empty($mountPoints)) {
  1756. $mounts[$row['storage']] = current($mountPoints);
  1757. }
  1758. }
  1759. if (!empty($mounts[$row['storage']])) {
  1760. $path = $mounts[$row['storage']]->getMountPoint().$row['path'];
  1761. $relPath = substr($path, $root); // path relative to data/user
  1762. $row['path'] = rtrim($relPath, '/');
  1763. }
  1764. }
  1765. }
  1766. if($checkExpireDate) {
  1767. if (self::expireItem($row)) {
  1768. continue;
  1769. }
  1770. }
  1771. // Check if resharing is allowed, if not remove share permission
  1772. if (isset($row['permissions']) && (!self::isResharingAllowed() | \OCP\Util::isSharingDisabledForUser())) {
  1773. $row['permissions'] &= ~\OCP\Constants::PERMISSION_SHARE;
  1774. }
  1775. // Add display names to result
  1776. $row['share_with_displayname'] = $row['share_with'];
  1777. if ( isset($row['share_with']) && $row['share_with'] != '' &&
  1778. $row['share_type'] === self::SHARE_TYPE_USER) {
  1779. $row['share_with_displayname'] = \OCP\User::getDisplayName($row['share_with']);
  1780. } else if(isset($row['share_with']) && $row['share_with'] != '' &&
  1781. $row['share_type'] === self::SHARE_TYPE_REMOTE) {
  1782. $addressBookEntries = \OC::$server->getContactsManager()->search($row['share_with'], ['CLOUD']);
  1783. foreach ($addressBookEntries as $entry) {
  1784. foreach ($entry['CLOUD'] as $cloudID) {
  1785. if ($cloudID === $row['share_with']) {
  1786. $row['share_with_displayname'] = $entry['FN'];
  1787. }
  1788. }
  1789. }
  1790. }
  1791. if ( isset($row['uid_owner']) && $row['uid_owner'] != '') {
  1792. $row['displayname_owner'] = \OCP\User::getDisplayName($row['uid_owner']);
  1793. }
  1794. if ($row['permissions'] > 0) {
  1795. $items[$row['id']] = $row;
  1796. }
  1797. }
  1798. // group items if we are looking for items shared with the current user
  1799. if (isset($shareWith) && $shareWith === \OCP\User::getUser()) {
  1800. $items = self::groupItems($items, $itemType);
  1801. }
  1802. if (!empty($items)) {
  1803. $collectionItems = array();
  1804. foreach ($items as &$row) {
  1805. // Return only the item instead of a 2-dimensional array
  1806. if ($limit == 1 && $row[$column] == $item && ($row['item_type'] == $itemType || $itemType == 'file')) {
  1807. if ($format == self::FORMAT_NONE) {
  1808. return $row;
  1809. } else {
  1810. break;
  1811. }
  1812. }
  1813. // Check if this is a collection of the requested item type
  1814. if ($includeCollections && $collectionTypes && $row['item_type'] !== 'folder' && in_array($row['item_type'], $collectionTypes)) {
  1815. if (($collectionBackend = self::getBackend($row['item_type']))
  1816. && $collectionBackend instanceof \OCP\Share_Backend_Collection) {
  1817. // Collections can be inside collections, check if the item is a collection
  1818. if (isset($item) && $row['item_type'] == $itemType && $row[$column] == $item) {
  1819. $collectionItems[] = $row;
  1820. } else {
  1821. $collection = array();
  1822. $collection['item_type'] = $row['item_type'];
  1823. if ($row['item_type'] == 'file' || $row['item_type'] == 'folder') {
  1824. $collection['path'] = basename($row['path']);
  1825. }
  1826. $row['collection'] = $collection;
  1827. // Fetch all of the children sources
  1828. $children = $collectionBackend->getChildren($row[$column]);
  1829. foreach ($children as $child) {
  1830. $childItem = $row;
  1831. $childItem['item_type'] = $itemType;
  1832. if ($row['item_type'] != 'file' && $row['item_type'] != 'folder') {
  1833. $childItem['item_source'] = $child['source'];
  1834. $childItem['item_target'] = $child['target'];
  1835. }
  1836. if ($backend instanceof \OCP\Share_Backend_File_Dependent) {
  1837. if ($row['item_type'] == 'file' || $row['item_type'] == 'folder') {
  1838. $childItem['file_source'] = $child['source'];
  1839. } else { // TODO is this really needed if we already know that we use the file backend?
  1840. $meta = \OC\Files\Filesystem::getFileInfo($child['file_path']);
  1841. $childItem['file_source'] = $meta['fileid'];
  1842. }
  1843. $childItem['file_target'] =
  1844. \OC\Files\Filesystem::normalizePath($child['file_path']);
  1845. }
  1846. if (isset($item)) {
  1847. if ($childItem[$column] == $item) {
  1848. // Return only the item instead of a 2-dimensional array
  1849. if ($limit == 1) {
  1850. if ($format == self::FORMAT_NONE) {
  1851. return $childItem;
  1852. } else {
  1853. // Unset the items array and break out of both loops
  1854. $items = array();
  1855. $items[] = $childItem;
  1856. break 2;
  1857. }
  1858. } else {
  1859. $collectionItems[] = $childItem;
  1860. }
  1861. }
  1862. } else {
  1863. $collectionItems[] = $childItem;
  1864. }
  1865. }
  1866. }
  1867. }
  1868. // Remove collection item
  1869. $toRemove = $row['id'];
  1870. if (array_key_exists($toRemove, $switchedItems)) {
  1871. $toRemove = $switchedItems[$toRemove];
  1872. }
  1873. unset($items[$toRemove]);
  1874. } elseif ($includeCollections && $collectionTypes && in_array($row['item_type'], $collectionTypes)) {
  1875. // FIXME: Thats a dirty hack to improve file sharing performance,
  1876. // see github issue #10588 for more details
  1877. // Need to find a solution which works for all back-ends
  1878. $collectionBackend = self::getBackend($row['item_type']);
  1879. $sharedParents = $collectionBackend->getParents($row['item_source']);
  1880. foreach ($sharedParents as $parent) {
  1881. $collectionItems[] = $parent;
  1882. }
  1883. }
  1884. }
  1885. if (!empty($collectionItems)) {
  1886. $collectionItems = array_unique($collectionItems, SORT_REGULAR);
  1887. $items = array_merge($items, $collectionItems);
  1888. }
  1889. // filter out invalid items, these can appear when subshare entries exist
  1890. // for a group in which the requested user isn't a member any more
  1891. $items = array_filter($items, function($item) {
  1892. return $item['share_type'] !== self::$shareTypeGroupUserUnique;
  1893. });
  1894. return self::formatResult($items, $column, $backend, $format, $parameters);
  1895. } elseif ($includeCollections && $collectionTypes && in_array('folder', $collectionTypes)) {
  1896. // FIXME: Thats a dirty hack to improve file sharing performance,
  1897. // see github issue #10588 for more details
  1898. // Need to find a solution which works for all back-ends
  1899. $collectionItems = array();
  1900. $collectionBackend = self::getBackend('folder');
  1901. $sharedParents = $collectionBackend->getParents($item, $shareWith, $uidOwner);
  1902. foreach ($sharedParents as $parent) {
  1903. $collectionItems[] = $parent;
  1904. }
  1905. if ($limit === 1) {
  1906. return reset($collectionItems);
  1907. }
  1908. return self::formatResult($collectionItems, $column, $backend, $format, $parameters);
  1909. }
  1910. return array();
  1911. }
  1912. /**
  1913. * group items with link to the same source
  1914. *
  1915. * @param array $items
  1916. * @param string $itemType
  1917. * @return array of grouped items
  1918. */
  1919. protected static function groupItems($items, $itemType) {
  1920. $fileSharing = ($itemType === 'file' || $itemType === 'folder') ? true : false;
  1921. $result = array();
  1922. foreach ($items as $item) {
  1923. $grouped = false;
  1924. foreach ($result as $key => $r) {
  1925. // for file/folder shares we need to compare file_source, otherwise we compare item_source
  1926. // only group shares if they already point to the same target, otherwise the file where shared
  1927. // before grouping of shares was added. In this case we don't group them toi avoid confusions
  1928. if (( $fileSharing && $item['file_source'] === $r['file_source'] && $item['file_target'] === $r['file_target']) ||
  1929. (!$fileSharing && $item['item_source'] === $r['item_source'] && $item['item_target'] === $r['item_target'])) {
  1930. // add the first item to the list of grouped shares
  1931. if (!isset($result[$key]['grouped'])) {
  1932. $result[$key]['grouped'][] = $result[$key];
  1933. }
  1934. $result[$key]['permissions'] = (int) $item['permissions'] | (int) $r['permissions'];
  1935. $result[$key]['grouped'][] = $item;
  1936. $grouped = true;
  1937. break;
  1938. }
  1939. }
  1940. if (!$grouped) {
  1941. $result[] = $item;
  1942. }
  1943. }
  1944. return $result;
  1945. }
  1946. /**
  1947. * Put shared item into the database
  1948. * @param string $itemType Item type
  1949. * @param string $itemSource Item source
  1950. * @param int $shareType SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK
  1951. * @param string $shareWith User or group the item is being shared with
  1952. * @param string $uidOwner User that is the owner of shared item
  1953. * @param int $permissions CRUDS permissions
  1954. * @param boolean|array $parentFolder Parent folder target (optional)
  1955. * @param string $token (optional)
  1956. * @param string $itemSourceName name of the source item (optional)
  1957. * @param \DateTime $expirationDate (optional)
  1958. * @throws \Exception
  1959. * @return mixed id of the new share or false
  1960. */
  1961. private static function put($itemType, $itemSource, $shareType, $shareWith, $uidOwner,
  1962. $permissions, $parentFolder = null, $token = null, $itemSourceName = null, \DateTime $expirationDate = null) {
  1963. $queriesToExecute = array();
  1964. $suggestedItemTarget = null;
  1965. $groupFileTarget = $fileTarget = $suggestedFileTarget = $filePath = '';
  1966. $groupItemTarget = $itemTarget = $fileSource = $parent = 0;
  1967. $result = self::checkReshare($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $permissions, $itemSourceName, $expirationDate);
  1968. if(!empty($result)) {
  1969. $parent = $result['parent'];
  1970. $itemSource = $result['itemSource'];
  1971. $fileSource = $result['fileSource'];
  1972. $suggestedItemTarget = $result['suggestedItemTarget'];
  1973. $suggestedFileTarget = $result['suggestedFileTarget'];
  1974. $filePath = $result['filePath'];
  1975. }
  1976. $isGroupShare = false;
  1977. if ($shareType == self::SHARE_TYPE_GROUP) {
  1978. $isGroupShare = true;
  1979. if (isset($shareWith['users'])) {
  1980. $users = $shareWith['users'];
  1981. } else {
  1982. $users = \OC_Group::usersInGroup($shareWith['group']);
  1983. }
  1984. // remove current user from list
  1985. if (in_array(\OCP\User::getUser(), $users)) {
  1986. unset($users[array_search(\OCP\User::getUser(), $users)]);
  1987. }
  1988. $groupItemTarget = Helper::generateTarget($itemType, $itemSource,
  1989. $shareType, $shareWith['group'], $uidOwner, $suggestedItemTarget);
  1990. $groupFileTarget = Helper::generateTarget($itemType, $itemSource,
  1991. $shareType, $shareWith['group'], $uidOwner, $filePath);
  1992. // add group share to table and remember the id as parent
  1993. $queriesToExecute['groupShare'] = array(
  1994. 'itemType' => $itemType,
  1995. 'itemSource' => $itemSource,
  1996. 'itemTarget' => $groupItemTarget,
  1997. 'shareType' => $shareType,
  1998. 'shareWith' => $shareWith['group'],
  1999. 'uidOwner' => $uidOwner,
  2000. 'permissions' => $permissions,
  2001. 'shareTime' => time(),
  2002. 'fileSource' => $fileSource,
  2003. 'fileTarget' => $groupFileTarget,
  2004. 'token' => $token,
  2005. 'parent' => $parent,
  2006. 'expiration' => $expirationDate,
  2007. );
  2008. } else {
  2009. $users = array($shareWith);
  2010. $itemTarget = Helper::generateTarget($itemType, $itemSource, $shareType, $shareWith, $uidOwner,
  2011. $suggestedItemTarget);
  2012. }
  2013. $run = true;
  2014. $error = '';
  2015. $preHookData = array(
  2016. 'itemType' => $itemType,
  2017. 'itemSource' => $itemSource,
  2018. 'shareType' => $shareType,
  2019. 'uidOwner' => $uidOwner,
  2020. 'permissions' => $permissions,
  2021. 'fileSource' => $fileSource,
  2022. 'expiration' => $expirationDate,
  2023. 'token' => $token,
  2024. 'run' => &$run,
  2025. 'error' => &$error
  2026. );
  2027. $preHookData['itemTarget'] = ($isGroupShare) ? $groupItemTarget : $itemTarget;
  2028. $preHookData['shareWith'] = ($isGroupShare) ? $shareWith['group'] : $shareWith;
  2029. \OC_Hook::emit('OCP\Share', 'pre_shared', $preHookData);
  2030. if ($run === false) {
  2031. throw new \Exception($error);
  2032. }
  2033. foreach ($users as $user) {
  2034. $sourceId = ($itemType === 'file' || $itemType === 'folder') ? $fileSource : $itemSource;
  2035. $sourceExists = self::getItemSharedWithBySource($itemType, $sourceId, self::FORMAT_NONE, null, true, $user);
  2036. $userShareType = ($isGroupShare) ? self::$shareTypeGroupUserUnique : $shareType;
  2037. if ($sourceExists && $sourceExists['item_source'] === $itemSource) {
  2038. $fileTarget = $sourceExists['file_target'];
  2039. $itemTarget = $sourceExists['item_target'];
  2040. // for group shares we don't need a additional entry if the target is the same
  2041. if($isGroupShare && $groupItemTarget === $itemTarget) {
  2042. continue;
  2043. }
  2044. } elseif(!$sourceExists && !$isGroupShare) {
  2045. $itemTarget = Helper::generateTarget($itemType, $itemSource, $userShareType, $user,
  2046. $uidOwner, $suggestedItemTarget, $parent);
  2047. if (isset($fileSource)) {
  2048. if ($parentFolder) {
  2049. if ($parentFolder === true) {
  2050. $fileTarget = Helper::generateTarget('file', $filePath, $userShareType, $user,
  2051. $uidOwner, $suggestedFileTarget, $parent);
  2052. if ($fileTarget != $groupFileTarget) {
  2053. $parentFolders[$user]['folder'] = $fileTarget;
  2054. }
  2055. } else if (isset($parentFolder[$user])) {
  2056. $fileTarget = $parentFolder[$user]['folder'].$itemSource;
  2057. $parent = $parentFolder[$user]['id'];
  2058. }
  2059. } else {
  2060. $fileTarget = Helper::generateTarget('file', $filePath, $userShareType,
  2061. $user, $uidOwner, $suggestedFileTarget, $parent);
  2062. }
  2063. } else {
  2064. $fileTarget = null;
  2065. }
  2066. } else {
  2067. // group share which doesn't exists until now, check if we need a unique target for this user
  2068. $itemTarget = Helper::generateTarget($itemType, $itemSource, self::SHARE_TYPE_USER, $user,
  2069. $uidOwner, $suggestedItemTarget, $parent);
  2070. // do we also need a file target
  2071. if (isset($fileSource)) {
  2072. $fileTarget = Helper::generateTarget('file', $filePath, self::SHARE_TYPE_USER, $user,
  2073. $uidOwner, $suggestedFileTarget, $parent);
  2074. } else {
  2075. $fileTarget = null;
  2076. }
  2077. if (($itemTarget === $groupItemTarget) &&
  2078. (!isset($fileSource) || $fileTarget === $groupFileTarget)) {
  2079. continue;
  2080. }
  2081. }
  2082. $queriesToExecute[] = array(
  2083. 'itemType' => $itemType,
  2084. 'itemSource' => $itemSource,
  2085. 'itemTarget' => $itemTarget,
  2086. 'shareType' => $userShareType,
  2087. 'shareWith' => $user,
  2088. 'uidOwner' => $uidOwner,
  2089. 'permissions' => $permissions,
  2090. 'shareTime' => time(),
  2091. 'fileSource' => $fileSource,
  2092. 'fileTarget' => $fileTarget,
  2093. 'token' => $token,
  2094. 'parent' => $parent,
  2095. 'expiration' => $expirationDate,
  2096. );
  2097. }
  2098. $id = false;
  2099. if ($isGroupShare) {
  2100. $id = self::insertShare($queriesToExecute['groupShare']);
  2101. // Save this id, any extra rows for this group share will need to reference it
  2102. $parent = \OC::$server->getDatabaseConnection()->lastInsertId('*PREFIX*share');
  2103. unset($queriesToExecute['groupShare']);
  2104. }
  2105. foreach ($queriesToExecute as $shareQuery) {
  2106. $shareQuery['parent'] = $parent;
  2107. $id = self::insertShare($shareQuery);
  2108. }
  2109. $postHookData = array(
  2110. 'itemType' => $itemType,
  2111. 'itemSource' => $itemSource,
  2112. 'parent' => $parent,
  2113. 'shareType' => $shareType,
  2114. 'uidOwner' => $uidOwner,
  2115. 'permissions' => $permissions,
  2116. 'fileSource' => $fileSource,
  2117. 'id' => $parent,
  2118. 'token' => $token,
  2119. 'expirationDate' => $expirationDate,
  2120. );
  2121. $postHookData['shareWith'] = ($isGroupShare) ? $shareWith['group'] : $shareWith;
  2122. $postHookData['itemTarget'] = ($isGroupShare) ? $groupItemTarget : $itemTarget;
  2123. $postHookData['fileTarget'] = ($isGroupShare) ? $groupFileTarget : $fileTarget;
  2124. \OC_Hook::emit('OCP\Share', 'post_shared', $postHookData);
  2125. return $id ? $id : false;
  2126. }
  2127. /**
  2128. * @param string $itemType
  2129. * @param string $itemSource
  2130. * @param int $shareType
  2131. * @param string $shareWith
  2132. * @param string $uidOwner
  2133. * @param int $permissions
  2134. * @param string|null $itemSourceName
  2135. * @param null|\DateTime $expirationDate
  2136. */
  2137. private static function checkReshare($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $permissions, $itemSourceName, $expirationDate) {
  2138. $backend = self::getBackend($itemType);
  2139. $l = \OC::$server->getL10N('lib');
  2140. $result = array();
  2141. $column = ($itemType === 'file' || $itemType === 'folder') ? 'file_source' : 'item_source';
  2142. $checkReshare = self::getItemSharedWithBySource($itemType, $itemSource, self::FORMAT_NONE, null, true);
  2143. if ($checkReshare) {
  2144. // Check if attempting to share back to owner
  2145. if ($checkReshare['uid_owner'] == $shareWith && $shareType == self::SHARE_TYPE_USER) {
  2146. $message = 'Sharing %s failed, because the user %s is the original sharer';
  2147. $message_t = $l->t('Sharing failed, because the user %s is the original sharer', [$shareWith]);
  2148. \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $shareWith), \OCP\Util::DEBUG);
  2149. throw new \Exception($message_t);
  2150. }
  2151. }
  2152. if ($checkReshare && $checkReshare['uid_owner'] !== \OC_User::getUser()) {
  2153. // Check if share permissions is granted
  2154. if (self::isResharingAllowed() && (int)$checkReshare['permissions'] & \OCP\Constants::PERMISSION_SHARE) {
  2155. if (~(int)$checkReshare['permissions'] & $permissions) {
  2156. $message = 'Sharing %s failed, because the permissions exceed permissions granted to %s';
  2157. $message_t = $l->t('Sharing %s failed, because the permissions exceed permissions granted to %s', array($itemSourceName, $uidOwner));
  2158. \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $uidOwner), \OCP\Util::DEBUG);
  2159. throw new \Exception($message_t);
  2160. } else {
  2161. // TODO Don't check if inside folder
  2162. $result['parent'] = $checkReshare['id'];
  2163. $result['expirationDate'] = $expirationDate;
  2164. // $checkReshare['expiration'] could be null and then is always less than any value
  2165. if(isset($checkReshare['expiration']) && $checkReshare['expiration'] < $expirationDate) {
  2166. $result['expirationDate'] = $checkReshare['expiration'];
  2167. }
  2168. // only suggest the same name as new target if it is a reshare of the
  2169. // same file/folder and not the reshare of a child
  2170. if ($checkReshare[$column] === $itemSource) {
  2171. $result['filePath'] = $checkReshare['file_target'];
  2172. $result['itemSource'] = $checkReshare['item_source'];
  2173. $result['fileSource'] = $checkReshare['file_source'];
  2174. $result['suggestedItemTarget'] = $checkReshare['item_target'];
  2175. $result['suggestedFileTarget'] = $checkReshare['file_target'];
  2176. } else {
  2177. $result['filePath'] = ($backend instanceof \OCP\Share_Backend_File_Dependent) ? $backend->getFilePath($itemSource, $uidOwner) : null;
  2178. $result['suggestedItemTarget'] = null;
  2179. $result['suggestedFileTarget'] = null;
  2180. $result['itemSource'] = $itemSource;
  2181. $result['fileSource'] = ($backend instanceof \OCP\Share_Backend_File_Dependent) ? $itemSource : null;
  2182. }
  2183. }
  2184. } else {
  2185. $message = 'Sharing %s failed, because resharing is not allowed';
  2186. $message_t = $l->t('Sharing %s failed, because resharing is not allowed', array($itemSourceName));
  2187. \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName), \OCP\Util::DEBUG);
  2188. throw new \Exception($message_t);
  2189. }
  2190. } else {
  2191. $result['parent'] = null;
  2192. $result['suggestedItemTarget'] = null;
  2193. $result['suggestedFileTarget'] = null;
  2194. $result['itemSource'] = $itemSource;
  2195. $result['expirationDate'] = $expirationDate;
  2196. if (!$backend->isValidSource($itemSource, $uidOwner)) {
  2197. $message = 'Sharing %s failed, because the sharing backend for '
  2198. .'%s could not find its source';
  2199. $message_t = $l->t('Sharing %s failed, because the sharing backend for %s could not find its source', array($itemSource, $itemType));
  2200. \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSource, $itemType), \OCP\Util::DEBUG);
  2201. throw new \Exception($message_t);
  2202. }
  2203. if ($backend instanceof \OCP\Share_Backend_File_Dependent) {
  2204. $result['filePath'] = $backend->getFilePath($itemSource, $uidOwner);
  2205. if ($itemType == 'file' || $itemType == 'folder') {
  2206. $result['fileSource'] = $itemSource;
  2207. } else {
  2208. $meta = \OC\Files\Filesystem::getFileInfo($result['filePath']);
  2209. $result['fileSource'] = $meta['fileid'];
  2210. }
  2211. if ($result['fileSource'] == -1) {
  2212. $message = 'Sharing %s failed, because the file could not be found in the file cache';
  2213. $message_t = $l->t('Sharing %s failed, because the file could not be found in the file cache', array($itemSource));
  2214. \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSource), \OCP\Util::DEBUG);
  2215. throw new \Exception($message_t);
  2216. }
  2217. } else {
  2218. $result['filePath'] = null;
  2219. $result['fileSource'] = null;
  2220. }
  2221. }
  2222. return $result;
  2223. }
  2224. /**
  2225. *
  2226. * @param array $shareData
  2227. * @return mixed false in case of a failure or the id of the new share
  2228. */
  2229. private static function insertShare(array $shareData) {
  2230. $query = \OC_DB::prepare('INSERT INTO `*PREFIX*share` ('
  2231. .' `item_type`, `item_source`, `item_target`, `share_type`,'
  2232. .' `share_with`, `uid_owner`, `permissions`, `stime`, `file_source`,'
  2233. .' `file_target`, `token`, `parent`, `expiration`) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)');
  2234. $query->bindValue(1, $shareData['itemType']);
  2235. $query->bindValue(2, $shareData['itemSource']);
  2236. $query->bindValue(3, $shareData['itemTarget']);
  2237. $query->bindValue(4, $shareData['shareType']);
  2238. $query->bindValue(5, $shareData['shareWith']);
  2239. $query->bindValue(6, $shareData['uidOwner']);
  2240. $query->bindValue(7, $shareData['permissions']);
  2241. $query->bindValue(8, $shareData['shareTime']);
  2242. $query->bindValue(9, $shareData['fileSource']);
  2243. $query->bindValue(10, $shareData['fileTarget']);
  2244. $query->bindValue(11, $shareData['token']);
  2245. $query->bindValue(12, $shareData['parent']);
  2246. $query->bindValue(13, $shareData['expiration'], 'datetime');
  2247. $result = $query->execute();
  2248. $id = false;
  2249. if ($result) {
  2250. $id = \OC::$server->getDatabaseConnection()->lastInsertId('*PREFIX*share');
  2251. }
  2252. return $id;
  2253. }
  2254. /**
  2255. * Delete all shares with type SHARE_TYPE_LINK
  2256. */
  2257. public static function removeAllLinkShares() {
  2258. // Delete any link shares
  2259. $query = \OC_DB::prepare('SELECT `id` FROM `*PREFIX*share` WHERE `share_type` = ?');
  2260. $result = $query->execute(array(self::SHARE_TYPE_LINK));
  2261. while ($item = $result->fetchRow()) {
  2262. Helper::delete($item['id']);
  2263. }
  2264. }
  2265. /**
  2266. * In case a password protected link is not yet authenticated this function will return false
  2267. *
  2268. * @param array $linkItem
  2269. * @return boolean
  2270. */
  2271. public static function checkPasswordProtectedShare(array $linkItem) {
  2272. if (!isset($linkItem['share_with'])) {
  2273. return true;
  2274. }
  2275. if (!isset($linkItem['share_type'])) {
  2276. return true;
  2277. }
  2278. if (!isset($linkItem['id'])) {
  2279. return true;
  2280. }
  2281. if ($linkItem['share_type'] != \OCP\Share::SHARE_TYPE_LINK) {
  2282. return true;
  2283. }
  2284. if ( \OC::$server->getSession()->exists('public_link_authenticated')
  2285. && \OC::$server->getSession()->get('public_link_authenticated') === (string)$linkItem['id'] ) {
  2286. return true;
  2287. }
  2288. return false;
  2289. }
  2290. /**
  2291. * construct select statement
  2292. * @param int $format
  2293. * @param boolean $fileDependent ist it a file/folder share or a generla share
  2294. * @param string $uidOwner
  2295. * @return string select statement
  2296. */
  2297. private static function createSelectStatement($format, $fileDependent, $uidOwner = null) {
  2298. $select = '*';
  2299. if ($format == self::FORMAT_STATUSES) {
  2300. if ($fileDependent) {
  2301. $select = '`*PREFIX*share`.`id`, `*PREFIX*share`.`parent`, `share_type`, `path`, `storage`, '
  2302. . '`share_with`, `uid_owner` , `file_source`, `stime`, `*PREFIX*share`.`permissions`, '
  2303. . '`*PREFIX*storages`.`id` AS `storage_id`, `*PREFIX*filecache`.`parent` as `file_parent`, '
  2304. . '`uid_initiator`';
  2305. } else {
  2306. $select = '`id`, `parent`, `share_type`, `share_with`, `uid_owner`, `item_source`, `stime`, `*PREFIX*share`.`permissions`';
  2307. }
  2308. } else {
  2309. if (isset($uidOwner)) {
  2310. if ($fileDependent) {
  2311. $select = '`*PREFIX*share`.`id`, `item_type`, `item_source`, `*PREFIX*share`.`parent`,'
  2312. . ' `share_type`, `share_with`, `file_source`, `file_target`, `path`, `*PREFIX*share`.`permissions`, `stime`,'
  2313. . ' `expiration`, `token`, `storage`, `mail_send`, `uid_owner`, '
  2314. . '`*PREFIX*storages`.`id` AS `storage_id`, `*PREFIX*filecache`.`parent` as `file_parent`';
  2315. } else {
  2316. $select = '`id`, `item_type`, `item_source`, `parent`, `share_type`, `share_with`, `*PREFIX*share`.`permissions`,'
  2317. . ' `stime`, `file_source`, `expiration`, `token`, `mail_send`, `uid_owner`';
  2318. }
  2319. } else {
  2320. if ($fileDependent) {
  2321. if ($format == \OCA\Files_Sharing\ShareBackend\File::FORMAT_GET_FOLDER_CONTENTS || $format == \OCA\Files_Sharing\ShareBackend\File::FORMAT_FILE_APP_ROOT) {
  2322. $select = '`*PREFIX*share`.`id`, `item_type`, `item_source`, `*PREFIX*share`.`parent`, `uid_owner`, '
  2323. . '`share_type`, `share_with`, `file_source`, `path`, `file_target`, `stime`, '
  2324. . '`*PREFIX*share`.`permissions`, `expiration`, `storage`, `*PREFIX*filecache`.`parent` as `file_parent`, '
  2325. . '`name`, `mtime`, `mimetype`, `mimepart`, `size`, `encrypted`, `etag`, `mail_send`';
  2326. } else {
  2327. $select = '`*PREFIX*share`.`id`, `item_type`, `item_source`, `item_target`,'
  2328. . '`*PREFIX*share`.`parent`, `share_type`, `share_with`, `uid_owner`,'
  2329. . '`file_source`, `path`, `file_target`, `*PREFIX*share`.`permissions`,'
  2330. . '`stime`, `expiration`, `token`, `storage`, `mail_send`,'
  2331. . '`*PREFIX*storages`.`id` AS `storage_id`, `*PREFIX*filecache`.`parent` as `file_parent`';
  2332. }
  2333. }
  2334. }
  2335. }
  2336. return $select;
  2337. }
  2338. /**
  2339. * transform db results
  2340. * @param array $row result
  2341. */
  2342. private static function transformDBResults(&$row) {
  2343. if (isset($row['id'])) {
  2344. $row['id'] = (int) $row['id'];
  2345. }
  2346. if (isset($row['share_type'])) {
  2347. $row['share_type'] = (int) $row['share_type'];
  2348. }
  2349. if (isset($row['parent'])) {
  2350. $row['parent'] = (int) $row['parent'];
  2351. }
  2352. if (isset($row['file_parent'])) {
  2353. $row['file_parent'] = (int) $row['file_parent'];
  2354. }
  2355. if (isset($row['file_source'])) {
  2356. $row['file_source'] = (int) $row['file_source'];
  2357. }
  2358. if (isset($row['permissions'])) {
  2359. $row['permissions'] = (int) $row['permissions'];
  2360. }
  2361. if (isset($row['storage'])) {
  2362. $row['storage'] = (int) $row['storage'];
  2363. }
  2364. if (isset($row['stime'])) {
  2365. $row['stime'] = (int) $row['stime'];
  2366. }
  2367. if (isset($row['expiration']) && $row['share_type'] !== self::SHARE_TYPE_LINK) {
  2368. // discard expiration date for non-link shares, which might have been
  2369. // set by ancient bugs
  2370. $row['expiration'] = null;
  2371. }
  2372. }
  2373. /**
  2374. * format result
  2375. * @param array $items result
  2376. * @param string $column is it a file share or a general share ('file_target' or 'item_target')
  2377. * @param \OCP\Share_Backend $backend sharing backend
  2378. * @param int $format
  2379. * @param array $parameters additional format parameters
  2380. * @return array format result
  2381. */
  2382. private static function formatResult($items, $column, $backend, $format = self::FORMAT_NONE , $parameters = null) {
  2383. if ($format === self::FORMAT_NONE) {
  2384. return $items;
  2385. } else if ($format === self::FORMAT_STATUSES) {
  2386. $statuses = array();
  2387. foreach ($items as $item) {
  2388. if ($item['share_type'] === self::SHARE_TYPE_LINK) {
  2389. if ($item['uid_initiator'] !== \OC::$server->getUserSession()->getUser()->getUID()) {
  2390. continue;
  2391. }
  2392. $statuses[$item[$column]]['link'] = true;
  2393. } else if (!isset($statuses[$item[$column]])) {
  2394. $statuses[$item[$column]]['link'] = false;
  2395. }
  2396. if (!empty($item['file_target'])) {
  2397. $statuses[$item[$column]]['path'] = $item['path'];
  2398. }
  2399. }
  2400. return $statuses;
  2401. } else {
  2402. return $backend->formatItems($items, $format, $parameters);
  2403. }
  2404. }
  2405. /**
  2406. * remove protocol from URL
  2407. *
  2408. * @param string $url
  2409. * @return string
  2410. */
  2411. public static function removeProtocolFromUrl($url) {
  2412. if (strpos($url, 'https://') === 0) {
  2413. return substr($url, strlen('https://'));
  2414. } else if (strpos($url, 'http://') === 0) {
  2415. return substr($url, strlen('http://'));
  2416. }
  2417. return $url;
  2418. }
  2419. /**
  2420. * try http post first with https and then with http as a fallback
  2421. *
  2422. * @param string $remoteDomain
  2423. * @param string $urlSuffix
  2424. * @param array $fields post parameters
  2425. * @return array
  2426. */
  2427. private static function tryHttpPostToShareEndpoint($remoteDomain, $urlSuffix, array $fields) {
  2428. $protocol = 'https://';
  2429. $result = [
  2430. 'success' => false,
  2431. 'result' => '',
  2432. ];
  2433. $try = 0;
  2434. $discoveryManager = new DiscoveryManager(
  2435. \OC::$server->getMemCacheFactory(),
  2436. \OC::$server->getHTTPClientService()
  2437. );
  2438. while ($result['success'] === false && $try < 2) {
  2439. $endpoint = $discoveryManager->getShareEndpoint($protocol . $remoteDomain);
  2440. $result = \OC::$server->getHTTPHelper()->post($protocol . $remoteDomain . $endpoint . $urlSuffix . '?format=' . self::RESPONSE_FORMAT, $fields);
  2441. $try++;
  2442. $protocol = 'http://';
  2443. }
  2444. return $result;
  2445. }
  2446. /**
  2447. * send server-to-server share to remote server
  2448. *
  2449. * @param string $token
  2450. * @param string $shareWith
  2451. * @param string $name
  2452. * @param int $remote_id
  2453. * @param string $owner
  2454. * @return bool
  2455. */
  2456. private static function sendRemoteShare($token, $shareWith, $name, $remote_id, $owner) {
  2457. list($user, $remote) = Helper::splitUserRemote($shareWith);
  2458. if ($user && $remote) {
  2459. $url = $remote;
  2460. $local = \OC::$server->getURLGenerator()->getAbsoluteURL('/');
  2461. $fields = array(
  2462. 'shareWith' => $user,
  2463. 'token' => $token,
  2464. 'name' => $name,
  2465. 'remoteId' => $remote_id,
  2466. 'owner' => $owner,
  2467. 'remote' => $local,
  2468. );
  2469. $url = self::removeProtocolFromUrl($url);
  2470. $result = self::tryHttpPostToShareEndpoint($url, '', $fields);
  2471. $status = json_decode($result['result'], true);
  2472. if ($result['success'] && ($status['ocs']['meta']['statuscode'] === 100 || $status['ocs']['meta']['statuscode'] === 200)) {
  2473. \OC_Hook::emit('OCP\Share', 'federated_share_added', ['server' => $remote]);
  2474. return true;
  2475. }
  2476. }
  2477. return false;
  2478. }
  2479. /**
  2480. * send server-to-server unshare to remote server
  2481. *
  2482. * @param string $remote url
  2483. * @param int $id share id
  2484. * @param string $token
  2485. * @return bool
  2486. */
  2487. private static function sendRemoteUnshare($remote, $id, $token) {
  2488. $url = rtrim($remote, '/');
  2489. $fields = array('token' => $token, 'format' => 'json');
  2490. $url = self::removeProtocolFromUrl($url);
  2491. $result = self::tryHttpPostToShareEndpoint($url, '/'.$id.'/unshare', $fields);
  2492. $status = json_decode($result['result'], true);
  2493. return ($result['success'] && ($status['ocs']['meta']['statuscode'] === 100 || $status['ocs']['meta']['statuscode'] === 200));
  2494. }
  2495. /**
  2496. * check if user can only share with group members
  2497. * @return bool
  2498. */
  2499. public static function shareWithGroupMembersOnly() {
  2500. $value = \OC::$server->getAppConfig()->getValue('core', 'shareapi_only_share_with_group_members', 'no');
  2501. return ($value === 'yes') ? true : false;
  2502. }
  2503. /**
  2504. * @return bool
  2505. */
  2506. public static function isDefaultExpireDateEnabled() {
  2507. $defaultExpireDateEnabled = \OCP\Config::getAppValue('core', 'shareapi_default_expire_date', 'no');
  2508. return ($defaultExpireDateEnabled === "yes") ? true : false;
  2509. }
  2510. /**
  2511. * @return bool
  2512. */
  2513. public static function enforceDefaultExpireDate() {
  2514. $enforceDefaultExpireDate = \OCP\Config::getAppValue('core', 'shareapi_enforce_expire_date', 'no');
  2515. return ($enforceDefaultExpireDate === "yes") ? true : false;
  2516. }
  2517. /**
  2518. * @return int
  2519. */
  2520. public static function getExpireInterval() {
  2521. return (int)\OCP\Config::getAppValue('core', 'shareapi_expire_after_n_days', '7');
  2522. }
  2523. /**
  2524. * Checks whether the given path is reachable for the given owner
  2525. *
  2526. * @param string $path path relative to files
  2527. * @param string $ownerStorageId storage id of the owner
  2528. *
  2529. * @return boolean true if file is reachable, false otherwise
  2530. */
  2531. private static function isFileReachable($path, $ownerStorageId) {
  2532. // if outside the home storage, file is always considered reachable
  2533. if (!(substr($ownerStorageId, 0, 6) === 'home::' ||
  2534. substr($ownerStorageId, 0, 13) === 'object::user:'
  2535. )) {
  2536. return true;
  2537. }
  2538. // if inside the home storage, the file has to be under "/files/"
  2539. $path = ltrim($path, '/');
  2540. if (substr($path, 0, 6) === 'files/') {
  2541. return true;
  2542. }
  2543. return false;
  2544. }
  2545. /**
  2546. * @param IConfig $config
  2547. * @return bool
  2548. */
  2549. public static function enforcePassword(IConfig $config) {
  2550. $enforcePassword = $config->getAppValue('core', 'shareapi_enforce_links_password', 'no');
  2551. return ($enforcePassword === "yes") ? true : false;
  2552. }
  2553. /**
  2554. * Get all share entries, including non-unique group items
  2555. *
  2556. * @param string $owner
  2557. * @return array
  2558. */
  2559. public static function getAllSharesForOwner($owner) {
  2560. $query = 'SELECT * FROM `*PREFIX*share` WHERE `uid_owner` = ?';
  2561. $result = \OC::$server->getDatabaseConnection()->executeQuery($query, [$owner]);
  2562. return $result->fetchAll();
  2563. }
  2564. /**
  2565. * Get all share entries, including non-unique group items for a file
  2566. *
  2567. * @param int $id
  2568. * @return array
  2569. */
  2570. public static function getAllSharesForFileId($id) {
  2571. $query = 'SELECT * FROM `*PREFIX*share` WHERE `file_source` = ?';
  2572. $result = \OC::$server->getDatabaseConnection()->executeQuery($query, [$id]);
  2573. return $result->fetchAll();
  2574. }
  2575. /**
  2576. * @param string $password
  2577. * @throws \Exception
  2578. */
  2579. private static function verifyPassword($password) {
  2580. $accepted = true;
  2581. $message = '';
  2582. \OCP\Util::emitHook('\OC\Share', 'verifyPassword', [
  2583. 'password' => $password,
  2584. 'accepted' => &$accepted,
  2585. 'message' => &$message
  2586. ]);
  2587. if (!$accepted) {
  2588. throw new \Exception($message);
  2589. }
  2590. }
  2591. }