Single quote in message results in error "scanner_yyerror"
cyrusmg opened this issue · 2 comments
I have been trying to get postgres-emitter working for our project, but I get following error thrown to socket.io clients:
code: "42601"
file: "scan.l"
length: 94
line: "1176"
name: "error"
position: "104"
routine: "scanner_yyerror"
severity: "ERROR"
The issue seems to be whenever the data sent to clients includes ' single quote. I unfortunately can't change the protocol, so this prevents me from using this library.
Minimal script reproduction below with your connectionString (in typescript project)
import { Pool } from 'pg';
import { Emitter } from '@socket.io/postgres-emitter';
const run = async () => {
const pool = new Pool({ connectionString: 'postgresql://<your connection string>' });
await pool.connect();
const io = new Emitter(pool);
io.emit('hello world with quote', "'"); // this one throws error
io.emit('hello world'); // this one gets to the clients correctly
};
run();
It's going to be this line probably, I will have closer look tomorrow:
socket.io-postgres-emitter/lib/index.ts
Line 383 in 1f8a6c4
This is a fix using the patch-package node module - the escapeLiteral and escapeIdentifier functions are verbatim from pg package repo: https://github.com/brianc/node-postgres/blob/684cd09bcecbf5ad5f451fdf608a3e9a9444524e/packages/pg/lib/client.js#L444
diff --git a/node_modules/@socket.io/postgres-emitter/dist/index.js b/node_modules/@socket.io/postgres-emitter/dist/index.js
index 214266f..33bb2af 100644
--- a/node_modules/@socket.io/postgres-emitter/dist/index.js
+++ b/node_modules/@socket.io/postgres-emitter/dist/index.js
@@ -244,6 +244,36 @@ class BroadcastOperator {
const flags = Object.assign({}, this.flags, { volatile: true });
return new BroadcastOperator(this.emitter, this.rooms, this.exceptRooms, flags);
}
+ // Ported from PostgreSQL 9.2.4 source code in src/interfaces/libpq/fe-exec.c
+ escapeIdentifier(str) {
+ return '"' + str.replace(/"/g, '""') + '"'
+ }
+
+ // Ported from PostgreSQL 9.2.4 source code in src/interfaces/libpq/fe-exec.c
+ escapeLiteral(str) {
+ var hasBackslash = false
+ var escaped = "'"
+
+ for (var i = 0; i < str.length; i++) {
+ var c = str[i]
+ if (c === "'") {
+ escaped += c + c
+ } else if (c === '\\') {
+ escaped += c + c
+ hasBackslash = true
+ } else {
+ escaped += c
+ }
+ }
+
+ escaped += "'"
+
+ if (hasBackslash === true) {
+ escaped = ' E' + escaped
+ }
+
+ return escaped
+ }
async publish(document) {
document.uid = EMITTER_UID;
try {
@@ -260,7 +290,7 @@ class BroadcastOperator {
return await this.publishWithAttachment(document);
}
debug("sending event of type %s to channel %s", document.type, this.emitter.channel);
- await this.emitter.pool.query(`NOTIFY "${this.emitter.channel}", '${payload}'`);
+ await this.emitter.pool.query(`NOTIFY ${this.escapeIdentifier(this.emitter.channel)}, ${this.escapeLiteral(payload)}`);
}
catch (err) {
// @ts-ignore