commit 303c9e982803c55377a8a22b1b3fb2fe2faa2ce7 Author: Evert Prants Date: Thu Dec 3 21:27:14 2020 +0200 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9d09377 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +/node_modules/ +/.out/ +deployment.json +*.js +*.d.ts +*.tsbuildinfo \ No newline at end of file diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..5cf2940 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,699 @@ +{ + "name": "plugins-evert", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@squeebot/core": { + "version": "file:../core", + "requires": { + "dateformat": "^4.0.0", + "fs-extra": "^9.0.1", + "semver": "^7.3.2", + "tar": "^6.0.5" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", + "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", + "requires": { + "@babel/highlight": "^7.10.4" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz", + "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==" + }, + "@babel/highlight": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", + "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "@types/dateformat": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/dateformat/-/dateformat-3.0.1.tgz", + "integrity": "sha512-KlPPdikagvL6ELjWsljbyDIPzNCeliYkqRpI+zea99vBBbCIA5JNshZAwQKTON139c87y9qvTFVgkFd14rtS4g==" + }, + "@types/fs-extra": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.4.tgz", + "integrity": "sha512-50GO5ez44lxK5MDH90DYHFFfqxH7+fTqEEnvguQRzJ/tY9qFrMSHLiYHite+F3SNmf7+LHC1eMXojuD+E3Qcyg==", + "requires": { + "@types/node": "*" + } + }, + "@types/minipass": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@types/minipass/-/minipass-2.2.0.tgz", + "integrity": "sha512-wuzZksN4w4kyfoOv/dlpov4NOunwutLA/q7uc00xU02ZyUY+aoM5PWIXEKBMnm0NHd4a+N71BMjq+x7+2Af1fg==", + "requires": { + "@types/node": "*" + } + }, + "@types/node": { + "version": "14.14.9", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.9.tgz", + "integrity": "sha512-JsoLXFppG62tWTklIoO4knA+oDTYsmqWxHRvd4lpmfQRNhX6osheUOWETP2jMoV/2bEHuMra8Pp3Dmo/stBFcw==" + }, + "@types/semver": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.4.tgz", + "integrity": "sha512-+nVsLKlcUCeMzD2ufHEYuJ9a2ovstb6Dp52A5VsoKxDXgvE051XgHI/33I1EymwkRGQkwnA0LkhnUzituGs4EQ==" + }, + "@types/tar": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/tar/-/tar-4.0.4.tgz", + "integrity": "sha512-0Xv+xcmkTsOZdIF4yCnd7RkOOyfyqPaqJ7RZFKnwdxfDbkN3eAAE9sHl8zJFqBz4VhxolW9EErbjR1oyH7jK2A==", + "requires": { + "@types/minipass": "*", + "@types/node": "*" + } + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "requires": { + "color-convert": "^1.9.0" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==" + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "builtin-modules": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=" + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==" + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + }, + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "dateformat": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-4.0.0.tgz", + "integrity": "sha512-zpKyDYpeePyYGJp2HhRxLHlA+jZQNjt+MwmcVmLxCIECeC4Ks3TI3yk/CSMKylbnCJ5htonfOugYtRRTpyoHow==" + }, + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==" + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" + }, + "fs-extra": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.1.tgz", + "integrity": "sha512-h2iAoN838FqAFJY2/qVpzFXy+EBxfVE220PalAqQLDVsFOHLJrZvut5puAbCdNv6WJk+B8ihI+k0c7JK5erwqQ==", + "requires": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^1.0.0" + } + }, + "fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "requires": { + "minipass": "^3.0.0" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "graceful-fs": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", + "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==" + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "is-core-module": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.1.0.tgz", + "integrity": "sha512-YcV7BgVMRFRua2FqQzKtTDMz8iCuLEyGKjr70q8Zm1yy2qKcurbFEd79PAdHV77oL3NrAaOVQIbMmiHQCHB7ZA==", + "requires": { + "has": "^1.0.3" + } + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "js-yaml": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", + "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" + }, + "dependencies": { + "universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==" + } + } + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + }, + "minipass": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.3.tgz", + "integrity": "sha512-Mgd2GdMVzY+x3IJ+oHnVM+KG3lA5c8tnabyJKmHSaG2kAGpudxuOf8ToDkhumF7UzME7DecbQE9uOZhNm7PuJg==", + "requires": { + "yallist": "^4.0.0" + } + }, + "minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "requires": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + } + }, + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "requires": { + "minimist": "^1.2.5" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" + }, + "resolve": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz", + "integrity": "sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==", + "requires": { + "is-core-module": "^2.1.0", + "path-parse": "^1.0.6" + } + }, + "semver": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", + "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==" + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } + }, + "tar": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.0.5.tgz", + "integrity": "sha512-0b4HOimQHj9nXNEAA7zWwMM91Zhhba3pspja6sQbgTpynOJf+bkjBnfybNYzbpLbnwXnbyB4LOREvlyXLkCHSg==", + "requires": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^3.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "dependencies": { + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" + } + } + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + }, + "tslint": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/tslint/-/tslint-6.1.3.tgz", + "integrity": "sha512-IbR4nkT96EQOvKE2PW/djGz8iGNeJ4rF2mBfiYaR/nvUWYKJhLwimoJKgjIFEIDibBtOevj7BqCRL4oHeWWUCg==", + "requires": { + "@babel/code-frame": "^7.0.0", + "builtin-modules": "^1.1.1", + "chalk": "^2.3.0", + "commander": "^2.12.1", + "diff": "^4.0.1", + "glob": "^7.1.1", + "js-yaml": "^3.13.1", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.3", + "resolve": "^1.3.2", + "semver": "^5.3.0", + "tslib": "^1.13.0", + "tsutils": "^2.29.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + } + } + }, + "tsutils": { + "version": "2.29.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", + "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", + "requires": { + "tslib": "^1.8.1" + } + }, + "typescript": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.0.5.tgz", + "integrity": "sha512-ywmr/VrTVCmNTJ6iV2LwIrfG1P+lv6luD8sUJs+2eI9NLGigaN+nUQc13iHqisq7bra9lnmUSYqbJvegraBOPQ==" + }, + "universalify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-1.0.0.tgz", + "integrity": "sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug==" + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + } + } + }, + "@types/convert-units": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/@types/convert-units/-/convert-units-2.3.3.tgz", + "integrity": "sha512-oo4ZyjU0nZMDQFP0AKYk4KvFjydlSpbgXTCdF+TC3d/TL4b85/zi0W5pC97UrzXXpwsbcVEfS01nEgUqKgjSww==", + "dev": true + }, + "@types/mathjs": { + "version": "6.0.8", + "resolved": "https://registry.npmjs.org/@types/mathjs/-/mathjs-6.0.8.tgz", + "integrity": "sha512-/oDt+o/q3cTHgOsYPgvHWw6xG8ZhIWMNnz8WJMogs2jeCEHz4PODOzrT3jzRzf7UeX7nPLXhqL+cV4hOfu1mWA==", + "dev": true, + "requires": { + "decimal.js": "^10.0.0" + } + }, + "@types/node": { + "version": "14.14.10", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.10.tgz", + "integrity": "sha512-J32dgx2hw8vXrSbu4ZlVhn1Nm3GbeCFNw2FWL8S5QKucHGY0cyNwjdQdO+KMBZ4wpmC7KhLCiNsdk1RFRIYUQQ==", + "dev": true + }, + "complex.js": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/complex.js/-/complex.js-2.0.11.tgz", + "integrity": "sha512-6IArJLApNtdg1P1dFtn3dnyzoZBEF0MwMnrfF1exSBRpZYoy4yieMkpZhQDC0uwctw48vii0CFVyHfpgZ/DfGw==" + }, + "convert-units": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/convert-units/-/convert-units-2.3.4.tgz", + "integrity": "sha512-ERHfdA0UhHJp1IpwE6PnFJx8LqG7B1ZjJ20UvVCmopEnVCfER68Tbe3kvN63dLbYXDA2xFWRE6zd4Wsf0w7POg==", + "requires": { + "lodash.foreach": "2.3.x", + "lodash.keys": "2.3.x" + } + }, + "decimal.js": { + "version": "10.2.1", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.2.1.tgz", + "integrity": "sha512-KaL7+6Fw6i5A2XSnsbhm/6B+NuEA7TZ4vqxnd5tXz9sbKtrN9Srj8ab4vKVdK8YAqZO9P1kg45Y6YLoduPf+kw==" + }, + "escape-latex": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/escape-latex/-/escape-latex-1.2.0.tgz", + "integrity": "sha512-nV5aVWW1K0wEiUIEdZ4erkGGH8mDxGyxSeqPzRNtWP7ataw+/olFObw7hujFWlVjNsaDFw5VZ5NzVSIqRgfTiw==" + }, + "fraction.js": { + "version": "4.0.12", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.0.12.tgz", + "integrity": "sha512-8Z1K0VTG4hzYY7kA/1sj4/r1/RWLBD3xwReT/RCrUCbzPszjNQCCsy3ktkU/eaEqX3MYa4pY37a52eiBlPMlhA==" + }, + "javascript-natural-sort": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/javascript-natural-sort/-/javascript-natural-sort-0.7.1.tgz", + "integrity": "sha1-+eIwPUUH9tdDVac2ZNFED7Wg71k=" + }, + "lodash._basebind": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/lodash._basebind/-/lodash._basebind-2.3.0.tgz", + "integrity": "sha1-K1vEUqDhBhQ7IYafIzvbWHQX0kg=", + "requires": { + "lodash._basecreate": "~2.3.0", + "lodash._setbinddata": "~2.3.0", + "lodash.isobject": "~2.3.0" + } + }, + "lodash._basecreate": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/lodash._basecreate/-/lodash._basecreate-2.3.0.tgz", + "integrity": "sha1-m4ioak3P97fzxh2Dovz8BnHsneA=", + "requires": { + "lodash._renative": "~2.3.0", + "lodash.isobject": "~2.3.0", + "lodash.noop": "~2.3.0" + } + }, + "lodash._basecreatecallback": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/lodash._basecreatecallback/-/lodash._basecreatecallback-2.3.0.tgz", + "integrity": "sha1-N7KrF1kaM56YjbMln81GAZ16w2I=", + "requires": { + "lodash._setbinddata": "~2.3.0", + "lodash.bind": "~2.3.0", + "lodash.identity": "~2.3.0", + "lodash.support": "~2.3.0" + } + }, + "lodash._basecreatewrapper": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/lodash._basecreatewrapper/-/lodash._basecreatewrapper-2.3.0.tgz", + "integrity": "sha1-qgxhrZYETDkzN2ExSDqXWcNlEkc=", + "requires": { + "lodash._basecreate": "~2.3.0", + "lodash._setbinddata": "~2.3.0", + "lodash._slice": "~2.3.0", + "lodash.isobject": "~2.3.0" + } + }, + "lodash._createwrapper": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/lodash._createwrapper/-/lodash._createwrapper-2.3.0.tgz", + "integrity": "sha1-0arhEC2t9EDo4G/BM6bt1/4UYHU=", + "requires": { + "lodash._basebind": "~2.3.0", + "lodash._basecreatewrapper": "~2.3.0", + "lodash.isfunction": "~2.3.0" + } + }, + "lodash._objecttypes": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/lodash._objecttypes/-/lodash._objecttypes-2.3.0.tgz", + "integrity": "sha1-aj6jmH3W7rgCGy1cnDA1Scwrrh4=" + }, + "lodash._renative": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/lodash._renative/-/lodash._renative-2.3.0.tgz", + "integrity": "sha1-d9jt1M7SbdWXH54Vpfdy5OMX+9M=" + }, + "lodash._setbinddata": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/lodash._setbinddata/-/lodash._setbinddata-2.3.0.tgz", + "integrity": "sha1-5WEEkKzRMnfVmFjZW18nJ/FQjwQ=", + "requires": { + "lodash._renative": "~2.3.0", + "lodash.noop": "~2.3.0" + } + }, + "lodash._shimkeys": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/lodash._shimkeys/-/lodash._shimkeys-2.3.0.tgz", + "integrity": "sha1-YR+TFJ4+bHIQlrSHae8pU3rai6k=", + "requires": { + "lodash._objecttypes": "~2.3.0" + } + }, + "lodash._slice": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/lodash._slice/-/lodash._slice-2.3.0.tgz", + "integrity": "sha1-FHGYEyhZly5GgMoppZkshVZpqlw=" + }, + "lodash.bind": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/lodash.bind/-/lodash.bind-2.3.0.tgz", + "integrity": "sha1-wqjhi2jl7MFS4rFoJmEW/qWwFsw=", + "requires": { + "lodash._createwrapper": "~2.3.0", + "lodash._renative": "~2.3.0", + "lodash._slice": "~2.3.0" + } + }, + "lodash.foreach": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/lodash.foreach/-/lodash.foreach-2.3.0.tgz", + "integrity": "sha1-CDQEyR6EbudyRf3512UZxosq8Wg=", + "requires": { + "lodash._basecreatecallback": "~2.3.0", + "lodash.forown": "~2.3.0" + } + }, + "lodash.forown": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/lodash.forown/-/lodash.forown-2.3.0.tgz", + "integrity": "sha1-JPtKr4ANRfwtxgv+w84EyDajrX8=", + "requires": { + "lodash._basecreatecallback": "~2.3.0", + "lodash._objecttypes": "~2.3.0", + "lodash.keys": "~2.3.0" + } + }, + "lodash.identity": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/lodash.identity/-/lodash.identity-2.3.0.tgz", + "integrity": "sha1-awGiEMlIU1XCqRO0i2cRIZoXPe0=" + }, + "lodash.isfunction": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/lodash.isfunction/-/lodash.isfunction-2.3.0.tgz", + "integrity": "sha1-aylz5HpkfPEucNZ2rqE2Q3BuUmc=" + }, + "lodash.isobject": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/lodash.isobject/-/lodash.isobject-2.3.0.tgz", + "integrity": "sha1-LhbT/Fg9qYMZaJU/LY5tc0NPZ5k=", + "requires": { + "lodash._objecttypes": "~2.3.0" + } + }, + "lodash.keys": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-2.3.0.tgz", + "integrity": "sha1-s1D0+Syqn0WkouzwGEVM8vKK4lM=", + "requires": { + "lodash._renative": "~2.3.0", + "lodash._shimkeys": "~2.3.0", + "lodash.isobject": "~2.3.0" + } + }, + "lodash.noop": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/lodash.noop/-/lodash.noop-2.3.0.tgz", + "integrity": "sha1-MFnWKNUbv5N80qC2/Dp/ISpmnCw=" + }, + "lodash.support": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/lodash.support/-/lodash.support-2.3.0.tgz", + "integrity": "sha1-fq8DivTw1qq3drRKptz8gDNMm/0=", + "requires": { + "lodash._renative": "~2.3.0" + } + }, + "mathjs": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/mathjs/-/mathjs-8.0.1.tgz", + "integrity": "sha512-lvdYNHLNrRORYKRpRs22RMeeAoqVxRePUCjDealCZLfN5io0tJHqQLyNZuJJSXWa8Pl0dkM434D4cIUsbYR1Mg==", + "requires": { + "complex.js": "^2.0.11", + "decimal.js": "^10.2.1", + "escape-latex": "^1.2.0", + "fraction.js": "^4.0.12", + "javascript-natural-sort": "^0.7.1", + "seedrandom": "^3.0.5", + "tiny-emitter": "^2.1.0", + "typed-function": "^2.0.0" + } + }, + "seedrandom": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/seedrandom/-/seedrandom-3.0.5.tgz", + "integrity": "sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg==" + }, + "tiny-emitter": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz", + "integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==" + }, + "typed-function": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/typed-function/-/typed-function-2.0.0.tgz", + "integrity": "sha512-Hhy1Iwo/e4AtLZNK10ewVVcP2UEs408DS35ubP825w/YgSBK1KVLwALvvIG4yX75QJrxjCpcWkzkVRB0BwwYlA==" + }, + "typescript": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.1.2.tgz", + "integrity": "sha512-thGloWsGH3SOxv1SoY7QojKi0tc+8FnOmiarEGMbd/lar7QOEd3hvlx3Fp5y6FlDUGl9L+pd4n2e+oToGMmhRQ==" + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..014f097 --- /dev/null +++ b/package.json @@ -0,0 +1,24 @@ +{ + "name": "plugins-evert", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "build": "tsc", + "watch": "tsc -w" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "@squeebot/core": "file:../core", + "convert-units": "^2.3.4", + "mathjs": "^8.0.1", + "typescript": "^4.1.2" + }, + "devDependencies": { + "@types/convert-units": "^2.3.3", + "@types/mathjs": "^6.0.8", + "@types/node": "^14.14.10" + } +} diff --git a/squeebot.repo.json b/squeebot.repo.json new file mode 100644 index 0000000..3af80fa --- /dev/null +++ b/squeebot.repo.json @@ -0,0 +1,10 @@ +{ + "name": "plugins-evert", + "plugins": [ + { + "name": "utility", + "version": "3.0.0" + } + ], + "typescript": true +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..f460d0c --- /dev/null +++ b/tsconfig.json @@ -0,0 +1 @@ +{"compilerOptions":{"downlevelIteration":true,"esModuleInterop":true,"experimentalDecorators":true,"forceConsistentCasingInFileNames":true,"skipLibCheck":true,"sourceMap":false,"strict":true,"target":"es5"}} diff --git a/tslint.json b/tslint.json new file mode 100644 index 0000000..9f05d30 --- /dev/null +++ b/tslint.json @@ -0,0 +1,122 @@ +{ + "extends": "tslint:recommended", + "rules": { + "align": { + "options": [ + "parameters", + "statements" + ] + }, + "array-type": false, + "arrow-return-shorthand": true, + "curly": true, + "deprecation": { + "severity": "warning" + }, + "eofline": true, + "import-spacing": true, + "indent": { + "options": [ + "spaces" + ] + }, + "max-classes-per-file": false, + "max-line-length": [ + true, + 140 + ], + "member-ordering": [ + true, + { + "order": [ + "static-field", + "instance-field", + "static-method", + "instance-method" + ] + } + ], + "no-console": [ + true, + "debug", + "info", + "time", + "timeEnd", + "trace" + ], + "no-empty": false, + "no-inferrable-types": [ + true, + "ignore-params" + ], + "no-non-null-assertion": true, + "no-redundant-jsdoc": true, + "no-switch-case-fall-through": true, + "no-var-requires": false, + "object-literal-key-quotes": [ + true, + "as-needed" + ], + "quotemark": [ + true, + "single" + ], + "semicolon": { + "options": [ + "always" + ] + }, + "space-before-function-paren": { + "options": { + "anonymous": "never", + "asyncArrow": "always", + "constructor": "never", + "method": "never", + "named": "never" + } + }, + "typedef": [ + true, + "call-signature" + ], + "forin": false, + "ban-types": { + "function": false + }, + "typedef-whitespace": { + "options": [ + { + "call-signature": "nospace", + "index-signature": "nospace", + "parameter": "nospace", + "property-declaration": "nospace", + "variable-declaration": "nospace" + }, + { + "call-signature": "onespace", + "index-signature": "onespace", + "parameter": "onespace", + "property-declaration": "onespace", + "variable-declaration": "onespace" + } + ] + }, + "variable-name": { + "options": [ + "ban-keywords", + "check-format", + "allow-pascal-case" + ] + }, + "whitespace": { + "options": [ + "check-branch", + "check-decl", + "check-operator", + "check-separator", + "check-type", + "check-typecast" + ] + } + } +} diff --git a/utility/math.ts b/utility/math.ts new file mode 100644 index 0000000..4ffe58a --- /dev/null +++ b/utility/math.ts @@ -0,0 +1,40 @@ +import { evaluate, simplify } from 'mathjs'; + +function done(data: string): void { + if (process && process.send) { + process.send(data); + } +} + +process.once('message', (msg) => { + msg = msg.toString(); + + const dat = msg.split(' '); + if (!(dat.length > 1)) { + return; + } + + let expr = dat.slice(1).join(' '); + + if (!expr) { + return done('null'); + } + if (expr.indexOf('=') === expr.length - 1) { + expr = expr.substring(0, expr.length - 1); + } + + expr = expr.replace(/π/g, 'pi'); + let result = 'null'; + + try { + if (dat[0] === 'eval') { + result = evaluate(expr); + } else if (dat[0] === 'simplify') { + result = simplify(expr).toString(); + } + } catch (e) { + return done(e.message); + } + + return done(result.toString()); +}); diff --git a/utility/plugin.json b/utility/plugin.json new file mode 100644 index 0000000..c515340 --- /dev/null +++ b/utility/plugin.json @@ -0,0 +1,12 @@ +{ + "main": "plugin.js", + "name": "utility", + "description": "Utility commands and math operations", + "version": "3.0.0", + "tags": ["commands", "tools"], + "dependencies": ["simplecommands"], + "npmDependencies": [ + "mathjs@^8.0.1", + "convert-units@^2.3.4" + ] +} diff --git a/utility/plugin.ts b/utility/plugin.ts new file mode 100644 index 0000000..5eaf29e --- /dev/null +++ b/utility/plugin.ts @@ -0,0 +1,829 @@ +import path from 'path'; +import net from 'net'; +import util from 'util'; +import cprog from 'child_process'; +import convert from 'convert-units'; + +import { + Plugin, + Configurable, + EventListener, + DependencyLoad +} from '@squeebot/core/lib/plugin'; + +import { IMessage } from '@squeebot/core/lib/types'; +import { httpGET, parseTimeToSeconds, readableTime } from '@squeebot/core/lib/common'; + +import { logger } from '@squeebot/core/lib/core'; + +type CEXResponse = {[key: string]: number}; + +const cexCache: {[key: string]: number | CEXResponse} = { + expiry: 0, + date: 0, + cache: {}, +}; + +const bases: {[key: number]: string[]} = { + 2: ['bin', 'binary'], + 8: ['oct', 'octal'], + 10: ['dec', 'decimal'], + 16: ['hex', 'hexadecimal'] +}; + +function getBaseNum(base: string): number | null { + let result = null; + for (const i in bases) { + const defs = bases[i]; + if (defs.indexOf(base) === -1) { + continue; + } + result = parseInt(i, 10); + } + + if (result) { + return result; + } + + if (base.indexOf('b') !== 0) { + return null; + } + + const matcher = base.match(/b(?:ase-?)?(\d+)/); + if (!matcher || !matcher[1] || isNaN(parseInt(matcher[1], 10))) { + return null; + } + return parseInt(matcher[1], 10); +} + +const urlRegex = /(((ftp|https?):\/\/)[-\w@:%_+.~#?,&//=]+)/g; +const fork = cprog.fork; + +// Run mathjs in a separate thread to avoid the killing of the main process +function opMath(expression: string, method = 'eval'): Promise { + return new Promise((resolve, reject) => { + // Fork the script + const mathThread = fork(path.join(__dirname, 'math.js')); + + let done = false; + + // Time the request out when user enters something too complex + const timeItOut = setTimeout(() => { + mathThread.kill('SIGKILL'); + done = true; + return reject(new Error('Timed out')); + }, 8000); + + // Send data to the thread to process + mathThread.send(method + ' ' + expression); + + // Recieve data + mathThread.on('message', (chunk) => { + clearTimeout(timeItOut); + + if (done) { + return; + } + const line = chunk.toString().trim(); + + if (line.length > 280) { + return reject(new Error('The response was too large')); + } + + done = true; + + if (line === 'null') { + return reject(new Error('Nothing was returned')); + } + + resolve(line); + }); + + mathThread.on('exit', () => { + clearTimeout(timeItOut); + + if (!done) { + reject(new Error('Nothing was returned')); + } + }); + }); +} + +function rgbToHex(r: number, g: number, b: number): string { + // tslint:disable-next-line: no-bitwise + return '#' + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1); +} + +function hexToRgb(hex: string): {[key: string]: number} | null { + // Expand shorthand form (e.g. "03F") to full form (e.g. "0033FF") + const shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i; + hex = hex.replace(shorthandRegex, (m, r, g, b) => { + return r + r + g + g + b + b; + }); + + const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); + return result ? { + r: parseInt(result[1], 16), + g: parseInt(result[2], 16), + b: parseInt(result[3], 16) + } : null; +} + +function pingTcpServer(host: string, port: number): Promise { + return new Promise((resolve, reject) => { + let isFinished = false; + let timeA = new Date().getTime(); + const timeB = new Date().getTime(); + + function returnResults(status: boolean, info: number | Error): void { + if (!isFinished) { + isFinished = true; + + if (info instanceof Error) { + return reject(info); + } + + resolve(info); + } + } + + const pingHost = net.connect({port, host}, () => { + timeA = new Date().getTime(); + returnResults(true, timeA - timeB); + pingHost.end(); + pingHost.destroy(); + }); + + pingHost.setTimeout(5000); + + pingHost.on('timeout', () => { + pingHost.end(); + pingHost.destroy(); + returnResults(false, new Error('timeout')); + }); + + pingHost.on('error', (e) => { + pingHost.end(); + pingHost.destroy(); + returnResults(false, e); + }); + + pingHost.on('close', () => { + returnResults(false, new Error('closed')); + }); + }); +} + +function addCommands(plugin: UtilityPlugin, commands: any): void { + const cmds = []; + + cmds.push({ + name: 'binary', + execute: async (msg: IMessage, spec: any, prefix: string, ...simplified: any[]): Promise => { + let response = ''; + let strArr; + let i; + let text = msg.data.split(' ').slice(2).join(' '); + + try { + switch (simplified[0] ? simplified[0].toUpperCase() : null) { + case 'ENCODE': + strArr = text.split(''); + + for (i in strArr) { + response += ' ' + ('0000000' + + parseInt(Buffer.from(strArr[i].toString(), 'utf8').toString('hex'), 16).toString(2)).slice(-8); + } + + response = response.substr(1); + + break; + case 'DECODE': + text = text.split(' ').join(''); + i = 0; + + while (8 * (i + 1) <= text.length) { + response += Buffer.from(parseInt(text.substr(8 * i, 8), 2).toString(16), 'hex').toString('utf8'); + i++; + } + + response = 'Decoded: ' + response.replace(/\n/g, '\\n').replace(/\r/g, '\\r'); + } + } catch (e) { + msg.resolve('Operation failed.'); + return true; + } + + msg.resolve(response); + return true; + }, + description: 'Encode/decode binary (ASCII only)', + usage: ' ' + }); + + cmds.push({ + name: 'hexstr', + execute: async (msg: IMessage, spec: any, prefix: string, ...simplified: any[]): Promise => { + let response = ''; + let i; + let text = msg.data.split(' ').slice(2).join(' '); + + try { + switch (simplified[0] ? simplified[0].toUpperCase() : null) { + case 'DECODE': + text = text.replace(/\s/g, ''); + + for (i = 0; i < text.length; i += 2) { + response += String.fromCharCode(parseInt(text.substr(i, 2), 16)); + } + + response = 'Decoded: ' + response.replace(/\n/g, '\\n').replace(/\r/g, '\\r'); + break; + case 'ENCODE': + for (i = 0; i < text.length; i++) { + response += text.charCodeAt(i).toString(16) + ' '; + } + break; + } + } catch (e) { + msg.resolve('Operation failed.'); + return true; + } + + msg.resolve(response); + return true; + }, + description: 'Encode/decode hexadecimal (ASCII only)', + usage: ' ' + }); + + cmds.push({ + name: 'base64', + execute: async (msg: IMessage, spec: any, prefix: string, ...simplified: any[]): Promise => { + let response = ''; + const text = msg.data.split(' ').slice(2).join(' '); + + try { + switch (simplified[0] ? simplified[0].toUpperCase() : null) { + case 'DECODE': + response = 'Decoded: ' + (Buffer.from(text, 'base64').toString('ascii')).replace(/\n/g, '\\n').replace(/\r/g, '\\r'); + break; + case 'ENCODE': + response = Buffer.from(text).toString('base64'); + break; + } + } catch (e) { + msg.resolve('Operation failed.'); + return true; + } + + msg.resolve(response); + return true; + }, + description: 'Encode/decode base64 (ASCII only)', + usage: ' ' + }); + + cmds.push({ + name: 'numsys', + execute: async (msg: IMessage, spec: any, prefix: string, ...simplified: any[]): Promise => { + const input = simplified[0]; + const src = simplified[1].toLowerCase(); + const dst = simplified[2].toLowerCase(); + + const srcBase = getBaseNum(src); + const dstBase = getBaseNum(dst); + + if (!srcBase || !dstBase || dstBase > 36 || dstBase < 2 || srcBase > 36 || srcBase < 2) { + msg.resolve('Invalid conversion.'); + return false; + } + + const decimal = parseInt(input, srcBase); + const result = decimal.toString(dstBase); + + msg.resolve('Result:', result); + return true; + }, + description: 'Convert a value into a value in another numbering system.', + usage: ' ', + aliases: ['convertnumbers', 'cvnums'] + }); + + cmds.push({ + name: 'convertseconds', + execute: async (msg: IMessage, spec: any, prefix: string, ...simplified: any[]): Promise => { + msg.resolve(readableTime(parseInt(simplified[0], 10))); + return true; + }, + description: 'Convert seconds to years days hours minutes seconds.', + usage: '', + aliases: ['cvs', 'parseseconds'] + }); + + cmds.push({ + name: 'converttime', + execute: async (msg: IMessage, spec: any, prefix: string, ...simplified: any[]): Promise => { + const str = msg.data.split(' ').slice(1).join(' '); + + if (!str) { + msg.resolve('Invalid input'); + return true; + } + + msg.resolve(parseTimeToSeconds(str) + ' seconds'); + return true; + }, + description: 'Convert ywdhms to seconds.', + usage: '[y] [w] [d] [h] [m] [s]', + aliases: ['cvt', 'parsetime'] + }); + + cmds.push({ + name: 'reconverttime', + execute: async (msg: IMessage, spec: any, prefix: string, ...simplified: any[]): Promise => { + const str = msg.data.split(' ').slice(1).join(' '); + + if (!str) { + msg.resolve('Invalid input'); + return true; + } + + const sec = parseTimeToSeconds(str); + msg.resolve(readableTime(sec)); + + return true; + }, + aliases: ['rcvt'] + }); + + cmds.push({ + name: 'eval', + execute: async (msg: IMessage, spec: any, prefix: string, ...simplified: any[]): Promise => { + if (!simplified[0]) { + return true; + } + + const wholeRow = msg.data.split(' ').slice(1).join(' '); + + opMath(wholeRow).then((repl) => { + msg.resolve(repl); + }, (e) => { + msg.resolve('Could not evaluate expression:', e.message); + }); + + return true; + }, + aliases: ['evaluate', 'math', 'equation', 'calc'], + usage: '', + description: 'Evaluate a math expression' + }); + + cmds.push({ + name: 'simplify', + execute: async (msg: IMessage, spec: any, prefix: string, ...simplified: any[]): Promise => { + if (!simplified[0]) { + return true; + } + + const wholeRow = msg.data.split(' ').slice(1).join(' '); + + opMath(wholeRow, 'simplify').then((repl) => { + msg.resolve(repl); + }, () => { + msg.resolve('Could not evaluate expression!'); + }); + + return true; + }, + aliases: ['mathsimple', 'algebra'], + usage: '', + description: 'Simplify a math expression' + }); + + cmds.push({ + name: 'evaljs', + execute: async (msg: IMessage, spec: any, prefix: string, ...simplified: any[]): Promise => { + if (!simplified[0]) { + return true; + } + const script = msg.data.split(' ').slice(1).join(' '); + + // Disallow child_process when shell is disallowed + if ((script.indexOf('child_process') !== -1 || + script.indexOf('cprog') !== -1 || + script.indexOf('fork') !== -1) && + !plugin.config.config.allowShell) { + msg.resolve('Error: child_process is not allowed in evaljs due to security reasons.'); + return true; + } + + try { + const mesh = eval(script); /* eslint no-eval: off */ + if (mesh === undefined) { + return true; + } + msg.resolve(util.format(mesh)); + } catch (e) { + msg.resolve('Error: ' + e.message); + } + + return true; + }, + description: 'Execute JavaScript in a command context', + permissions: ['system_execute'], + hidden: true + }); + + cmds.push({ + name: 'userid', + execute: async (msg: IMessage, spec: any, prefix: string, ...simplified: any[]): Promise => { + msg.resolve('Your userId is %s.', msg.fullSenderID); + return true; + }, + description: 'Display your userId (internal user identification)', + hidden: true + }); + + cmds.push({ + name: 'roomid', + execute: async (msg: IMessage, spec: any, prefix: string, ...simplified: any[]): Promise => { + msg.resolve('Current roomId is %s.', msg.fullRoomID); + return true; + }, + description: 'Display the internal identification of this room', + hidden: true + }); + + cmds.push({ + name: 'serverid', + execute: async (msg: IMessage, spec: any, prefix: string, ...simplified: any[]): Promise => { + if (msg.target && msg.target.server) { + msg.resolve('Current server ID is s:%s.', msg.target.server); + return true; + } + + msg.resolve('This protocol does not specify a server. ' + + 'Either the protocol is for a single server only or the server variable is not supported.'); + + return true; + }, + description: 'Display the internal identification of this room', + hidden: true + }); + + cmds.push({ + name: 'rgb2hex', + execute: async (msg: IMessage, spec: any, prefix: string, ...simplified: any[]): Promise => { + if (!simplified[0]) { + return true; + } + + const fullmsg = msg.data.split(' ').slice(1).join(' '); + const channels = fullmsg.match(/(rgb)?\(?(\d{1,3}),?\s(\d{1,3}),?\s(\d{1,3})\)?/i); + if (!channels || channels[2] == null) { + msg.resolve('Invalid parameter'); + return true; + } + + const r = parseInt(channels[2], 10); + const g = parseInt(channels[3], 10); + const b = parseInt(channels[4], 10); + + if (r > 255 || g > 255 || b > 255) { + msg.resolve('Invalid colors'); + return true; + } + const hex = rgbToHex(r, g, b); + + msg.resolve(hex); + return true; + }, + description: 'Convert RGB to HEX colors', + usage: '[rgb](, , )| ' + }); + + cmds.push({ + name: 'hex2rgb', + execute: async (msg: IMessage, spec: any, prefix: string, ...simplified: any[]): Promise => { + if (!simplified[0]) { + return true; + } + let hexcode = simplified[0]; + + if (hexcode.indexOf('#') === -1) { + hexcode = '#' + hexcode; + } + + if (hexcode.length !== 4 && hexcode.length !== 7) { + msg.resolve('Invalid length'); + return true; + } + + const rgb = hexToRgb(hexcode); + if (!rgb) { + msg.resolve('Invalid HEX notation'); + return true; + } + + msg.resolve('rgb(%d, %d, %d)', rgb.r, rgb.g, rgb.b); + return true; + }, + description: 'Convert HEX to RGB colors', + usage: '#|#' + }); + + cmds.push({ + name: 'isup', + execute: async (msg: IMessage, spec: any, prefix: string, ...simplified: any[]): Promise => { + if (!simplified[0]) { + msg.resolve('Please specify host name!'); + return true; + } + if (!simplified[1]) { + msg.resolve('Please specify port!'); + return true; + } + + const host = simplified[0]; + const port = parseInt(simplified[1], 10); + + if (isNaN(port) || port <= 0 || port > 65535) { + msg.resolve('Invalid port number!'); + return true; + } + + let statusString = msg.source.format.format('bold', 'closed'); + let status; + + try { + status = await pingTcpServer(host, port); + statusString = msg.source.format.format('bold', 'open'); + } catch (e) { + status = e.message; + } + + if (!isNaN(parseFloat(status))) { + status = status + ' ms'; + } + + msg.resolve(`Port ${port} on ${host} is ${statusString} (${status})`); + return true; + }, + description: 'Ping a host', + usage: ' ', + aliases: ['tcpup', 'tping'], + hidden: true + }); + + cmds.push({ + name: 'convert', + execute: async (msg: IMessage, spec: any, prefix: string, ...simplified: any[]): Promise => { + const tqnt = parseFloat(simplified[0]); + if (isNaN(tqnt)) { + msg.resolve('Please specify a quantity, either an integer or a float!'); + return true; + } + + const src = simplified[1]; + let dst = simplified[2]; + if (dst && dst.toLowerCase() === 'to') { + dst = simplified[3]; + } + + if (!src) { + msg.resolve('Please specify source unit!'); + return true; + } + + if (!dst) { + msg.resolve('Please specify destination unit!'); + return true; + } + + let res = null; + + try { + res = convert(tqnt).from(src).to(dst); + } catch (e) { + res = null; + } + + if (res) { + const srcdesc = convert().describe(src); + const dstdesc = convert().describe(dst); + + const bsrcdesc = (Math.floor(tqnt) !== 1) ? srcdesc.plural : srcdesc.singular; + const bdstdesc = (Math.floor(res) !== 1) ? dstdesc.plural : dstdesc.singular; + + msg.resolve(` ${tqnt} ${bsrcdesc} => ${res} ${bdstdesc}`); + return true; + } + + msg.resolve('Failed to convert.'); + return true; + }, + description: 'Convert between quantities in different units.', + usage: ' ', + aliases: ['cv', 'unit'] + }); + + cmds.push({ + name: 'currency', + execute: async (msg: IMessage, spec: any, prefix: string, ...simplified: any[]): Promise => { + let ctw: CEXResponse | null = cexCache.cache as CEXResponse; + if (cexCache.expiry < Date.now()) { + let fetched; + try { + const data = await httpGET('https://api.exchangeratesapi.io/latest'); + fetched = JSON.parse(data); + logger.log('[utility] Fetched currency exchange rates successfully.'); + } catch (e) { + ctw = null; + } + + if (!ctw || !fetched.rates) { + msg.resolve('Could not fetch currency exchange rates at this time. Please try again later.'); + return true; + } + + cexCache.cache = fetched.rates; + cexCache.date = fetched.date; + cexCache.expiry = Date.now() + 86400000; // day + ctw = cexCache.cache as CEXResponse; + } + + if (simplified[0] === 'date') { + msg.resolve('Currency exchange rates are as of %s', cexCache.date); + return true; + } else if (simplified[0] === 'list') { + msg.resolve('Currently supported currencies: EUR, %s', Object.keys(cexCache.cache).join(', ')); + return true; + } + + const n = parseFloat(simplified[0]); + let f = simplified[1]; + let t = simplified[2]; + if (isNaN(n) || !f || !t) { + msg.resolve('Invalid parameters.'); + return true; + } + f = f.toUpperCase(); + t = t.toUpperCase(); + + if (f !== 'EUR' && !ctw[f]) { + msg.resolve('This currency is currently not supported.'); + return true; + } + + if (t !== 'EUR' && !ctw[t]) { + msg.resolve('This currency is currently not supported.'); + return true; + } + + if (f === t) { + msg.resolve('%f %s', n, f); + return true; + } + + let ramnt: string; + if (f === 'EUR') { + ramnt = (n * ctw[t]).toFixed(4); + msg.resolve('%f EUR => %f %s', n, ramnt, t); + return true; + } else if (t === 'EUR') { + ramnt = (n / ctw[f]).toFixed(4); + msg.resolve('%f %s => %f EUR', n, f, ramnt); + return true; + } + + const amnt = (ctw[t] * n / ctw[f]).toFixed(4); + msg.resolve('%f %s => %f %s', n, f, amnt, t); + return true; + }, + description: 'Convert between currencies.', + usage: ' | [date | list] [] []', + aliases: ['cex', 'exchange'] + }); + + cmds.push({ + name: 'randomnumber', + execute: async (msg: IMessage, spec: any, prefix: string, ...simplified: any[]): Promise => { + let min = parseInt(simplified[0], 10); + let max = parseInt(simplified[1], 10); + let count = parseInt(simplified[2], 10); + const countMax = plugin.config.config.randomMax || 64; + if (isNaN(min) || isNaN(max)) { + msg.resolve('Invalid numbers.'); + return true; + } + if (min > max) { + const realMax = min + 0; + min = max; + max = realMax; + } + if (isNaN(count)) { count = 1; } + if (String(Math.abs(min)).length > 9 || String(Math.abs(max)).length > 9) { + msg.resolve('The numbers are too large!'); + return true; + } + if (count > countMax) { + msg.resolve('Too many to generate. Maximum: ' + countMax); + return true; + } + const numbers = []; + for (let i = 0; i < count; i++) { + numbers.push(Math.floor(Math.random() * (max - min + 1)) + min); + } + msg.resolve(numbers.join(' ')); + return true; + }, + description: 'Generate a random number between and .', + usage: ' []', + aliases: ['rnum', 'rand'] + }); + + if (plugin.config.config.allowShell) { + logger.warn('WARNING! Shell command execution is enabled! Make absolutely sure that there is proper authentication!'); + if (process.getuid && process.getuid() === 0) { + logger.warn('NEVER run Squeebot as root! Run `useradd squeebot`! We are not responsible for possible security leaks!'); + } + + cmds.push({ + name: 'sh', + execute: async (msg: IMessage, spec: any, prefix: string, ...simplified: any[]): Promise => { + const stripnl = (simplified[0] !== '-n'); + const cmd = simplified.slice(stripnl ? 0 : 1).join(' '); + if (!cmd) { + msg.resolve('Nothing to execute!'); + return true; + } + + cprog.exec(cmd, {shell: '/bin/bash'}, (error, stdout, stderr) => { + if (stdout) { + if (stripnl) { stdout = stdout.replace(/\n/g, ' ;; '); } + + return msg.resolve(stdout); + } + + msg.resolve('Error executing command.'); + logger.error(stderr || error); + }); + + return true; + }, + description: 'Run raw shell command.', + usage: '', + hidden: true, + permissions: ['system_execute'], + }); + } + + commands.registerCommand(cmds.map((x: any) => { + x.plugin = plugin.manifest.name; + return x; + })); +} + +@Configurable({ + allowShell: false, + googleapikey: null, + ipfsGateway: 'https://ipfs.io', + randomMax: 64 +}) +class UtilityPlugin extends Plugin { + bindEvents(): void { + this.on('message', (msg: IMessage) => { + // Pre-regex check + if (msg.data.indexOf('ipfs://') === -1 && msg.data.indexOf('Qm') === -1) { + return; + } + + // IPFS urlify + const mmatch = msg.data.match(/(?:ipfs:\/\/|\s|^)(Qm[\w\d]{44})(?:\s|$)/); + if (mmatch && mmatch[1]) { + msg.resolve(this.config.config.ipfsGateway + '/ipfs/' + mmatch[1]); + } + }); + } + + @DependencyLoad('simplecommands') + addCommands(cmd: any): void { + addCommands(this, cmd); + } + + @EventListener('pluginUnload') + public unloadEventHandler(plugin: string | Plugin): void { + if (plugin === this.name || plugin === this) { + this.config.save().then(() => + this.emit('pluginUnloaded', this)); + } + } + + initialize(): void { + this.bindEvents(); + this.emit('pluginLoaded', this); + } +} + +module.exports = UtilityPlugin;