Dockerfile

This commit is contained in:
Sébastien Hut 2015-04-01 10:56:40 +02:00
parent d67440a7cc
commit 9c501c7a54
6 changed files with 579 additions and 0 deletions

44
Docker/Dockerfile Normal file
View File

@ -0,0 +1,44 @@
FROM ubuntu:14.04
ENV DEBIAN_FRONTEND noninteractive
ENV HOME /root
ENV XMPP_NAME Otalk
ENV XMPP_DOMAIN example.com
ENV XMPP_WSS wss://example.com:5281/xmpp-websocket/
ENV XMPP_MUC chat.example.com
ENV XMPP_STARTUP groupchat/room%40chat.example.com
ENV XMPP_ADMIN admin
ENV LDAP_BASE dc=example.com
ENV LDAP_DN cn=admin,dc=example.com
ENV LDAP_PWD password
ENV LDAP_GROUP mygroup
RUN sed -i 's/^#\s*\(deb.*universe\)$/\1/g' /etc/apt/sources.list && \
sed -i 's/^#\s*\(deb.*multiverse\)$/\1/g' /etc/apt/sources.list && \
apt-get -y update && \
dpkg-divert --local --rename --add /sbin/initctl && \
ln -sf /bin/true /sbin/initctl && \
dpkg-divert --local --rename --add /usr/bin/ischroot && \
ln -sf /bin/true /usr/bin/ischroot && \
apt-get -y upgrade && \
apt-get install -y vim wget sudo net-tools pwgen unzip openssh-server \
logrotate supervisor language-pack-en software-properties-common \
python-software-properties apt-transport-https ca-certificates curl && \
apt-get clean
RUN locale-gen en_US && locale-gen en_US.UTF-8 && echo 'LANG="en_US.UTF-8"' > /etc/default/locale
RUN apt-get update && apt-get install -y --force-yes nodejs git-core libldap2-dev uuid-dev
RUN apt-get remove -y --force-yes nodejs && apt-get install -y --force-yes nodejs-legacy npm
RUN git clone git://github.com/digicoop/otalk.git
RUN cd otalk && npm install
ADD app /app
RUN chmod +x /app/start.sh
CMD "/app/start.sh"

View File

@ -0,0 +1,28 @@
{
"isDev": true,
"http": {
"baseUrl": "http://localhost:8000",
"port": 8000,
"key": "./fakekeys/privatekey.pem",
"cert": "./fakekeys/certificate.pem"
},
"session": {
"secret": "shhhhhh don't tell anyone ok?"
},
"server": {
"name": "{{XMPP_NAME}}",
"domain": "{{XMPP_DOMAIN}}",
"wss": "{{XMPP_WSS}}",
"muc": "{{XMPP_MUC}}",
"startup": "{{XMPP_STARTUP}}",
"admin": "{{XMPP_ADMIN}}"
},
"ldap": {
"address": "{{LDAP_HOST}}",
"user": "{{LDAP_DN}}",
"password": "{{LDAP_PWD}}",
"base": "ou=users,{{LDAP_BASE}}",
"filter": "objectClass=person",
"group": "cn={{LDAP_GROUP}},ou=groups,{{LDAP_BASE}}"
}
}

View File

@ -0,0 +1,49 @@
'use strict';
module.exports = function (client) {
// We always need this one first
client.use(require('./disco'));
client.use(require('./attention'));
client.use(require('./avatar'));
client.use(require('./blocking'));
client.use(require('./bob'));
client.use(require('./bookmarks'));
client.use(require('./carbons'));
client.use(require('./chatstates'));
client.use(require('./command'));
client.use(require('./correction'));
client.use(require('./csi'));
client.use(require('./dataforms'));
client.use(require('./delayed'));
client.use(require('./escaping'));
client.use(require('./extdisco'));
client.use(require('./forwarding'));
client.use(require('./geoloc'));
client.use(require('./hashes'));
client.use(require('./idle'));
client.use(require('./invisible'));
client.use(require('./jidprep'));
//client.use(require('./jingle'));
client.use(require('./json'));
client.use(require('./keepalive'));
client.use(require('./logging'));
client.use(require('./mam'));
client.use(require('./muc'));
client.use(require('./mood'));
client.use(require('./nick'));
client.use(require('./oob'));
client.use(require('./ping'));
client.use(require('./private'));
client.use(require('./psa'));
client.use(require('./pubsub'));
client.use(require('./reach'));
client.use(require('./receipts'));
client.use(require('./register'));
client.use(require('./roster'));
client.use(require('./rtt'));
client.use(require('./shim'));
client.use(require('./time'));
client.use(require('./vcard'));
client.use(require('./version'));
};

