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