Bladeren bron

- Add error handling
- Secure socket closing

Parad0x 7 jaren geleden
bovenliggende
commit
49668c2d62
6 gewijzigde bestanden met toevoegingen van 176 en 101 verwijderingen
  1. 60 43
      src/bot/app.js
  2. 56 39
      src/bot/auth.js
  3. 48 18
      src/connectionHandler.js
  4. 4 1
      src/index.js
  5. 1 0
      src/init.js
  6. 7 0
      src/utils/internalError.js

+ 60 - 43
src/bot/app.js

@@ -7,6 +7,7 @@ const telegraf = require("../telegraf");
 const Extra = require('telegraf/extra');
 const Markup = require('telegraf/markup');
 const db = require("../db");
+const ie = require("../utils/internalError")("bot/app");
 
 function app() {
   if (telegraf.bot == null) {
@@ -14,61 +15,77 @@ function app() {
   }
 
   telegraf.bot.hears(/✔️\[(\d+)\] [\w ]+/, async (ctx) => {
-    let id = ctx.match[1];
-    let app = await db.App.findById(id);
-    await app.update({
-      activated: true
-    })
-    ctx.reply(`${app.name} accepted`);
+    try {
+      let id = ctx.match[1];
+      let app = await db.App.findById(id);
+      await app.update({
+        activated: true
+      })
+      ctx.reply(`${app.name} accepted`);
+    } catch (e) {
+      ie(1);
+    }
   });
 
   telegraf.bot.hears(/❌\[(\d+)\] [\w ]+/, async (ctx) => {
-    let id = ctx.match[1];
-    let app = await db.App.findById(id);
-    await app.destroy();
-    ctx.reply(`${app.name} deleted`);
+    try {
+      let id = ctx.match[1];
+      let app = await db.App.findById(id);
+      await app.destroy();
+      ctx.reply(`${app.name} deleted`);
+    } catch (e) {
+      ie(2);
+    }
   });
 
   cmdRegistry.register("pendingApps", async (ctx) => {
-    let pendingApps = await db.App.findAll({
-      where: {
-        activated: false
-      },
-      limit: 5
-    });
-    if (pendingApps <= 0) {
-      ctx.reply("No application is waiting for activation");
-      return;
+    try {
+      let pendingApps = await db.App.findAll({
+        where: {
+          activated: false
+        },
+        limit: 5
+      });
+      if (pendingApps <= 0) {
+        ctx.reply("No application is waiting for activation");
+        return;
+      }
+      let apps = pendingApps.map(el => {
+        return [
+          `✔️[${el.id}] ${el.name}`,
+          `❌[${el.id}] ${el.name}`
+        ]
+      });
+      console.log(apps);
+      return ctx.reply('Activate app', Markup
+        .keyboard(apps)
+        .oneTime()
+        .resize()
+        .extra());
+    } catch (e) {
+      ie(3);
     }
-    let apps = pendingApps.map(el => {
-      return [
-        `✔️[${el.id}] ${el.name}`,
-        `❌[${el.id}] ${el.name}`
-      ]
-    });
-    console.log(apps);
-    return ctx.reply('Activate app', Markup
-      .keyboard(apps)
-      .oneTime()
-      .resize()
-      .extra());
   });
 
   cmdRegistry.register("registerApp", async (ctx) => {
-    const args: string = await ctx.state.command.args;
-    if (args.length > 25) {
-      ctx.reply("Name to long!");
+    try {
+      const args: string = await ctx.state.command.args;
+      if (args.length > 25) {
+        ctx.reply("Name to long!");
+        return;
+      }
+      const appName = args;
+      const instance = await db.App.create({
+        name: appName,
+        activated: true
+      });
+      ctx.reply(`App registered\n` +
+        `Name: ${instance.name}\n` +
+        `Auth: ${instance.auth}`);
       return;
+    } catch (e) {
+      ie(4);
     }
-    const appName = args;
-    const instance = await db.App.create({
-      name: appName,
-      activated: true
-    });
-    ctx.reply(`App registered\n` +
-      `Name: ${instance.name}\n` +
-      `Auth: ${instance.auth}`);
-    return;
   });
 }
 module.exports = app;

+ 56 - 39
src/bot/auth.js

@@ -6,6 +6,7 @@ const cmdRegistry = require("../commandRegistry");
 const telegraf = require("../telegraf");
 const db = require("../db");
 const authCode = require("../authCode");
+const ie = require("../utils/internalError")("bot/auth");
 
 function auth() {
   if (telegraf.bot == null) {
@@ -13,62 +14,78 @@ function auth() {
   }
 
   telegraf.bot.use(async (ctx, next) => {
-    ctx.user = await db.User.findOne({
-      where: {
-        userTelegramId: ctx.from.id
-      }
-    });
+    try {
+      ctx.user = await db.User.findOne({
+        where: {
+          userTelegramId: ctx.from.id
+        }
+      });
 
-    if (!!ctx.user) {
-      if (ctx.user.permanentBan || ctx.user.activated === false && moment().diff(ctx.user.updatedAt) < moment.duration(1, 'days')) {
-        return;
+      if (!!ctx.user) {
+        if (ctx.user.permanentBan || ctx.user.activated === false && moment().diff(ctx.user.updatedAt) < moment.duration(1, 'days')) {
+          return;
+        }
       }
+      next();
+    } catch (e) {
+      ie(1);
     }
-    next();
   });
 
   cmdRegistry.register("auth", async (ctx, next) => {
-    if (ctx.user && ctx.user.activated == true) {
-      ctx.reply("Already authorised");
-      return
-    }
-    const args = ctx.state.command.args;
-    let actualAuthCode = authCode.get();
-    if (args === actualAuthCode) {
-      if (ctx.user) {
-        await ctx.user.update({
-          activated: true
-        });
-      } else {
-        let user = await db.User.findOrCreate({
-          where: {
-            userTelegramId: ctx.from.id
-          }, defaults: {
+    try {
+      if (ctx.user && ctx.user.activated == true) {
+        ctx.reply("Already authorised");
+        return
+      }
+      const args = ctx.state.command.args;
+      let actualAuthCode = authCode.get();
+      if (args === actualAuthCode) {
+        if (ctx.user) {
+          await ctx.user.update({
             activated: true
-          }
+          });
+        } else {
+          let user = await db.User.findOrCreate({
+            where: {
+              userTelegramId: ctx.from.id
+            }, defaults: {
+              activated: true
+            }
+          });
+        }
+        authCode.generate();
+        ctx.reply("User authenticated");
+      } else {
+        let user = await db.User.create({
+          userTelegramId: ctx.from.id,
+          activated: false
         });
+        ctx.reply("Wrong authentication code. Will be banned for 24H")
       }
-      authCode.generate();
-      ctx.reply("User authenticated");
-    } else {
-      let user = await db.User.create({
-        userTelegramId: ctx.from.id,
-        activated: false
-      });
-      ctx.reply("Wrong authentication code. Will be banned for 24H")
+    } catch (e) {
+      ie(2);
     }
   });
 
   telegraf.bot.use((ctx, next) => {
-    if (ctx.user) {
-      next()
-    } else {
-      ctx.reply("You need to be authorised");
+    try {
+      if (ctx.user) {
+        next()
+      } else {
+        ctx.reply("You need to be authorised");
+      }
+    } catch (e) {
+      ie(3);
     }
   })
 
   cmdRegistry.register("getAuthCode", (ctx) => {
-    ctx.reply(`Actual authentication code: ${authCode.get()}`);
+    try {
+      ctx.reply(`Actual authentication code: ${authCode.get()}`);
+    } catch (e) {
+      ie(4);
+    }
   });
 }
 module.exports = auth;

+ 48 - 18
src/connectionHandler.js

@@ -6,6 +6,7 @@ const countAndSlice = require("./utils/countAndSlice");
 const Queue = require("./utils/Queue");
 const db = require("./db");
 const telegraf = require("./telegraf");
+const ie = require("./utils/internalError")("connHand");
 
 // All connections stored by id
 const Connections = {};
@@ -24,6 +25,7 @@ class Connection {
   buffer: string;
   queue: Queue<string>;
   session: any;
+  ended: boolean;
 
   constructor(id: number, socket: Socket) {
     console.log("New connection", id);
@@ -32,31 +34,56 @@ class Connection {
     this.socket = socket;
     this.buffer = "";
     this.queue = new Queue();
+    this.ended = false;
 
     Connections[id] = this;
 
     socket.on("data", async data => {
-      data = data.toString();
-      this.buffer = this.buffer.concat(data);
-      console.log("Buffer", this.buffer);
-      let [arr, count] = countAndSlice(this.buffer);
-      if (arr.length > count) {
-        this.buffer = arr.pop();
-      } else {
-        this.buffer = "";
-      }
-      this.queue.concat(arr);
-
-      while (this.queue.length > 0) {
-        let op = this.queue.removeSync();
-        op = op.trim();
-        if (op.length > 0) {
-          await this.execute(op);
+      try {
+        data = data.toString();
+        this.buffer = this.buffer.concat(data);
+        console.log("Buffer", this.buffer);
+        let [arr, count] = countAndSlice(this.buffer);
+        if (arr.length > count) {
+          this.buffer = arr.pop();
+        } else {
+          this.buffer = "";
+        }
+        this.queue.concat(arr);
+
+        while (this.queue.length > 0) {
+          let op = this.queue.removeSync();
+          op = op.trim();
+          if (op.length > 0) {
+            try {
+              await this.execute(op);
+            } catch (e) {
+              console.log(`Error while executing op: ${op}`);
+              console.log(`ConID: ${this.id}`);
+              console.log(e);
+            }
+          }
         }
+      } catch (e) {
+        ie(1);
       }
     })
 
-    socket.on("end", () => {
+    socket.on("error", (err) => {
+      if (err.code === 'EPIPE') {
+        console.log("Socket used after being closed. (Probably by client)");
+        socket.end();
+        this.end();
+        return;
+      }
+      console.log("Connection error");
+      console.log(`ConID: ${this.id}`);
+      console.log(err);
+    });
+
+
+    socket.once("end", () => {
+      this.ended = true;
       this.end();
     });
   }
@@ -68,6 +95,7 @@ class Connection {
     } else {
       this.write("Unkown operator\n\r");
     }
+
   }
 
   // Session`s Operations
@@ -124,7 +152,9 @@ class Connection {
   // Connection methods
 
   write(input: string | Buffer) {
-    this.socket.write(input);
+    if (!this.socket.destroyed && !this.ended) {
+      this.socket.write(input);
+    }
   }
 
   end() {

+ 4 - 1
src/index.js

@@ -55,4 +55,7 @@ const socketPath = socketPathCon();
 
   process.on("SIGINT", sigHandler);
   process.on("SIGTERM", sigHandler);
-})();
+})().catch(err => {
+  console.log("Main thread error:");
+  console.log(err);
+});

+ 1 - 0
src/init.js

@@ -7,6 +7,7 @@ async function init() {
     await db.sequelize.sync();
     await bot.init();
   } catch (e) {
+    console.log("Error while initialiazing:");
     console.log(e.message);
     process.exit(-1);
   }

+ 7 - 0
src/utils/internalError.js

@@ -0,0 +1,7 @@
+//@flow
+
+module.exports = (modid) => {
+  return id => {
+    console.log(`Internal Error: sig[${modid}]${id}`);
+  }
+}