Skip to content

Commit

Permalink
starttls: rework
Browse files Browse the repository at this point in the history
  • Loading branch information
sonnyp committed Oct 7, 2018
1 parent b4a01bf commit 2ffe4ec
Show file tree
Hide file tree
Showing 8 changed files with 1,276 additions and 58 deletions.
8 changes: 4 additions & 4 deletions packages/client/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const _iqCaller = require('@xmpp/iq/caller')
const resolve = require('@xmpp/resolve')

// Stream features - order matters and define priority
const starttls = require('@xmpp/starttls')
const _starttls = require('@xmpp/starttls')
const _sasl = require('@xmpp/sasl')
const _resourceBinding = require('@xmpp/resource-binding')
const _sessionEstablishment = require('@xmpp/session-establishment')
Expand All @@ -39,9 +39,8 @@ function xmpp(options = {}) {
const iqCaller = _iqCaller({middleware, entity: client})

// Stream features
if (starttls.streamFeature) {
streamFeatures.use(...starttls.streamFeature())
}
const starttls =
typeof _starttls === 'function' ? _starttls({streamFeatures}) : undefined
const sasl = _sasl({streamFeatures}, credentials)
const resourceBinding = _resourceBinding({iqCaller, streamFeatures}, resource)
const sessionEstablishment = _sessionEstablishment({iqCaller, streamFeatures})
Expand All @@ -59,6 +58,7 @@ function xmpp(options = {}) {
router,
streamFeatures,
iqCaller,
starttls,
sasl,
resourceBinding,
sessionEstablishment,
Expand Down
10 changes: 5 additions & 5 deletions packages/connection/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ function socketConnect(socket, ...params) {

socket.once('error', onError)
socket.once('connect', onConnect)

socket.connect(...params)
})
}
Expand Down Expand Up @@ -136,12 +135,13 @@ class Connection extends EventEmitter {
}

_detachSocket() {
const listeners = this.socketListeners
Object.getOwnPropertyNames(listeners).forEach(k => {
this.socket.removeListener(k, listeners[k])
delete listeners[k]
const {socketListeners, socket} = this
Object.getOwnPropertyNames(socketListeners).forEach(k => {
socket.removeListener(k, socketListeners[k])
delete socketListeners[k]
})
this.socket = null
return socket
}

_onElement(element) {
Expand Down
2 changes: 2 additions & 0 deletions packages/session-establishment/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

const xml = require('@xmpp/xml')

// https://tools.ietf.org/html/draft-cridland-xmpp-session-01

const NS = 'urn:ietf:params:xml:ns:xmpp-session'

module.exports = function({iqCaller, streamFeatures}) {
Expand Down
18 changes: 2 additions & 16 deletions packages/starttls/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,10 @@

STARTTLS negotiation for `@xmpp/client`.

Included and enabled in `@xmpp/client`.

Supports Node.js.

## Install

```js
npm install @xmpp/plugins
```

## Usage

```js
client.plugin(require('@xmpp/plugins/starttls'))
```
Included and enabled in `@xmpp/client` for Node.js

STARTTLS will automatically be negotiated upon TCP connection.

## References

[RFC 6120 XMPP Core](https://xmpp.org/rfcs/rfc6120.html#tls)
[RFC 6120 STARTTLS Negotiation](https://xmpp.org/rfcs/rfc6120.html#tls)
53 changes: 21 additions & 32 deletions packages/starttls/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

const xml = require('@xmpp/xml')
const tls = require('tls')
const net = require('net')

/*
* References
Expand All @@ -11,43 +10,33 @@ const net = require('net')

const NS = 'urn:ietf:params:xml:ns:xmpp-tls'

function proceed(entity, options) {
function proceed(entity, options = {}) {
return new Promise((resolve, reject) => {
options.socket = entity.socket
entity._detachSocket()
const tlsSocket = tls.connect(options, err => {
if (err) {
return reject(err)
options.socket = entity._detachSocket()
const tlsSocket = tls.connect(
options,
err => {
if (err) return reject(err)
entity._attachSocket(tlsSocket)
resolve()
}
entity._attachSocket(tlsSocket)
resolve()
})
)
})
}

function starttls(entity) {
return entity.sendReceive(xml('starttls', {xmlns: NS})).then(element => {
if (element.is('failure', NS)) {
throw new Error('STARTTLS_FAILURE')
} else if (element.is('proceed', NS)) {
return proceed(entity, {})
}
})
}

function route() {
return function({entity}, next) {
// https://prosody.im/issues/issue/837
if (entity.socket.constructor !== net.Socket) return next()
return starttls(entity).then(() => {
return entity.restart()
})
async function starttls(entity) {
const element = await entity.sendReceive(xml('starttls', {xmlns: NS}))
if (element.is('proceed', NS)) {
return element
}

throw new Error('STARTTLS_FAILURE')
}

module.exports.proceed = proceed
module.exports.starttls = starttls
module.exports.route = route
module.exports.streamFeature = function() {
return ['starttls', NS, route()]
module.exports = function({streamFeatures}) {
return streamFeatures.use('starttls', NS, async ({entity}) => {
await starttls(entity)
await proceed(entity)
await entity.restart()
})
}
25 changes: 25 additions & 0 deletions packages/starttls/test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
'use strict'

const test = require('ava')
const {mockClient, promise} = require('@xmpp/test')

test('failure', async t => {
const {client, entity} = mockClient()

client.mockInput(
<features xmlns="http://etherx.jabber.org/streams">
<starttls xmlns="urn:ietf:params:xml:ns:xmpp-tls" />
</features>
)

t.deepEqual(
await promise(entity, 'send'),
<starttls xmlns="urn:ietf:params:xml:ns:xmpp-tls" />
)

client.mockInput(<failure xmlns="urn:ietf:params:xml:ns:xmpp-tls" />)

const err = await promise(entity, 'error')
t.true(err instanceof Error)
t.is(err.message, 'STARTTLS_FAILURE')
})
2 changes: 1 addition & 1 deletion server/prosody.cfg.lua
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ pidfile = "prosody.pid";
allow_registration = true;

allow_unencrypted_plain_auth = true;
c2s_require_encryption = false
c2s_require_encryption = false;

consider_websocket_secure = true;
consider_bosh_secure = true;
Expand Down
Loading

0 comments on commit 2ffe4ec

Please sign in to comment.