265
Docker/app/stanza.io/muc.js Normal file
View File

@ -0,0 +1,265 @@
'use strict';
var stanza = require('jxt');
var Message = require('./message');
var Presence = require('./presence');
var Iq = require('./iq');
var DataForm = require('./dataforms').DataForm;
var jxtutil = require('jxt-xmpp-types');
var NS = 'http://jabber.org/protocol/muc';
var USER_NS = NS + '#user';
var ADMIN_NS = NS + '#admin';
var OWNER_NS = NS + '#owner';
var UNIQ_NS = NS + '#unique';
var proxy = function (child, field) {
return {
get: function () {
if (this._extensions[child]) {
return this[child][field];
}
},
set: function (value) {
this[child][field] = value;
}
};
};
var UserItem = stanza.define({
name: '_mucUserItem',
namespace: USER_NS,
element: 'item',
fields: {
affiliation: stanza.attribute('affiliation'),
nick: stanza.attribute('nick'),
jid: jxtutil.jidAttribute('jid'),
role: stanza.attribute('role'),
reason: stanza.subText(USER_NS, 'reason')
}
});
var UserActor = stanza.define({
name: '_mucUserActor',
namespace: USER_NS,
element: 'actor',
fields: {
nick: stanza.attribute('nick'),
jid: jxtutil.jidAttribute('jid')
}
});
var Destroyed = stanza.define({
name: 'destroyed',
namespace: USER_NS,
element: 'destroy',
fields: {
jid: jxtutil.jidAttribute('jid'),
reason: stanza.subText(USER_NS, 'reason')
}
});
var Invite = stanza.define({
name: 'invite',
namespace: USER_NS,
element: 'invite',
fields: {
to: jxtutil.jidAttribute('to'),
from: jxtutil.jidAttribute('from'),
reason: stanza.subText(USER_NS, 'reason'),
thread: stanza.subAttribute(USER_NS, 'continue', 'thread'),
'continue': stanza.boolSub(USER_NS, 'continue')
}
});
var Decline = stanza.define({
name: 'decline',
namespace: USER_NS,
element: 'decline',
fields: {
to: jxtutil.jidAttribute('to'),
from: jxtutil.jidAttribute('from'),
reason: stanza.subText(USER_NS, 'reason')
}
});
var AdminItem = stanza.define({
name: '_mucAdminItem',
namespace: ADMIN_NS,
element: 'item',
fields: {
affiliation: stanza.attribute('affiliation'),
nick: stanza.attribute('nick'),
jid: jxtutil.jidAttribute('jid'),
role: stanza.attribute('role'),
reason: stanza.subText(ADMIN_NS, 'reason')
}
});
var AdminActor = stanza.define({
name: 'actor',
namespace: USER_NS,
element: 'actor',
fields: {
nick: stanza.attribute('nick'),
jid: jxtutil.jidAttribute('jid')
}
});
var Destroy = stanza.define({
name: 'destroy',
namespace: OWNER_NS,
element: 'destroy',
fields: {
jid: jxtutil.jidAttribute('jid'),
password: stanza.subText(OWNER_NS, 'password'),
reason: stanza.subText(OWNER_NS, 'reason')
}
});
exports.MUC = stanza.define({
name: 'muc',
namespace: USER_NS,
element: 'x',
fields: {
affiliation: proxy('_mucUserItem', 'affiliation'),
nick: proxy('_mucUserItem', 'nick'),
jid: proxy('_mucUserItem', 'jid'),
role: proxy('_mucUserItem', 'role'),
actor: proxy('_mucUserItem', '_mucUserActor'),
reason: proxy('_mucUserItem', 'reason'),
password: stanza.subText(USER_NS, 'password'),
codes: {
get: function () {
return stanza.getMultiSubText(this.xml, USER_NS, 'status', function (sub) {
return stanza.getAttribute(sub, 'code');
});
},
set: function (value) {
var self = this;
stanza.setMultiSubText(this.xml, USER_NS, 'status', value, function (val) {
var child = stanza.createElement(USER_NS, 'status', USER_NS);
stanza.setAttribute(child, 'code', val);
self.xml.appendChild(child);
});
}
}
}
});
exports.MUCAdmin = stanza.define({
name: 'mucAdmin',
namespace: ADMIN_NS,
element: 'query',
fields: {
affiliation: proxy('_mucAdminItem', 'affiliation'),
nick: proxy('_mucAdminItem', 'nick'),
jid: proxy('_mucAdminItem', 'jid'),
role: proxy('_mucAdminItem', 'role'),
actor: proxy('_mucAdminItem', '_mucAdminActor'),
reason: proxy('_mucAdminItem', 'reason')
}
});
exports.MUCOwner = stanza.define({
name: 'mucOwner',
namespace: OWNER_NS,
element: 'query'
});
exports.MUCJoin = stanza.define({
name: 'joinMuc',
namespace: NS,
element: 'x',
fields: {
password: stanza.subText(NS, 'password'),
history: {
get: function () {
var result = {};
var hist = stanza.find(this.xml, this._NS, 'history');
if (!hist.length) {
return {};
}
hist = hist[0];
var maxchars = hist.getAttribute('maxchars') || '';
var maxstanzas = hist.getAttribute('maxstanas') || '';
var seconds = hist.getAttribute('seconds') || '';
var since = hist.getAttribute('since') || '';
if (maxchars) {
result.maxchars = parseInt(maxchars, 10);
}
if (maxstanzas) {
result.maxstanzas = parseInt(maxstanzas, 10);
}
if (seconds) {
result.seconds = parseInt(seconds, 10);
}
if (since) {
result.since = new Date(since);
}
},
set: function (opts) {
var existing = stanza.find(this.xml, this._NS, 'history');
if (existing.length) {
for (var i = 0; i < existing.length; i++) {
this.xml.removeChild(existing[i]);
}
}
var hist = stanza.createElement(this._NS, 'history', this._NS);
this.xml.appendChild(hist);
if (opts.maxchars) {
hist.setAttribute('maxchars' + opts.maxchars);
}
if (opts.maxstanzas) {
hist.setAttribute('maxstanzas', opts.maxstanzas);
}
if (opts.seconds) {
hist.setAttribute('seconds' + opts.seconds);
}
if (opts.since) {
hist.setAttribute('since', opts.since.toISOString());
}
}
}
}
});
exports.DirectInvite = stanza.define({
name: 'mucInvite',
namespace: 'jabber:x:conference',
element: 'x',
fields: {
jid: jxtutil.jidAttribute('jid'),
password: stanza.attribute('password'),
reason: stanza.attribute('reason'),
thread: stanza.attribute('thread'),
'continue': stanza.boolAttribute('continue')
}
});
stanza.add(Iq, 'mucUnique', stanza.subText(UNIQ_NS, 'unique'));
stanza.extend(UserItem, UserActor);
stanza.extend(exports.MUC, UserItem);
stanza.extend(exports.MUC, Invite, 'invites');
stanza.extend(exports.MUC, Decline);
stanza.extend(exports.MUC, Destroyed);
stanza.extend(AdminItem, AdminActor);
stanza.extend(exports.MUCAdmin, AdminItem, 'items');
stanza.extend(exports.MUCOwner, Destroy);
stanza.extend(exports.MUCOwner, DataForm);
stanza.extend(Presence, exports.MUC);
stanza.extend(Message, exports.MUC);
stanza.extend(Presence, exports.MUCJoin);
stanza.extend(Message, exports.DirectInvite);
stanza.extend(Iq, exports.MUCAdmin);
stanza.extend(Iq, exports.MUCOwner);

