Skip to content

Commit

Permalink
hapi 18. Closes #265
Browse files Browse the repository at this point in the history
  • Loading branch information
hueniverse committed Jan 18, 2019
1 parent 79cb91d commit 8e6f257
Show file tree
Hide file tree
Showing 9 changed files with 160 additions and 18 deletions.
2 changes: 1 addition & 1 deletion dist/client.js

Large diffs are not rendered by default.

22 changes: 11 additions & 11 deletions lib/client.js
Expand Up @@ -333,8 +333,8 @@
const ws = this._ws;
this._ws = null;

if (ws.readyState === Client.WebSocket.OPEN ||
ws.readyState === Client.WebSocket.CONNECTING) {
if (ws.readyState !== Client.WebSocket.CLOSED &&
ws.readyState !== Client.WebSocket.CLOSING) {

ws.close();
}
Expand Down Expand Up @@ -433,11 +433,14 @@
return this._send(request, true);
};

Client.prototype._send = function (request, track) {
Client.prototype._isReady = function () {

if (!this._ws ||
this._ws.readyState !== Client.WebSocket.OPEN) {
return this._ws && this._ws.readyState === Client.WebSocket.OPEN;
};

Client.prototype._send = function (request, track) {

if (!this._isReady()) {
return Promise.reject(new NesError('Failed to send message - server disconnected', errorTypes.DISCONNECT));
}

Expand Down Expand Up @@ -544,8 +547,7 @@

this._subscriptions[path] = [handler];

if (!this._ws ||
this._ws.readyState !== Client.WebSocket.OPEN) {
if (!this._isReady()) {

// Queued subscription

Expand Down Expand Up @@ -598,8 +600,7 @@
}

if (!sync ||
!this._ws ||
this._ws.readyState !== Client.WebSocket.OPEN) {
!this._isReady()) {

return Promise.resolve();
}
Expand Down Expand Up @@ -646,8 +647,7 @@

let error = null;
if (update.statusCode &&
update.statusCode >= 400 &&
update.statusCode <= 599) {
update.statusCode >= 400) {

error = new NesError(update.payload.message || update.payload.error || 'Error', errorTypes.SERVER);
error.statusCode = update.statusCode;
Expand Down
2 changes: 1 addition & 1 deletion lib/index.js
Expand Up @@ -92,7 +92,7 @@ internals.schema = Joi.object({
exports.plugin = {
pkg: require('../package.json'),
requirements: {
hapi: '>=17.8.1'
hapi: '>=18.0.0'
},
register: function (server, options) {

Expand Down
3 changes: 1 addition & 2 deletions lib/socket.js
Expand Up @@ -416,8 +416,7 @@ internals.Socket.prototype._processRequest = async function (request) {
url: path,
payload: request.payload,
headers: request.headers,
credentials: this.auth.credentials,
artifacts: this.auth.artifacts,
auth: this.auth.isAuthenticated ? this.auth : null,
validate: false,
plugins: {
nes: {
Expand Down
4 changes: 2 additions & 2 deletions package.json
Expand Up @@ -26,8 +26,8 @@
"babel-preset-env": "^1.6.1",
"babel-preset-minify": "^0.2.0",
"code": "5.x.x",
"hapi": "17.x.x",
"lab": "17.x.x",
"hapi": "18.x.x",
"lab": "18.x.x",
"mkdirp": "0.5.1"
},
"babel": {
Expand Down
40 changes: 39 additions & 1 deletion test/auth.js
Expand Up @@ -114,7 +114,7 @@ describe('authentication', () => {
await server.stop();
});

it('limits connections per user', async () => {
it('limits connections per user (single)', async () => {

const server = Hapi.server();

Expand Down Expand Up @@ -148,6 +148,44 @@ describe('authentication', () => {
await server.stop();
});

it('limits connections per user', async () => {

const server = Hapi.server();

await server.register({ plugin: Nes, options: { auth: { type: 'cookie', maxConnectionsPerUser: 2, index: true } } });

server.auth.scheme('custom', internals.implementation);
server.auth.strategy('default', 'custom');
server.auth.default('default');

server.route({
method: 'GET',
path: '/',
handler: () => 'hello'
});

await server.start();
const res = await server.inject({ url: '/nes/auth', headers: { authorization: 'Custom john' } });
expect(res.result.status).to.equal('authenticated');

const header = res.headers['set-cookie'][0];
const cookie = header.match(/(?:[^\x00-\x20\(\)<>@\,;\:\\"\/\[\]\?\=\{\}\x7F]+)\s*=\s*(?:([^\x00-\x20\"\,\;\\\x7F]*))/);

const client = new Nes.Client('http://localhost:' + server.info.port, { ws: { headers: { cookie: 'nes=' + cookie[1] } } });
await client.connect();

const client2 = new Nes.Client('http://localhost:' + server.info.port, { ws: { headers: { cookie: 'nes=' + cookie[1] } } });
await client2.connect();

const client3 = new Nes.Client('http://localhost:' + server.info.port, { ws: { headers: { cookie: 'nes=' + cookie[1] } } });
await expect(client3.connect()).to.reject('Too many connections for the authenticated user');

client.disconnect();
client2.disconnect();
client3.disconnect();
await server.stop();
});

it('protects an endpoint (no default auth)', async () => {

const server = Hapi.server();
Expand Down
31 changes: 31 additions & 0 deletions test/client.js
Expand Up @@ -1028,6 +1028,21 @@ describe('Client', () => {
client.disconnect();
await server.stop();
});

it('errors on premature send', async () => {

const server = Hapi.server();
await server.register({ plugin: Nes, options: { auth: false } });

await server.start();
const client = new Nes.Client('http://localhost:' + server.info.port);
const connecting = client.connect();
await expect(client.message('x')).to.reject();

await connecting;
client.disconnect();
await server.stop();
});
});

describe('_onMessage', () => {
Expand Down Expand Up @@ -1626,6 +1641,22 @@ describe('Client', () => {
client.disconnect();
await server.stop();
});

it('queues on premature send', async () => {

const server = Hapi.server();
await server.register({ plugin: Nes, options: { auth: false } });
server.subscription('/', {});

await server.start();
const client = new Nes.Client('http://localhost:' + server.info.port);
const connecting = client.connect();
await expect(client.subscribe('/', Hoek.ignore)).to.not.reject();

await connecting;
client.disconnect();
await server.stop();
});
});

describe('unsubscribe()', () => {
Expand Down
50 changes: 50 additions & 0 deletions test/listener.js
Expand Up @@ -829,6 +829,56 @@ describe('Listener', () => {
await server.stop();
});

it('publishes to selected user (ignores non-user credentials)', async () => {

const server = Hapi.server();

const implementation = (srv, options) => {

let count = 0;
return {
authenticate: (request, h) => {

return h.authenticated({ credentials: { user: count++ ? 'steve' : null } });
}
};
};

server.auth.scheme('custom', implementation);
server.auth.strategy('default', 'custom');
server.auth.default({ strategy: 'default', mode: 'optional' });

const password = 'some_not_random_password_that_is_also_long_enough';
await server.register({ plugin: Nes, options: { auth: { type: 'direct', password } } });

const onUnsubscribe = Hoek.ignore;
server.subscription('/', { onUnsubscribe, auth: { mode: 'optional', index: true } });

await server.start();
const client1 = new Nes.Client('http://localhost:' + server.info.port);
await client1.connect({ auth: { headers: { authorization: 'Custom steve' } } });

const updates = [];
const handler = (update) => updates.push(update);

await client1.subscribe('/', handler);
const client2 = new Nes.Client('http://localhost:' + server.info.port);
await client2.connect({ auth: { headers: { authorization: 'Custom steve' } } });
await client2.subscribe('/', handler);

server.publish('/', 'heya', { user: 'steve' });

await Hoek.wait(50);

await client1.unsubscribe('/', null);
await client2.unsubscribe('/', null);
client1.disconnect();
client2.disconnect();

expect(updates).to.equal(['heya']);
await server.stop();
});

it('ignores unknown path', async () => {

const server = Hapi.server();
Expand Down
24 changes: 24 additions & 0 deletions test/socket.js
Expand Up @@ -347,6 +347,30 @@ describe('Socket', () => {
await server.stop();
});

it('leaves message small enough to fit into single packets', async () => {

const server = Hapi.server();
await server.register({ plugin: Nes, options: { auth: false, payload: { maxChunkChars: 100 } } });

await server.start();
const client = new Nes.Client('http://localhost:' + server.info.port);
const text = 'this is a message shorter than 100 bytes';

const team = new Teamwork();
client.onUpdate = (message) => {

expect(message).to.equal(text);
team.attend();
};

await client.connect();
server.broadcast(text);

await team.work;
client.disconnect();
await server.stop();
});

it('errors on socket send error', async () => {

const server = Hapi.server();
Expand Down

0 comments on commit 8e6f257

Please sign in to comment.