From 091d7bdd4ae60eacbb695f710fbea9f6a1223927 Mon Sep 17 00:00:00 2001 From: 3urobeat <35304405+HerrEurobeat@users.noreply.github.com> Date: Wed, 29 Jul 2020 20:00:33 +0200 Subject: [PATCH] Version 2.8 (read commit description) Added proxy support (add them in proxies.txt). Added webserver to request comments and view the log. Added !update command. Added !rc alias to !resetcooldown and "global" argument to reset global cooldown. A Steam cooldown error will now apply a 5 min global cooldown to cmd requests. Moved updater.js to src folder. Fixed a lot of bugs, made things a bit more user-friendly and made other more minor changes. (Please start the bot again manually after downloading the update!) --- README.md | 10 +- config.json | 6 +- package-lock.json | 406 ++++++++++++++++++++++++++++++-- package.json | 5 +- src/bot.js | 443 ++++++++++++++++++++--------------- src/controller.js | 136 +++++++++-- src/data.json | 10 +- updater.js => src/updater.js | 92 +++++--- start.js | 42 ++-- 9 files changed, 856 insertions(+), 294 deletions(-) rename updater.js => src/updater.js (81%) diff --git a/README.md b/README.md index 2b2f9b39..995ca892 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,7 @@ * Send comments to other steam profiles * Apply cooldowns & customize nearly any value * Advertise your group & automatically invite users to it +* Use proxies and requests comments via URL in your browser If you would like to see a detailed tutorial in the form of a video, [click here!](https://www.youtube.com/watch?v=gmA-ccD05g4) This written tutorial will also contain a video tutorial badge link for each specific part! @@ -82,7 +83,14 @@ If you have more than 1 account set up in `logininfo.json` you can specify how m Hey, if you like this project please consider donating a buck on my [PayPal!](https://paypal.me/3urobeat) [![Donate](https://img.shields.io/badge/donate-%241-orange)](https://paypal.me/3urobeat) If you like the work I put into this project, please give this repository a star! -![Star](https://img.shields.io/github/stars/HerrEurobeat/steam-comment-service-bot) +![Star](https://img.shields.io/github/stars/HerrEurobeat/steam-comment-service-bot) + +#### **Web (URL) Comment Requests** +To requests comment with an URL in your browser you need to turn the feature on. +Go into your `config.json` and set `enableurltocomment` to `true` and restart the bot. + +Open localhost:3034 in your browser and follow the instructions there. +To request comments from outside your network you need to allow the port `3034` in your router settings and visit the server with your public ip address. #### **Bugs, Issues & Betas** If you encountered a **bug**, you **need help** or wish a feature to be added, please open an [**issue!**](https://github.com/HerrEurobeat/steam-comment-service-bot/issues/new/choose) diff --git a/config.json b/config.json index ea448976..fbb8cdd1 100644 --- a/config.json +++ b/config.json @@ -2,11 +2,10 @@ "disableautoupdate": false, "childaccsplaygames": false, "commentdelay": 5000, - "logindelay": 2500, "allowcommentcmdusage": true, "skipSteamGuard": false, "commentcooldown": 5, - "globalcommentcooldown": 10000, + "globalcommentcooldown": 60000, "repeatedComments": 2, "unfriendtime": 31, "playinggames": ["!help | 3urobeat", 440, 730], @@ -15,5 +14,6 @@ "acceptgroupinvites": true, "owner": "https://steamcommunity.com/id/3urobeat", "ownerid": ["76561198260031749"], - "enableevalcmd": false + "enableevalcmd": true, + "enableurltocomment": true } \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 70481859..6ff40425 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,17 +5,17 @@ "requires": true, "dependencies": { "@bbob/parser": { - "version": "2.5.6", - "resolved": "https://registry.npmjs.org/@bbob/parser/-/parser-2.5.6.tgz", - "integrity": "sha512-qBt88OQvjfkdHH7JhTzFSIU/zV6kwhiMchADnlFIkuRMWH8dSt6pmzPzjRQzS/v8NHGSwiKtTbC01AGGLOmmOA==", + "version": "2.5.8", + "resolved": "https://registry.npmjs.org/@bbob/parser/-/parser-2.5.8.tgz", + "integrity": "sha512-B51LwSZF+Qh7XvnLFl5+HdzDvtfJ56jspuLiCa7nLOUDdnmOEF09a4rjXN2mI5YLmGnJWN0rDV032C4w3Uo3oA==", "requires": { - "@bbob/plugin-helper": "^2.5.6" + "@bbob/plugin-helper": "^2.5.8" } }, "@bbob/plugin-helper": { - "version": "2.5.6", - "resolved": "https://registry.npmjs.org/@bbob/plugin-helper/-/plugin-helper-2.5.6.tgz", - "integrity": "sha512-JQRr5aughtj9S2SyzK9kmalwbTEEpnDeyv21NRpPateehHUxiNM70QPERx/7mm4dVk21sEizUGYiMd61xfFXQQ==" + "version": "2.5.8", + "resolved": "https://registry.npmjs.org/@bbob/plugin-helper/-/plugin-helper-2.5.8.tgz", + "integrity": "sha512-mAjQGPkiIsF99ECZLTiEuTpqNedfmQr2gtKvUJFyR98oibirJIRi9Puw1WMqXOW1ZomjXYFl26LrtHEgCwHxbA==" }, "@doctormckay/stats-reporter": { "version": "1.0.5", @@ -23,9 +23,9 @@ "integrity": "sha512-lCAuKW053zz91sKZZcGfOHxigBqn0Lo+/JvHBQq3XqzLJxn0YeZ5mJ96+PZto+PDCkgg+c/BX2Xo8DvAN44xLg==" }, "@doctormckay/stdlib": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@doctormckay/stdlib/-/stdlib-1.11.1.tgz", - "integrity": "sha512-5Y30OgITXy4rGEy5hk5U2UpygGyP55IvYEBi9DJfz4+cM2spSMBxpMypbSYoVgzGKgz7byeYM4IRNeB3VWLSQw==" + "version": "1.11.2", + "resolved": "https://registry.npmjs.org/@doctormckay/stdlib/-/stdlib-1.11.2.tgz", + "integrity": "sha512-iuCNW9VVtu/hwfPMMiXAJXQfFMqW9SIkMYDQASnvY3JTP02RL0yhZE3IfsJKi5A7ht5HglgPKXRaMCYW4wDXVA==" }, "@doctormckay/steam-crypto": { "version": "1.2.0", @@ -92,9 +92,18 @@ "integrity": "sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w==" }, "@types/node": { - "version": "13.13.12", - "resolved": "https://registry.npmjs.org/@types/node/-/node-13.13.12.tgz", - "integrity": "sha512-zWz/8NEPxoXNT9YyF2osqyA9WjssZukYpgI4UYZpOjcyqwIUqWGkcCionaEb9Ki+FULyPyvNFpg/329Kd2/pbw==" + "version": "13.13.14", + "resolved": "https://registry.npmjs.org/@types/node/-/node-13.13.14.tgz", + "integrity": "sha512-Az3QsOt1U/K1pbCQ0TXGELTuTkPLOiFIQf3ILzbOyo0FqgV9SxRnxbxM5QlAveERZMHpZY+7u3Jz2tKyl+yg6g==" + }, + "accepts": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", + "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "requires": { + "mime-types": "~2.1.24", + "negotiator": "0.6.2" + } }, "adm-zip": { "version": "0.4.16", @@ -102,9 +111,9 @@ "integrity": "sha512-TFi4HBKSGfIKsK5YCkKaaFG2m4PEDyViZmEwof3MTIgzimHLto6muaHVpbrljdIvIrFZzEq/p4nafOeLcYegrg==" }, "ajv": { - "version": "6.12.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.2.tgz", - "integrity": "sha512-k+V+hzjm5q/Mr8ef/1Y9goCmlsK4I6Sm74teeyGvFk1XrOsbsKLjEdrvny42CZ+a8sXbk8KWpY/bDwS+FLL2UQ==", + "version": "6.12.3", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.3.tgz", + "integrity": "sha512-4K0cK3L1hsqk9xIb2z9vs/XU+PGJZ9PNpJRDS9YLzmNdX6jmVPfamLvTJr0aDAusnHyCHO6MjzlkAsgtqp9teA==", "requires": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -122,6 +131,11 @@ "resolved": "https://registry.npmjs.org/array-filter/-/array-filter-1.0.0.tgz", "integrity": "sha1-uveeYubvTCpMC4MSMtr/7CUfnYM=" }, + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, "asn1": { "version": "0.2.4", "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", @@ -188,6 +202,30 @@ } } }, + "body-parser": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", + "requires": { + "bytes": "3.1.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "on-finished": "~2.3.0", + "qs": "6.7.0", + "raw-body": "2.4.0", + "type-is": "~1.6.17" + }, + "dependencies": { + "qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" + } + } + }, "boolbase": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", @@ -201,6 +239,11 @@ "long": "~3" } }, + "bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" + }, "caseless": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", @@ -260,6 +303,29 @@ "delayed-stream": "~1.0.0" } }, + "content-disposition": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", + "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", + "requires": { + "safe-buffer": "5.1.2" + } + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" + }, + "cookie": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", + "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==" + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, "core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", @@ -294,6 +360,14 @@ "assert-plus": "^1.0.0" } }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, "define-properties": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", @@ -307,6 +381,16 @@ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, "dom-serializer": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.1.tgz", @@ -354,6 +438,16 @@ "safer-buffer": "^2.1.0" } }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" + }, "entities": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", @@ -387,6 +481,60 @@ "is-symbol": "^1.0.2" } }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" + }, + "express": { + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", + "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", + "requires": { + "accepts": "~1.3.7", + "array-flatten": "1.1.1", + "body-parser": "1.19.0", + "content-disposition": "0.5.3", + "content-type": "~1.0.4", + "cookie": "0.4.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.1.2", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.5", + "qs": "6.7.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.1.2", + "send": "0.17.1", + "serve-static": "1.14.1", + "setprototypeof": "1.1.1", + "statuses": "~1.5.0", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "dependencies": { + "qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" + } + } + }, "extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", @@ -412,6 +560,20 @@ "resolved": "https://registry.npmjs.org/file-manager/-/file-manager-2.0.0.tgz", "integrity": "sha512-AX9jtqrrHK9JT4v3J7uMZGkDNiuuG4y4T6LoNm3lKzT/vReLCY8mnRWIpaG2ffNEpJHSkiwKejpu8x8THEYPzg==" }, + "finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + } + }, "foreach": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", @@ -432,6 +594,16 @@ "mime-types": "^2.1.12" } }, + "forwarded": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" + }, "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", @@ -514,6 +686,25 @@ } } }, + "http-errors": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", + "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + }, + "dependencies": { + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + } + } + }, "http-signature": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", @@ -529,6 +720,14 @@ "resolved": "https://registry.npmjs.org/https/-/https-1.0.0.tgz", "integrity": "sha1-PDfHrhqO65ZpBKKtHpdaGUt+06Q=" }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, "image-size": { "version": "0.8.3", "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.8.3.tgz", @@ -542,6 +741,11 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, + "ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" + }, "is-arguments": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.0.4.tgz", @@ -705,6 +909,26 @@ "resolved": "https://registry.npmjs.org/lzma/-/lzma-2.3.2.tgz", "integrity": "sha1-N4OySFi5wOdHoN88vx+1/KqSxEE=" }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" + }, "mime-db": { "version": "1.44.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz", @@ -718,6 +942,16 @@ "mime-db": "1.44.0" } }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "negotiator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" + }, "node-bignumber": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/node-bignumber/-/node-bignumber-1.2.1.tgz", @@ -757,6 +991,24 @@ "object-keys": "^1.0.11" } }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "requires": { + "ee-first": "1.1.1" + } + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + }, "performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", @@ -771,9 +1023,9 @@ } }, "protobufjs": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.9.0.tgz", - "integrity": "sha512-LlGVfEWDXoI/STstRDdZZKb/qusoAWUnmLg9R8OLSO473mBLWHowx8clbX5/+mKDEI+v7GzjoK9tRPZMMcoTrg==", + "version": "6.10.1", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.10.1.tgz", + "integrity": "sha512-pb8kTchL+1Ceg4lFd5XUpK8PdWacbvV5SK2ULH2ebrYtl4GjJmS24m6CKME67jzV53tbJxHlnNOSqQHbTsR9JQ==", "requires": { "@protobufjs/aspromise": "^1.1.2", "@protobufjs/base64": "^1.1.2", @@ -797,6 +1049,15 @@ } } }, + "proxy-addr": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz", + "integrity": "sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==", + "requires": { + "forwarded": "~0.1.2", + "ipaddr.js": "1.9.1" + } + }, "psl": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", @@ -820,6 +1081,22 @@ "inherits": "~2.0.3" } }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" + }, + "raw-body": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", + "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", + "requires": { + "bytes": "3.1.0", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + } + }, "readable-stream": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", @@ -872,6 +1149,49 @@ "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" }, + "send": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", + "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", + "requires": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.7.2", + "mime": "1.6.0", + "ms": "2.1.1", + "on-finished": "~2.3.0", + "range-parser": "~1.2.1", + "statuses": "~1.5.0" + }, + "dependencies": { + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + } + } + }, + "serve-static": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", + "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.17.1" + } + }, + "setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + }, "sshpk": { "version": "1.16.1", "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", @@ -888,6 +1208,11 @@ "tweetnacl": "~0.14.0" } }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" + }, "steam-appticket": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/steam-appticket/-/steam-appticket-1.0.1.tgz", @@ -906,12 +1231,12 @@ "integrity": "sha512-d+tjnr3wwDkbrKFxjYZ0uK4CSF09oJwCmlGH8SdOlTDkbtBPuNhPKY0XzZxQVltZF6/JkEYj+uz+kBr6UrY7BQ==" }, "steam-user": { - "version": "4.16.2", - "resolved": "https://registry.npmjs.org/steam-user/-/steam-user-4.16.2.tgz", - "integrity": "sha512-WZLtb3fqKRJNprKfnxyRL0w/iTdqZFUHiiuVpQ4xk3qVXME8e5KygV2tDZ/P1nDtJ/cLjkv5ksWHKHDiHe/K2w==", + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/steam-user/-/steam-user-4.17.0.tgz", + "integrity": "sha512-WpyCbd/BfUbNiJ+R+NzUeRuZlm/vzSyn4TGfRDayw0epCpaGxoB8dGIJHHtdkxqv9O/2+URUtEB0F9CHJ+SGew==", "requires": { "@bbob/parser": "^2.2.0", - "@doctormckay/stdlib": "^1.11.0", + "@doctormckay/stdlib": "^1.11.1", "@doctormckay/steam-crypto": "^1.2.0", "adm-zip": "^0.4.13", "appdirectory": "^0.1.0", @@ -928,9 +1253,9 @@ } }, "steamcommunity": { - "version": "3.41.5", - "resolved": "https://registry.npmjs.org/steamcommunity/-/steamcommunity-3.41.5.tgz", - "integrity": "sha512-BtjvLG9QM/Y9s5nKjzJ0LX2s/bJhf8d4gcdzeL1wM9OCo8e+bZFIbgucy+CxRO/L6/k/lIeSiATWMW56CZbWCA==", + "version": "3.41.6", + "resolved": "https://registry.npmjs.org/steamcommunity/-/steamcommunity-3.41.6.tgz", + "integrity": "sha512-ruO20CNGrnNn3zq1PcRU34Aw/9no0PS9jQx1oAm4C5+T2M034i0uO4Wi22RtByLBKLMce0UYZ54x4BJ5NRfxhg==", "requires": { "async": "^2.6.3", "cheerio": "0.22.0", @@ -993,6 +1318,11 @@ } } }, + "toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" + }, "tough-cookie": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", @@ -1015,6 +1345,20 @@ "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + } + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + }, "uri-js": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", @@ -1041,11 +1385,21 @@ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" + }, "uuid": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + }, "vdf": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/vdf/-/vdf-0.0.2.tgz", diff --git a/package.json b/package.json index 3ffb82be..97ba18c0 100644 --- a/package.json +++ b/package.json @@ -4,10 +4,11 @@ "description": "Request multiple steam profile comments by texting a bot network!", "main": "start.js", "dependencies": { + "express": "^4.17.1", "htmlparser2": "^4.1.0", "https": "^1.0.0", - "steam-user": "^4.16.2", - "steamcommunity": "^3.41.4" + "steam-user": "^4.17.0", + "steamcommunity": "^3.41.6" }, "devDependencies": {}, "scripts": { diff --git a/src/bot.js b/src/bot.js index 72d89a70..5cc5b3b2 100644 --- a/src/bot.js +++ b/src/bot.js @@ -1,6 +1,7 @@ //Code by: https://github.com/HerrEurobeat/ //If you are here, you are wrong. Open config.json and configure everything there! +//This file contains: Code for each bot instance (most of the code only affects the main bot) and handling most of the talking with Steam. module.exports.run = async (logOnOptions, loginindex) => { const SteamUser = require('steam-user'); @@ -10,7 +11,7 @@ module.exports.run = async (logOnOptions, loginindex) => { const xml2js = require('xml2js'); const https = require('https') - var updater = require('../updater.js'); + var updater = require('./updater.js'); var controller = require("./controller.js"); var config = require('../config.json'); var extdata = require('./data.json'); @@ -18,14 +19,21 @@ module.exports.run = async (logOnOptions, loginindex) => { var lastcomment = require("./lastcomment.json"); var logger = controller.logger - - const bot = new SteamUser(); - const community = new SteamCommunity(); var commentedrecently = false; //global cooldown for the comment command accstoadd = [] + lastcommentrequestmsg = [] if (loginindex == 0) var thisbot = "Main" else var thisbot = `Bot ${loginindex}` + + //Get proxy of this bot account + if (controller.proxyShift >= controller.proxies.length) controller.proxyShift = 0; //reset proxy counter + controller.proxyShift++ //switch to next proxy + var thisproxy = controller.proxies[controller.proxyShift] + + const bot = new SteamUser({ httpProxy: thisproxy }); + const community = new SteamCommunity(); + if (loginindex == 0) { //group64id only needed by main bot -> remove unnecessary load from other bots if (cachefile.configgroup == config.yourgroup) { //id is stored in cache file, no need to get it again @@ -71,13 +79,15 @@ module.exports.run = async (logOnOptions, loginindex) => { if(controller.accisloggedin) { clearInterval(loggedininterval) //stop interval controller.accisloggedin = false; //set to false again - logger(`[${thisbot}] Trying to log in...`, false, true) + if (thisproxy == null) logger(`[${thisbot}] Trying to log in without proxy...`, false, true) + else logger(`[${thisbot}] Trying to log in with proxy ${controller.proxyShift}...`, false, true) bot.logOn(logOnOptions) } }, 250); bot.on('error', (err) => { //Handle errors that were caused during logOn logger(`Error while trying to log in bot${loginindex}: ${err}`, true) + if (thisproxy != null) logger(`Is your proxy ${controller.proxyShift} offline or blocked by Steam?`, true) if (loginindex == 0) { logger("\nAborting because the first bot account always needs to be logged in!\nPlease correct what caused the error and try again.", true) @@ -159,11 +169,173 @@ module.exports.run = async (logOnOptions, loginindex) => { bot.on('loggedOn', () => { //this account is now logged on logger(`[${thisbot}] Account logged in! Waiting for websession...`, false, true) bot.setPersona(1); //set online status - if (loginindex == 0) bot.gamesPlayed(config.playinggames); //set game only for the "leader" bot - else if (config.childaccsplaygames) { config.playinggames.shift(); bot.gamesPlayed(config.playinggames); } + if (loginindex == 0) bot.gamesPlayed(config.playinggames); //set game only for the main bot + if (loginindex != 0 && config.childaccsplaygames) bot.gamesPlayed(config.playinggames.slice(1, config.playinggames.length)) //play game with child bots but remove the custom game controller.communityobject[loginindex] = community //export this community instance to the communityobject to access it from controller.js controller.botobject[loginindex] = bot //export this bot instance to the botobject to access it from controller.js + + + if (loginindex == 0) { + /* --------- The comment command (outside of friendMessage Event to be able to call it from controller.js) --------- */ + + commentcmd = function commentcmd(steamID, args, res) { + var requesterSteamID = new SteamID(String(steamID)).getSteamID64() //save steamID of comment requesting user so that messages are being send to the requesting user and not to the reciever if a profileid has been provided + + function respondmethod(msg) { //we need a function to get each response back to the user (web request & steam chat) + if (res) { + logger("Web Comment Request response: " + msg) + res.send(msg + "

The log will contain further information and errors (if one should occur). You can display it by visiting: /output") + } else { + bot.chat.sendFriendMessage(requesterSteamID, msg) + } } + + var steam64id = new SteamID(String(steamID)).getSteamID64() + var lastcommentsteamID = steam64id + loginindex + + /* --------- Check for cmd spamming --------- */ + if (Date.now() - lastcommentrequestmsg[requesterSteamID] < 2500) { + return bot.chat.sendFriendMessage(steamID, "Please don't spam this command.") } + + lastcommentrequestmsg[requesterSteamID] = Date.now() + + /* --------- Check for disabled comment cmd or if update is queued --------- */ + if (updater.activeupdate) return respondmethod("The bot is currently waiting for the last requested comment to be finished in order to download an update!\nPlease wait a moment and try again."); + if (config.allowcommentcmdusage === false && !config.ownerid.includes(steam64id)) return respondmethod("The bot owner set this command to owners only.\nType !owner to get information who the owner is.\nType !about to get a link to the bot creator.") + + + /* --------- Define command usage messages for each user's priviliges --------- */ //Note: Web Comment Requests always use config.ownerid[0] + var ownercheck = config.ownerid.includes(steam64id) + if (ownercheck) { + if (Object.keys(controller.communityobject).length > 1 || config.repeatedComments > 1) var commentcmdusage = `'!comment number_of_comments/"all" profileid' for X many or the max amount of comments (max ${Object.keys(controller.communityobject).length * config.repeatedComments}). Provide a profile id to comment on a specific profile.` + else var commentcmdusage = `'!comment 1 profileid'. Provide a profile id to comment on a specific profile.` + } else { + if (Object.keys(controller.communityobject).length > 1 || config.repeatedComments > 1) var commentcmdusage = `'!comment number_of_comments/"all"' for X many or the max amount of comments (max ${Object.keys(controller.communityobject).length * config.repeatedComments}).` + else var commentcmdusage = `'!comment' for a comment on your profile!` } + + + /* ------------------ Check for cooldowns ------------------ */ + if (config.commentcooldown !== 0) { //check for user specific cooldown + if ((Date.now() - lastcomment[lastcommentsteamID].time) < (config.commentcooldown * 60000)) { //check if user has cooldown applied + var remainingcooldown = Math.abs(((Date.now() - lastcomment[lastcommentsteamID].time) / 1000) - (config.commentcooldown * 60)) + var remainingcooldownunit = "seconds" + if (remainingcooldown > 120) { var remainingcooldown = remainingcooldown / 60; var remainingcooldownunit = "minutes" } + if (remainingcooldown > 120) { var remainingcooldown = remainingcooldown / 60; var remainingcooldownunit = "hours" } + + respondmethod(`You requested a comment in the last ${config.commentcooldown} minutes. Please wait the remaining ${controller.round(remainingcooldown, 2)} ${remainingcooldownunit}.`) //send error message + return; } + } else { + if (controller.activecommentprocess.indexOf(String(steam64id)) !== -1) { //is the user already getting comments? (-1 means not included) + return respondmethod("You are currently recieving previously requested comments. Please wait for them to be completed.") }} + + if (config.globalcommentcooldown != 0) { //check for global cooldown + if ((Date.now() - commentedrecently) < config.globalcommentcooldown) { + var remainingglobalcooldown = Math.abs((((Date.now() - commentedrecently)) - (config.globalcommentcooldown)) / 1000) + var remainingglobalcooldownunit = "seconds" + if (remainingglobalcooldown > 120) { var remainingglobalcooldown = remainingglobalcooldown / 60; var remainingglobalcooldownunit = "minutes" } + if (remainingglobalcooldown > 120) { var remainingglobalcooldown = remainingglobalcooldown / 60; var remainingglobalcooldownunit = "hours" } + + respondmethod(`Someone else requested a comment in the last ${controller.round(remainingglobalcooldown, 2)} ${remainingglobalcooldownunit} or a cooldown error occurred. Please wait a moment before trying again.`) //send error message + return; }} + + /* --------- Check numberofcomments argument if it was provided --------- */ + if (args[0] !== undefined) { + if (isNaN(args[0])) { //isn't a number? + if (args[0].toLowerCase() == "all") { + args[0] = Object.keys(controller.communityobject).length * config.repeatedComments //replace the argument with the max amount of comments + } else { + return respondmethod(`This is not a valid number!\nCommand usage: ${commentcmdusage}`) + } + } + + if (args[0] > Object.keys(controller.communityobject).length * config.repeatedComments) { //number is greater than accounts * repeatedComments? + return respondmethod(`You can request max. ${Object.keys(controller.communityobject).length * config.repeatedComments} comments.\nCommand usage: ${commentcmdusage}`) } + var numberofcomments = args[0] + + //Code by: https://github.com/HerrEurobeat/ + + + /* --------- Check profileid argument if it was provided --------- */ + if (args[1] !== undefined) { + if (config.ownerid.includes(new SteamID(String(steamID)).getSteamID64()) || args[1] == new SteamID(String(steamID)).getSteamID64()) { //check if user is a bot owner or if he provided his own profile id + if (isNaN(args[1])) return respondmethod(`This is not a valid profileid! A profile id must look like this: 76561198260031749\nCommand usage: ${commentcmdusage}`) + if (new SteamID(args[1]).isValid() == false) return respondmethod(`This is not a valid profileid! A profile id must look like this: 76561198260031749\nCommand usage: ${commentcmdusage}`) + + steamID.accountid = parseInt(new SteamID(args[1]).accountid) //edit accountid value of steamID parameter of friendMessage event and replace requester's accountid with the new one + } else { + respondmethod("Specifying a profileid is only allowed for bot owners.\nIf you are a bot owner, make sure you added your ownerid to the config.json.") + return; }} } //arg[0] if statement ends here + + + /* --------- Check if user did not provide numberofcomments --------- */ + if (numberofcomments === undefined) { //no numberofcomments given? ask again + if (Object.keys(controller.botobject).length == 1 && config.repeatedComments == 1) { var numberofcomments = 1 } else { //if only one account is active, set 1 automatically + respondmethod(`Please specify how many comments out of ${Object.keys(controller.communityobject).length * config.repeatedComments} you would like to request.\nCommand usage: ${commentcmdusage}`) + return; }} + + + /* --------- Check for steamcommunity related errors/limitations --------- */ + //Check all accounts if they are limited and send user profile link if not friends + accstoadd[requesterSteamID] = [] + + for (i in controller.botobject) { + if (Number(i) + 1 <= numberofcomments && Number(i) + 1 <= Object.keys(controller.botobject).length) { //only check if this acc is needed for a comment + try { + if (controller.botobject[i].limitations.limited == true && !Object.keys(controller.botobject[i].myFriends).includes(new SteamID(String(steamID)).getSteamID64())) { + accstoadd[requesterSteamID].push(`\n 'https://steamcommunity.com/profiles/${new SteamID(String(controller.botobject[i].steamID)).getSteamID64()}'`) } + } catch (err) { + logger("Error checking if comment requester is friend with limited bot accounts: " + err) }} //This error check was implemented as a temporary solution to fix this error (and should be fine since it seems that this error is rare and at least prevents from crashing the bot): https://github.com/HerrEurobeat/steam-comment-service-bot/issues/54 + + + if (Number(i) + 1 == numberofcomments && accstoadd[requesterSteamID].length > 0 || Number(i) + 1 == Object.keys(controller.botobject).length && accstoadd[requesterSteamID].length > 0) { + respondmethod(`In order to request ${numberofcomments} comments you/the recieving user will first need to add this/these accounts: (limited bot accounts)\n` + accstoadd[requesterSteamID]) + return; } } //stop right here criminal + + community.getSteamUser(steamID, (err, user) => { //check if profile is private + if (err) return logger(`[${thisbot}] comment check for private account error: ${err}`) + if (user.privacyState != "public") return respondmethod("Your/the recieving profile seems to be private. Please edit your/the privacy settings on your/the recieving profile and try again!") + + /* --------- Actually start the commenting process --------- */ + var randomstring = arr => arr[Math.floor(Math.random() * arr.length)]; + var comment = randomstring(controller.quotes); //get random quote + + community.postUserComment(steamID, comment, (error) => { //post comment + if(error) { + respondmethod(`Oops, an error occurred! Details: \n[${thisbot}] postUserComment error: ${error}\nPlease try again in a moment!`); + logger(`[${thisbot}] postUserComment error: ${error}`); + + if (error == "Error: HTTP error 429" || error == "Error: You've been posting too frequently, and can't make another post right now") commentedrecently = Date.now() + 300000 //add 5 minutes to commentedrecently if cooldown error + return; } + + logger(`\x1b[32m[${thisbot}] ${numberofcomments} Comment(s) requested. Comment on ${steam64id}: ${comment}\x1b[0m`) + if (numberofcomments == 1) respondmethod('Okay I commented on your/the recieving profile! If you are a nice person then leave a +rep on my profile!') + else { + var waittime = ((numberofcomments - 1) * config.commentdelay) / 1000 //calculate estimated wait time (first comment is instant -> remove 1 from numberofcomments) + var waittimeunit = "seconds" + if (waittime > 120) { var waittime = waittime / 60; var waittimeunit = "minutes" } + if (waittime > 120) { var waittime = waittime / 60; var waittimeunit = "hours" } + respondmethod(`Estimated wait time for ${numberofcomments} comments: ${Number(Math.round(waittime+'e'+3)+'e-'+3)} ${waittimeunit}.`) + + controller.commenteverywhere(steamID, numberofcomments, requesterSteamID, res) } //Let all other accounts comment + + + /* --------- Activate globalcooldown & give user cooldown --------- */ + if (config.globalcommentcooldown !== 0) { + commentedrecently = Date.now() } + + if (controller.botobject[loginindex].myFriends[requesterSteamID] === 3) { + lastcomment[requesterSteamID + loginindex] = { + time: Date.now(), + bot: bot.steamID.accountid } + fs.writeFile("./src/lastcomment.json", JSON.stringify(lastcomment, null, 4), err => { + if (err) logger(`[${thisbot}] delete user from lastcomment.json error: ${err}`) }) } }) + }) } //This was the critical part of this bot. Let's carry on and hope that everything holds together. + + Object.keys(controller.botobject[0]).push(commentcmd) + controller.botobject[0].commentcmd = commentcmd + + /* --------- End of comment command --------- */ + } }); bot.on("webSession", (sessionID, cookies) => { //get websession (log in to chat) @@ -183,7 +355,7 @@ module.exports.run = async (logOnOptions, loginindex) => { if (bot.myFriends[Object.keys(bot.myFriends)[i]] == 2) { bot.addFriend(Object.keys(bot.myFriends)[i]); //accept friend request logger(`[${thisbot}] Added user while I was offline! User: ` + Object.keys(bot.myFriends)[i]) - bot.chatMessage(String(Object.keys(bot.myFriends)[i]), 'Hello there! Thanks for adding me!\nRequest a free comment with !comment\nType !help for more commands or !about for more information!') + bot.chat.sendFriendMessage(String(Object.keys(bot.myFriends)[i]), 'Hello there! Thanks for adding me!\nRequest a free comment with !comment\nType !help for more commands or !about for more information!') lastcomment[Object.keys(bot.myFriends)[i] + loginindex] = { //add user to lastcomment file in order to also unfriend him when he never used !comment time: Date.now() - (config.commentcooldown * 60000), //subtract unfriendtime to enable comment usage immediately @@ -217,7 +389,7 @@ module.exports.run = async (logOnOptions, loginindex) => { bot.addFriend(steamID); //accept friend request logger(`[${thisbot}] Added User: ` + new SteamID(String(steamID)).getSteamID64()) if (loginindex === 0) { - bot.chatMessage(steamID, 'Hello there! Thanks for adding me!\nRequest a free comment with !comment\nType !help for more commands or !about for more information!') } + bot.chat.sendFriendMessage(steamID, 'Hello there! Thanks for adding me!\nRequest a free comment with !comment\nType !help for more commands or !about for more information!') } if (configgroup64id.length > 1 && Object.keys(bot.myGroups).includes(configgroup64id)) { bot.inviteToGroup(steamID, new SteamID(configgroup64id)); //invite the user to your group @@ -244,13 +416,19 @@ module.exports.run = async (logOnOptions, loginindex) => { } }); + /* ------------ Message interactions: ------------ */ bot.on('friendMessage', function(steamID, message) { var steam64id = new SteamID(String(steamID)).getSteamID64() logger(`[${thisbot}] Friend message from ${steam64id}: ${message}`); //log message + //Deny non-friends the use of any command + if (bot.myFriends[steam64id] != 3) return bot.chat.sendFriendMessage(steamID, "Please add me before using a command!") + if (loginindex === 0) { //check if this is the main bot - var msgrecievedtime = Date.now() //timestamp to calculate time needed to process request + //Check if bot is not fully started yet and block cmd usage if that is the case to prevent errors + if (controller.readyafter == 0) return bot.chat.sendFriendMessage(steamID, "The bot is not completely started yet. Please wait a moment before using a command.") + var lastcommentsteamID = steam64id + loginindex var cont = message.slice("!").split(" "); @@ -275,170 +453,50 @@ module.exports.run = async (logOnOptions, loginindex) => { if (Object.keys(controller.communityobject).length > 1 || config.repeatedComments > 1) var commenttext = `'!comment (amount/"all")' - Request x many or the max amount of comments (max ${Object.keys(controller.communityobject).length * config.repeatedComments}).` else var commenttext = `'!comment' - Request a comment on your profile!` } - if (ownercheck) var resetcooldowntext = `\n'!resetcooldown [profileid]'                 - Clear your or the profileid's comment cooldown.`; else var resetcooldowntext = ""; + if (ownercheck) var resetcooldowntext = `\n'!resetcooldown [profileid/"global"]' - Clear your, the profileid's or the global comment cooldown. Alias: !rc`; else var resetcooldowntext = ""; if (ownercheck) var addfriendtext = `\n'!addfriend (profileid)'                          - Add friend with all bot accounts.`; else var addfriendtext = ""; if (ownercheck) var unfriendtext = `\n'!unfriend (profileid)'                            - Unfriend the user from all bot accounts.`; else var unfriendtext = ""; if (ownercheck) var leavegrouptext = `\n'!leavegroup (groupid64/group url)' - Leave this group with all bot accounts.`; else var leavegrouptext = ""; if (ownercheck) var evaltext = `\n'!eval (javascript code)'                       - Run javascript code from the steam chat.`; else var evaltext = ""; if (ownercheck) var restarttext = `\n'!restart'                                                  - Restart the bot.`; else var restarttext = ""; + if (ownercheck) var updatetext = `\n'!update [true]'                                      - Check for an available update. 'true' forces an update.`; else var updatetext = ""; if (config.yourgroup.length > 1) var yourgrouptext = "\nJoin my '!group'!"; else var yourgrouptext = ""; - bot.chatMessage(steamID, ` + bot.chat.sendFriendMessage(steamID, ` () <-- needed argument\n[] <-- optional argument\n\nCommand list:\n ${commenttext} '!ping'                                                       - Get a pong and heartbeat in ms. '!info'                                                        - Get useful information about the bot and you.${resetcooldowntext}${addfriendtext}${unfriendtext}${leavegrouptext} '!failed'                                                     - See the exact errors of your last comment request. '!about'                                                    - Returns information what this is about. - '!owner'                                                   - Get a link to the profile of the operator of this bot instance.${evaltext}${restarttext} + '!owner'                                                   - Get a link to the profile of the operator of this bot instance.${evaltext}${restarttext}${updatetext} ${yourgrouptext} `) break; /* ------------------ Comment command ------------------ */ case '!comment': - - /* --------- Check for disabled comment cmd or if update is queued --------- */ - if (updater.activeupdate) return bot.chatMessage(steamID, "The bot is currently waiting for the last requested comment to be finished in order to download an update!\nPlease wait a moment and try again."); - if (config.allowcommentcmdusage === false && !config.ownerid.includes(steam64id)) return bot.chatMessage(steamID, "The bot owner set this command to owners only.\nType !owner to get information who the owner is.\nType !about to get a link to the bot creator.") - - - /* --------- Define command usage messages for each user's priviliges --------- */ - var ownercheck = config.ownerid.includes(steam64id) - if (ownercheck) { - if (Object.keys(controller.communityobject).length > 1 || config.repeatedComments > 1) var commentcmdusage = `'!comment number_of_comments/"all" profileid' for X many or the max amount of comments (max ${Object.keys(controller.communityobject).length * config.repeatedComments}). Provide a profile id to comment on a specific profile.` - else var commentcmdusage = `'!comment 1 profileid'. Provide a profile id to comment on a specific profile.` - } else { - if (Object.keys(controller.communityobject).length > 1 || config.repeatedComments > 1) var commentcmdusage = `'!comment number_of_comments/"all"' for X many or the max amount of comments (max ${Object.keys(controller.communityobject).length * config.repeatedComments}).` - else var commentcmdusage = `'!comment' for a comment on your profile!` } - - - /* ------------------ Check for cooldowns ------------------ */ - if (config.commentcooldown !== 0) { //check for user specific cooldown - if ((Date.now() - lastcomment[lastcommentsteamID].time) < (config.commentcooldown * 60000)) { //check if user has cooldown applied - var remainingcooldown = Math.abs(((Date.now() - lastcomment[lastcommentsteamID].time) / 1000) - (config.commentcooldown * 60)) - var remainingcooldownunit = "seconds" - if (remainingcooldown > 120) { var remainingcooldown = remainingcooldown / 60; var remainingcooldownunit = "minutes" } - if (remainingcooldown > 120) { var remainingcooldown = remainingcooldown / 60; var remainingcooldownunit = "hours" } - - bot.chatMessage(steamID, `You requested a comment in the last ${config.commentcooldown} minutes. Please wait the remaining ${controller.round(remainingcooldown, 2)} ${remainingcooldownunit}.`) //send error message - return; } - } else { - if (controller.activecommentprocess.indexOf(String(steam64id)) !== -1) { //is the user already getting comments? (-1 means not included) - return bot.chatMessage(steamID, "You are currently recieving previously requested comments. Please wait for them to be completed.") }} - - if (config.globalcommentcooldown !== 0) { //check for global cooldown - if (commentedrecently) { - bot.chatMessage(steamID, `Someone else requested a comment in the last ${config.globalcommentcooldown / 1000} seconds. Please wait a moment.`) //send error message - return; }} - - - var requesterSteamID = new SteamID(String(steamID)).getSteamID64() //save steamID of comment requesting user so that messages are being send to the requesting user and not to the reciever if a profileid has been provided - - - /* --------- Check numberofcomments argument if it was provided --------- */ - if (args[0] !== undefined) { - if (isNaN(args[0])) { //isn't a number? - if (args[0].toLowerCase() == "all") { - args[0] = Object.keys(controller.communityobject).length * config.repeatedComments //replace the argument with the max amount of comments - } else { - return bot.chatMessage(steamID, `This is not a valid number!\nCommand usage: ${commentcmdusage}`) - } - } - - if (args[0] > Object.keys(controller.communityobject).length * config.repeatedComments) { //number is greater than accounts * repeatedComments? - return bot.chatMessage(steamID, `You can request max. ${Object.keys(controller.communityobject).length * config.repeatedComments} comments.\nCommand usage: ${commentcmdusage}`) } - var numberofcomments = args[0] - - //Code by: https://github.com/HerrEurobeat/ - - - /* --------- Check profileid argument if it was provided --------- */ - if (args[1] !== undefined) { - if (config.ownerid.includes(new SteamID(String(steamID)).getSteamID64()) || args[1] == new SteamID(String(steamID)).getSteamID64()) { //check if user is a bot owner or if he provided his own profile id - if (isNaN(args[1])) return bot.chatMessage(steamID, `This is not a valid profileid! A profile id must look like this: 76561198260031749\nCommand usage: ${commentcmdusage}`) - if (new SteamID(args[1]).isValid() === false) return bot.chatMessage(steamID, `This is not a valid profileid! A profile id must look like this: 76561198260031749\nCommand usage: ${commentcmdusage}`) - - steamID.accountid = parseInt(new SteamID(args[1]).accountid) //edit accountid value of steamID parameter of friendMessage event and replace requester's accountid with the new one - } else { - bot.chatMessage(steamID, "Specifying a profileid is only allowed for bot owners.\nIf you are a bot owner, make sure you added your ownerid to the config.json.") - return; }} } //arg[0] if statement ends here - - - /* --------- Check if user did not provide numberofcomments --------- */ - if (numberofcomments === undefined) { //no numberofcomments given? ask again - if (Object.keys(controller.botobject).length == 1 && config.repeatedComments == 1) { var numberofcomments = 1 } else { //if only one account is active, set 1 automatically - bot.chatMessage(requesterSteamID, `Please specify how many comments out of ${Object.keys(controller.communityobject).length * config.repeatedComments} you would like to request.\nCommand usage: ${commentcmdusage}`) - return; }} - - - /* --------- Check for steamcommunity related errors/limitations --------- */ - //Check all accounts if they are limited and send user profile link if not friends - accstoadd[requesterSteamID] = [] - - for (i in controller.botobject) { - if (Number(i) + 1 <= numberofcomments && Number(i) + 1 <= Object.keys(controller.botobject).length) { //only check if this acc is wanted for a comment - if (controller.botobject[i].limitations.limited == true && !Object.keys(controller.botobject[i].myFriends).includes(steam64id)) { - accstoadd[requesterSteamID].push(`\n 'https://steamcommunity.com/profiles/${new SteamID(String(controller.botobject[i].steamID)).getSteamID64()}'`) }} - - if (Number(i) + 1 == numberofcomments && accstoadd[requesterSteamID].length > 0 || Number(i) + 1 == Object.keys(controller.botobject).length && accstoadd[requesterSteamID].length > 0) { - bot.chatMessage(steamID, `In order to request ${numberofcomments} comments you will first need to add this/these accounts: (limited bot accounts)\n` + accstoadd[requesterSteamID]) - return; } } //stop right here criminal - - community.getSteamUser(steamID, (err, user) => { //check if profile is private - if (err) return logger(`[${thisbot}] comment check for private account error: ${err}`) - if (user.privacyState != "public") return bot.chatMessage(steamID, "Your/the recieving profile seems to be private. Please edit your/the privacy settings on your/the recieving profile and try again!") }); - - - /* --------- Actually start the commenting process --------- */ - var randomstring = arr => arr[Math.floor(Math.random() * arr.length)]; - var comment = randomstring(controller.quotes); //get random quote - - community.postUserComment(steamID, comment, (error) => { //post comment - if(error) { - bot.chatMessage(requesterSteamID, `Oops, an error occurred! Details: \n[${thisbot}] postUserComment error: ${error}\nPlease try again in a moment!`); - logger(`[${thisbot}] postUserComment error: ${error}`); - return; } - - logger(`\x1b[32m[${thisbot}] ${numberofcomments} Comment(s) requested. Comment on ${steam64id}: ${comment}\x1b[0m`) - if (numberofcomments == 1) bot.chatMessage(requesterSteamID, 'Okay I commented on your/the recieving profile! If you are a nice person then leave a +rep on my profile!') - else { - var waittime = ((numberofcomments - 1) * config.commentdelay) / 1000 //calculate estimated wait time (first comment is instant -> remove 1 from numberofcomments) - var waittimeunit = "seconds" - if (waittime > 120) { var waittime = waittime / 60; var waittimeunit = "minutes" } - if (waittime > 120) { var waittime = waittime / 60; var waittimeunit = "hours" } - bot.chatMessage(requesterSteamID, `Estimated wait time for ${numberofcomments} comments: ${Number(Math.round(waittime+'e'+3)+'e-'+3)} ${waittimeunit}.`) - - controller.commenteverywhere(steamID, numberofcomments, requesterSteamID) //Let all other accounts comment - } - - - /* --------- Activate globalcooldown & give user cooldown --------- */ - if (config.globalcommentcooldown !== 0) { - commentedrecently = true; - setTimeout(() => { //global cooldown - commentedrecently = false; - }, config.globalcommentcooldown) } - - if (controller.botobject[loginindex].myFriends[requesterSteamID] === 3) { - lastcomment[requesterSteamID + loginindex] = { - time: Date.now(), - bot: bot.steamID.accountid } - fs.writeFile("./src/lastcomment.json", JSON.stringify(lastcomment, null, 4), err => { - if (err) logger(`[${thisbot}] delete user from lastcomment.json error: ${err}`) }) } }) - - //This was the critical part of this bot. Let's carry on and hope that everything holds together. + commentcmd(steamID, args) //Just call the function like normal when the command was used break; - case '!ping': - bot.chatMessage(steamID, `Pong!\nHeartbeat: ${Date.now() - msgrecievedtime}ms`) + var pingstart = Date.now() + + output = "" + https.get(`https://steamcommunity.com/ping`, function(res){ + res.setEncoding('utf8'); + res.on('data', function (chunk) { + output += chunk }); + + res.on('end', () => { + bot.chat.sendFriendMessage(steamID, `Pong! 🏓\nTime to steamcommunity.com/ping response: ${Date.now() - pingstart}ms`) + }) }) break; case '!info': - bot.chatMessage(steamID, ` + bot.chat.sendFriendMessage(steamID, ` -----------------------------------~~~~~------------------------------------ >   ${extdata.mestr}'s Comment Bot [Version ${extdata.version}] (More info: !about) >   Uptime: ${Number(Math.round(((new Date() - controller.bootstart) / 3600000)+'e'+2)+'e-'+2)} hours | Heartbeat: ${Date.now() - msgrecievedtime}ms >   'node.js' Version: ${process.version} | RAM Usage (RSS): ${Math.round(process.memoryUsage()["rss"] / 1024 / 1024 * 100) / 100} MB - >   Accounts logged in: ${Object.keys(controller.communityobject).length} | Branch: ${updater.releasemode} + >   Accounts logged in: ${Object.keys(controller.communityobject).length} | repeatedComments: ${config.repeatedComments} | Branch: ${updater.releasemode} | >   Your steam64ID: ${steam64id} >   Your last comment request: ${(new Date(lastcomment[lastcommentsteamID].time)).toISOString().replace(/T/, ' ').replace(/\..+/, '')} (UTC/GMT time) @@ -446,52 +504,57 @@ module.exports.run = async (logOnOptions, loginindex) => { `) break; case '!owner': - if (config.owner.length < 1) return bot.chatMessage(steamID, "I don't know that command. Type !help for more info.\n(Bot Owner didn't include link to him/herself.)") - bot.chatMessage(steamID, "Check out my owner's profile: (for more information about the bot type !about)\n" + config.owner) + if (config.owner.length < 1) return bot.chat.sendFriendMessage(steamID, "I don't know that command. Type !help for more info.\n(Bot Owner didn't include link to him/herself.)") + bot.chat.sendFriendMessage(steamID, "Check out my owner's profile: (for more information about the bot type !about)\n" + config.owner) break; case '!group': - if (config.yourgroup.length < 1 || configgroup64id.length < 1) return bot.chatMessage(steamID, "The botowner of this instance hasn't provided any group or the group doesn't exist.") //no group info at all? stop. + if (config.yourgroup.length < 1 || configgroup64id.length < 1) return bot.chat.sendFriendMessage(steamID, "The botowner of this instance hasn't provided any group or the group doesn't exist.") //no group info at all? stop. if (configgroup64id.length > 1 && Object.keys(bot.myGroups).includes(configgroup64id)) { - bot.inviteToGroup(steamID, configgroup64id); bot.chatMessage(steamID, "I send you an invite! Thanks for joining!"); + bot.inviteToGroup(steamID, configgroup64id); bot.chat.sendFriendMessage(steamID, "I send you an invite! Thanks for joining!"); if (configgroup64id != "103582791464712227") { //https://steamcommunity.com/groups/3urobeatGroup bot.inviteToGroup(steamID, new SteamID("103582791464712227")); } return; } //id? send invite and stop - bot.chatMessage(steamID, "Join my group here: " + config.yourgroup) //seems like no id has been saved but an url. Send the user the url + bot.chat.sendFriendMessage(steamID, "Join my group here: " + config.yourgroup) //seems like no id has been saved but an url. Send the user the url break; + case '!rc': case '!resetcooldown': - if (!config.ownerid.includes(steam64id)) return bot.chatMessage(steamID, "This command is only available for the botowner.\nIf you are the botowner, make sure you added your ownerid to the config.json.") + if (!config.ownerid.includes(steam64id)) return bot.chat.sendFriendMessage(steamID, "This command is only available for the botowner.\nIf you are the botowner, make sure you added your ownerid to the config.json.") if (config.commentcooldown === 0) { //is the cooldown enabled? - return bot.chatMessage(steamID, "The cooldown is disabled in the config!") } + return bot.chat.sendFriendMessage(steamID, "The cooldown is disabled in the config!") } if (args[0]) { - if (isNaN(args[0])) return bot.chatMessage(steamID, "This is not a valid profileid! A profile id must look like this: 76561198260031749") - if (new SteamID(args[0]).isValid() === false) return bot.chatMessage(steamID, "This is not a valid profileid! A profile id must look like this: 76561198260031749") + if (args[0] == "global") { //Check if user wants to reset the global cooldown + commentedrecently -= config.globalcommentcooldown //subtract cooldown on top the stored time + return bot.chat.sendFriendMessage(steamID, "The global comment cooldown has been reset.") } + + if (isNaN(args[0])) return bot.chat.sendFriendMessage(steamID, "This is not a valid profileid! A profile id must look like this: 76561198260031749") + if (new SteamID(args[0]).isValid() === false) return bot.chat.sendFriendMessage(steamID, "This is not a valid profileid! A profile id must look like this: 76561198260031749") var lastcommentsteamID = args[0] + loginindex } if ((Date.now() - lastcomment[lastcommentsteamID].time) < (config.commentcooldown * 60000)) { //check if user has cooldown applied lastcomment[lastcommentsteamID].time = Date.now() - (config.commentcooldown * 60000) fs.writeFile("./src/lastcomment.json", JSON.stringify(lastcomment, null, 4), err => { if (err) logger(`[${thisbot}] remove ${lastcommentsteamID} from lastcomment.json error: ${err}`) }) - bot.chatMessage(steamID, `${lastcommentsteamID.toString().slice(0, -1)}'s cooldown has been cleared.`) } else { - bot.chatMessage(steamID, `There is no cooldown for ${lastcommentsteamID.toString().slice(0, -1)} applied.`) } + bot.chat.sendFriendMessage(steamID, `${lastcommentsteamID.toString().slice(0, -1)}'s cooldown has been cleared.`) } else { + bot.chat.sendFriendMessage(steamID, `There is no cooldown for ${lastcommentsteamID.toString().slice(0, -1)} applied.`) } break; case '!failed': - if (!controller.failedcomments[steam64id] || Object.keys(controller.failedcomments[steam64id]).length < 1) return bot.chatMessage(steamID, "I can't remember any failed comments you have requested."); - bot.chatMessage(steamID, `Your last request for '${steam64id}' from '${(new Date(lastcomment[lastcommentsteamID].time)).toISOString().replace(/T/, ' ').replace(/\..+/, '')}' (UTC/GMT time) had these errors:\n\n${JSON.stringify(controller.failedcomments[steam64id], null, 4)}`) + if (!controller.failedcomments[steam64id] || Object.keys(controller.failedcomments[steam64id]).length < 1) return bot.chat.sendFriendMessage(steamID, "I can't remember any failed comments you have requested."); + bot.chat.sendFriendMessage(steamID, `Your last request for '${steam64id}' from '${(new Date(lastcomment[lastcommentsteamID].time)).toISOString().replace(/T/, ' ').replace(/\..+/, '')}' (UTC/GMT time) had these errors:\n\n${JSON.stringify(controller.failedcomments[steam64id], null, 4)}`) break; case '!about': //Please don't change this message as it gives credit to me; the person who put really much of his free time into this project. The bot will still refer to you - the operator of this instance. - bot.chatMessage(steamID, controller.aboutstr) + bot.chat.sendFriendMessage(steamID, controller.aboutstr) break; case '!addfriend': - if (!config.ownerid.includes(steam64id)) return bot.chatMessage(steamID, "This command is only available for the botowner.\nIf you are the botowner, make sure you added your ownerid to the config.json.") - if (isNaN(args[0])) return bot.chatMessage(steamID, "This is not a valid profileid! A profile id must look like this: 76561198260031749") - if (new SteamID(args[0]).isValid() === false) return bot.chatMessage(steamID, "This is not a valid profileid! A profile id must look like this: 76561198260031749") + if (!config.ownerid.includes(steam64id)) return bot.chat.sendFriendMessage(steamID, "This command is only available for the botowner.\nIf you are the botowner, make sure you added your ownerid to the config.json.") + if (isNaN(args[0])) return bot.chat.sendFriendMessage(steamID, "This is not a valid profileid! A profile id must look like this: 76561198260031749") + if (new SteamID(args[0]).isValid() === false) return bot.chat.sendFriendMessage(steamID, "This is not a valid profileid! A profile id must look like this: 76561198260031749") if (controller.botobject[0].limitations.limited == true) { - bot.chatMessage(steamID, `Can't add friend ${args[0]} with bot0 because the bot account is limited.`) + bot.chat.sendFriendMessage(steamID, `Can't add friend ${args[0]} with bot0 because the bot account is limited.`) return; } - bot.chatMessage(steamID, `Adding friend ${args[0]} with all bots... This will take ~${5 * Object.keys(controller.botobject).length} seconds. Please check the terminal for potential errors.`) + bot.chat.sendFriendMessage(steamID, `Adding friend ${args[0]} with all bots... This will take ~${5 * Object.keys(controller.botobject).length} seconds. Please check the terminal for potential errors.`) logger(`Adding friend ${args[0]} with all bots. This will take ~${5 * Object.keys(controller.botobject).length} seconds.`) Object.keys(controller.botobject).forEach((i) => { @@ -511,19 +574,19 @@ module.exports.run = async (logOnOptions, loginindex) => { } }) break; case '!unfriend': - if (!config.ownerid.includes(steam64id)) return bot.chatMessage(steamID, "This command is only available for the botowner.\nIf you are the botowner, make sure you added your ownerid to the config.json.") - if (isNaN(args[0])) return bot.chatMessage(steamID, "This is not a valid profileid! A profile id must look like this: 76561198260031749") - if (new SteamID(args[0]).isValid() === false) return bot.chatMessage(steamID, "This is not a valid profileid! A profile id must look like this: 76561198260031749") + if (!config.ownerid.includes(steam64id)) return bot.chat.sendFriendMessage(steamID, "This command is only available for the botowner.\nIf you are the botowner, make sure you added your ownerid to the config.json.") + if (isNaN(args[0])) return bot.chat.sendFriendMessage(steamID, "This is not a valid profileid! A profile id must look like this: 76561198260031749") + if (new SteamID(args[0]).isValid() === false) return bot.chat.sendFriendMessage(steamID, "This is not a valid profileid! A profile id must look like this: 76561198260031749") Object.keys(controller.botobject).forEach((i) => { if (controller.botobject[i].myFriends[new SteamID(args[0])] === 3) { //check if provided user is really a friend controller.botobject[i].removeFriend(new SteamID(args[0])) }}) - bot.chatMessage(steamID, `Removed friend ${args[0]} from all bots.`) + bot.chat.sendFriendMessage(steamID, `Removed friend ${args[0]} from all bots.`) logger(`Removed friend ${args[0]} from all bots.`) break; case '!leavegroup': - if (!config.ownerid.includes(steam64id)) return bot.chatMessage(steamID, "This command is only available for the botowner.\nIf you are the botowner, make sure you added your ownerid to the config.json.") - if (isNaN(args[0]) && !String(args[0]).startsWith('https://steamcommunity.com/groups/')) return bot.chatMessage(steamID, "This is not a valid group id or group url! \nA groupid must look like this: '103582791464712227' \n...or a group url like this: 'https://steamcommunity.com/groups/3urobeatGroup'") + if (!config.ownerid.includes(steam64id)) return bot.chat.sendFriendMessage(steamID, "This command is only available for the botowner.\nIf you are the botowner, make sure you added your ownerid to the config.json.") + if (isNaN(args[0]) && !String(args[0]).startsWith('https://steamcommunity.com/groups/')) return bot.chat.sendFriendMessage(steamID, "This is not a valid group id or group url! \nA groupid must look like this: '103582791464712227' \n...or a group url like this: 'https://steamcommunity.com/groups/3urobeatGroup'") if (String(args[0]).startsWith('https://steamcommunity.com/groups/')) { leavegroupoutput = "" @@ -534,7 +597,7 @@ module.exports.run = async (logOnOptions, loginindex) => { leavegroupres.on('end', () => { if (!String(leavegroupoutput).includes("")) { //Check if botsgroupoutput is steam group xml data before parsing it logger("\x1b[0m[\x1b[31mNotice\x1b[0m] Your leave group link doesn't seem to be valid!", true); - bot.chatMessage("\x1b[0m[\x1b[31mNotice\x1b[0m] Your leave group link doesn't seem to be valid!\n") + bot.chat.sendFriendMessage("\x1b[0m[\x1b[31mNotice\x1b[0m] Your leave group link doesn't seem to be valid!\n") } else { new xml2js.Parser().parseString(leavegroupoutput, function(err, leavegroupResult) { if (err) return logger("error parsing leavegroup xml: " + err, true) @@ -544,56 +607,62 @@ module.exports.run = async (logOnOptions, loginindex) => { }) } }) }).on("error", function(err) { logger("\x1b[0m[\x1b[31mNotice\x1b[0m]: Couldn't get leavegroup information. Either Steam is down or your internet isn't working.\n Error: " + err) - bot.chatMessage(steamID, "\x1b[0m[\x1b[31mNotice\x1b[0m]: Couldn't get leavegroup information. Either Steam is down or your internet isn't working.\n Error: " + err) + bot.chat.sendFriendMessage(steamID, "\x1b[0m[\x1b[31mNotice\x1b[0m]: Couldn't get leavegroup information. Either Steam is down or your internet isn't working.\n Error: " + err) return; }) } else { startleavegroup() } function startleavegroup() { var argsSteamID = new SteamID(String(args[0])) - if (argsSteamID.isValid() === false || argsSteamID["type"] !== 7) return bot.chatMessage(steamID, "This is not a valid group id or group url! \nA groupid must look like this: '103582791464712227' \n...or a group url like this: 'https://steamcommunity.com/groups/3urobeatGroup'") + if (argsSteamID.isValid() === false || argsSteamID["type"] !== 7) return bot.chat.sendFriendMessage(steamID, "This is not a valid group id or group url! \nA groupid must look like this: '103582791464712227' \n...or a group url like this: 'https://steamcommunity.com/groups/3urobeatGroup'") Object.keys(controller.botobject).forEach((i) => { if (controller.botobject[i].myGroups[argsSteamID] === 3) { controller.communityobject[i].leaveGroup(argsSteamID) }}) - bot.chatMessage(steamID, `Left group '${args[0]}' with all bots.`) + bot.chat.sendFriendMessage(steamID, `Left group '${args[0]}' with all bots.`) logger(`Left group ${args[0]} with all bots.`) } break; case '!restart': - if (!config.ownerid.includes(steam64id)) return bot.chatMessage(steamID, "This command is only available for the botowner.\nIf you are the botowner, make sure you added your ownerid to the config.json.") - bot.chatMessage(steamID, 'Restarting...') + if (!config.ownerid.includes(steam64id)) return bot.chat.sendFriendMessage(steamID, "This command is only available for the botowner.\nIf you are the botowner, make sure you added your ownerid to the config.json.") + bot.chat.sendFriendMessage(steamID, 'Restarting...') require('../start.js').restart(updater.skippedaccounts) break; + case '!update': + if (!config.ownerid.includes(steam64id)) return bot.chat.sendFriendMessage(steamID, "This command is only available for the botowner.\nIf you are the botowner, make sure you added your ownerid to the config.json.") + + if (args[0] == "true") { updater.checkforupdate(true, steamID); bot.chat.sendFriendMessage(steamID, `Forcing an update from the ${extdata.branch} branch...`) } + else { updater.checkforupdate(false, steamID); bot.chat.sendFriendMessage(steamID, `Checking for an update in the ${extdata.branch} branch...`) } + break; case '!eval': - if (config.enableevalcmd !== true) return bot.chatMessage(steamID, "The eval command has been turned off!") - if (!config.ownerid.includes(steam64id)) return bot.chatMessage(steamID, "This command is only available for the botowner.\nIf you are the botowner, make sure you added your ownerid to the config.json.") + if (config.enableevalcmd !== true) return bot.chat.sendFriendMessage(steamID, "The eval command has been turned off!") + if (!config.ownerid.includes(steam64id)) return bot.chat.sendFriendMessage(steamID, "This command is only available for the botowner.\nIf you are the botowner, make sure you added your ownerid to the config.json.") const clean = text => { if (typeof(text) === "string") return text.replace(/`/g, "`" + String.fromCharCode(8203)).replace(/@/g, "@" + String.fromCharCode(8203)); else return text; } try { const code = args.join(" "); - if (code.includes('logininfo')) return bot.chatMessage(steamID, "Your code includes 'logininfo'. In order to protect passwords this is not allowed.") //not 100% save but should be at least some protection (only owners can use this cmd) + if (code.includes('logininfo')) return bot.chat.sendFriendMessage(steamID, "Your code includes 'logininfo'. In order to protect passwords this is not allowed.") //not 100% save but should be at least some protection (only owners can use this cmd) let evaled = eval(code); if (typeof evaled !== "string") evaled = require("util").inspect(evaled); - bot.chatMessage(steamID, `Code executed. Result:\n\n${clean(evaled)}`) + bot.chat.sendFriendMessage(steamID, `Code executed. Result:\n\n${clean(evaled)}`) logger('\n\x1b[33mEval result:\x1b[0m \n' + clean(evaled) + "\n", true) } catch (err) { - bot.chatMessage(steamID, `Error:\n${clean(err)}`) + bot.chat.sendFriendMessage(steamID, `Error:\n${clean(err)}`) logger('\n\x1b[33mEval error:\x1b[0m \n' + clean(err) + "\n", true) //Hi I'm a comment that serves no purpose return; } break; default: //cmd not recognized - bot.chatMessage(steamID, "I don't know that command. Type !help for more info.") } + bot.chat.sendFriendMessage(steamID, "I don't know that command. Type !help for more info.") } } else { switch(message.toLowerCase()) { case '!about': //Please don't change this message as it gives credit to me; the person who put really much of his free time into this project. The bot will still refer to you - the operator of this instance. - bot.chatMessage(steamID, controller.aboutstr) + bot.chat.sendFriendMessage(steamID, controller.aboutstr) break; default: - bot.chatMessage(steamID, `This is one account running in a bot cluster.\nPlease add the main bot and send him a !help message.\nIf you want to check out what this is about, type: !about\nhttps://steamcommunity.com/profiles/${new SteamID(String(controller.botobject[0].steamID)).getSteamID64()}`) + bot.chat.sendFriendMessage(steamID, `This is one account running in a bot cluster.\nPlease add the main bot and send him a !help message.\nIf you want to check out what this is about, type: !about\nhttps://steamcommunity.com/profiles/${new SteamID(String(controller.botobject[0].steamID)).getSteamID64()}`) } } }); diff --git a/src/controller.js b/src/controller.js index 708546e3..42767091 100644 --- a/src/controller.js +++ b/src/controller.js @@ -1,13 +1,15 @@ //Code by: https://github.com/HerrEurobeat/ //If you are here, you are wrong. Open config.json and configure everything there! +//This file contains: Controlling bot.js instances, processing instance over-reaching requests, handling web comment requests and saving stuff in variables. + const SteamID = require('steamid'); const fs = require('fs'); const https = require('https') const readline = require("readline") const xml2js = require('xml2js') -var updater = require('../updater.js') +var updater = require('./updater.js') var b = require('./bot.js'); var logininfo = require('../logininfo.json'); var config = require('../config.json'); @@ -18,15 +20,20 @@ var botobject = new Object(); var readyafterlogs = new Array(); var failedcomments = new Array(); var accstoadd = new Array(); -var bootstart = 0; +var bootstart = 0 var bootstart = new Date(); -var steamGuardInputTime = 0; +var steamGuardInputTime = 0 var readyafter = 0 var activecommentprocess = new Array(); +var logindelay = 2500 +var proxyShift = 0 skippednow = [] //array to track which accounts have been skipped stoplogin = false; -process.title = `${extdata.mestr}'s Steam Comment Service Bot v${extdata.version} | ${process.platform}` //set node process name to find it in task manager etc. +if (process.platform == "win32") { //set node process name to find it in task manager etc. + process.title = `${extdata.mestr}'s Steam Comment Service Bot v${extdata.version} | ${process.platform}` //Windows allows long terminal/process names +} else { + process.title = `CommentBot` } //Linux has a length limit of 10 /* ------------ Functions: ------------ */ var logger = (str, nodate, remove) => { //Custom logger @@ -56,12 +63,20 @@ process.on('unhandledRejection', (reason, p) => { var quotes = new Array(); var quotes = fs.readFileSync('quotes.txt', 'utf8').split("\n"); //get all quotes from the quotes.txt file into an array +var quotes = quotes.filter(str => str != "") //remove empty quotes as empty comments will not work/make no sense //Please don't change this message as it gives credit to me; the person who put really much of his free time into this project. The bot will still refer to you - the operator of this instance. if (config.owner.length > 1) var ownertext = config.owner; else var ownertext = "anonymous (no owner link provided)"; const aboutstr = `${extdata.aboutstr} \n\nDisclaimer: I (the developer) am not responsible and cannot be held liable for any action the operator/user of this bot uses it for.\nThis instance of the bot is used and operated by: ${ownertext}`; -var commenteverywhere = (steamID, numberofcomments, requesterSteamID) => { //function to let all bots comment +var commenteverywhere = (steamID, numberofcomments, requesterSteamID, res) => { //function to let all bots comment + function respondmethod(msg) { //we need a function to get each response back to the user (web request & steam chat) + if (res) { + logger("Web Comment Request: " + msg) + } else { + botobject[0].chat.sendFriendMessage(requesterSteamID, msg) + } } + failedcomments[requesterSteamID] = {} module.exports.activecommentprocess.push(requesterSteamID) @@ -71,8 +86,8 @@ var commenteverywhere = (steamID, numberofcomments, requesterSteamID) => { //fun if (Object.keys(failedcomments[requesterSteamID]).length > 0) { failedcmdreference = "To get detailed information why which comment failed please type '!failed'. You can read why your error was probably caused here: https://github.com/HerrEurobeat/steam-comment-service-bot/wiki/Errors,-FAQ-&-Common-problems" } else { failedcmdreference = "" } - if (!Object.values(failedcomments[requesterSteamID]).includes("postUserComment error: Skipped because of previous HTTP 429 error.")) { //send chatMessage only the first time - botobject[0].chatMessage(requesterSteamID, `Stopped comment process because of a HTTP 429 (cooldown) error. Please try again later. Failed: ${numberofcomments - i + 1}/${numberofcomments}\n\n${failedcmdreference}`) + if (!Object.values(failedcomments[requesterSteamID]).includes("postUserComment error: Skipped because of previous HTTP 429 error.")) { //send chat.sendFriendMessage only the first time + respondmethod(`Stopped comment process because of a HTTP 429 (cooldown) error. Please try again later. Failed: ${numberofcomments - i + 1}/${numberofcomments}\n\n${failedcmdreference}`) var m = 0; for (var l = i + 1; l <= numberofcomments; l++) { //push all other comments to instanly complete the failedcomments obj @@ -101,9 +116,9 @@ var commenteverywhere = (steamID, numberofcomments, requesterSteamID) => { //fun if (i == numberofcomments - 1) { //last iteration - if (Object.keys(failedcomments[requesterSteamID]).length > 0) { failedcmdreference = "To get detailed information why which comment failed please type '!failed'. You can read why your error was probably caused here: https://github.com/HerrEurobeat/steam-comment-service-bot/wiki/Errors,-FAQ-&-Common-problems" + if (Object.keys(failedcomments[requesterSteamID]).length > 0) { failedcmdreference = "\nTo get detailed information why which comment failed please type '!failed'. You can read why your error was probably caused here: https://github.com/HerrEurobeat/steam-comment-service-bot/wiki/Errors,-FAQ-&-Common-problems" } else { failedcmdreference = "" } - botobject[0].chatMessage(requesterSteamID, `All comments have been sent. Failed: ${Object.keys(failedcomments[requesterSteamID]).length}/${numberofcomments}\n${failedcmdreference}`); + respondmethod(`All comments have been sent. Failed: ${Object.keys(failedcomments[requesterSteamID]).length}/${numberofcomments}${failedcmdreference}`); fs.writeFile("./src/lastcomment.json", JSON.stringify(lastcomment, null, 4), err => { //write all lastcomment changes on last iteration if (err) logger("add user to lastcomment.json from updateeverywhere() error: " + err) }) @@ -116,7 +131,7 @@ var commenteverywhere = (steamID, numberofcomments, requesterSteamID) => { //fun accstoadd[requesterSteamID].push(`\n 'https://steamcommunity.com/profiles/${new SteamID(String(botobject[i].steamID)).getSteamID64()}'`) } if (i == Object.keys(botobject).length - 1) - botobject[0].chatMessage(requesterSteamID, "-----------------------------------\nIt seems like at least one of the requested comments could have failed because you/the recieving account aren't/isn't friend with the commenting bot account.\n\nPlease make sure that you have added these accounts in order to eventually avoid this error in the future: \n" + accstoadd[requesterSteamID] + "\n-----------------------------------") + respondmethod("-----------------------------------\nIt seems like at least one of the requested comments could have failed because you/the recieving account aren't/isn't friend with the commenting bot account.\n\nPlease make sure that you have added these accounts in order to eventually avoid this error in the future: \n" + accstoadd[requesterSteamID] + "\n-----------------------------------") } } module.exports.activecommentprocess = activecommentprocess.filter(item => item !== requesterSteamID) @@ -174,7 +189,7 @@ if(updater.onlinemestr!==extdata.mestr||updater.onlineaboutstr!==extdata.aboutst //Check config values: if (stoplogin == true) return; logger("Checking for invalid config values...", false, true) -if (config.allowcommentcmdusage === false && new SteamID(config.ownerid[0]).isValid() === false) { +if (config.allowcommentcmdusage === false && new SteamID(String(config.ownerid[0])).isValid() === false) { logger("\x1b[31mYou set allowcommentcmdusage to false but didn't specify an ownerid! Aborting...\x1b[0m", true) process.exit(0); } if (config.repeatedComments < 1) { @@ -196,14 +211,14 @@ fs.readFile('./src/cache.json', function (err, data) { cachefile = require("./cache.json") } catch (err) { if (err) { - logger("Your cache.json is broken. No worries I will apply duct tape.\nError: " + err + "\n", true) + if (!extdata.firststart) logger("Your cache.json is broken. No worries I will apply duct tape.\nError: " + err + "\n", true); fs.writeFile('./src/cache.json', "{}", (err) => { //write empty valid json if (err) { logger("Error writing {} to cache.json.\nPlease do this manually: Go into 'src' folder, open 'cache.json', write '{}' and save.\nOtherwise the bot will always crash.\nError: " + err + "\n\nAborting...", true); process.exit(0) //abort since writeFile was unable to write and any further execution would crash } else { - logger("Successfully cleared cache.json.", false, true) + logger("Successfully cleared/created cache.json.", false, true) cachefile = require("./cache.json") } }) }} }) @@ -227,15 +242,36 @@ fs.readFile('./src/lastcomment.json', function (err, data) { logger("Error writing {} to lastcomment.json.\nPlease do this manually: Go into 'src' folder, open 'lastcomment.json', write '{}' and save.\nOtherwise the bot will always crash.\nError: " + err + "\n\nAborting...", true); process.exit(0) //abort since writeFile was unable to write and any further execution would crash } else { - logger("Successfully cleared logininfo.json.", false, true) + logger("Successfully cleared lastcomment.json.", false, true) lastcomment = require("./lastcomment.json") isSteamOnline(true, true); //Continue startup } }) }} }) +//Check proxies.txt +var proxies = [] //when the file is just created there can't be proxies in it (this bot doesn't support magic) + +if (!fs.existsSync('./proxies.txt')){ + fs.writeFile("./proxies.txt", "", err => { + if (err) logger("error creating proxies.txt file: ") + err }) +} else { //file does seem to exist so now we can try and read it + var proxies = fs.readFileSync('./proxies.txt', 'utf8').split("\n"); + var proxies = proxies.filter(str => str != "") //remove empty lines + proxies.unshift(null) } //add no proxy (default) + + if(typeof checkm8 == "undefined"){logger("\n\n\x1b[31mYou removed needed parts from the code! Please redownload the application and not modify anything.\x1b[0m",true);process.exit(0)} if(checkm8!="b754jfJNgZWGnzogvl { + if (err) logger("error writing created urlrequestsecretkey to data.json: " + err) }) +} + //Check if Steam is online: var isSteamOnline = function isSteamOnline(continuewithlogin, stoponerr) { if (stoplogin == true) return; @@ -253,6 +289,7 @@ module.exports={ bootstart, steamGuardInputTimeFunc, steamGuardInputTime, + readyafter, logger, communityobject, botobject, @@ -266,7 +303,10 @@ module.exports={ aboutstr, round, isSteamOnline, - skippednow } + skippednow, + proxies, + proxyShift, + logininfo } /* ------------ Startup & Login: ------------ */ @@ -282,7 +322,7 @@ function startlogin() { //function will be called when steamcommunity status che //Evaluate estimated wait time for login: logger("Evaluating estimated login time...", false, true) if (extdata.timesloggedin < 5) { //only use new evaluation method when the bot was started more than 5 times - var estimatedlogintime = ((config.logindelay * (Object.keys(logininfo).length - 1 - updater.skippedaccounts.length)) / 1000) + 10 //10 seconds tolerance + var estimatedlogintime = ((logindelay * (Object.keys(logininfo).length - 1 - updater.skippedaccounts.length)) / 1000) + 10 //10 seconds tolerance } else { var estimatedlogintime = (extdata.totallogintime / extdata.timesloggedin) * (Object.keys(logininfo).length - updater.skippedaccounts.length) } @@ -301,7 +341,7 @@ function startlogin() { //function will be called when steamcommunity status che clearInterval(startnextinterval) if (updater.skippedaccounts.includes(i)) { logger(`[skippedaccounts] Automatically skipped ${k}!`, false, true); skippednow.push(i); return; } //if this iteration exists in the skippedaccounts array, automatically skip acc again - if (i > 0) logger(`Waiting ${config.logindelay / 1000} seconds... (config logindelay)`, false, true) //first iteration doesn't need to wait duh + if (i > 0) logger(`Waiting ${logindelay / 1000} seconds... (config logindelay)`, false, true) //first iteration doesn't need to wait duh setTimeout(() => { //wait logindelay logger(`Starting bot.js for ${k}...`, false, true) @@ -312,7 +352,7 @@ function startlogin() { //function will be called when steamcommunity status che machineName: `${extdata.mestr}'s Comment Bot` }; b.run(logOnOptions, i); //run bot.js with corresponding account - }, config.logindelay) } + }, logindelay) } }, 250); }, 1500 * (i - skippednow.length)); //1.5 seconds before checking if next account can be logged in should be ok }) } @@ -345,8 +385,7 @@ var readyinterval = setInterval(() => { //log startup to console else { var failedtocheckmsg = ""; } logger(`\x1b[92m>\x1b[0m ${limitedaccs}/${Object.keys(botobject).length} account(s) are \x1b[31mlimited\x1b[0m ${failedtocheckmsg}`, true) }} } catch (err) { - logger(`Error in limited checker: ${err}`) - } + logger(`Error in limited checker: ${err}`) } if (config.disableautoupdate) logger("\x1b[41m\x1b[30m>\x1b[0m Automatic updating is \x1b[4m\x1b[31mturned off\x1b[0m!", true) @@ -356,6 +395,7 @@ var readyinterval = setInterval(() => { //log startup to console const bootend = (new Date() - bootstart) - steamGuardInputTime readyafter = bootend / 1000 + module.exports.readyafter = readyafter //refresh exported variable to now allow cmd usage var readyafterunit = "seconds" if (readyafter > 60) { readyafter = readyafter / 60; var readyafterunit = "minutes" } @@ -367,12 +407,12 @@ var readyinterval = setInterval(() => { //log startup to console logger('*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*', true) logger(' ', true) if (updater.skippedaccounts.length > 0) logger(`Skipped Accounts: ${updater.skippedaccounts.length}/${Object.keys(logininfo).length}\n`, true) - if (extdata.firststart) logger(`If you like my work please consider giving my repository a star! I would really appreciate it!\nhttps://github.com/HerrEurobeat/steam-comment-service-bot`, true) + if (extdata.firststart) logger(`If you like my work please consider giving my repository a star! I would really appreciate it!\nhttps://github.com/HerrEurobeat/steam-comment-service-bot\n`, true) //Check if ownerids are correct: logger(`Checking for invalid ownerids...`, false, true) config.ownerid.forEach((e) => { - if (isNaN(e) || new SteamID(e).isValid() === false) { + if (isNaN(e) || new SteamID(String(e)).isValid() == false) { logger(`[\x1b[31mWarning\x1b[0m] ${e} is not a valid ownerid!`, true) } }) //Check if owner link is correct @@ -450,6 +490,7 @@ var readyinterval = setInterval(() => { //log startup to console if (config.unfriendtime > 0) { logger(`Associating bot's accountids with botobject entries...`, false, true) var accountids = {} + var lastcomment = require('./lastcomment.json') Object.keys(botobject).forEach((e, i) => { Object.keys(accountids).push(e) accountids[e] = botobject[e]['steamID']['accountid'] @@ -482,7 +523,7 @@ var readyinterval = setInterval(() => { //log startup to console } else { //bot does seem to be logged in if (targetbot.myFriends[iminusid] === 3 && !config.ownerid.includes(iminusid)) { //check if the targeted user is still friend and not the owner - targetbot.chatMessage(new SteamID(iminusid), `You have been unfriended for being inactive for ${config.unfriendtime} days.\nIf you need me again, feel free to add me again!`) + targetbot.chat.sendFriendMessage(new SteamID(iminusid), `You have been unfriended for being inactive for ${config.unfriendtime} days.\nIf you need me again, feel free to add me again!`) targetbot.removeFriend(new SteamID(iminusid)); //unfriend user logger(`[Bot ${targetkey}] Unfriended ${iminusid} after ${config.unfriendtime} days of inactivity.`) } @@ -502,6 +543,51 @@ var readyinterval = setInterval(() => { //log startup to console logger('Startup complete!', false, true) }) + if (config.enableurltocomment) { + var express = require("express") + var app = express() + + app.get('/', (req, res) => { + res.send("Comment Bot Web Request3urobeat's Comment Bot | Comment Web Request
Please use /comment?n=123&id=123&key=123 to request n comments on id profile with your secret key.
If you forgot your secret key you can see it in your 'data.json' file in the 'src' folder.

Visit /output to see the complete output.txt in your browser!

https://github.com/HerrEurobeat/steam-comment-service-bot") }) + + app.get('/comment', (req, res) => { + logger("Web Comment Request recieved by: " + req.ip) + + if (req.query.n == undefined) { + logger("Web Request denied. Reason: numberofcomments (n) is not specified.") + return res.send("You have to provide an amount of comments.
Usage: /comment?n=123&id=123&key=123 to request n comments on id profile with your secret key.
If you forgot your secret key you can see it in your 'data.json' file in the 'src' folder.") } + + if (req.query.id == undefined) { + logger("Web Request denied. Reason: Steam profileid (id) is not specified.") + return res.send("You have to provide a profile id where I should comment.
Usage: /comment?n=123&id=123&key=123 to request n comments on id profile with your secret key.
If you forgot your secret key you can see it in your 'data.json' file in the 'src' folder.") } + + if (req.query.key == undefined || req.query.key != extdata.urlrequestsecretkey) { + logger("Web Request denied. Reason: Invalid secret key.") + return res.status(403).send("Your secret key is not defined or invalid. Request denied.
If you forgot your secret key you can see it in your 'data.json' file in the 'src' folder.
Usage: /comment?n=123&id=123&key=123 to request n comments on id profile with your secret key.") } + + if (isNaN(config.ownerid[0]) || new SteamID(String(config.ownerid[0])).isValid() == false) { + logger("Web Request denied. Reason: Config's first ownerid is invalid.") + return res.status(403).send("You can't use the web request feature unless you provided a valid ownerid in your config!") } + + logger(`Web Comment Request accepted. Amount: ${req.query.n} | Profile: ${req.query.id}`) + botobject[0].commentcmd(new SteamID(String(config.ownerid[0])), [req.query.n, req.query.id], res) //steamID: Make the bot owner responsible for request + }); + + app.get('/output', (req, res) => { //Show output + fs.readFile("./output.txt", (err, data) => { + if(err) logger("urltocomment: error reading output.txt: " + err) + + res.write(String(data)) + res.end() + }) }) + + app.use((req, res) => { //Show idk page thanks + res.status(404).send("404: Page not Found.
Please use /comment?n=123&id=123&key=123 to request n comments on id profile with your secret key.") }); + + module.exports.server = app.listen(3034, () => { + logger('EnableURLToComment is on: Server is listening on port 3034.\nVisit it on: localhost:3034\n', true) }); + } + setTimeout(() => { //Startup is done, clean up delete readyafterlogs; //delete var as the logs got logged by now @@ -628,11 +714,11 @@ Y88b d88P Y88..88P 888 888 888 888 888 888 Y8b. 888 888 Y88b. 88 ######## ######## ### ### ### ### ########## ### #### ### ######### ######## ### `, ` _____ _ ____ _ -/ ____| | | | _ \\ | | + / ____| | | | _ \\ | | | | ___ _ __ ___ _ __ ___ ___ _ __ | |_ | |_) | ___ | |_ | | / _ \\| '_ \` _ \\| '_ \` _ \\ / _ \\ '_ \\| __| | _ < / _ \\| __| | |___| (_) | | | | | | | | | | | __/ | | | |_ | |_) | (_) | |_ -\\_____\\___/|_| |_| |_|_| |_| |_|\\___|_| |_|\\__| |____/ \\___/ \\__|`, + \\_____\\___/|_| |_| |_|_| |_| |_|\\___|_| |_|\\__| |____/ \\___/ \\__|`, ` _|_|_| _| _|_|_| _| _| _|_| _|_|_| _|_| _|_|_| _|_| _|_| _|_|_| _|_|_|_| _| _| _|_| _|_|_|_| diff --git a/src/data.json b/src/data.json index 309f1386..228a7950 100644 --- a/src/data.json +++ b/src/data.json @@ -1,13 +1,15 @@ { - "version": "2.7.2", + "version": "2.8", "branch": "master", - "filetostart": "./updater.js", - "filetostarturl": "https://raw.githubusercontent.com/HerrEurobeat/steam-comment-service-bot/master/updater.js", + "filetostart": "./src/updater.js", + "filetostarturl": "https://raw.githubusercontent.com/HerrEurobeat/steam-comment-service-bot/master/src/updater.js", "botobjectfile": "./src/controller.js", "mestr": "3urobeat", "aboutstr": "This bot was created by 3urobeat.\nGitHub: https://github.com/HerrEurobeat/steam-comment-service-bot \nSteam: https://steamcommunity.com/id/3urobeat \nIf you like my work, any donation would be appreciated! https://paypal.me/3urobeat", "firststart": true, - "whatsnew": "New !addfriend command. Added cache.json file. Fixed group invite crash. Fixed steam guard code issues. Added more ascii arts. Fixed limitedaccs crashes. Added childaccsplaygames in config.", + "compatibilityfeaturedone": false, + "whatsnew": "Added proxy support. Added webserver to request comments with URL. Fixed a lot of bugs and made other changes. (see more on GitHub)", + "urlrequestsecretkey": "", "timesloggedin": 0, "totallogintime": 0 } \ No newline at end of file diff --git a/updater.js b/src/updater.js similarity index 81% rename from updater.js rename to src/updater.js index 0f1ce3b2..a9ad7a0f 100644 --- a/updater.js +++ b/src/updater.js @@ -1,11 +1,13 @@ //Code by: https://github.com/HerrEurobeat/ //If you are here, you are wrong. Open config.json and configure everything there! +//This file contains: Checking for updates, updating the bot's files and starting the controller.js. + const fs = require('fs') const https = require("https") const readline = require("readline") -var config = require("./config.json") -var extdata = require('./src/data.json') +var config = require("../config.json") +var extdata = require('./data.json') var skippedaccounts = [] //array to save which accounts have been skipped to skip them automatically when restarting var botisloggedin = false var activeupdate = false @@ -33,7 +35,7 @@ var logger = (str, nodate, remove) => { //Custom logger var restartdata = (data) => { module.exports.skippedaccounts = data } -var checkforupdate = (forceupdate) => { +var checkforupdate = (forceupdate, responseSteamID, compatibilityfeaturedone) => { try { /* ------------------ Check for new version ------------------ */ logger(`Checking for update in ${releasemode} branch...`, false, true) @@ -48,21 +50,24 @@ var checkforupdate = (forceupdate) => { logger(`\x1b[32mUpdate available!\x1b[0m Your version: \x1b[31m${extdata.version}\x1b[0m | New version: \x1b[32m${onlineversion}\x1b[0m`, true) logger("", true) - /* ------------------ Check for permission to update ------------------ */ - var config = require("./config.json") + var config = require("../config.json") - if (config.disableautoupdate == false) { //check if the user has disabled the automatic updater + if (responseSteamID) { require('./controller.js').botobject[0].chat.sendFriendMessage(responseSteamID, `Update available! Your version: ${extdata.version} | New version: ${onlineversion}`) + if (config.disableautoupdate == true && !forceupdate) { require('./controller.js').botobject[0].chat.sendFriendMessage(responseSteamID, "You have turned automatic updating off. You need to confirm the update in the console!") }} + + /* ------------------ Check for permission to update ------------------ */ + if (config.disableautoupdate == false || forceupdate) { //check if the user has disabled the automatic updater or an update was forced logger('Starting the automatic updater...') startupdate(); } else { //user has it disabled, ask for confirmation - if (botisloggedin == false) { //only ask on start, otherwise this will annoy the user + if (botisloggedin == false || responseSteamID) { //only ask on start, otherwise this will annoy the user process.stdout.write(`You have disabled the automatic updater.\nWould you like to update now? [y/n] `) var stdin = process.openStdin(); stdin.addListener('data', text => { var response = text.toString().trim() if (response == "y") startupdate(); - else { require('./src/controller.js'); botisloggedin = true } //start bot or do nothing + else { require('./controller.js'); botisloggedin = true } //start bot or do nothing stdin.pause() }) //stop reading } @@ -76,7 +81,7 @@ var checkforupdate = (forceupdate) => { logger(`Bot is logged in. Checking for active comment process...`, false, true) var activecommentinterval = setInterval(() => { //check if a comment request is being processed every 2.5 secs - var controller = require('./src/controller.js') + var controller = require('./controller.js') if (controller.activecommentprocess.length == 0) { //start logging off accounts when no comment request is being processed anymore logger("Logging off your accounts...", true) @@ -102,14 +107,14 @@ var checkforupdate = (forceupdate) => { try { logger("Updating updater.js...", true) logger(`Getting updater.js code from GitHub...`, false, true) - https.get(`https://raw.githubusercontent.com/HerrEurobeat/steam-comment-service-bot/${releasemode}/updater.js`, function(res){ + https.get(`https://raw.githubusercontent.com/HerrEurobeat/steam-comment-service-bot/${releasemode}/src/updater.js`, function(res){ res.setEncoding('utf8'); res.on('data', function (chunk) { output += chunk }); res.on('end', () => { logger(`Writing new code to updater.js...`, false, true) - fs.writeFile("./updater.js", output, err => { + fs.writeFile("./src/updater.js", output, err => { if (err) logger("error writing updater.js: " + err, true) botjs(); })}) }); @@ -119,7 +124,7 @@ var checkforupdate = (forceupdate) => { output = "" try { logger("Updating bot.js...", true) - logger(`Getting updater.js code from GitHub...`, false, true) + logger(`Getting bot.js code from GitHub...`, false, true) https.get(`https://raw.githubusercontent.com/HerrEurobeat/steam-comment-service-bot/${releasemode}/src/bot.js`, function(res){ res.setEncoding('utf8'); res.on('data', function (chunk) { @@ -236,7 +241,7 @@ var checkforupdate = (forceupdate) => { output += chunk }); res.on('end', () => { - logger(`Writing new code to updater.js...`, false, true) + logger(`Writing new code to controller.js...`, false, true) fs.writeFile("./src/controller.js", output, err => { if (err) logger("error writing controller.js: " + err, true); datajson(); }) @@ -256,19 +261,44 @@ var checkforupdate = (forceupdate) => { res.on('end', () => { logger(`Parsing new json data...`, false, true) output = JSON.parse(output) + output.urlrequestsecretkey = extdata.urlrequestsecretkey //keep these 3 values + output.timesloggedin = extdata.timesloggedin + output.totallogintime = extdata.totallogintime + + if (compatibilityfeaturedone) output.compatibilityfeaturedone = true //prevents compatibility feature from running again logger(`Writing new data to data.json...`, false, true) fs.writeFile("./src/data.json", JSON.stringify(output, null, 4), err => { if (err) logger("error writing data.json: " + err, true) - logger("\x1b[32mUpdate finished. Restarting myself in 5 seconds...\x1b[0m", true); - setTimeout(() => { - module.exports.activeupdate = false - require('./start.js').restart(skippedaccounts, true); - }, 5000); })}) }); //restart the bot - } catch (err) { logger('get data.json function Error: ' + err, true) }} + npmupdate(); }) + })}); + } catch (err) { + logger('get data.json function Error: ' + err, true); + logger("The updater failed to update data.json. Please restart the bot and try again - if this error still happens please open an issue: https://github.com/HerrEurobeat/steam-comment-service-bot/issues/new/choose", true); + return; }} + + function npmupdate() { + try { + const { exec } = require('child_process'); + + logger("Updating packages with npm...", true) + exec('npm install', (err, stdout) => { //wanted to do it with the npm package but that didn't work out (BETA 2.8 b2) + if (err) { + logger("Error running the npm install command: " + err) + return; } + + logger(`Log:\n${stdout}`, true) //entire log + + logger("\x1b[32mUpdate finished. Restarting myself in 5 seconds...\x1b[0m", true); + setTimeout(() => { + module.exports.activeupdate = false + require('../start.js').restart(skippedaccounts, true); //restart the bot + }, 5000); }) + } catch (err) { logger('update npm packages Error: ' + err, true) }} } else { logger(`No available update found. (online: ${onlineversion} | local: ${extdata.version})`, false, true) - if (botisloggedin == false) require('./src/controller.js'); botisloggedin = true //no update, start bot + if (botisloggedin == false) require('./controller.js'); botisloggedin = true //no update, start bot + if (responseSteamID) require('./controller.js').botobject[0].chat.sendFriendMessage(responseSteamID, `No available update in the ${releasemode} branch found.`) } }) }) @@ -279,7 +309,7 @@ var checkforupdate = (forceupdate) => { if (botisloggedin == false) { logger("\nTrying to start the bot anyway in 5 seconds...", true) setTimeout(() => { - require('./src/controller.js'); + require('./controller.js'); botisloggedin = true //try to start bot anyway }, 5000); } }) @@ -289,7 +319,7 @@ var checkforupdate = (forceupdate) => { logger("\nBootup sequence started...", true, true) //mark new execution in output.txt //Compatibility features -if (!fs.existsSync('./src')){ //this has to trigger if user was on version <2.6 +if (!fs.existsSync('./src')) { //this has to trigger if user was on version <2.6 try { logger("Applying 2.6 compatibility changes...", false, true) fs.mkdirSync('./src') @@ -301,7 +331,7 @@ if (!fs.existsSync('./src')){ //this has to trigger if user was on version <2.6 fs.rename("./lastcomment.json", "./src/lastcomment.json", (err) => { //move lastcomment.json if (err) logger("error moving lastcomment.json: " + err, true) }) - var logininfo = require('./logininfo.json') + var logininfo = require('../logininfo.json') if (Object.keys(logininfo)[0] == "bot1") { //check if first bot is 1 (old) and not 0 Object.keys(logininfo).forEach((e, i) => { @@ -325,7 +355,7 @@ if (!fs.existsSync('./src')){ //this has to trigger if user was on version <2.6 } else if (Object.keys(config).includes("botsgroupid")) { //this has to trigger if user was on version <2.7 if (config.botsgroupid != "") { - logger("Applying 2.7 compatibility changes...", false, true) + logger("Applying 2.7 compatibility changes...") const xml2js = require("xml2js") Object.keys(config).push("botsgroup") //add new key @@ -345,14 +375,22 @@ if (!fs.existsSync('./src')){ //this has to trigger if user was on version <2.6 checkforupdate(true) //force update so that config gets cleaned up }) }) }) } catch (err) { - if (err) logger("error getting groupurl of botsgroupid or getting new config: " + err) } + if (err) logger("error getting groupurl of botsgroupid or getting new config: " + err) } } else { checkforupdate(true) } +} else if (!extdata.compatibilityfeaturedone && (extdata.version == "2.8" || extdata.version == "BETA 2.8 b3")) { + if (fs.existsSync('./updater.js')) { + logger("Applying 2.8 compatibility changes...") + fs.unlink("./updater.js", (err) => { //delete old updater.js + if (err) logger("error deleting old updater.js: " + err, true) + checkforupdate(true, null, true) }) + } else { + checkforupdate(true, null, true) } + } else { if (releasemode == "beta-testing") logger("\x1b[0m[\x1b[31mNotice\x1b[0m] Your updater and bot is running in beta mode. These versions are often unfinished and can be unstable.\n If you would like to switch, open data.json and change 'beta-testing' to 'master'.\n If you find an error or bug please report it: https://github.com/HerrEurobeat/steam-comment-service-bot/issues/new/choose\n", true) - checkforupdate() //check will start the bot afterwards -} + checkforupdate() } //check will start the bot afterwards module.exports={ restartdata, diff --git a/start.js b/start.js index 1c844de9..5f40b67f 100644 --- a/start.js +++ b/start.js @@ -1,46 +1,51 @@ //Code by: https://github.com/HerrEurobeat/ //If you are here, you are wrong. Open config.json and configure everything there! -//This file can't get updated automatically. -//Therefore it is designed to be modular and to start and restart the whole application. +//This file contains: Starting the updater.js and restarting the whole application without restarting the node process. Very cool! -var fs = require('fs') -var https = require("https") +//This file can't get updated automatically. +//It is designed to be modular and to start and restart the whole application. +//To be able to change the file it is supposed to start on the fly it pulls the necessary file path from the data.json file -if (fs.existsSync('./src/data.json')) { - var data = require('./src/data.json') -} else { - var data = { filetostart: "./updater.js", filetostarturl: "https://raw.githubusercontent.com/HerrEurobeat/steam-comment-service-bot/master/updater.js" } //relevant for update from <2.6 -} +var data = require('./src/data.json') +var fs = require("fs") +/* ------------------ Restart function ------------------ */ var restart = (args, nologOff) => { //Restart the application console.log("Restarting application...") + var data = require('./src/data.json') + + if (!nologOff) { + var controller = require(data.botobjectfile) //get the file we want from data.json - if (nologOff != true) { - var data = require('./src/data.json') - var controller = require(data.botobjectfile) + if (typeof controller.server != "undefined") { //check if the server was exported instead of checking config.json to require less files + console.log("Stopping URLToComment webserver...") + controller.server.close() } Object.keys(controller.botobject).forEach((e) => { //log out all bots - controller.botobject[e].logOff() }) - } + controller.botobject[e].logOff() }) } Object.keys(require.cache).forEach(function(key) { delete require.cache[key] }) //clear cache to include file changes setTimeout(() => { - require("./updater.js").restartdata(args) //start again after 2.5 sec + require(data.filetostart).restartdata(args) //start again after 2.5 sec }, 2500) } +/* ------------------ Stop function ------------------ */ var stop = () => { console.log("Stopping application...") process.exit(1) } +//Exporting functions to be able to call them module.exports={ restart, stop } -if (!fs.existsSync(data.filetostart)) { + +if (!fs.existsSync(data.filetostart)) { //Function that downloads filetostart if it doesn't exist (file location change etc.) output = "" try { + var https = require("https") https.get(data.filetostarturl, function(res){ res.setEncoding('utf8'); res.on('data', function (chunk) { @@ -50,9 +55,8 @@ if (!fs.existsSync(data.filetostart)) { fs.writeFile(data.filetostart, output, err => { if (err) return logger(err, true) require(data.filetostart) })}) }); //start - } catch (err) { logger('start.js get updater.js function Error: ' + err, true) } + } catch (err) { console.log('start.js get updater.js function Error: ' + err) } } else { - require(data.filetostart) //Just passing startup to updater -} + require(data.filetostart) } //Just passing startup to updater //Code by: https://github.com/HerrEurobeat/ \ No newline at end of file