mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-21 20:47:08 -05:00
Merge pull request #16979 from overleaf/jpa-join-project-remove-sl-1
[misc] joinProject: pass userId and anonymous access token in body 1/2 GitOrigin-RevId: 5d7832246c7262c004c2cd465d62488384b35ee3
This commit is contained in:
parent
19ba6c6a15
commit
974069bf1c
9 changed files with 165 additions and 6 deletions
2
package-lock.json
generated
2
package-lock.json
generated
|
@ -45571,6 +45571,7 @@
|
||||||
"mocha": "^10.2.0",
|
"mocha": "^10.2.0",
|
||||||
"sandboxed-module": "~0.3.0",
|
"sandboxed-module": "~0.3.0",
|
||||||
"sinon": "^9.2.4",
|
"sinon": "^9.2.4",
|
||||||
|
"sinon-chai": "^3.7.0",
|
||||||
"timekeeper": "0.0.4",
|
"timekeeper": "0.0.4",
|
||||||
"typescript": "^5.0.4",
|
"typescript": "^5.0.4",
|
||||||
"uid-safe": "^2.1.5"
|
"uid-safe": "^2.1.5"
|
||||||
|
@ -54587,6 +54588,7 @@
|
||||||
"request": "^2.88.2",
|
"request": "^2.88.2",
|
||||||
"sandboxed-module": "~0.3.0",
|
"sandboxed-module": "~0.3.0",
|
||||||
"sinon": "^9.2.4",
|
"sinon": "^9.2.4",
|
||||||
|
"sinon-chai": "^3.7.0",
|
||||||
"socket.io": "github:overleaf/socket.io#0.9.19-overleaf-10",
|
"socket.io": "github:overleaf/socket.io#0.9.19-overleaf-10",
|
||||||
"socket.io-client": "github:overleaf/socket.io-client#0.9.17-overleaf-5",
|
"socket.io-client": "github:overleaf/socket.io-client#0.9.17-overleaf-5",
|
||||||
"timekeeper": "0.0.4",
|
"timekeeper": "0.0.4",
|
||||||
|
|
|
@ -27,7 +27,10 @@ module.exports = {
|
||||||
pass: settings.apis.web.pass,
|
pass: settings.apis.web.pass,
|
||||||
sendImmediately: true,
|
sendImmediately: true,
|
||||||
},
|
},
|
||||||
json: true,
|
json: {
|
||||||
|
userId,
|
||||||
|
anonymousAccessToken: user.anonymousAccessToken,
|
||||||
|
},
|
||||||
jar: false,
|
jar: false,
|
||||||
headers,
|
headers,
|
||||||
},
|
},
|
||||||
|
|
|
@ -44,6 +44,7 @@
|
||||||
"mocha": "^10.2.0",
|
"mocha": "^10.2.0",
|
||||||
"sandboxed-module": "~0.3.0",
|
"sandboxed-module": "~0.3.0",
|
||||||
"sinon": "^9.2.4",
|
"sinon": "^9.2.4",
|
||||||
|
"sinon-chai": "^3.7.0",
|
||||||
"timekeeper": "0.0.4",
|
"timekeeper": "0.0.4",
|
||||||
"typescript": "^5.0.4",
|
"typescript": "^5.0.4",
|
||||||
"uid-safe": "^2.1.5"
|
"uid-safe": "^2.1.5"
|
||||||
|
|
|
@ -1,9 +1,13 @@
|
||||||
const chai = require('chai')
|
const chai = require('chai')
|
||||||
const SandboxedModule = require('sandboxed-module')
|
const SandboxedModule = require('sandboxed-module')
|
||||||
const sinon = require('sinon')
|
const sinon = require('sinon')
|
||||||
|
const chaiAsPromised = require('chai-as-promised')
|
||||||
|
const sinonChai = require('sinon-chai')
|
||||||
|
|
||||||
// Chai configuration
|
// Chai configuration
|
||||||
chai.should()
|
chai.should()
|
||||||
|
chai.use(chaiAsPromised)
|
||||||
|
chai.use(sinonChai)
|
||||||
|
|
||||||
// Global stubs
|
// Global stubs
|
||||||
const sandbox = sinon.createSandbox()
|
const sandbox = sinon.createSandbox()
|
||||||
|
|
|
@ -68,7 +68,10 @@ describe('WebApiManager', function () {
|
||||||
pass: this.settings.apis.web.pass,
|
pass: this.settings.apis.web.pass,
|
||||||
sendImmediately: true,
|
sendImmediately: true,
|
||||||
},
|
},
|
||||||
json: true,
|
json: {
|
||||||
|
userId: this.user_id,
|
||||||
|
anonymousAccessToken: undefined,
|
||||||
|
},
|
||||||
jar: false,
|
jar: false,
|
||||||
headers: {},
|
headers: {},
|
||||||
})
|
})
|
||||||
|
@ -91,6 +94,65 @@ describe('WebApiManager', function () {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('with anon user', function () {
|
||||||
|
beforeEach(function () {
|
||||||
|
this.user_id = 'anonymous-user'
|
||||||
|
this.token = 'a-ro-token'
|
||||||
|
this.user = {
|
||||||
|
_id: this.user_id,
|
||||||
|
anonymousAccessToken: this.token,
|
||||||
|
}
|
||||||
|
this.response = {
|
||||||
|
project: { name: 'Test project' },
|
||||||
|
privilegeLevel: 'readOnly',
|
||||||
|
isRestrictedUser: true,
|
||||||
|
isTokenMember: false,
|
||||||
|
isInvitedMember: false,
|
||||||
|
}
|
||||||
|
this.request.post = sinon
|
||||||
|
.stub()
|
||||||
|
.yields(null, { statusCode: 200 }, this.response)
|
||||||
|
this.WebApiManager.joinProject(
|
||||||
|
this.project_id,
|
||||||
|
this.user,
|
||||||
|
this.callback
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should send a request to web to join the project', function () {
|
||||||
|
this.request.post.should.have.been.calledWith({
|
||||||
|
url: `${this.settings.apis.web.url}/project/${this.project_id}/join`,
|
||||||
|
qs: {
|
||||||
|
user_id: this.user_id,
|
||||||
|
},
|
||||||
|
auth: {
|
||||||
|
user: this.settings.apis.web.user,
|
||||||
|
pass: this.settings.apis.web.pass,
|
||||||
|
sendImmediately: true,
|
||||||
|
},
|
||||||
|
json: {
|
||||||
|
userId: this.user_id,
|
||||||
|
anonymousAccessToken: this.token,
|
||||||
|
},
|
||||||
|
jar: false,
|
||||||
|
headers: { 'x-sl-anonymous-access-token': this.token },
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return the project, privilegeLevel, and restricted flag', function () {
|
||||||
|
this.callback.should.have.been.calledWith(
|
||||||
|
null,
|
||||||
|
this.response.project,
|
||||||
|
this.response.privilegeLevel,
|
||||||
|
{
|
||||||
|
isRestrictedUser: this.response.isRestrictedUser,
|
||||||
|
isTokenMember: this.response.isTokenMember,
|
||||||
|
isInvitedMember: this.response.isInvitedMember,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
describe('when web replies with a 403', function () {
|
describe('when web replies with a 403', function () {
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
this.request.post = sinon
|
this.request.post = sinon
|
||||||
|
|
|
@ -57,7 +57,7 @@ const unsupportedSpellcheckLanguages = [
|
||||||
|
|
||||||
async function joinProject(req, res, next) {
|
async function joinProject(req, res, next) {
|
||||||
const projectId = req.params.Project_id
|
const projectId = req.params.Project_id
|
||||||
let userId = req.query.user_id // keep schema in sync with router
|
let userId = req.body.userId || req.query.user_id // keep schema in sync with router
|
||||||
if (userId === 'anonymous-user') {
|
if (userId === 'anonymous-user') {
|
||||||
userId = null
|
userId = null
|
||||||
}
|
}
|
||||||
|
@ -177,7 +177,8 @@ async function _buildJoinProjectView(req, projectId, userId) {
|
||||||
await CollaboratorsGetter.promises.getInvitedMembersWithPrivilegeLevels(
|
await CollaboratorsGetter.promises.getInvitedMembersWithPrivilegeLevels(
|
||||||
projectId
|
projectId
|
||||||
)
|
)
|
||||||
const token = req.headers['x-sl-anonymous-access-token']
|
const token =
|
||||||
|
req.body.anonymousAccessToken || req.headers['x-sl-anonymous-access-token']
|
||||||
const privilegeLevel =
|
const privilegeLevel =
|
||||||
await AuthorizationManager.promises.getPrivilegeLevelForProject(
|
await AuthorizationManager.promises.getPrivilegeLevelForProject(
|
||||||
userId,
|
userId,
|
||||||
|
|
|
@ -71,7 +71,7 @@ module.exports = {
|
||||||
RateLimiterMiddleware.rateLimit(rateLimiters.joinProject, {
|
RateLimiterMiddleware.rateLimit(rateLimiters.joinProject, {
|
||||||
params: ['Project_id'],
|
params: ['Project_id'],
|
||||||
// keep schema in sync with controller
|
// keep schema in sync with controller
|
||||||
getUserId: req => req.query.user_id,
|
getUserId: req => req.body.userId || req.query.user_id,
|
||||||
}),
|
}),
|
||||||
EditorHttpController.joinProject
|
EditorHttpController.joinProject
|
||||||
)
|
)
|
||||||
|
|
|
@ -160,7 +160,15 @@ const _doTryTokenAccept = (
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const tryContentAccess = (user, projcetId, test, callback) => {
|
const tryContentAccess = (user, projectId, test, callback) => {
|
||||||
|
tryContentAccessQuery(user, projectId, test, err1 => {
|
||||||
|
tryContentAccessBody(user, projectId, test, err2 => {
|
||||||
|
callback(err1 || err2)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const tryContentAccessQuery = (user, projcetId, test, callback) => {
|
||||||
// The real-time service calls this end point to determine the user's
|
// The real-time service calls this end point to determine the user's
|
||||||
// permissions.
|
// permissions.
|
||||||
let userId
|
let userId
|
||||||
|
@ -191,7 +199,47 @@ const tryContentAccess = (user, projcetId, test, callback) => {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const tryContentAccessBody = (user, projcetId, test, callback) => {
|
||||||
|
// The real-time service calls this end point to determine the user's
|
||||||
|
// permissions.
|
||||||
|
let userId
|
||||||
|
if (user.id != null) {
|
||||||
|
userId = user.id
|
||||||
|
} else {
|
||||||
|
userId = 'anonymous-user'
|
||||||
|
}
|
||||||
|
request.post(
|
||||||
|
{
|
||||||
|
url: `/project/${projcetId}/join`,
|
||||||
|
auth: {
|
||||||
|
user: settings.apis.web.user,
|
||||||
|
pass: settings.apis.web.pass,
|
||||||
|
sendImmediately: true,
|
||||||
|
},
|
||||||
|
json: {
|
||||||
|
userId,
|
||||||
|
},
|
||||||
|
jar: false,
|
||||||
|
},
|
||||||
|
(error, response, body) => {
|
||||||
|
if (error != null) {
|
||||||
|
return callback(error)
|
||||||
|
}
|
||||||
|
test(response, body)
|
||||||
|
callback()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
const tryAnonContentAccess = (user, projectId, token, test, callback) => {
|
const tryAnonContentAccess = (user, projectId, token, test, callback) => {
|
||||||
|
tryAnonContentAccessHeader(user, projectId, token, test, err1 => {
|
||||||
|
tryAnonContentAccessBody(user, projectId, token, test, err2 => {
|
||||||
|
callback(err1 || err2)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const tryAnonContentAccessHeader = (user, projectId, token, test, callback) => {
|
||||||
// The real-time service calls this end point to determine the user's
|
// The real-time service calls this end point to determine the user's
|
||||||
// permissions.
|
// permissions.
|
||||||
let userId
|
let userId
|
||||||
|
@ -225,6 +273,39 @@ const tryAnonContentAccess = (user, projectId, token, test, callback) => {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const tryAnonContentAccessBody = (user, projectId, token, test, callback) => {
|
||||||
|
// The real-time service calls this end point to determine the user's
|
||||||
|
// permissions.
|
||||||
|
let userId
|
||||||
|
if (user.id != null) {
|
||||||
|
userId = user.id
|
||||||
|
} else {
|
||||||
|
userId = 'anonymous-user'
|
||||||
|
}
|
||||||
|
request.post(
|
||||||
|
{
|
||||||
|
url: `/project/${projectId}/join`,
|
||||||
|
auth: {
|
||||||
|
user: settings.apis.web.user,
|
||||||
|
pass: settings.apis.web.pass,
|
||||||
|
sendImmediately: true,
|
||||||
|
},
|
||||||
|
json: {
|
||||||
|
userId,
|
||||||
|
anonymousAccessToken: token,
|
||||||
|
},
|
||||||
|
jar: false,
|
||||||
|
},
|
||||||
|
(error, response, body) => {
|
||||||
|
if (error != null) {
|
||||||
|
return callback(error)
|
||||||
|
}
|
||||||
|
test(response, body)
|
||||||
|
callback()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
const tryFetchProjectTokens = (user, projectId, callback) => {
|
const tryFetchProjectTokens = (user, projectId, callback) => {
|
||||||
user.request.get(
|
user.request.get(
|
||||||
{ url: `/project/${projectId}/tokens`, json: true },
|
{ url: `/project/${projectId}/tokens`, json: true },
|
||||||
|
|
|
@ -167,6 +167,7 @@ describe('EditorHttpController', function () {
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
this.req.params = { Project_id: this.project._id }
|
this.req.params = { Project_id: this.project._id }
|
||||||
this.req.query = { user_id: this.user._id }
|
this.req.query = { user_id: this.user._id }
|
||||||
|
this.req.body = { userId: this.user._id }
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('successfully', function () {
|
describe('successfully', function () {
|
||||||
|
@ -251,6 +252,10 @@ describe('EditorHttpController', function () {
|
||||||
beforeEach(function (done) {
|
beforeEach(function (done) {
|
||||||
this.token = 'token'
|
this.token = 'token'
|
||||||
this.TokenAccessHandler.getRequestToken.returns(this.token)
|
this.TokenAccessHandler.getRequestToken.returns(this.token)
|
||||||
|
this.req.body = {
|
||||||
|
userId: 'anonymous-user',
|
||||||
|
anonymousAccessToken: this.token,
|
||||||
|
}
|
||||||
this.req.query = { user_id: 'anonymous-user' }
|
this.req.query = { user_id: 'anonymous-user' }
|
||||||
this.req.headers = { 'x-sl-anonymous-access-token': this.token }
|
this.req.headers = { 'x-sl-anonymous-access-token': this.token }
|
||||||
this.res.callback = done
|
this.res.callback = done
|
||||||
|
|
Loading…
Reference in a new issue