AuthorizationManager.js 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. const CollaboratorsGetter = require('../Collaborators/CollaboratorsGetter')
  2. const CollaboratorsHandler = require('../Collaborators/CollaboratorsHandler')
  3. const ProjectGetter = require('../Project/ProjectGetter')
  4. const { User } = require('../../models/User')
  5. const PrivilegeLevels = require('./PrivilegeLevels')
  6. const TokenAccessHandler = require('../TokenAccess/TokenAccessHandler')
  7. const PublicAccessLevels = require('./PublicAccessLevels')
  8. const Errors = require('../Errors/Errors')
  9. const { ObjectId } = require('mongodb')
  10. const { promisifyAll } = require('../../util/promises')
  11. const AuthorizationManager = {
  12. isRestrictedUser(userId, privilegeLevel, isTokenMember) {
  13. if (privilegeLevel === PrivilegeLevels.NONE) {
  14. return true
  15. }
  16. return (
  17. privilegeLevel === PrivilegeLevels.READ_ONLY && (isTokenMember || !userId)
  18. )
  19. },
  20. isRestrictedUserForProject(userId, projectId, token, callback) {
  21. AuthorizationManager.getPrivilegeLevelForProject(
  22. userId,
  23. projectId,
  24. token,
  25. (err, privilegeLevel) => {
  26. if (err) {
  27. return callback(err)
  28. }
  29. CollaboratorsHandler.userIsTokenMember(
  30. userId,
  31. projectId,
  32. (err, isTokenMember) => {
  33. if (err) {
  34. return callback(err)
  35. }
  36. callback(
  37. null,
  38. AuthorizationManager.isRestrictedUser(
  39. userId,
  40. privilegeLevel,
  41. isTokenMember
  42. )
  43. )
  44. }
  45. )
  46. }
  47. )
  48. },
  49. getPublicAccessLevel(projectId, callback) {
  50. if (!ObjectId.isValid(projectId)) {
  51. return callback(new Error('invalid project id'))
  52. }
  53. // Note, the Project property in the DB is `publicAccesLevel`, without the second `s`
  54. ProjectGetter.getProject(
  55. projectId,
  56. { publicAccesLevel: 1 },
  57. function (error, project) {
  58. if (error) {
  59. return callback(error)
  60. }
  61. if (!project) {
  62. return callback(
  63. new Errors.NotFoundError(`no project found with id ${projectId}`)
  64. )
  65. }
  66. callback(null, project.publicAccesLevel)
  67. }
  68. )
  69. },
  70. // Get the privilege level that the user has for the project
  71. // Returns:
  72. // * privilegeLevel: "owner", "readAndWrite", of "readOnly" if the user has
  73. // access. false if the user does not have access
  74. // * becausePublic: true if the access level is only because the project is public.
  75. // * becauseSiteAdmin: true if access level is only because user is admin
  76. getPrivilegeLevelForProject(userId, projectId, token, callback) {
  77. if (userId) {
  78. AuthorizationManager.getPrivilegeLevelForProjectWithUser(
  79. userId,
  80. projectId,
  81. token,
  82. callback
  83. )
  84. } else {
  85. AuthorizationManager.getPrivilegeLevelForProjectWithoutUser(
  86. projectId,
  87. token,
  88. callback
  89. )
  90. }
  91. },
  92. // User is present, get their privilege level from database
  93. getPrivilegeLevelForProjectWithUser(userId, projectId, token, callback) {
  94. CollaboratorsGetter.getMemberIdPrivilegeLevel(
  95. userId,
  96. projectId,
  97. function (error, privilegeLevel) {
  98. if (error) {
  99. return callback(error)
  100. }
  101. if (privilegeLevel && privilegeLevel !== PrivilegeLevels.NONE) {
  102. // The user has direct access
  103. return callback(null, privilegeLevel, false, false)
  104. }
  105. AuthorizationManager.isUserSiteAdmin(userId, function (error, isAdmin) {
  106. if (error) {
  107. return callback(error)
  108. }
  109. if (isAdmin) {
  110. return callback(null, PrivilegeLevels.OWNER, false, true)
  111. }
  112. // Legacy public-access system
  113. // User is present (not anonymous), but does not have direct access
  114. AuthorizationManager.getPublicAccessLevel(
  115. projectId,
  116. function (err, publicAccessLevel) {
  117. if (err) {
  118. return callback(err)
  119. }
  120. if (publicAccessLevel === PublicAccessLevels.READ_ONLY) {
  121. return callback(null, PrivilegeLevels.READ_ONLY, true, false)
  122. }
  123. if (publicAccessLevel === PublicAccessLevels.READ_AND_WRITE) {
  124. return callback(
  125. null,
  126. PrivilegeLevels.READ_AND_WRITE,
  127. true,
  128. false
  129. )
  130. }
  131. callback(null, PrivilegeLevels.NONE, false, false)
  132. }
  133. )
  134. })
  135. }
  136. )
  137. },
  138. // User is Anonymous, Try Token-based access
  139. getPrivilegeLevelForProjectWithoutUser(projectId, token, callback) {
  140. AuthorizationManager.getPublicAccessLevel(
  141. projectId,
  142. function (err, publicAccessLevel) {
  143. if (err) {
  144. return callback(err)
  145. }
  146. if (publicAccessLevel === PublicAccessLevels.READ_ONLY) {
  147. // Legacy public read-only access for anonymous user
  148. return callback(null, PrivilegeLevels.READ_ONLY, true, false)
  149. }
  150. if (publicAccessLevel === PublicAccessLevels.READ_AND_WRITE) {
  151. // Legacy public read-write access for anonymous user
  152. return callback(null, PrivilegeLevels.READ_AND_WRITE, true, false)
  153. }
  154. if (publicAccessLevel === PublicAccessLevels.TOKEN_BASED) {
  155. return AuthorizationManager.getPrivilegeLevelForProjectWithToken(
  156. projectId,
  157. token,
  158. callback
  159. )
  160. }
  161. // Deny anonymous user access
  162. callback(null, PrivilegeLevels.NONE, false, false)
  163. }
  164. )
  165. },
  166. getPrivilegeLevelForProjectWithToken(projectId, token, callback) {
  167. // Anonymous users can have read-only access to token-based projects,
  168. // while read-write access must be logged in,
  169. // unless the `enableAnonymousReadAndWriteSharing` setting is enabled
  170. TokenAccessHandler.validateTokenForAnonymousAccess(
  171. projectId,
  172. token,
  173. function (err, isValidReadAndWrite, isValidReadOnly) {
  174. if (err) {
  175. return callback(err)
  176. }
  177. if (isValidReadOnly) {
  178. // Grant anonymous user read-only access
  179. return callback(null, PrivilegeLevels.READ_ONLY, false, false)
  180. }
  181. if (isValidReadAndWrite) {
  182. // Grant anonymous user read-and-write access
  183. return callback(null, PrivilegeLevels.READ_AND_WRITE, false, false)
  184. }
  185. // Deny anonymous access
  186. callback(null, PrivilegeLevels.NONE, false, false)
  187. }
  188. )
  189. },
  190. canUserReadProject(userId, projectId, token, callback) {
  191. AuthorizationManager.getPrivilegeLevelForProject(
  192. userId,
  193. projectId,
  194. token,
  195. function (error, privilegeLevel) {
  196. if (error) {
  197. return callback(error)
  198. }
  199. callback(
  200. null,
  201. [
  202. PrivilegeLevels.OWNER,
  203. PrivilegeLevels.READ_AND_WRITE,
  204. PrivilegeLevels.READ_ONLY,
  205. ].includes(privilegeLevel)
  206. )
  207. }
  208. )
  209. },
  210. canUserWriteProjectContent(userId, projectId, token, callback) {
  211. AuthorizationManager.getPrivilegeLevelForProject(
  212. userId,
  213. projectId,
  214. token,
  215. function (error, privilegeLevel) {
  216. if (error) {
  217. return callback(error)
  218. }
  219. callback(
  220. null,
  221. [PrivilegeLevels.OWNER, PrivilegeLevels.READ_AND_WRITE].includes(
  222. privilegeLevel
  223. )
  224. )
  225. }
  226. )
  227. },
  228. canUserWriteProjectSettings(userId, projectId, token, callback) {
  229. AuthorizationManager.getPrivilegeLevelForProject(
  230. userId,
  231. projectId,
  232. token,
  233. function (error, privilegeLevel, becausePublic) {
  234. if (error) {
  235. return callback(error)
  236. }
  237. if (privilegeLevel === PrivilegeLevels.OWNER) {
  238. return callback(null, true)
  239. }
  240. if (
  241. privilegeLevel === PrivilegeLevels.READ_AND_WRITE &&
  242. !becausePublic
  243. ) {
  244. return callback(null, true)
  245. }
  246. callback(null, false)
  247. }
  248. )
  249. },
  250. canUserAdminProject(userId, projectId, token, callback) {
  251. AuthorizationManager.getPrivilegeLevelForProject(
  252. userId,
  253. projectId,
  254. token,
  255. function (error, privilegeLevel, becausePublic, becauseSiteAdmin) {
  256. if (error) {
  257. return callback(error)
  258. }
  259. callback(
  260. null,
  261. privilegeLevel === PrivilegeLevels.OWNER,
  262. becauseSiteAdmin
  263. )
  264. }
  265. )
  266. },
  267. isUserSiteAdmin(userId, callback) {
  268. if (!userId) {
  269. return callback(null, false)
  270. }
  271. User.findOne({ _id: userId }, { isAdmin: 1 }, function (error, user) {
  272. if (error) {
  273. return callback(error)
  274. }
  275. callback(null, (user && user.isAdmin) === true)
  276. })
  277. },
  278. }
  279. module.exports = AuthorizationManager
  280. module.exports.promises = promisifyAll(AuthorizationManager, {
  281. without: 'isRestrictedUser',
  282. })