XMPP fixes
This commit is contained in:
1 parent
79ede00ef2
commit
0e0380917f
3 files changed
+64
-17
No files matched your search
@@ -51,6 +51,8 @@ const externals = [
|
||||
"tls",
|
||||
"http",
|
||||
"https",
|
||||
"net",
|
||||
"events",
|
||||
"zlib",
|
||||
"crypto",
|
||||
"util",
|
||||
|
||||
@@ -244,11 +244,8 @@ const XMPP_PASSWORD = config.get("XMPP_PASSWORD") as string;
|
||||
const XMPP_RESOURCE = crypto.randomBytes(8).toString("hex");
|
||||
|
||||
let xmppClient: XmppClient;
|
||||
let xmppclientTimeout: NodeJS.Timeout;
|
||||
|
||||
function xmppClientOnError(err: Error): void {
|
||||
clearTimeout(xmppclientTimeout);
|
||||
xmppClient.disconnect();
|
||||
xmppClient = null;
|
||||
logger.error({
|
||||
message: "XMPP exception",
|
||||
@@ -257,8 +254,7 @@ function xmppClientOnError(err: Error): void {
|
||||
});
|
||||
}
|
||||
|
||||
function xmppClientTimeoutCallback(): void {
|
||||
xmppClient.disconnect();
|
||||
function xmppClientOnClose(): void {
|
||||
xmppClient = null;
|
||||
}
|
||||
|
||||
@@ -276,11 +272,12 @@ export async function xmppConnectionRequest(
|
||||
username,
|
||||
resource: XMPP_RESOURCE,
|
||||
password: XMPP_PASSWORD,
|
||||
timeout: 120000,
|
||||
});
|
||||
xmppClient.on("error", xmppClientOnError);
|
||||
xmppClient.on("close", xmppClientOnClose);
|
||||
xmppClient.unref();
|
||||
}
|
||||
clearTimeout(xmppclientTimeout);
|
||||
setTimeout(xmppClientTimeoutCallback, 120000);
|
||||
|
||||
let username: string;
|
||||
let password: string;
|
||||
|
||||
+58
-10
@@ -131,7 +131,29 @@ function saltPassword(
|
||||
return hi;
|
||||
}
|
||||
|
||||
function* login(
|
||||
function* loginPlain(
|
||||
socket: net.Socket,
|
||||
username: string,
|
||||
password: string
|
||||
): Generator<void, void, Element> {
|
||||
socket.write(
|
||||
`<auth xmlns="urn:ietf:params:xml:ns:xmpp-sasl" mechanism="PLAIN">${encodeBase64(
|
||||
`\x00${username}\x00${password}`
|
||||
)}</auth>`
|
||||
);
|
||||
const res1 = yield;
|
||||
|
||||
if (
|
||||
res1.name === "failure" &&
|
||||
res1.children.some((c) => c.name === "not-authorized")
|
||||
)
|
||||
throw new Error("Not authorized");
|
||||
|
||||
if (res1.name !== "success")
|
||||
throw new Error(`Unexpected response ${res1.name}`);
|
||||
}
|
||||
|
||||
function* loginScram(
|
||||
socket: net.Socket,
|
||||
username: string,
|
||||
password: string
|
||||
@@ -263,9 +285,14 @@ function* init(
|
||||
const mechanisms: Set<string> = new Set(
|
||||
feature.children.map((c) => c.text)
|
||||
);
|
||||
if (mechanisms.has("SCRAM-SHA-1")) {
|
||||
yield* login(socket, username, password);
|
||||
if (mechanisms.has("PLAIN")) {
|
||||
yield* loginPlain(socket, username, password);
|
||||
return STATUS_RESTART_STREAM;
|
||||
} else if (mechanisms.has("SCRAM-SHA-1")) {
|
||||
yield* loginScram(socket, username, password);
|
||||
return STATUS_RESTART_STREAM;
|
||||
} else {
|
||||
throw new Error("No supported SASL method");
|
||||
}
|
||||
} else if (feature.name === "bind") {
|
||||
if (feature.children.some((c) => c.name === "required")) {
|
||||
@@ -293,6 +320,7 @@ interface XmppClientOptions {
|
||||
username?: string;
|
||||
password?: string;
|
||||
resource?: string;
|
||||
timeout?: number;
|
||||
}
|
||||
|
||||
export default class XmppClient extends EventEmitter {
|
||||
@@ -343,8 +371,10 @@ export default class XmppClient extends EventEmitter {
|
||||
client._host = opts.host;
|
||||
client._username = opts.username;
|
||||
client._resource = opts.resource;
|
||||
socket.on("data", client._onData);
|
||||
socket.on("error", client._onError);
|
||||
socket.on("data", client._onData.bind(client));
|
||||
socket.on("error", client._onError.bind(client));
|
||||
if (opts.timeout)
|
||||
socket.setTimeout(opts.timeout, client.close.bind(client));
|
||||
resolve(client);
|
||||
} catch (err) {
|
||||
socket.destroy();
|
||||
@@ -354,10 +384,16 @@ export default class XmppClient extends EventEmitter {
|
||||
});
|
||||
}
|
||||
|
||||
disconnect(): void {
|
||||
this._socket.removeListener("data", this._onData);
|
||||
this._socket.removeListener("error", this._onError);
|
||||
this._socket.end();
|
||||
close(): void {
|
||||
this._socket.end("</stream>");
|
||||
}
|
||||
|
||||
ref(): void {
|
||||
this._socket.ref();
|
||||
}
|
||||
|
||||
unref(): void {
|
||||
this._socket.unref();
|
||||
}
|
||||
|
||||
get host(): string {
|
||||
@@ -374,7 +410,12 @@ export default class XmppClient extends EventEmitter {
|
||||
|
||||
private _onData(chunk: Buffer): void {
|
||||
try {
|
||||
const str = chunk.toString("utf8");
|
||||
let close = false;
|
||||
let str = chunk.toString("utf8");
|
||||
if (str.endsWith("</stream:stream>")) {
|
||||
str = str.slice(0, -16);
|
||||
close = true;
|
||||
}
|
||||
const xml = parseXml(str);
|
||||
const idx = xml.children.map((c) => c.bodyIndex);
|
||||
for (const [i, c] of xml.children.entries()) {
|
||||
@@ -389,7 +430,14 @@ export default class XmppClient extends EventEmitter {
|
||||
}
|
||||
this.emit("stanza", c, s);
|
||||
}
|
||||
if (close) {
|
||||
this._socket.removeAllListeners("data");
|
||||
this._socket.removeAllListeners("error");
|
||||
this.emit("close");
|
||||
}
|
||||
} catch (err) {
|
||||
this._socket.removeAllListeners("data");
|
||||
this._socket.removeAllListeners("error");
|
||||
this.emit("error", err);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user