View File

@ -0,0 +1,158 @@
'use strict';
var util = require('util');
var stanza = require('jxt');
var WildEmitter = require('wildemitter');
var async = require('async');
var framing = require('../stanza/framing');
var StreamError = require('../stanza/streamError');
var WS = (require('faye-websocket') && require('faye-websocket').Client) ?
require('faye-websocket').Client :
window.WebSocket;
var WS_OPEN = 1;
function WSConnection(sm) {
var self = this;
WildEmitter.call(this);
self.sm = sm;
self.closing = false;
self.sendQueue = async.queue(function (data, cb) {
if (self.conn) {
if (typeof data !== 'string') {
data = data.toString();
}
data = new Buffer(data, 'utf8').toString();
self.emit('raw:outgoing', data);
if (self.conn.readyState === WS_OPEN) {
self.conn.send(data);
}
}
cb();
}, 1);
self.on('connected', function () {
self.send(self.startHeader());
});
self.on('raw:incoming', function (data) {
var stanzaObj, err;
data = data.trim();
if (data === '') {
return;
}
if (data.indexOf("<stream:stream") > 0 && data.indexOf("</stream:stream") == -1) {
data += "</stream:stream>";
}
if (data.indexOf("<subject/></message>") > 0) {
data = data.replace("<subject/></message>", "<subject>true</subject></message>");
}
try {
stanzaObj = stanza.parse(data);
} catch (e) {
err = new StreamError({
condition: 'invalid-xml'
});
self.emit('stream:error', err, e);
self.send(err);
return self.disconnect();
}
if (stanzaObj._name === 'openStream') {
self.hasStream = true;
self.stream = stanzaObj;
return self.emit('stream:start', stanzaObj.toJSON());
}
if (stanzaObj._name === 'closeStream') {
self.emit('stream:end');
return self.disconnect();
}
if (!stanzaObj.lang) {
stanzaObj.lang = self.stream ? self.stream.lang : "en";
}
self.emit('stream:data', stanzaObj);
});
}
util.inherits(WSConnection, WildEmitter);
WSConnection.prototype.connect = function (opts) {
var self = this;
self.config = opts;
self.hasStream = false;
self.closing = false;
self.conn = new WS(opts.wsURL, 'xmpp');
self.conn.onerror = function (e) {
e.preventDefault();
self.emit('disconnected', self);
};
self.conn.onclose = function () {
self.emit('disconnected', self);
};
self.conn.onopen = function () {
self.sm.started = false;
self.emit('connected', self);
};
self.conn.onmessage = function (wsMsg) {
self.emit('raw:incoming', new Buffer(wsMsg.data, 'utf8').toString());
};
};
WSConnection.prototype.startHeader = function () {
return new framing.Open({
version: this.config.version || '1.0',
lang: this.config.lang || 'en',
to: this.config.server
});
};
WSConnection.prototype.closeHeader = function () {
return new framing.Close();
};
WSConnection.prototype.disconnect = function () {
if (this.conn && !this.closing) {
this.closing = true;
this.send(this.closeHeader());
} else {
this.hasStream = false;
this.stream = undefined;
if (this.conn.readyState === WS_OPEN) {
this.conn.close();
}
this.conn = undefined;
}
};
WSConnection.prototype.restart = function () {
var self = this;
self.hasStream = false;
self.send(this.startHeader());
};
WSConnection.prototype.send = function (data) {
this.sendQueue.push(data);
};
module.exports = WSConnection;

