-
Notifications
You must be signed in to change notification settings - Fork 11.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
5f3d07c
commit 3d7876b
Showing
6 changed files
with
683 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
import { expect } from 'chai'; | ||
import { describe, it } from 'mocha'; | ||
import proxyquire from 'proxyquire'; | ||
import sinon from 'sinon'; | ||
|
||
const mocks = { | ||
utils: { | ||
userCanAccessAvatar: sinon.stub(), | ||
renderSVGLetters: sinon.stub(), | ||
}, | ||
}; | ||
|
||
const { protectAvatarsWithFallback } = proxyquire.noCallThru().load('./auth.ts', { | ||
'../utils': mocks.utils, | ||
}); | ||
|
||
describe('#protectAvatarsWithFallback()', () => { | ||
const response = { | ||
setHeader: sinon.spy(), | ||
writeHead: sinon.spy(), | ||
write: sinon.spy(), | ||
end: sinon.spy(), | ||
}; | ||
const next = sinon.spy(); | ||
|
||
afterEach(() => { | ||
response.setHeader.resetHistory(); | ||
response.writeHead.resetHistory(); | ||
response.end.resetHistory(); | ||
next.resetHistory(); | ||
|
||
Object.values(mocks.utils).forEach((mock) => mock.reset()); | ||
}); | ||
|
||
it(`should write 404 to head if no url provided`, async () => { | ||
await protectAvatarsWithFallback({}, response, next); | ||
expect(next.called).to.be.false; | ||
expect(response.setHeader.called).to.be.false; | ||
expect(response.writeHead.calledWith(404)).to.be.true; | ||
expect(response.end.calledOnce).to.be.true; | ||
}); | ||
|
||
it(`should write 200 to head and write fallback to body (user avatar)`, async () => { | ||
mocks.utils.renderSVGLetters.returns('fallback'); | ||
|
||
await protectAvatarsWithFallback({ url: '/jon' }, response, next); | ||
expect(next.called).to.be.false; | ||
expect(response.setHeader.called).to.be.false; | ||
|
||
expect(response.writeHead.calledWith(200, { 'Content-Type': 'image/svg+xml' })).to.be.true; | ||
expect(mocks.utils.renderSVGLetters.calledWith('jon')).to.be.true; | ||
expect(response.write.calledWith('fallback')).to.be.true; | ||
|
||
expect(response.end.calledOnce).to.be.true; | ||
}); | ||
|
||
it(`should write 200 to head and write fallback to body (user avatar)`, async () => { | ||
mocks.utils.renderSVGLetters.returns('fallback'); | ||
|
||
await protectAvatarsWithFallback({ url: '/jon' }, response, next); | ||
expect(next.called).to.be.false; | ||
expect(response.setHeader.called).to.be.false; | ||
expect(response.writeHead.calledWith(200, { 'Content-Type': 'image/svg+xml' })).to.be.true; | ||
expect(response.write.calledWith('fallback')).to.be.true; | ||
expect(response.end.calledOnce).to.be.true; | ||
}); | ||
|
||
it(`should write 200 to head and write fallback to body (room avatar)`, async () => { | ||
mocks.utils.renderSVGLetters.returns('fallback'); | ||
|
||
await protectAvatarsWithFallback({ url: '/room/jon' }, response, next); | ||
expect(next.called).to.be.false; | ||
expect(response.setHeader.called).to.be.false; | ||
expect(response.writeHead.calledWith(200, { 'Content-Type': 'image/svg+xml' })).to.be.true; | ||
expect(response.write.calledWith('fallback')).to.be.true; | ||
expect(response.end.calledOnce).to.be.true; | ||
}); | ||
|
||
it(`should call next if user can access avatar`, async () => { | ||
mocks.utils.userCanAccessAvatar.returns(true); | ||
const request = { url: '/jon' }; | ||
|
||
await protectAvatarsWithFallback(request, response, next); | ||
expect(mocks.utils.userCanAccessAvatar.calledWith(request)).to.be.true; | ||
expect(next.called).to.be.true; | ||
}); | ||
}); |
87 changes: 87 additions & 0 deletions
87
apps/meteor/server/routes/avatar/middlewares/browserVersion.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
import { expect } from 'chai'; | ||
import { describe, it } from 'mocha'; | ||
import proxyquire from 'proxyquire'; | ||
import sinon from 'sinon'; | ||
|
||
// const getCookie = sinon.stub(); | ||
class CookiesMock { | ||
public get = (_key: any, value: any) => value; | ||
} | ||
const { handleBrowserVersionCheck, isIEOlderThan11 } = proxyquire.noCallThru().load('./browserVersion', { | ||
'meteor/ostrio:cookies': { | ||
Cookies: CookiesMock, | ||
}, | ||
'../../../../app/utils/server/getURL': { | ||
getURL: () => '', | ||
}, | ||
}); | ||
|
||
describe('#isIEOlderThan11()', () => { | ||
it('should return false if user agent is IE11', () => { | ||
const userAgent = { | ||
browser: { | ||
name: 'IE', | ||
version: '11.0', | ||
}, | ||
}; | ||
expect(isIEOlderThan11(userAgent)).to.be.false; | ||
}); | ||
|
||
it('should return true if user agent is IE < 11', () => { | ||
const userAgent = { | ||
browser: { | ||
name: 'IE', | ||
version: '10.0', | ||
}, | ||
}; | ||
expect(isIEOlderThan11(userAgent)).to.be.true; | ||
}); | ||
}); | ||
|
||
describe('#handleBrowserVersionCheck()', () => { | ||
it('should call next if browser_version_check cookie is set to "bypass"', async () => { | ||
const next = sinon.spy(); | ||
const request = { | ||
headers: { | ||
cookie: 'bypass', | ||
}, | ||
}; | ||
handleBrowserVersionCheck(request as any, {} as any, next); | ||
|
||
expect(next.calledOnce).to.be.true; | ||
}); | ||
|
||
it('should call next if browser_version_check cookie is not set to "force" and user agent is not IE < 11', async () => { | ||
const next = sinon.spy(); | ||
const request = { | ||
headers: { | ||
'cookie': 'anything', | ||
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36', | ||
}, | ||
}; | ||
handleBrowserVersionCheck(request as any, {} as any, next); | ||
|
||
expect(next.calledOnce).to.be.true; | ||
}); | ||
|
||
it('should respond with Browser not supported', async () => { | ||
const next = sinon.spy(); | ||
const request = { | ||
headers: { | ||
'cookie': 'anything', | ||
'user-agent': 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 7.0; InfoPath.3; .NET CLR 3.1.40767; Trident/6.0; en-IN)', | ||
}, | ||
}; | ||
|
||
const response = { | ||
setHeader: sinon.spy(), | ||
write: sinon.spy(), | ||
end: sinon.spy(), | ||
}; | ||
handleBrowserVersionCheck(request as any, response as any, next); | ||
|
||
expect(response.setHeader.calledWith('content-type', 'text/html; charset=utf-8')).to.be.true; | ||
expect(response.write.calledWith(sinon.match('Browser not supported'))).to.be.true; | ||
expect(response.end.calledOnce).to.be.true; | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
import { expect } from 'chai'; | ||
import { describe, it } from 'mocha'; | ||
import proxyquire from 'proxyquire'; | ||
import sinon from 'sinon'; | ||
|
||
const mocks = { | ||
settingsGet: sinon.stub(), | ||
findOneById: sinon.stub(), | ||
utils: { | ||
serveSvgAvatarInRequestedFormat: sinon.spy(), | ||
wasFallbackModified: sinon.stub(), | ||
setCacheAndDispositionHeaders: sinon.spy(), | ||
serveAvatarFile: sinon.spy(), | ||
}, | ||
avatarFindOneByRoomId: sinon.stub(), | ||
getRoomName: sinon.stub(), | ||
}; | ||
|
||
class CookiesMock { | ||
public get = (_key: any, value: any) => value; | ||
} | ||
|
||
const { roomAvatar } = proxyquire.noCallThru().load('./room', { | ||
'@rocket.chat/models': { | ||
Rooms: { | ||
findOneById: mocks.findOneById, | ||
}, | ||
Avatars: { | ||
findOneByRoomId: mocks.avatarFindOneByRoomId, | ||
}, | ||
}, | ||
'../../../app/settings/server': { | ||
settings: { | ||
get: mocks.settingsGet, | ||
}, | ||
}, | ||
'./utils': mocks.utils, | ||
'../../lib/rooms/roomCoordinator': { | ||
roomCoordinator: { | ||
getRoomName: mocks.getRoomName, | ||
}, | ||
}, | ||
'meteor/ostrio:cookies': { | ||
Cookies: CookiesMock, | ||
}, | ||
}); | ||
|
||
describe('#roomAvatar()', () => { | ||
const response = { | ||
setHeader: sinon.spy(), | ||
writeHead: sinon.spy(), | ||
end: sinon.spy(), | ||
}; | ||
const next = sinon.spy(); | ||
|
||
afterEach(() => { | ||
mocks.settingsGet.reset(); | ||
mocks.avatarFindOneByRoomId.reset(); | ||
mocks.findOneById.reset(); | ||
|
||
response.setHeader.resetHistory(); | ||
response.writeHead.resetHistory(); | ||
response.end.resetHistory(); | ||
next.resetHistory(); | ||
|
||
Object.values(mocks.utils).forEach((mock) => ('reset' in mock ? mock.reset() : mock.resetHistory())); | ||
}); | ||
|
||
it(`should do nothing if url is not in request object`, async () => { | ||
await roomAvatar({}, response, next); | ||
expect(next.called).to.be.false; | ||
expect(response.setHeader.called).to.be.false; | ||
expect(response.writeHead.called).to.be.false; | ||
expect(response.end.called).to.be.false; | ||
}); | ||
|
||
it(`should write 404 if room is not found`, async () => { | ||
mocks.findOneById.returns(null); | ||
await roomAvatar({ url: '/' }, response, next); | ||
expect(next.called).to.be.false; | ||
expect(response.setHeader.called).to.be.false; | ||
expect(response.writeHead.calledWith(404)).to.be.true; | ||
expect(response.end.calledOnce).to.be.true; | ||
}); | ||
|
||
it(`should serve avatar file if found`, async () => { | ||
const request = { url: '/roomId' }; | ||
|
||
const file = { uploadedAt: new Date(0), type: 'image/png', size: 100 }; | ||
|
||
mocks.findOneById.withArgs('roomId').returns({ _id: 'roomId' }); | ||
mocks.avatarFindOneByRoomId.withArgs('roomId').returns(file); | ||
|
||
await roomAvatar(request, response, next); | ||
|
||
expect(mocks.utils.setCacheAndDispositionHeaders.calledWith(request, response)).to.be.true; | ||
expect(mocks.utils.serveAvatarFile.calledWith(file, request, response, next)).to.be.true; | ||
}); | ||
|
||
it(`should serve parent room avatar file if current room avatar is not found`, async () => { | ||
const request = { url: '/roomId' }; | ||
|
||
const file = { uploadedAt: new Date(0), type: 'image/png', size: 100 }; | ||
|
||
mocks.findOneById.withArgs('roomId').returns({ _id: 'roomId', prid: 'roomId2' }); | ||
mocks.findOneById.withArgs('roomId2').returns({ _id: 'roomId2' }); | ||
mocks.avatarFindOneByRoomId.withArgs('roomId2').returns(file); | ||
|
||
await roomAvatar(request, response, next); | ||
|
||
expect(mocks.utils.setCacheAndDispositionHeaders.calledWith(request, response)).to.be.true; | ||
expect(mocks.utils.serveAvatarFile.calledWith(file, request, response, next)).to.be.true; | ||
}); | ||
|
||
it(`should write 304 if fallback content is not modified`, async () => { | ||
const request = { url: '/roomId', headers: {} }; | ||
|
||
mocks.findOneById.withArgs('roomId').returns({ _id: 'roomId' }); | ||
mocks.utils.wasFallbackModified.returns(false); | ||
await roomAvatar(request, response, next); | ||
|
||
expect(mocks.utils.setCacheAndDispositionHeaders.calledWith(request, response)).to.be.true; | ||
expect(response.writeHead.calledWith(304)).to.be.true; | ||
expect(response.end.calledOnce).to.be.true; | ||
}); | ||
|
||
it(`should serve svg fallback if no file found`, async () => { | ||
const request = { url: '/roomId', headers: { cookie: 'userId' } }; | ||
|
||
mocks.utils.wasFallbackModified.returns(true); | ||
mocks.findOneById.withArgs('roomId').returns({ _id: 'roomId' }); | ||
mocks.getRoomName.returns('roomName'); | ||
|
||
await roomAvatar(request, response, next); | ||
|
||
expect(mocks.utils.setCacheAndDispositionHeaders.calledWith(request, response)).to.be.true; | ||
expect(mocks.utils.serveSvgAvatarInRequestedFormat.calledWith({ nameOrUsername: 'roomName', req: request, res: response })).to.be.true; | ||
}); | ||
}); |
Oops, something went wrong.