Permalink
Browse files

Migrate xmpp-jid module back into stanza.io

  • Loading branch information...
legastero committed Dec 19, 2018
1 parent 6063d78 commit 539fe19abacba152325fe8207c67a40bf17f9a59
@@ -7,6 +7,7 @@
- Replaced use of `request` and `xhr` with `cross-fetch`.
- SASL mech implementations now live inside `stanza.io`.
- Moved host-meta fetching logic into `stanza.io`.
- Moved `xmpp-jid` implementation back into `stanza.io`, obsoleting `xmpp-jid`.
- Use `ws` module instead of `faye-websocket`.
- Dropped support of old, pre-RFC XMPP-over-WebSocket.

@@ -0,0 +1,115 @@
# XMPP JIDs

In XMPP, addresses are refered to as JIDs (ostensibly Jabber IDs, based on the old Jabber name).

A JID often looks a lot like an email address with a `user@host` form, but there's more to it:

```
full JID
/ \
[local@]domain[/resource]
\ /
bare JID
```

A JID can be composed of a local part, a domain part, and a resource part. The domain part is
mandatory for all JIDs, and can even stand alone (e.g., as the address for a server).

The combination of a local (user) part and a domain is called a "bare JID", and it is used
to identitfy a particular account at a server.

A JID that includes a resource is called a "full JID", and it is used to identify a particular
client connection (i.e., a specific connection for the associated "bare JID" account).

## Usage

```javascript
const jid = require('stanza.io').jid;
const res = new jid.JID('user@example.com');
// or jid.create('user@example.com');
// res == {
// local: 'user',
// domain: 'example.com',
// resource: 'res',
// bare: 'user@example.com',
// full: 'user@example.com/res',
// unescapedLocal: 'user',
// unescapedBare: 'user@example.com',
// unescapedFull: 'user@example.com/res',
// prepped: true
// }
```

## StringPrep

Correctly working with JIDs can be slightly tricky thanks to Unicode, which requires us
to use StringPrep to normalize the individual parts of a JID so that we can safely use
them in comparisons. Unfortunately, we don't have always have access to StringPrep, so
all `JID` objects are marked with a `prepped` attribute indicating if StringPrep has
been applied.

To enable full StringPrep application, also add the `node-stringprep` module to your
dependcies:

```sh
npm i node-stringprep
```

Comparisons between JIDs should only be trusted if both JIDs have `prepped` set to `true`.

The provided `equal` function can be used to reliably check that two JIDs are equivalent,
with an optional parameter to disable the `prepped` flag check.

```javascript
jid.equal('user@example.com/res', 'USER@EXAMPLE.COM/res');
// true, if StringPrep is available
jid.equal('user@example.com/res', 'USER@EXAMPLE.COM/res', false);
// true
jid.equal('user@example.com/res1', 'user@example.com/res2');
// false, full JIDs don't match
```

The same applies for the provided `equalBare` function, which checks that two
JIDs have the same "bare JID" form (i.e., it ignores differences in resources).

```javascript
jid.equal('user@example.com/resource1', 'USER@EXAMPLE.COM/resource2');
// true, if StringPrep is available
jid.equal('user@example.com/resource1', 'USER@EXAMPLE.COM/resource2', false);
// true
jid.equal('user@example.com/resource1', 'otheruser@EXAMPLE.COM/resource2', false);
// false, bare JIDs don't match
```

Even in the browser, there are ways to ensure that StringPrep is applied by getting
your XMPP server to do the prepping for you. This is already done for the standard
stanza routing attributes (`"to"` and `"from"`), and other places where the server
can reliably ensure that the JIDs are prepped (e.g., roster entries).

In other cases, you may need to use [XEP-0328: JID Prep](http://xmpp.org/extensions/xep-0328.html)
to explicity ask your server to prep a given JID.

## JID Escaping

[XEP-0106: JID Escaping](http://xmpp.org/extensions/xep-0106.html) allows you to create JIDs
using characters typically prohibited in the local part: `"' <:>&@`

When creating a new JID by specifying the local part separately (e.g. `new JID('localpart', 'domain')`),
the local part will be automatically escaped where necessary.

(Using `new JID('local@domain')` will **not**
escape the local part, as that is assumed to already be the escaped form.)

These fields on the resulting `JID` object yield the human-presentable, unescaped forms:

- `unescapedLocal`
- `unescapedBare`
- `unescapedFull`

If you show the unescaped forms _anywhere_ to a user, you should do so _everywhere_ to be consistent and
prevent potential security issues related to JID spoofing.
@@ -4,6 +4,7 @@
"version": "9.3.0",
"author": "Lance Stout <lancestout@gmail.com>",
"browser": {
"node-stringprep": false,
"ws": false
},
"bugs": "https://github.com/legastero/stanza.io/issues",
@@ -21,8 +22,7 @@
"tslib": "^1.9.3",
"uuid": "^3.0.1",
"wildemitter": "^1.0.1",
"ws": "^6.1.2",
"xmpp-jid": "^1.0.0"
"ws": "^6.1.2"
},
"devDependencies": {
"husky": "^1.1.3",
@@ -19,8 +19,8 @@ FS.writeFileSync(
JSON.stringify(
{
...Pkg,
'jsnext:main': './module.js',
devDependencies: undefined,
'jsnext:main': './module.js',
main: './index.js',
module: './module.js',
private: false,
@@ -1,4 +1,3 @@
import { JID } from 'xmpp-jid';
import * as uuid from 'uuid';
import jxt from 'jxt';
import WildEmitter from 'wildemitter';
@@ -14,6 +13,8 @@ import Smacks from './plugins/smacks';
import Bind from './plugins/bind';
import Session from './plugins/session';

import { JID } from './protocol/jid';

import WebSocket from './transports/websocket';
import BOSH from './transports/bosh';

@@ -1,11 +1,12 @@
import { JID } from 'xmpp-jid';
import * as jid from './protocol/jid';

import Client from './client';
import Plugins from './plugins';

export const VERSION = '__STANZAIO_VERSION__';
export const JID = jid.JID;

export { Client, JID };
export { Client, jid };

export function createClient(opts) {
const client = new Client(opts);
@@ -1,4 +1,4 @@
import { JID } from 'xmpp-jid';
import { JID } from '../protocol/jid';

export default function(client, stanzas, config) {
client.registerFeature('bind', 300, function(features, cb) {
@@ -1,4 +1,4 @@
import { JID } from 'xmpp-jid';
import { JID } from '../protocol/jid';

export default function(client) {
client.getBookmarks = function(cb) {
@@ -1,7 +1,7 @@
import { JID } from 'xmpp-jid';
import * as hashes from 'iana-hashes';

import { Namespaces } from '../protocol';
import { JID } from '../protocol/jid';

function generateVerString(info, hash) {
let S = '';
@@ -1,6 +1,5 @@
import { JID } from 'xmpp-jid';

import { Namespaces } from '../protocol';
import { JID } from '../protocol/jid';

function timeoutPromise(targetPromise, queryid, delay) {
let timeoutRef;
@@ -1,6 +1,5 @@
import { JID } from 'xmpp-jid';

import { Namespaces } from '../protocol';
import { JID } from '../protocol/jid';

export default function(client) {
client.disco.addFeature(Namespaces.MUC);
@@ -72,7 +72,9 @@ import * as Namespaces from './namespaces';
import XMPPShortcuts from './shortcuts';
import XMPPTypes from './types';

export { Namespaces };
import * as JID from './jid';

export { JID, Namespaces };

export default function(JXT) {
JXT.use(XMPPTypes);
Oops, something went wrong.

0 comments on commit 539fe19

Please sign in to comment.