35
Docker/app/start.sh Normal file
View File

@ -0,0 +1,35 @@
#!/bin/bash
echo "Configuring dev_config.json..."
export XMPP_NAME="$(echo ${XMPP_NAME} | sed 's/\//\\\//g')"
export XMPP_DOMAIN="$(echo ${XMPP_DOMAIN} | sed 's/\//\\\//g')"
export XMPP_WSS="$(echo ${XMPP_WSS} | sed 's/\//\\\//g')"
export XMPP_MUC="$(echo ${XMPP_MUC} | sed 's/\//\\\//g')"
export XMPP_STARTUP="$(echo ${XMPP_STARTUP} | sed 's/\//\\\//g')"
export XMPP_ADMIN="$(echo ${XMPP_ADMIN} | sed 's/\//\\\//g')"
sed 's/{{XMPP_NAME}}/'"${XMPP_NAME}"'/' -i /app/config/dev_config.json
sed 's/{{XMPP_DOMAIN}}/'"${XMPP_DOMAIN}"'/' -i /app/config/dev_config.json
sed 's/{{XMPP_WSS}}/'"${XMPP_WSS}"'/' -i /app/config/dev_config.json
sed 's/{{XMPP_MUC}}/'"${XMPP_MUC}"'/' -i /app/config/dev_config.json
sed 's/{{XMPP_STARTUP}}/'"${XMPP_STARTUP}"'/' -i /app/config/dev_config.json
sed 's/{{XMPP_ADMIN}}/'"${XMPP_ADMIN}"'/' -i /app/config/dev_config.json
sed 's/{{LDAP_HOST}}/'"${LDAP_PORT_389_TCP_ADDR}"'/' -i /app/config/dev_config.json
sed 's/{{LDAP_BASE}}/'"${LDAP_BASE}"'/' -i /app/config/dev_config.json
sed 's/{{LDAP_DN}}/'"${LDAP_DN}"'/' -i /app/config/dev_config.json
sed 's/{{LDAP_PWD}}/'"${LDAP_PWD}"'/' -i /app/config/dev_config.json
sed 's/{{LDAP_GROUP}}/'"${LDAP_GROUP}"'/' -i /app/config/dev_config.json
cp /app/config/dev_config.json /otalk
echo "Configuring otalk..."
cd otalk
cp /app/stanza.io/websocket.js node_modules/stanza.io/lib/transports
cp /app/stanza.io/index-browser.js node_modules/stanza.io/lib/plugins
cp /app/stanza.io/muc.js node_modules/stanza.io/lib/stanza
node server