AuthorizationManager.js 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  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('mongojs')
  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(projectId, { publicAccesLevel: 1 }, function(
  55. error,
  56. project
  57. ) {
  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. // Get the privilege level that the user has for the project
  70. // Returns:
  71. // * privilegeLevel: "owner", "readAndWrite", of "readOnly" if the user has
  72. // access. false if the user does not have access
  73. // * becausePublic: true if the access level is only because the project is public.
  74. // * becauseSiteAdmin: true if access level is only because user is admin
  75. getPrivilegeLevelForProject(userId, projectId, token, callback) {
  76. if (userId) {
  77. AuthorizationManager.getPrivilegeLevelForProjectWithUser(
  78. userId,
  79. projectId,
  80. token,
  81. callback
  82. )
  83. } else {
  84. AuthorizationManager.getPrivilegeLevelForProjectWithoutUser(
  85. projectId,
  86. token,
  87. callback
  88. )
  89. }
  90. },
  91. // User is present, get their privilege level from database
  92. getPrivilegeLevelForProjectWithUser(userId, projectId, token, callback) {
  93. CollaboratorsGetter.getMemberIdPrivilegeLevel(userId, projectId, function(
  94. error,
  95. privilegeLevel
  96. ) {
  97. if (error) {
  98. return callback(error)
  99. }
  100. if (privilegeLevel && privilegeLevel !== PrivilegeLevels.NONE) {
  101. // The user has direct access
  102. return callback(null, privilegeLevel, false, false)
  103. }
  104. AuthorizationManager.isUserSiteAdmin(userId, function(error, isAdmin) {
  105. if (error) {
  106. return callback(error)
  107. }
  108. if (isAdmin) {
  109. return callback(null, PrivilegeLevels.OWNER, false, true)
  110. }
  111. // Legacy public-access system
  112. // User is present (not anonymous), but does not have direct access
  113. AuthorizationManager.getPublicAccessLevel(projectId, function(
  114. err,
  115. publicAccessLevel
  116. ) {
  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(null, PrivilegeLevels.READ_AND_WRITE, true, false)
  125. }
  126. callback(null, PrivilegeLevels.NONE, false, false)
  127. })
  128. })
  129. })
  130. },
  131. // User is Anonymous, Try Token-based access
  132. getPrivilegeLevelForProjectWithoutUser(projectId, token, callback) {
  133. AuthorizationManager.getPublicAccessLevel(projectId, function(
  134. err,
  135. publicAccessLevel
  136. ) {
  137. if (err) {
  138. return callback(err)
  139. }
  140. if (publicAccessLevel === PublicAccessLevels.READ_ONLY) {
  141. // Legacy public read-only access for anonymous user
  142. return callback(null, PrivilegeLevels.READ_ONLY, true, false)
  143. }
  144. if (publicAccessLevel === PublicAccessLevels.READ_AND_WRITE) {
  145. // Legacy public read-write access for anonymous user
  146. return callback(null, PrivilegeLevels.READ_AND_WRITE, true, false)
  147. }
  148. if (publicAccessLevel === PublicAccessLevels.TOKEN_BASED) {
  149. return AuthorizationManager.getPrivilegeLevelForProjectWithToken(
  150. projectId,
  151. token,
  152. callback
  153. )
  154. }
  155. // Deny anonymous user access
  156. callback(null, PrivilegeLevels.NONE, false, false)
  157. })
  158. },
  159. getPrivilegeLevelForProjectWithToken(projectId, token, callback) {
  160. // Anonymous users can have read-only access to token-based projects,
  161. // while read-write access must be logged in,
  162. // unless the `enableAnonymousReadAndWriteSharing` setting is enabled
  163. TokenAccessHandler.validateTokenForAnonymousAccess(
  164. projectId,
  165. token,
  166. function(err, isValidReadAndWrite, isValidReadOnly) {
  167. if (err) {
  168. return callback(err)
  169. }
  170. if (isValidReadOnly) {
  171. // Grant anonymous user read-only access
  172. return callback(null, PrivilegeLevels.READ_ONLY, false, false)
  173. }
  174. if (isValidReadAndWrite) {
  175. // Grant anonymous user read-and-write access
  176. return callback(null, PrivilegeLevels.READ_AND_WRITE, false, false)
  177. }
  178. // Deny anonymous access
  179. callback(null, PrivilegeLevels.NONE, false, false)
  180. }
  181. )
  182. },
  183. canUserReadProject(userId, projectId, token, callback) {
  184. AuthorizationManager.getPrivilegeLevelForProject(
  185. userId,
  186. projectId,
  187. token,
  188. function(error, privilegeLevel) {
  189. if (error) {
  190. return callback(error)
  191. }
  192. callback(
  193. null,
  194. [
  195. PrivilegeLevels.OWNER,
  196. PrivilegeLevels.READ_AND_WRITE,
  197. PrivilegeLevels.READ_ONLY
  198. ].includes(privilegeLevel)
  199. )
  200. }
  201. )
  202. },
  203. canUserWriteProjectContent(userId, projectId, token, callback) {
  204. AuthorizationManager.getPrivilegeLevelForProject(
  205. userId,
  206. projectId,
  207. token,
  208. function(error, privilegeLevel) {
  209. if (error) {
  210. return callback(error)
  211. }
  212. callback(
  213. null,
  214. [PrivilegeLevels.OWNER, PrivilegeLevels.READ_AND_WRITE].includes(
  215. privilegeLevel
  216. )
  217. )
  218. }
  219. )
  220. },
  221. canUserWriteProjectSettings(userId, projectId, token, callback) {
  222. AuthorizationManager.getPrivilegeLevelForProject(
  223. userId,
  224. projectId,
  225. token,
  226. function(error, privilegeLevel, becausePublic) {
  227. if (error) {
  228. return callback(error)
  229. }
  230. if (privilegeLevel === PrivilegeLevels.OWNER) {
  231. return callback(null, true)
  232. }
  233. if (
  234. privilegeLevel === PrivilegeLevels.READ_AND_WRITE &&
  235. !becausePublic
  236. ) {
  237. return callback(null, true)
  238. }
  239. callback(null, false)
  240. }
  241. )
  242. },
  243. canUserAdminProject(userId, projectId, token, callback) {
  244. AuthorizationManager.getPrivilegeLevelForProject(
  245. userId,
  246. projectId,
  247. token,
  248. function(error, privilegeLevel, becausePublic, becauseSiteAdmin) {
  249. if (error) {
  250. return callback(error)
  251. }
  252. callback(
  253. null,
  254. privilegeLevel === PrivilegeLevels.OWNER,
  255. becauseSiteAdmin
  256. )
  257. }
  258. )
  259. },
  260. isUserSiteAdmin(userId, callback) {
  261. if (!userId) {
  262. return callback(null, false)
  263. }
  264. User.findOne({ _id: userId }, { isAdmin: 1 }, function(error, user) {
  265. if (error) {
  266. return callback(error)
  267. }
  268. callback(null, (user && user.isAdmin) === true)
  269. })
  270. }
  271. }
  272. module.exports = AuthorizationManager
  273. module.exports.promises = promisifyAll(AuthorizationManager, {
  274. without: 'isRestrictedUser'
  275. })