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",
|
"tls",
|
||||||
"http",
|
"http",
|
||||||
"https",
|
"https",
|
||||||
|
"net",
|
||||||
|
"events",
|
||||||
"zlib",
|
"zlib",
|
||||||
"crypto",
|
"crypto",
|
||||||
"util",
|
"util",
|
||||||
|
|||||||
@@ -244,11 +244,8 @@ const XMPP_PASSWORD = config.get("XMPP_PASSWORD") as string;
|
|||||||
const XMPP_RESOURCE = crypto.randomBytes(8).toString("hex");
|
const XMPP_RESOURCE = crypto.randomBytes(8).toString("hex");
|
||||||
|
|
||||||
let xmppClient: XmppClient;
|
let xmppClient: XmppClient;
|
||||||
let xmppclientTimeout: NodeJS.Timeout;
|
|
||||||
|
|
||||||
function xmppClientOnError(err: Error): void {
|
function xmppClientOnError(err: Error): void {
|
||||||
clearTimeout(xmppclientTimeout);
|
|
||||||
xmppClient.disconnect();
|
|
||||||
xmppClient = null;
|
xmppClient = null;
|
||||||
logger.error({
|
logger.error({
|
||||||
message: "XMPP exception",
|
message: "XMPP exception",
|
||||||
@@ -257,8 +254,7 @@ function xmppClientOnError(err: Error): void {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function xmppClientTimeoutCallback(): void {
|
function xmppClientOnClose(): void {
|
||||||
xmppClient.disconnect();
|
|
||||||
xmppClient = null;
|
xmppClient = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -276,11 +272,12 @@ export async function xmppConnectionRequest(
|
|||||||
username,
|
username,
|
||||||
resource: XMPP_RESOURCE,
|
resource: XMPP_RESOURCE,
|
||||||
password: XMPP_PASSWORD,
|
password: XMPP_PASSWORD,
|
||||||
|
timeout: 120000,
|
||||||
});
|
});
|
||||||
xmppClient.on("error", xmppClientOnError);
|
xmppClient.on("error", xmppClientOnError);
|
||||||
|
xmppClient.on("close", xmppClientOnClose);
|
||||||
|
xmppClient.unref();
|
||||||
}
|
}
|
||||||
clearTimeout(xmppclientTimeout);
|
|
||||||
setTimeout(xmppClientTimeoutCallback, 120000);
|
|
||||||
|
|
||||||
let username: string;
|
let username: string;
|
||||||
let password: string;
|
let password: string;
|
||||||
|
|||||||
+58
-10
@@ -131,7 +131,29 @@ function saltPassword(
|
|||||||
return hi;
|
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,
|
socket: net.Socket,
|
||||||
username: string,
|
username: string,
|
||||||
password: string
|
password: string
|
||||||
@@ -263,9 +285,14 @@ function* init(
|
|||||||
const mechanisms: Set<string> = new Set(
|
const mechanisms: Set<string> = new Set(
|
||||||
feature.children.map((c) => c.text)
|
feature.children.map((c) => c.text)
|
||||||
);
|
);
|
||||||
if (mechanisms.has("SCRAM-SHA-1")) {
|
if (mechanisms.has("PLAIN")) {
|
||||||
yield* login(socket, username, password);
|
yield* loginPlain(socket, username, password);
|
||||||
return STATUS_RESTART_STREAM;
|
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") {
|
} else if (feature.name === "bind") {
|
||||||
if (feature.children.some((c) => c.name === "required")) {
|
if (feature.children.some((c) => c.name === "required")) {
|
||||||
@@ -293,6 +320,7 @@ interface XmppClientOptions {
|
|||||||
username?: string;
|
username?: string;
|
||||||
password?: string;
|
password?: string;
|
||||||
resource?: string;
|
resource?: string;
|
||||||
|
timeout?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class XmppClient extends EventEmitter {
|
export default class XmppClient extends EventEmitter {
|
||||||
@@ -343,8 +371,10 @@ export default class XmppClient extends EventEmitter {
|
|||||||
client._host = opts.host;
|
client._host = opts.host;
|
||||||
client._username = opts.username;
|
client._username = opts.username;
|
||||||
client._resource = opts.resource;
|
client._resource = opts.resource;
|
||||||
socket.on("data", client._onData);
|
socket.on("data", client._onData.bind(client));
|
||||||
socket.on("error", client._onError);
|
socket.on("error", client._onError.bind(client));
|
||||||
|
if (opts.timeout)
|
||||||
|
socket.setTimeout(opts.timeout, client.close.bind(client));
|
||||||
resolve(client);
|
resolve(client);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
socket.destroy();
|
socket.destroy();
|
||||||
@@ -354,10 +384,16 @@ export default class XmppClient extends EventEmitter {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
disconnect(): void {
|
close(): void {
|
||||||
this._socket.removeListener("data", this._onData);
|
this._socket.end("</stream>");
|
||||||
this._socket.removeListener("error", this._onError);
|
}
|
||||||
this._socket.end();
|
|
||||||
|
ref(): void {
|
||||||
|
this._socket.ref();
|
||||||
|
}
|
||||||
|
|
||||||
|
unref(): void {
|
||||||
|
this._socket.unref();
|
||||||
}
|
}
|
||||||
|
|
||||||
get host(): string {
|
get host(): string {
|
||||||
@@ -374,7 +410,12 @@ export default class XmppClient extends EventEmitter {
|
|||||||
|
|
||||||
private _onData(chunk: Buffer): void {
|
private _onData(chunk: Buffer): void {
|
||||||
try {
|
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 xml = parseXml(str);
|
||||||
const idx = xml.children.map((c) => c.bodyIndex);
|
const idx = xml.children.map((c) => c.bodyIndex);
|
||||||
for (const [i, c] of xml.children.entries()) {
|
for (const [i, c] of xml.children.entries()) {
|
||||||
@@ -389,7 +430,14 @@ export default class XmppClient extends EventEmitter {
|
|||||||
}
|
}
|
||||||
this.emit("stanza", c, s);
|
this.emit("stanza", c, s);
|
||||||
}
|
}
|
||||||
|
if (close) {
|
||||||
|
this._socket.removeAllListeners("data");
|
||||||
|
this._socket.removeAllListeners("error");
|
||||||
|
this.emit("close");
|
||||||
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
this._socket.removeAllListeners("data");
|
||||||
|
this._socket.removeAllListeners("error");
|
||||||
this.emit("error", err);
|
this.emit("error", err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user