mirror of
https://github.com/ether/etherpad-lite.git
synced 2025-02-08 03:02:03 +01:00
tests: Move socket.io connection helpers to common.js
This commit is contained in:
parent
bea57ff249
commit
65bd597053
2 changed files with 161 additions and 146 deletions
|
@ -1,9 +1,11 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const apiHandler = require('../../node/handler/APIHandler');
|
const apiHandler = require('../../node/handler/APIHandler');
|
||||||
|
const io = require('socket.io-client');
|
||||||
const log4js = require('log4js');
|
const log4js = require('log4js');
|
||||||
const process = require('process');
|
const process = require('process');
|
||||||
const server = require('../../node/server');
|
const server = require('../../node/server');
|
||||||
|
const setCookieParser = require('set-cookie-parser');
|
||||||
const settings = require('../../node/utils/Settings');
|
const settings = require('../../node/utils/Settings');
|
||||||
const supertest = require('supertest');
|
const supertest = require('supertest');
|
||||||
const webaccess = require('../../node/hooks/express/webaccess');
|
const webaccess = require('../../node/hooks/express/webaccess');
|
||||||
|
@ -68,3 +70,101 @@ exports.init = async function () {
|
||||||
agentResolve(exports.agent);
|
agentResolve(exports.agent);
|
||||||
return exports.agent;
|
return exports.agent;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Waits for the next named socket.io event. Rejects if there is an error event while waiting
|
||||||
|
* (unless waiting for that error event).
|
||||||
|
*
|
||||||
|
* @param {io.Socket} socket - The socket.io Socket object to listen on.
|
||||||
|
* @param {string} event - The socket.io Socket event to listen for.
|
||||||
|
* @returns The argument(s) passed to the event handler.
|
||||||
|
*/
|
||||||
|
exports.getSocketEvent = async (socket, event) => {
|
||||||
|
const errorEvents = [
|
||||||
|
'error',
|
||||||
|
'connect_error',
|
||||||
|
'connect_timeout',
|
||||||
|
'reconnect_error',
|
||||||
|
'reconnect_failed',
|
||||||
|
];
|
||||||
|
const handlers = {};
|
||||||
|
let timeoutId;
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
timeoutId = setTimeout(() => reject(new Error(`timed out waiting for ${event} event`)), 1000);
|
||||||
|
for (const event of errorEvents) {
|
||||||
|
handlers[event] = (errorString) => {
|
||||||
|
logger.debug(`socket.io ${event} event: ${errorString}`);
|
||||||
|
reject(new Error(errorString));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// This will overwrite one of the above handlers if the user is waiting for an error event.
|
||||||
|
handlers[event] = (...args) => {
|
||||||
|
logger.debug(`socket.io ${event} event`);
|
||||||
|
if (args.length > 1) return resolve(args);
|
||||||
|
resolve(args[0]);
|
||||||
|
};
|
||||||
|
Object.entries(handlers).forEach(([event, handler]) => socket.on(event, handler));
|
||||||
|
}).finally(() => {
|
||||||
|
clearTimeout(timeoutId);
|
||||||
|
Object.entries(handlers).forEach(([event, handler]) => socket.off(event, handler));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Establishes a new socket.io connection.
|
||||||
|
*
|
||||||
|
* @param {object} [res] - Optional HTTP response object. The cookies from this response's
|
||||||
|
* `set-cookie` header(s) are passed to the server when opening the socket.io connection. If
|
||||||
|
* nullish, no cookies are passed to the server.
|
||||||
|
* @returns {io.Socket} A socket.io client Socket object.
|
||||||
|
*/
|
||||||
|
exports.connect = async (res = null) => {
|
||||||
|
// Convert the `set-cookie` header(s) into a `cookie` header.
|
||||||
|
const resCookies = (res == null) ? {} : setCookieParser.parse(res, {map: true});
|
||||||
|
const reqCookieHdr = Object.entries(resCookies).map(
|
||||||
|
([name, cookie]) => `${name}=${encodeURIComponent(cookie.value)}`).join('; ');
|
||||||
|
|
||||||
|
logger.debug('socket.io connecting...');
|
||||||
|
let padId = null;
|
||||||
|
if (res) {
|
||||||
|
padId = res.req.path.split('/p/')[1];
|
||||||
|
}
|
||||||
|
const socket = io(`${exports.baseUrl}/`, {
|
||||||
|
forceNew: true, // Different tests will have different query parameters.
|
||||||
|
path: '/socket.io',
|
||||||
|
// socketio.js-client on node.js doesn't support cookies (see https://git.io/JU8u9), so the
|
||||||
|
// express_sid cookie must be passed as a query parameter.
|
||||||
|
query: {cookie: reqCookieHdr, padId},
|
||||||
|
});
|
||||||
|
try {
|
||||||
|
await exports.getSocketEvent(socket, 'connect');
|
||||||
|
} catch (e) {
|
||||||
|
socket.close();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
logger.debug('socket.io connected');
|
||||||
|
|
||||||
|
return socket;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper function to exchange CLIENT_READY+CLIENT_VARS messages for the named pad.
|
||||||
|
*
|
||||||
|
* @param {io.Socket} socket - Connected socket.io Socket object.
|
||||||
|
* @param {string} padId - Which pad to join.
|
||||||
|
* @returns The CLIENT_VARS message from the server.
|
||||||
|
*/
|
||||||
|
exports.handshake = async (socket, padId) => {
|
||||||
|
logger.debug('sending CLIENT_READY...');
|
||||||
|
socket.send({
|
||||||
|
component: 'pad',
|
||||||
|
type: 'CLIENT_READY',
|
||||||
|
padId,
|
||||||
|
sessionID: null,
|
||||||
|
token: 't.12345',
|
||||||
|
});
|
||||||
|
logger.debug('waiting for CLIENT_VARS response...');
|
||||||
|
const msg = await exports.getSocketEvent(socket, 'message');
|
||||||
|
logger.debug('received CLIENT_VARS message');
|
||||||
|
return msg;
|
||||||
|
};
|
||||||
|
|
|
@ -2,97 +2,12 @@
|
||||||
|
|
||||||
const assert = require('assert').strict;
|
const assert = require('assert').strict;
|
||||||
const common = require('../common');
|
const common = require('../common');
|
||||||
const io = require('socket.io-client');
|
|
||||||
const padManager = require('../../../node/db/PadManager');
|
const padManager = require('../../../node/db/PadManager');
|
||||||
const plugins = require('../../../static/js/pluginfw/plugin_defs');
|
const plugins = require('../../../static/js/pluginfw/plugin_defs');
|
||||||
const readOnlyManager = require('../../../node/db/ReadOnlyManager');
|
const readOnlyManager = require('../../../node/db/ReadOnlyManager');
|
||||||
const setCookieParser = require('set-cookie-parser');
|
|
||||||
const settings = require('../../../node/utils/Settings');
|
const settings = require('../../../node/utils/Settings');
|
||||||
const socketIoRouter = require('../../../node/handler/SocketIORouter');
|
const socketIoRouter = require('../../../node/handler/SocketIORouter');
|
||||||
|
|
||||||
const logger = common.logger;
|
|
||||||
|
|
||||||
// Waits for and returns the next named socket.io event. Rejects if there is any error while waiting
|
|
||||||
// (unless waiting for that error event).
|
|
||||||
const getSocketEvent = async (socket, event) => {
|
|
||||||
const errorEvents = [
|
|
||||||
'error',
|
|
||||||
'connect_error',
|
|
||||||
'connect_timeout',
|
|
||||||
'reconnect_error',
|
|
||||||
'reconnect_failed',
|
|
||||||
];
|
|
||||||
const handlers = {};
|
|
||||||
let timeoutId;
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
timeoutId = setTimeout(() => reject(new Error(`timed out waiting for ${event} event`)), 1000);
|
|
||||||
for (const event of errorEvents) {
|
|
||||||
handlers[event] = (errorString) => {
|
|
||||||
logger.debug(`socket.io ${event} event: ${errorString}`);
|
|
||||||
reject(new Error(errorString));
|
|
||||||
};
|
|
||||||
}
|
|
||||||
// This will overwrite one of the above handlers if the user is waiting for an error event.
|
|
||||||
handlers[event] = (...args) => {
|
|
||||||
logger.debug(`socket.io ${event} event`);
|
|
||||||
if (args.length > 1) return resolve(args);
|
|
||||||
resolve(args[0]);
|
|
||||||
};
|
|
||||||
Object.entries(handlers).forEach(([event, handler]) => socket.on(event, handler));
|
|
||||||
}).finally(() => {
|
|
||||||
clearTimeout(timeoutId);
|
|
||||||
Object.entries(handlers).forEach(([event, handler]) => socket.off(event, handler));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// Establishes a new socket.io connection. Passes the cookies from the `set-cookie` header(s) in
|
|
||||||
// `res` (which may be nullish) to the server. Returns a socket.io Socket object.
|
|
||||||
const connect = async (res) => {
|
|
||||||
// Convert the `set-cookie` header(s) into a `cookie` header.
|
|
||||||
const resCookies = (res == null) ? {} : setCookieParser.parse(res, {map: true});
|
|
||||||
const reqCookieHdr = Object.entries(resCookies).map(
|
|
||||||
([name, cookie]) => `${name}=${encodeURIComponent(cookie.value)}`).join('; ');
|
|
||||||
|
|
||||||
logger.debug('socket.io connecting...');
|
|
||||||
let padId = null;
|
|
||||||
if (res) {
|
|
||||||
padId = res.req.path.split('/p/')[1];
|
|
||||||
}
|
|
||||||
const socket = io(`${common.baseUrl}/`, {
|
|
||||||
forceNew: true, // Different tests will have different query parameters.
|
|
||||||
path: '/socket.io',
|
|
||||||
// socketio.js-client on node.js doesn't support cookies (see https://git.io/JU8u9), so the
|
|
||||||
// express_sid cookie must be passed as a query parameter.
|
|
||||||
query: {cookie: reqCookieHdr, padId},
|
|
||||||
});
|
|
||||||
try {
|
|
||||||
await getSocketEvent(socket, 'connect');
|
|
||||||
} catch (e) {
|
|
||||||
socket.close();
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
logger.debug('socket.io connected');
|
|
||||||
|
|
||||||
return socket;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Helper function to exchange CLIENT_READY+CLIENT_VARS messages for the named pad.
|
|
||||||
// Returns the CLIENT_VARS message from the server.
|
|
||||||
const handshake = async (socket, padID) => {
|
|
||||||
logger.debug('sending CLIENT_READY...');
|
|
||||||
socket.send({
|
|
||||||
component: 'pad',
|
|
||||||
type: 'CLIENT_READY',
|
|
||||||
padId: padID,
|
|
||||||
sessionID: null,
|
|
||||||
token: 't.12345',
|
|
||||||
});
|
|
||||||
logger.debug('waiting for CLIENT_VARS response...');
|
|
||||||
const msg = await getSocketEvent(socket, 'message');
|
|
||||||
logger.debug('received CLIENT_VARS message');
|
|
||||||
return msg;
|
|
||||||
};
|
|
||||||
|
|
||||||
describe(__filename, function () {
|
describe(__filename, function () {
|
||||||
this.timeout(30000);
|
this.timeout(30000);
|
||||||
let agent;
|
let agent;
|
||||||
|
@ -143,26 +58,26 @@ describe(__filename, function () {
|
||||||
describe('Normal accesses', function () {
|
describe('Normal accesses', function () {
|
||||||
it('!authn anonymous cookie /p/pad -> 200, ok', async function () {
|
it('!authn anonymous cookie /p/pad -> 200, ok', async function () {
|
||||||
const res = await agent.get('/p/pad').expect(200);
|
const res = await agent.get('/p/pad').expect(200);
|
||||||
socket = await connect(res);
|
socket = await common.connect(res);
|
||||||
const clientVars = await handshake(socket, 'pad');
|
const clientVars = await common.handshake(socket, 'pad');
|
||||||
assert.equal(clientVars.type, 'CLIENT_VARS');
|
assert.equal(clientVars.type, 'CLIENT_VARS');
|
||||||
});
|
});
|
||||||
it('!authn !cookie -> ok', async function () {
|
it('!authn !cookie -> ok', async function () {
|
||||||
socket = await connect(null);
|
socket = await common.connect(null);
|
||||||
const clientVars = await handshake(socket, 'pad');
|
const clientVars = await common.handshake(socket, 'pad');
|
||||||
assert.equal(clientVars.type, 'CLIENT_VARS');
|
assert.equal(clientVars.type, 'CLIENT_VARS');
|
||||||
});
|
});
|
||||||
it('!authn user /p/pad -> 200, ok', async function () {
|
it('!authn user /p/pad -> 200, ok', async function () {
|
||||||
const res = await agent.get('/p/pad').auth('user', 'user-password').expect(200);
|
const res = await agent.get('/p/pad').auth('user', 'user-password').expect(200);
|
||||||
socket = await connect(res);
|
socket = await common.connect(res);
|
||||||
const clientVars = await handshake(socket, 'pad');
|
const clientVars = await common.handshake(socket, 'pad');
|
||||||
assert.equal(clientVars.type, 'CLIENT_VARS');
|
assert.equal(clientVars.type, 'CLIENT_VARS');
|
||||||
});
|
});
|
||||||
it('authn user /p/pad -> 200, ok', async function () {
|
it('authn user /p/pad -> 200, ok', async function () {
|
||||||
settings.requireAuthentication = true;
|
settings.requireAuthentication = true;
|
||||||
const res = await agent.get('/p/pad').auth('user', 'user-password').expect(200);
|
const res = await agent.get('/p/pad').auth('user', 'user-password').expect(200);
|
||||||
socket = await connect(res);
|
socket = await common.connect(res);
|
||||||
const clientVars = await handshake(socket, 'pad');
|
const clientVars = await common.handshake(socket, 'pad');
|
||||||
assert.equal(clientVars.type, 'CLIENT_VARS');
|
assert.equal(clientVars.type, 'CLIENT_VARS');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -176,16 +91,16 @@ describe(__filename, function () {
|
||||||
};
|
};
|
||||||
settings.requireAuthentication = authn;
|
settings.requireAuthentication = authn;
|
||||||
let res = await get('/p/pad');
|
let res = await get('/p/pad');
|
||||||
socket = await connect(res);
|
socket = await common.connect(res);
|
||||||
let clientVars = await handshake(socket, 'pad');
|
let clientVars = await common.handshake(socket, 'pad');
|
||||||
assert.equal(clientVars.type, 'CLIENT_VARS');
|
assert.equal(clientVars.type, 'CLIENT_VARS');
|
||||||
assert.equal(clientVars.data.readonly, false);
|
assert.equal(clientVars.data.readonly, false);
|
||||||
const readOnlyId = clientVars.data.readOnlyId;
|
const readOnlyId = clientVars.data.readOnlyId;
|
||||||
assert(readOnlyManager.isReadOnlyId(readOnlyId));
|
assert(readOnlyManager.isReadOnlyId(readOnlyId));
|
||||||
socket.close();
|
socket.close();
|
||||||
res = await get(`/p/${readOnlyId}`);
|
res = await get(`/p/${readOnlyId}`);
|
||||||
socket = await connect(res);
|
socket = await common.connect(res);
|
||||||
clientVars = await handshake(socket, readOnlyId);
|
clientVars = await common.handshake(socket, readOnlyId);
|
||||||
assert.equal(clientVars.type, 'CLIENT_VARS');
|
assert.equal(clientVars.type, 'CLIENT_VARS');
|
||||||
assert.equal(clientVars.data.readonly, true);
|
assert.equal(clientVars.data.readonly, true);
|
||||||
});
|
});
|
||||||
|
@ -195,8 +110,8 @@ describe(__filename, function () {
|
||||||
settings.requireAuthentication = true;
|
settings.requireAuthentication = true;
|
||||||
settings.requireAuthorization = true;
|
settings.requireAuthorization = true;
|
||||||
const res = await agent.get('/p/pad').auth('user', 'user-password').expect(200);
|
const res = await agent.get('/p/pad').auth('user', 'user-password').expect(200);
|
||||||
socket = await connect(res);
|
socket = await common.connect(res);
|
||||||
const clientVars = await handshake(socket, 'pad');
|
const clientVars = await common.handshake(socket, 'pad');
|
||||||
assert.equal(clientVars.type, 'CLIENT_VARS');
|
assert.equal(clientVars.type, 'CLIENT_VARS');
|
||||||
});
|
});
|
||||||
it('supports pad names with characters that must be percent-encoded', async function () {
|
it('supports pad names with characters that must be percent-encoded', async function () {
|
||||||
|
@ -208,8 +123,8 @@ describe(__filename, function () {
|
||||||
settings.requireAuthorization = true;
|
settings.requireAuthorization = true;
|
||||||
const encodedPadId = encodeURIComponent('päd');
|
const encodedPadId = encodeURIComponent('päd');
|
||||||
const res = await agent.get(`/p/${encodedPadId}`).auth('user', 'user-password').expect(200);
|
const res = await agent.get(`/p/${encodedPadId}`).auth('user', 'user-password').expect(200);
|
||||||
socket = await connect(res);
|
socket = await common.connect(res);
|
||||||
const clientVars = await handshake(socket, 'päd');
|
const clientVars = await common.handshake(socket, 'päd');
|
||||||
assert.equal(clientVars.type, 'CLIENT_VARS');
|
assert.equal(clientVars.type, 'CLIENT_VARS');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -219,31 +134,31 @@ describe(__filename, function () {
|
||||||
settings.requireAuthentication = true;
|
settings.requireAuthentication = true;
|
||||||
const res = await agent.get('/p/pad').expect(401);
|
const res = await agent.get('/p/pad').expect(401);
|
||||||
// Despite the 401, try to create the pad via a socket.io connection anyway.
|
// Despite the 401, try to create the pad via a socket.io connection anyway.
|
||||||
socket = await connect(res);
|
socket = await common.connect(res);
|
||||||
const message = await handshake(socket, 'pad');
|
const message = await common.handshake(socket, 'pad');
|
||||||
assert.equal(message.accessStatus, 'deny');
|
assert.equal(message.accessStatus, 'deny');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('authn anonymous read-only /p/pad -> 401, error', async function () {
|
it('authn anonymous read-only /p/pad -> 401, error', async function () {
|
||||||
settings.requireAuthentication = true;
|
settings.requireAuthentication = true;
|
||||||
let res = await agent.get('/p/pad').auth('user', 'user-password').expect(200);
|
let res = await agent.get('/p/pad').auth('user', 'user-password').expect(200);
|
||||||
socket = await connect(res);
|
socket = await common.connect(res);
|
||||||
const clientVars = await handshake(socket, 'pad');
|
const clientVars = await common.handshake(socket, 'pad');
|
||||||
assert.equal(clientVars.type, 'CLIENT_VARS');
|
assert.equal(clientVars.type, 'CLIENT_VARS');
|
||||||
const readOnlyId = clientVars.data.readOnlyId;
|
const readOnlyId = clientVars.data.readOnlyId;
|
||||||
assert(readOnlyManager.isReadOnlyId(readOnlyId));
|
assert(readOnlyManager.isReadOnlyId(readOnlyId));
|
||||||
socket.close();
|
socket.close();
|
||||||
res = await agent.get(`/p/${readOnlyId}`).expect(401);
|
res = await agent.get(`/p/${readOnlyId}`).expect(401);
|
||||||
// Despite the 401, try to read the pad via a socket.io connection anyway.
|
// Despite the 401, try to read the pad via a socket.io connection anyway.
|
||||||
socket = await connect(res);
|
socket = await common.connect(res);
|
||||||
const message = await handshake(socket, readOnlyId);
|
const message = await common.handshake(socket, readOnlyId);
|
||||||
assert.equal(message.accessStatus, 'deny');
|
assert.equal(message.accessStatus, 'deny');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('authn !cookie -> error', async function () {
|
it('authn !cookie -> error', async function () {
|
||||||
settings.requireAuthentication = true;
|
settings.requireAuthentication = true;
|
||||||
socket = await connect(null);
|
socket = await common.connect(null);
|
||||||
const message = await handshake(socket, 'pad');
|
const message = await common.handshake(socket, 'pad');
|
||||||
assert.equal(message.accessStatus, 'deny');
|
assert.equal(message.accessStatus, 'deny');
|
||||||
});
|
});
|
||||||
it('authorization bypass attempt -> error', async function () {
|
it('authorization bypass attempt -> error', async function () {
|
||||||
|
@ -253,9 +168,9 @@ describe(__filename, function () {
|
||||||
settings.requireAuthorization = true;
|
settings.requireAuthorization = true;
|
||||||
// First authenticate and establish a session.
|
// First authenticate and establish a session.
|
||||||
const res = await agent.get('/p/pad').auth('user', 'user-password').expect(200);
|
const res = await agent.get('/p/pad').auth('user', 'user-password').expect(200);
|
||||||
socket = await connect(res);
|
socket = await common.connect(res);
|
||||||
// Accessing /p/other-pad should fail, despite the successful fetch of /p/pad.
|
// Accessing /p/other-pad should fail, despite the successful fetch of /p/pad.
|
||||||
const message = await handshake(socket, 'other-pad');
|
const message = await common.handshake(socket, 'other-pad');
|
||||||
assert.equal(message.accessStatus, 'deny');
|
assert.equal(message.accessStatus, 'deny');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -269,16 +184,16 @@ describe(__filename, function () {
|
||||||
it("level='create' -> can create", async function () {
|
it("level='create' -> can create", async function () {
|
||||||
authorize = () => 'create';
|
authorize = () => 'create';
|
||||||
const res = await agent.get('/p/pad').auth('user', 'user-password').expect(200);
|
const res = await agent.get('/p/pad').auth('user', 'user-password').expect(200);
|
||||||
socket = await connect(res);
|
socket = await common.connect(res);
|
||||||
const clientVars = await handshake(socket, 'pad');
|
const clientVars = await common.handshake(socket, 'pad');
|
||||||
assert.equal(clientVars.type, 'CLIENT_VARS');
|
assert.equal(clientVars.type, 'CLIENT_VARS');
|
||||||
assert.equal(clientVars.data.readonly, false);
|
assert.equal(clientVars.data.readonly, false);
|
||||||
});
|
});
|
||||||
it('level=true -> can create', async function () {
|
it('level=true -> can create', async function () {
|
||||||
authorize = () => true;
|
authorize = () => true;
|
||||||
const res = await agent.get('/p/pad').auth('user', 'user-password').expect(200);
|
const res = await agent.get('/p/pad').auth('user', 'user-password').expect(200);
|
||||||
socket = await connect(res);
|
socket = await common.connect(res);
|
||||||
const clientVars = await handshake(socket, 'pad');
|
const clientVars = await common.handshake(socket, 'pad');
|
||||||
assert.equal(clientVars.type, 'CLIENT_VARS');
|
assert.equal(clientVars.type, 'CLIENT_VARS');
|
||||||
assert.equal(clientVars.data.readonly, false);
|
assert.equal(clientVars.data.readonly, false);
|
||||||
});
|
});
|
||||||
|
@ -286,8 +201,8 @@ describe(__filename, function () {
|
||||||
await padManager.getPad('pad'); // Create the pad.
|
await padManager.getPad('pad'); // Create the pad.
|
||||||
authorize = () => 'modify';
|
authorize = () => 'modify';
|
||||||
const res = await agent.get('/p/pad').auth('user', 'user-password').expect(200);
|
const res = await agent.get('/p/pad').auth('user', 'user-password').expect(200);
|
||||||
socket = await connect(res);
|
socket = await common.connect(res);
|
||||||
const clientVars = await handshake(socket, 'pad');
|
const clientVars = await common.handshake(socket, 'pad');
|
||||||
assert.equal(clientVars.type, 'CLIENT_VARS');
|
assert.equal(clientVars.type, 'CLIENT_VARS');
|
||||||
assert.equal(clientVars.data.readonly, false);
|
assert.equal(clientVars.data.readonly, false);
|
||||||
});
|
});
|
||||||
|
@ -295,31 +210,31 @@ describe(__filename, function () {
|
||||||
authorize = () => 'create';
|
authorize = () => 'create';
|
||||||
settings.editOnly = true;
|
settings.editOnly = true;
|
||||||
const res = await agent.get('/p/pad').auth('user', 'user-password').expect(200);
|
const res = await agent.get('/p/pad').auth('user', 'user-password').expect(200);
|
||||||
socket = await connect(res);
|
socket = await common.connect(res);
|
||||||
const message = await handshake(socket, 'pad');
|
const message = await common.handshake(socket, 'pad');
|
||||||
assert.equal(message.accessStatus, 'deny');
|
assert.equal(message.accessStatus, 'deny');
|
||||||
});
|
});
|
||||||
it("level='modify' settings.editOnly=false -> unable to create", async function () {
|
it("level='modify' settings.editOnly=false -> unable to create", async function () {
|
||||||
authorize = () => 'modify';
|
authorize = () => 'modify';
|
||||||
settings.editOnly = false;
|
settings.editOnly = false;
|
||||||
const res = await agent.get('/p/pad').auth('user', 'user-password').expect(200);
|
const res = await agent.get('/p/pad').auth('user', 'user-password').expect(200);
|
||||||
socket = await connect(res);
|
socket = await common.connect(res);
|
||||||
const message = await handshake(socket, 'pad');
|
const message = await common.handshake(socket, 'pad');
|
||||||
assert.equal(message.accessStatus, 'deny');
|
assert.equal(message.accessStatus, 'deny');
|
||||||
});
|
});
|
||||||
it("level='readOnly' -> unable to create", async function () {
|
it("level='readOnly' -> unable to create", async function () {
|
||||||
authorize = () => 'readOnly';
|
authorize = () => 'readOnly';
|
||||||
const res = await agent.get('/p/pad').auth('user', 'user-password').expect(200);
|
const res = await agent.get('/p/pad').auth('user', 'user-password').expect(200);
|
||||||
socket = await connect(res);
|
socket = await common.connect(res);
|
||||||
const message = await handshake(socket, 'pad');
|
const message = await common.handshake(socket, 'pad');
|
||||||
assert.equal(message.accessStatus, 'deny');
|
assert.equal(message.accessStatus, 'deny');
|
||||||
});
|
});
|
||||||
it("level='readOnly' -> unable to modify", async function () {
|
it("level='readOnly' -> unable to modify", async function () {
|
||||||
await padManager.getPad('pad'); // Create the pad.
|
await padManager.getPad('pad'); // Create the pad.
|
||||||
authorize = () => 'readOnly';
|
authorize = () => 'readOnly';
|
||||||
const res = await agent.get('/p/pad').auth('user', 'user-password').expect(200);
|
const res = await agent.get('/p/pad').auth('user', 'user-password').expect(200);
|
||||||
socket = await connect(res);
|
socket = await common.connect(res);
|
||||||
const clientVars = await handshake(socket, 'pad');
|
const clientVars = await common.handshake(socket, 'pad');
|
||||||
assert.equal(clientVars.type, 'CLIENT_VARS');
|
assert.equal(clientVars.type, 'CLIENT_VARS');
|
||||||
assert.equal(clientVars.data.readonly, true);
|
assert.equal(clientVars.data.readonly, true);
|
||||||
});
|
});
|
||||||
|
@ -333,39 +248,39 @@ describe(__filename, function () {
|
||||||
it('user.canCreate = true -> can create and modify', async function () {
|
it('user.canCreate = true -> can create and modify', async function () {
|
||||||
settings.users.user.canCreate = true;
|
settings.users.user.canCreate = true;
|
||||||
const res = await agent.get('/p/pad').auth('user', 'user-password').expect(200);
|
const res = await agent.get('/p/pad').auth('user', 'user-password').expect(200);
|
||||||
socket = await connect(res);
|
socket = await common.connect(res);
|
||||||
const clientVars = await handshake(socket, 'pad');
|
const clientVars = await common.handshake(socket, 'pad');
|
||||||
assert.equal(clientVars.type, 'CLIENT_VARS');
|
assert.equal(clientVars.type, 'CLIENT_VARS');
|
||||||
assert.equal(clientVars.data.readonly, false);
|
assert.equal(clientVars.data.readonly, false);
|
||||||
});
|
});
|
||||||
it('user.canCreate = false -> unable to create', async function () {
|
it('user.canCreate = false -> unable to create', async function () {
|
||||||
settings.users.user.canCreate = false;
|
settings.users.user.canCreate = false;
|
||||||
const res = await agent.get('/p/pad').auth('user', 'user-password').expect(200);
|
const res = await agent.get('/p/pad').auth('user', 'user-password').expect(200);
|
||||||
socket = await connect(res);
|
socket = await common.connect(res);
|
||||||
const message = await handshake(socket, 'pad');
|
const message = await common.handshake(socket, 'pad');
|
||||||
assert.equal(message.accessStatus, 'deny');
|
assert.equal(message.accessStatus, 'deny');
|
||||||
});
|
});
|
||||||
it('user.readOnly = true -> unable to create', async function () {
|
it('user.readOnly = true -> unable to create', async function () {
|
||||||
settings.users.user.readOnly = true;
|
settings.users.user.readOnly = true;
|
||||||
const res = await agent.get('/p/pad').auth('user', 'user-password').expect(200);
|
const res = await agent.get('/p/pad').auth('user', 'user-password').expect(200);
|
||||||
socket = await connect(res);
|
socket = await common.connect(res);
|
||||||
const message = await handshake(socket, 'pad');
|
const message = await common.handshake(socket, 'pad');
|
||||||
assert.equal(message.accessStatus, 'deny');
|
assert.equal(message.accessStatus, 'deny');
|
||||||
});
|
});
|
||||||
it('user.readOnly = true -> unable to modify', async function () {
|
it('user.readOnly = true -> unable to modify', async function () {
|
||||||
await padManager.getPad('pad'); // Create the pad.
|
await padManager.getPad('pad'); // Create the pad.
|
||||||
settings.users.user.readOnly = true;
|
settings.users.user.readOnly = true;
|
||||||
const res = await agent.get('/p/pad').auth('user', 'user-password').expect(200);
|
const res = await agent.get('/p/pad').auth('user', 'user-password').expect(200);
|
||||||
socket = await connect(res);
|
socket = await common.connect(res);
|
||||||
const clientVars = await handshake(socket, 'pad');
|
const clientVars = await common.handshake(socket, 'pad');
|
||||||
assert.equal(clientVars.type, 'CLIENT_VARS');
|
assert.equal(clientVars.type, 'CLIENT_VARS');
|
||||||
assert.equal(clientVars.data.readonly, true);
|
assert.equal(clientVars.data.readonly, true);
|
||||||
});
|
});
|
||||||
it('user.readOnly = false -> can create and modify', async function () {
|
it('user.readOnly = false -> can create and modify', async function () {
|
||||||
settings.users.user.readOnly = false;
|
settings.users.user.readOnly = false;
|
||||||
const res = await agent.get('/p/pad').auth('user', 'user-password').expect(200);
|
const res = await agent.get('/p/pad').auth('user', 'user-password').expect(200);
|
||||||
socket = await connect(res);
|
socket = await common.connect(res);
|
||||||
const clientVars = await handshake(socket, 'pad');
|
const clientVars = await common.handshake(socket, 'pad');
|
||||||
assert.equal(clientVars.type, 'CLIENT_VARS');
|
assert.equal(clientVars.type, 'CLIENT_VARS');
|
||||||
assert.equal(clientVars.data.readonly, false);
|
assert.equal(clientVars.data.readonly, false);
|
||||||
});
|
});
|
||||||
|
@ -373,8 +288,8 @@ describe(__filename, function () {
|
||||||
settings.users.user.canCreate = true;
|
settings.users.user.canCreate = true;
|
||||||
settings.users.user.readOnly = true;
|
settings.users.user.readOnly = true;
|
||||||
const res = await agent.get('/p/pad').auth('user', 'user-password').expect(200);
|
const res = await agent.get('/p/pad').auth('user', 'user-password').expect(200);
|
||||||
socket = await connect(res);
|
socket = await common.connect(res);
|
||||||
const message = await handshake(socket, 'pad');
|
const message = await common.handshake(socket, 'pad');
|
||||||
assert.equal(message.accessStatus, 'deny');
|
assert.equal(message.accessStatus, 'deny');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -389,8 +304,8 @@ describe(__filename, function () {
|
||||||
settings.users.user.readOnly = true;
|
settings.users.user.readOnly = true;
|
||||||
authorize = () => 'create';
|
authorize = () => 'create';
|
||||||
const res = await agent.get('/p/pad').auth('user', 'user-password').expect(200);
|
const res = await agent.get('/p/pad').auth('user', 'user-password').expect(200);
|
||||||
socket = await connect(res);
|
socket = await common.connect(res);
|
||||||
const message = await handshake(socket, 'pad');
|
const message = await common.handshake(socket, 'pad');
|
||||||
assert.equal(message.accessStatus, 'deny');
|
assert.equal(message.accessStatus, 'deny');
|
||||||
});
|
});
|
||||||
it('user settings does not elevate level from authorize hook', async function () {
|
it('user settings does not elevate level from authorize hook', async function () {
|
||||||
|
@ -398,8 +313,8 @@ describe(__filename, function () {
|
||||||
settings.users.user.canCreate = true;
|
settings.users.user.canCreate = true;
|
||||||
authorize = () => 'readOnly';
|
authorize = () => 'readOnly';
|
||||||
const res = await agent.get('/p/pad').auth('user', 'user-password').expect(200);
|
const res = await agent.get('/p/pad').auth('user', 'user-password').expect(200);
|
||||||
socket = await connect(res);
|
socket = await common.connect(res);
|
||||||
const message = await handshake(socket, 'pad');
|
const message = await common.handshake(socket, 'pad');
|
||||||
assert.equal(message.accessStatus, 'deny');
|
assert.equal(message.accessStatus, 'deny');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -430,7 +345,7 @@ describe(__filename, function () {
|
||||||
socketIoRouter.addComponent(this.test.fullTitle(), new class extends Module {
|
socketIoRouter.addComponent(this.test.fullTitle(), new class extends Module {
|
||||||
handleConnect(socket) { serverSocket = socket; }
|
handleConnect(socket) { serverSocket = socket; }
|
||||||
}());
|
}());
|
||||||
socket = await connect();
|
socket = await common.connect();
|
||||||
assert(serverSocket != null);
|
assert(serverSocket != null);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -452,7 +367,7 @@ describe(__filename, function () {
|
||||||
resolveDisconnected();
|
resolveDisconnected();
|
||||||
}
|
}
|
||||||
}());
|
}());
|
||||||
socket = await connect();
|
socket = await common.connect();
|
||||||
await connected;
|
await connected;
|
||||||
socket.close();
|
socket.close();
|
||||||
socket = null;
|
socket = null;
|
||||||
|
@ -474,7 +389,7 @@ describe(__filename, function () {
|
||||||
socketIoRouter.addComponent(`${this.test.fullTitle()} #2`, new class extends Module {
|
socketIoRouter.addComponent(`${this.test.fullTitle()} #2`, new class extends Module {
|
||||||
handleMessage(socket, message) { assert.fail('wrong handler called'); }
|
handleMessage(socket, message) { assert.fail('wrong handler called'); }
|
||||||
}());
|
}());
|
||||||
socket = await connect();
|
socket = await common.connect();
|
||||||
socket.send(want);
|
socket.send(want);
|
||||||
assert.deepEqual(await got, want);
|
assert.deepEqual(await got, want);
|
||||||
});
|
});
|
||||||
|
@ -492,7 +407,7 @@ describe(__filename, function () {
|
||||||
socketIoRouter.addComponent(this.test.fullTitle(), new class extends Module {
|
socketIoRouter.addComponent(this.test.fullTitle(), new class extends Module {
|
||||||
handleMessage(socket, msg) { return want; }
|
handleMessage(socket, msg) { return want; }
|
||||||
}());
|
}());
|
||||||
socket = await connect();
|
socket = await common.connect();
|
||||||
const got = await tx(socket, {component: this.test.fullTitle()});
|
const got = await tx(socket, {component: this.test.fullTitle()});
|
||||||
assert.equal(got, want);
|
assert.equal(got, want);
|
||||||
});
|
});
|
||||||
|
@ -504,7 +419,7 @@ describe(__filename, function () {
|
||||||
socketIoRouter.addComponent(this.test.fullTitle(), new class extends Module {
|
socketIoRouter.addComponent(this.test.fullTitle(), new class extends Module {
|
||||||
handleMessage(socket, msg) { throw new InjectedError(); }
|
handleMessage(socket, msg) { throw new InjectedError(); }
|
||||||
}());
|
}());
|
||||||
socket = await connect();
|
socket = await common.connect();
|
||||||
await assert.rejects(tx(socket, {component: this.test.fullTitle()}), new InjectedError());
|
await assert.rejects(tx(socket, {component: this.test.fullTitle()}), new InjectedError());
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue