コード例 #1
0
ファイル: index.js プロジェクト: athombv/nl.nefit.easy
module.exports = plugin(
  'sasl',
  {
    start() {
      this.SASL = new SASLFactory()
      this.streamFeature = {
        name: 'sasl',
        priority: 1000,
        match,
        restart: true,
        run: (entity, features) => {
          return this.gotFeatures(features)
        },
      }
      this.plugins['stream-features'].add(this.streamFeature)
    },

    stop() {
      delete this.SASL
      this.plugins['stream-features'].remove(this.streamFeature)
      delete this.streamFeature
      delete this.mech
    },

    use(...args) {
      this.SASL.use(...args)
    },

    gotFeatures(features) {
      const offered = getMechanismNames(features)
      const usable = this.getUsableMechanisms(offered)
      // FIXME const available = this.getAvailableMechanisms()

      return Promise.resolve(this.getMechanism(usable)).then(mech => {
        this.mech = mech
        return this.handleMechanism(mech, features)
      })
    },

    handleMechanism(mech, features) {
      this.entity._status('authenticate')

      if (mech === 'ANONYMOUS') {
        return this.authenticate(mech, {}, features)
      }

      return this.entity.delegate(
        'authenticate',
        (username, password) => {
          return this.authenticate(mech, {username, password}, features)
        },
        mech
      )
    },

    getAvailableMechanisms() {
      return this.SASL._mechs.map(({name}) => name)
    },

    getUsableMechanisms(mechs) {
      const supported = this.getAvailableMechanisms()
      return mechs.filter(mech => {
        return supported.indexOf(mech) > -1
      })
    },

    getMechanism(usable) {
      return usable[0] // FIXME prefer SHA-1, ... maybe order usable, available, ... by preferred?
    },

    findMechanism(name) {
      return this.SASL.create([name])
    },

    authenticate(mechname, credentials) {
      const mech = this.findMechanism(mechname)
      if (!mech) {
        return Promise.reject(new Error('no compatible mechanism'))
      }

      const {domain} = this.entity.options
      const creds = Object.assign(
        {
          username: null,
          password: null,
          server: domain,
          host: domain,
          realm: domain,
          serviceType: 'xmpp',
          serviceName: domain,
        },
        credentials
      )

      this.entity._status('authenticating')

      return new Promise((resolve, reject) => {
        const handler = element => {
          if (element.attrs.xmlns !== NS) {
            return
          }

          if (element.name === 'challenge') {
            mech.challenge(decode(element.text()))
            const resp = mech.response(creds)
            this.entity.send(
              xml(
                'response',
                {xmlns: NS, mechanism: mech.name},
                typeof resp === 'string' ? encode(resp) : ''
              )
            )
            return
          }

          if (element.name === 'failure') {
            reject(
              new SASLError(
                element.children[0].name,
                element.getChildText('text') || '',
                element
              )
            )
          } else if (element.name === 'success') {
            resolve()
            this.entity._status('authenticated')
          }

          this.entity.removeListener('nonza', handler)
        }
        this.entity.on('nonza', handler)

        if (mech.clientFirst) {
          this.entity.send(
            xml(
              'auth',
              {xmlns: NS, mechanism: mech.name},
              encode(mech.response(creds))
            )
          )
        }
      })
    },
  },
  [streamFeatures]
)
コード例 #2
0
ファイル: index.js プロジェクト: athombv/nl.nefit.easy
module.exports = plugin('stream-features', {
  start() {
    this.features = []

    const {entity} = this
    this.handler = el => {
      if (el.name !== 'stream:features') {
        return
      }

      const streamFeatures = this.selectFeatures(el)
      if (streamFeatures.length === 0) {
        return
      }

      function iterate(c) {
        const feature = streamFeatures[c]
        return feature
          .run(entity, el)
          .then(() => {
            if (feature.restart) {
              return entity.restart()
            } else if (c === streamFeatures.length - 1) {
              if (entity.jid) entity._status('online', entity.jid)
            } else {
              iterate(c + 1)
            }
          })
          .catch(err => entity.emit('error', err))
      }

      return iterate(0)
    }

    entity.on('nonza', this.handler)
  },

  stop() {
    delete this.features
    this.entity.off('nonza', this.handler)
    delete this.handler
  },

  selectFeatures(el) {
    return this.features
      .filter(f => f.match(el, this.entity) && typeof f.priority === 'number')
      .sort((a, b) => {
        return a.priority < b.priority
      })
  },

  add({name, priority, run, match, restart}) {
    this.features.push({name, priority, run, match, restart})
  },
})
コード例 #3
0
ファイル: index.js プロジェクト: jaredhanson/node-xmpp
module.exports = plugin('stream-features', {
  start() {
    this.features = []
    this.negotiated = []

    const {entity} = this
    this.handler = el => {
      if (el.name !== 'stream:features') {
        return
      }

      const streamFeatures = this.selectFeatures(el)
      if (streamFeatures.length === 0) {
        return
      }

      const features = streamFeatures.map(feature => {
        return {
          name: feature.name,
          run: (...args) => {
            return feature.run(entity, el, ...args).then(() => {
              if (feature.restart) {
                return entity.restart()
              } else if (entity.jid) {
                entity._status('online', entity.jid)
              } else {
                this.onStreamFeatures(features, el)
              }
            })
            .catch(err => entity.emit('error', err))
          },
        }
      })

      this.onStreamFeatures(features, el)
    }

    entity.on('nonza', this.handler)
  },

  stop() {
    delete this.features
    delete this.negotiated
    this.entity.off('nonza', this.handler)
    delete this.handler
  },

  selectFeatures(el) {
    return this.features
      .filter(f => f.match(el, this.entity) && this.negotiated.indexOf(f) === -1 && typeof f.priority === 'number')
      .sort((a, b) => {
        return a.priority < b.priority
      })
  },

  onStreamFeatures(features) {
    const feature = features.shift()
    feature.run()
  },

  add({name, priority, run, match, restart}) {
    this.features.push({name, priority, run, match, restart})
  },
})
コード例 #4
0
ファイル: index.js プロジェクト: jaredhanson/node-xmpp
'use strict'

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

const callee = require('./callee')
const caller = require('./caller')

module.exports = plugin('ping', {
  NS_PING: 'urn:xmpp:ping',
  ping(...args) {
    return this.plugins['ping-caller'].ping(...args)
  },
}, [callee, caller])
コード例 #5
0
ファイル: index.js プロジェクト: jaredhanson/node-xmpp
module.exports = plugin('reconnect', {
  delay: 1000,
  reconnect() {
    const {entity} = this
    this.emit('reconnecting')
    return delay(this.delay).then(() => {
      entity.start(entity.startOptions)
      .then(() => {
        this.emit('reconnected')
      })
      .catch(err => {
        this.emit('error', err)
        this.reconnect()
      })
    })
  },
  enable() {
    this.entity.on('close', () => this.reconnect())
  },
  start() {
    const {entity} = this

    if (entity.jid) {
      this.enable()
    } else {
      entity.once('online', () => this.enable())
    }
  },
  stop() {
    this.entity.removeListener('online', this.enable)
    this.entity.removeListener('close', this.onClose)
    clearTimeout(this._timeout)
  },
})