mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-11-15 06:33:55 +01:00
add option to disable link sharing (#27626)
* add option to remove link-sharing from backend * restrict make link-sharing in the frontend based on capability * extend e2e project-sharing tests to cover OVERLEAF_DISABLE_LINK_SHARING=true * throw an error when link sharing is disabled in TokenAccessHandler * throw errors when attempting to add users to projects with link sharing disabled * Update server-ce/test/project-sharing.spec.ts Co-authored-by: Jakob Ackermann <jakob.ackermann@overleaf.com> * add tests for existing access when link sharing is disabled * update tests to specify access restrictions for read-only and read-write link shared projects * [web] block access to legacy public project with link-sharing disabled --------- Co-authored-by: Jakob Ackermann <jakob.ackermann@overleaf.com> GitOrigin-RevId: 5f194dbcb790e973e427c58a3a4a738a5dd74cb4
This commit is contained in:
committed by
Copybot
co-authored by
Jakob Ackermann
parent
0138ae0dff
commit
f5dbbadf79
@@ -1,5 +1,6 @@
|
||||
const { callbackify } = require('util')
|
||||
const { ObjectId } = require('mongodb-legacy')
|
||||
const Features = require('../../infrastructure/Features')
|
||||
const CollaboratorsGetter = require('../Collaborators/CollaboratorsGetter')
|
||||
const CollaboratorsHandler = require('../Collaborators/CollaboratorsHandler')
|
||||
const ProjectGetter = require('../Project/ProjectGetter')
|
||||
@@ -213,6 +214,10 @@ async function _getPrivilegeLevelForProjectWithoutUserWithPublicAccessLevel(
|
||||
publicAccessLevel,
|
||||
opts = {}
|
||||
) {
|
||||
if (!Features.hasFeature('link-sharing')) {
|
||||
// Link sharing disabled globally.
|
||||
return PrivilegeLevels.NONE
|
||||
}
|
||||
if (!opts.ignorePublicAccess) {
|
||||
if (publicAccessLevel === PublicAccessLevels.READ_ONLY) {
|
||||
// Legacy public read-only access for anonymous user
|
||||
|
||||
@@ -14,6 +14,7 @@ import { hasAdminAccess } from '../Helpers/AdminAuthorizationHelper.js'
|
||||
import TokenAccessHandler from '../TokenAccess/TokenAccessHandler.js'
|
||||
import ProjectAuditLogHandler from '../Project/ProjectAuditLogHandler.js'
|
||||
import LimitationsManager from '../Subscription/LimitationsManager.js'
|
||||
import Features from '../../infrastructure/Features.js'
|
||||
|
||||
const ObjectId = mongodb.ObjectId
|
||||
|
||||
@@ -159,6 +160,10 @@ async function getShareTokens(req, res) {
|
||||
const projectId = req.params.Project_id
|
||||
const userId = SessionManager.getLoggedInUserId(req.session)
|
||||
|
||||
if (!Features.hasFeature('link-sharing')) {
|
||||
return res.sendStatus(403) // return Forbidden if link sharing is not enabled
|
||||
}
|
||||
|
||||
let tokens
|
||||
if (userId) {
|
||||
tokens = await CollaboratorsGetter.promises.getPublicShareTokens(
|
||||
|
||||
@@ -107,6 +107,9 @@ const _ProjectController = {
|
||||
async updateProjectAdminSettings(req, res) {
|
||||
const projectId = req.params.Project_id
|
||||
const user = SessionManager.getSessionUser(req.session)
|
||||
if (!Features.hasFeature('link-sharing')) {
|
||||
return res.sendStatus(403) // return Forbidden if link sharing is not enabled
|
||||
}
|
||||
const publicAccessLevel = req.body.publicAccessLevel
|
||||
const publicAccessLevels = [
|
||||
PublicAccessLevels.READ_ONLY,
|
||||
@@ -694,6 +697,15 @@ const _ProjectController = {
|
||||
capabilities.push('chat')
|
||||
}
|
||||
|
||||
// Note: this is not part of the default capabilities in the backend.
|
||||
// See services/web/modules/group-settings/app/src/DefaultGroupPolicy.mjs.
|
||||
// We are only using it on the frontend at the moment.
|
||||
// Add !Features.hasFeature('saas') to the conditional, as for chat above
|
||||
// if you define the capability in the backend.
|
||||
if (Features.hasFeature('link-sharing')) {
|
||||
capabilities.push('link-sharing')
|
||||
}
|
||||
|
||||
const isOverleafAssistBundleEnabled =
|
||||
splitTestAssignments['overleaf-assist-bundle']?.variant === 'enabled'
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ const V1Api = require('../V1/V1Api')
|
||||
const crypto = require('crypto')
|
||||
const { callbackifyAll } = require('@overleaf/promise-utils')
|
||||
const Analytics = require('../Analytics/AnalyticsManager')
|
||||
|
||||
const Features = require('../../infrastructure/Features')
|
||||
const READ_AND_WRITE_TOKEN_PATTERN = '([0-9]+[a-z]{6,12})'
|
||||
const READ_ONLY_TOKEN_PATTERN = '([a-z]{12})'
|
||||
|
||||
@@ -152,6 +152,9 @@ const TokenAccessHandler = {
|
||||
},
|
||||
|
||||
async addReadOnlyUserToProject(userId, projectId, ownerId) {
|
||||
if (!Features.hasFeature('link-sharing')) {
|
||||
throw new Error('link sharing is disabled')
|
||||
}
|
||||
userId = new ObjectId(userId.toString())
|
||||
projectId = new ObjectId(projectId.toString())
|
||||
Analytics.recordEventForUserInBackground(userId, 'project-joined', {
|
||||
@@ -202,6 +205,9 @@ const TokenAccessHandler = {
|
||||
},
|
||||
|
||||
grantSessionTokenAccess(req, projectId, token) {
|
||||
if (!Features.hasFeature('link-sharing')) {
|
||||
throw new Error('link sharing is disabled')
|
||||
}
|
||||
if (!req.session) {
|
||||
return
|
||||
}
|
||||
@@ -213,6 +219,7 @@ const TokenAccessHandler = {
|
||||
|
||||
getRequestToken(req, projectId) {
|
||||
const token =
|
||||
Features.hasFeature('link-sharing') &&
|
||||
req.session &&
|
||||
req.session.anonTokenAccess &&
|
||||
req.session.anonTokenAccess[projectId.toString()]
|
||||
@@ -220,7 +227,7 @@ const TokenAccessHandler = {
|
||||
},
|
||||
|
||||
async validateTokenForAnonymousAccess(projectId, token, callback) {
|
||||
if (!token) {
|
||||
if (!Features.hasFeature('link-sharing') || !token) {
|
||||
return { isValidReadAndWrite: false, isValidReadOnly: false }
|
||||
}
|
||||
|
||||
|
||||
@@ -69,6 +69,8 @@ const Features = {
|
||||
return Boolean(Settings.overleaf)
|
||||
case 'chat':
|
||||
return Boolean(Settings.disableChat) === false
|
||||
case 'link-sharing':
|
||||
return Boolean(Settings.disableLinkSharing) === false
|
||||
case 'github-sync':
|
||||
return Boolean(Settings.enableGithubSync)
|
||||
case 'git-bridge':
|
||||
|
||||
@@ -1226,39 +1226,41 @@ async function initialize(webRouter, privateApiRouter, publicApiRouter) {
|
||||
res.sendStatus(204)
|
||||
})
|
||||
|
||||
webRouter.get(
|
||||
`/read/:token(${TokenAccessController.READ_ONLY_TOKEN_PATTERN})`,
|
||||
RateLimiterMiddleware.rateLimit(rateLimiters.readOnlyToken),
|
||||
AnalyticsRegistrationSourceMiddleware.setSource(
|
||||
'collaboration',
|
||||
'link-sharing'
|
||||
),
|
||||
TokenAccessController.tokenAccessPage,
|
||||
AnalyticsRegistrationSourceMiddleware.clearSource()
|
||||
)
|
||||
if (Features.hasFeature('link-sharing')) {
|
||||
webRouter.get(
|
||||
`/read/:token(${TokenAccessController.READ_ONLY_TOKEN_PATTERN})`,
|
||||
RateLimiterMiddleware.rateLimit(rateLimiters.readOnlyToken),
|
||||
AnalyticsRegistrationSourceMiddleware.setSource(
|
||||
'collaboration',
|
||||
'link-sharing'
|
||||
),
|
||||
TokenAccessController.tokenAccessPage,
|
||||
AnalyticsRegistrationSourceMiddleware.clearSource()
|
||||
)
|
||||
|
||||
webRouter.get(
|
||||
`/:token(${TokenAccessController.READ_AND_WRITE_TOKEN_PATTERN})`,
|
||||
RateLimiterMiddleware.rateLimit(rateLimiters.readAndWriteToken),
|
||||
AnalyticsRegistrationSourceMiddleware.setSource(
|
||||
'collaboration',
|
||||
'link-sharing'
|
||||
),
|
||||
TokenAccessController.tokenAccessPage,
|
||||
AnalyticsRegistrationSourceMiddleware.clearSource()
|
||||
)
|
||||
webRouter.get(
|
||||
`/:token(${TokenAccessController.READ_AND_WRITE_TOKEN_PATTERN})`,
|
||||
RateLimiterMiddleware.rateLimit(rateLimiters.readAndWriteToken),
|
||||
AnalyticsRegistrationSourceMiddleware.setSource(
|
||||
'collaboration',
|
||||
'link-sharing'
|
||||
),
|
||||
TokenAccessController.tokenAccessPage,
|
||||
AnalyticsRegistrationSourceMiddleware.clearSource()
|
||||
)
|
||||
|
||||
webRouter.post(
|
||||
`/:token(${TokenAccessController.READ_AND_WRITE_TOKEN_PATTERN})/grant`,
|
||||
RateLimiterMiddleware.rateLimit(rateLimiters.grantTokenAccessReadWrite),
|
||||
TokenAccessController.grantTokenAccessReadAndWrite
|
||||
)
|
||||
webRouter.post(
|
||||
`/:token(${TokenAccessController.READ_AND_WRITE_TOKEN_PATTERN})/grant`,
|
||||
RateLimiterMiddleware.rateLimit(rateLimiters.grantTokenAccessReadWrite),
|
||||
TokenAccessController.grantTokenAccessReadAndWrite
|
||||
)
|
||||
|
||||
webRouter.post(
|
||||
`/read/:token(${TokenAccessController.READ_ONLY_TOKEN_PATTERN})/grant`,
|
||||
RateLimiterMiddleware.rateLimit(rateLimiters.grantTokenAccessReadOnly),
|
||||
TokenAccessController.grantTokenAccessReadOnly
|
||||
)
|
||||
webRouter.post(
|
||||
`/read/:token(${TokenAccessController.READ_ONLY_TOKEN_PATTERN})/grant`,
|
||||
RateLimiterMiddleware.rateLimit(rateLimiters.grantTokenAccessReadOnly),
|
||||
TokenAccessController.grantTokenAccessReadOnly
|
||||
)
|
||||
}
|
||||
|
||||
webRouter.get('/unsupported-browser', renderUnsupportedBrowserPage)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user