From 9c6a31e7655ea0e524223fb105f9bd36f2243568 Mon Sep 17 00:00:00 2001 From: Evert Prants Date: Sun, 29 Nov 2020 20:54:25 +0200 Subject: [PATCH] Initial commit --- .gitignore | 6 + package-lock.json | 460 +++++++++++++++++++++++++++++++++++++ package.json | 17 ++ permissions/plugin.json | 9 + permissions/plugin.ts | 115 ++++++++++ simplecommands/plugin.json | 9 + simplecommands/plugin.ts | 423 ++++++++++++++++++++++++++++++++++ squeebot.repo.json | 14 ++ tsconfig.json | 1 + tslint.json | 122 ++++++++++ 10 files changed, 1176 insertions(+) create mode 100644 .gitignore create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 permissions/plugin.json create mode 100644 permissions/plugin.ts create mode 100644 simplecommands/plugin.json create mode 100644 simplecommands/plugin.ts create mode 100644 squeebot.repo.json create mode 100644 tsconfig.json create mode 100644 tslint.json 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..9f54f25 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,460 @@ +{ + "name": "plugins-core", + "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==" + } + } + }, + "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..ab6c3cc --- /dev/null +++ b/package.json @@ -0,0 +1,17 @@ +{ + "name": "plugins-core", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "build": "tsc", + "watch": "tsc -w" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "@squeebot/core": "file:../core", + "typescript": "^4.1.2" + } +} diff --git a/permissions/plugin.json b/permissions/plugin.json new file mode 100644 index 0000000..ae5717b --- /dev/null +++ b/permissions/plugin.json @@ -0,0 +1,9 @@ +{ + "main": "plugin.js", + "name": "permissions", + "description": "Official permissions system for commands", + "tags": ["api", "permissions"], + "version": "0.0.0", + "dependencies": ["control?"], + "npmDependencies": [] +} diff --git a/permissions/plugin.ts b/permissions/plugin.ts new file mode 100644 index 0000000..21ac694 --- /dev/null +++ b/permissions/plugin.ts @@ -0,0 +1,115 @@ +import { + Plugin, + EventListener, + Configurable, +} from '@squeebot/core/lib/plugin'; + +import { logger } from '@squeebot/core/lib/core'; +import { IMessage } from '@squeebot/core/lib/types'; +import { fullIDMatcher } from '@squeebot/core/lib/common'; + +/* + users: { + 'service/instance/name': [ + 'one', + 'two', + '*' + ] + }, + rooms: { + 'service/instance/room': { + 'service/instance/name': [ + 'three', + 'four', + ] + } + } +*/ + +@Configurable({users: {}, rooms: {}}) +class PermissionsPlugin extends Plugin { + userPermitted(msg: IMessage, required: string[]): boolean { + // Boot all guests instantly + if (msg.guest === true) { + return false; + } + + const userFull = msg.fullSenderID; + const roomFull = msg.fullRoomID; + if (!userFull || !roomFull) { + return false; + } + + // Check for room access + for (const ch in this.config.config.rooms) { + if (fullIDMatcher(roomFull, ch)) { + const users = this.config.config.rooms[ch]; + for (const user in users) { + if (fullIDMatcher(userFull, user)) { + const perms = users[user]; + if (perms.indexOf('*') !== -1) { + return true; + } + + let has = false; + for (const perm of required) { + if (perm === '*') { + has = true; + break; + } + + if (perms.indexOf(perm) !== -1) { + has = true; + break; + } + } + + if (has) { + return true; + } + } + } + } + } + + // Check for per-user-basis permissions + for (const user in this.config.config.users) { + if (fullIDMatcher(userFull, user)) { + const perms = this.config.config.users[user]; + if (perms.indexOf('*') !== -1) { + return true; + } + + let has = false; + for (const perm of required) { + if (perm === '*') { + has = true; + break; + } + + if (perms.indexOf(perm) !== -1) { + has = true; + break; + } + } + + if (has) { + return true; + } + } + } + + return false; + } + + @EventListener('pluginUnload') + unloadEventHandler(plugin: string | Plugin): void { + if (plugin === this.name || plugin === this) { + logger.debug('[%s]', this.name, 'shutting down..'); + this.config.save().then(() => + this.emit('pluginUnloaded', this)); + } + } +} + +module.exports = PermissionsPlugin; diff --git a/simplecommands/plugin.json b/simplecommands/plugin.json new file mode 100644 index 0000000..77a53b4 --- /dev/null +++ b/simplecommands/plugin.json @@ -0,0 +1,9 @@ +{ + "main": "plugin.js", + "name": "simplecommands", + "description": "Official Simplistic Commands API for Squeebot 3", + "tags": ["handler", "commands", "api"], + "version": "1.0.0", + "dependencies": ["control?", "permissions?"], + "npmDependencies": [] +} diff --git a/simplecommands/plugin.ts b/simplecommands/plugin.ts new file mode 100644 index 0000000..3d535ca --- /dev/null +++ b/simplecommands/plugin.ts @@ -0,0 +1,423 @@ +import { + Plugin, + EventListener, + Configurable, + DependencyLoad, + DependencyUnload +} from '@squeebot/core/lib/plugin'; + +import { EMessageType, IMessage, IMessageTarget } from '@squeebot/core/lib/types'; + +import { fullIDMatcher } from '@squeebot/core/lib/common'; + +import { logger } from '@squeebot/core/lib/core'; + +declare type Matcher = (msg: IMessage) => boolean; + +interface CommandSpec { + name: string; + plugin: string; + description?: string; + usage?: string; + source?: string | string[] | Matcher; + tags?: string[]; + aliases?: string[]; + alias?: string; + match?: string | Matcher; + hidden?: boolean; + permissions?: string[]; + execute(msg: IMessage, command: CommandSpec, prefix: string, ...args: any[]): Promise; +} + +@Configurable({ + prefix: { + '*': '!' + }, + keywords: ['squeebot'] +}) +class SqueebotCommandsAPIPlugin extends Plugin { + private commands: CommandSpec[] = []; + private permissions: any = null; + + private roomMatcher(msg: IMessage, specList: CommandSpec[]): CommandSpec[] { + const roomMatches = []; + + for (const spec of specList) { + if (spec.source) { + // This message can't room match + if (!msg.fullRoomID) { + continue; + } + if (typeof spec.source === 'function') { + try { + if (spec.source(msg)) { + roomMatches.push(spec); + } + } catch (e) {} + } else if (typeof spec.source === 'string') { + if (fullIDMatcher(msg.fullRoomID, spec.source)) { + roomMatches.push(spec); + } + } else if (Array.isArray(spec.source)) { + for (const room of spec.source) { + if (fullIDMatcher(msg.fullRoomID, room)) { + roomMatches.push(spec); + break; + } + } + } + continue; + } + + // No source requirement + roomMatches.push(spec); + } + + return roomMatches; + } + + public permissionMatcher(msg: IMessage, specList: CommandSpec[]): CommandSpec[] { + const permitted = []; + for (const spec of specList) { + if (!spec.permissions) { + permitted.push(spec); + continue; + } + + if (!this.permissions) { + continue; + } + + if (!this.permissions.userPermitted(msg, spec.permissions)) { + continue; + } + + permitted.push(spec); + } + + return permitted; + } + + public async handlePrefix(msg: IMessage, prefix: string): Promise { + const text = msg.data.text ? msg.data.text : msg.data; + const separate = text.split(' '); + if (separate[0].indexOf(prefix) === 0) { + separate[0] = separate[0].substring(prefix.length); + } + + // Iteration 1: Resolve commands by name and by aliases + const withAliases = []; + for (const spec of this.commands) { + if (spec.aliases && spec.aliases.indexOf(separate[0]) !== -1) { + const copy = Object.assign({}, spec); + copy.alias = spec.name; + withAliases.push(copy); + continue; + } + + if (spec.name !== separate[0]) { + continue; + } + + withAliases.push(spec); + } + + // Iteration 2: Match rooms, if needed + const roomMatches = this.roomMatcher(msg, withAliases); + + // Nothing matches room requirements + if (!roomMatches.length) { + return; + } + + // Iteration 3: Sort the array so that the ones that had room matching come up first + const sorted = []; + for (const spec of roomMatches) { + if (spec.source) { + sorted.push(spec); + continue; + } + sorted.push(spec); + } + + // Iteration 4: Match permissions for user + const permitted = this.permissionMatcher(msg, sorted); + + // Start executing + for (const spec of permitted) { + const success = await spec.execute(msg, spec, prefix, ...separate.slice(1)); + if (success) { + break; + } + } + + // Done + } + + public async handleKeywords(msg: IMessage, keyword: string): Promise { + const text = msg.data.text ? msg.data.text : msg.data; + + // Only pass command specs which have `match` and match rooms + let matching = []; + for (const spec of this.commands) { + if (!spec.match) { + continue; + } + + if (typeof spec.match === 'function') { + try { + if (!spec.match(msg)) { + continue; + } + } catch (e) {} + } else { + if (!text.match(spec.match)) { + continue; + } + } + + matching.push(spec); + } + + matching = this.roomMatcher(msg, matching); + + // Nothing matches room requirements + if (!matching.length) { + return; + } + + // Iteration 2: Sort the array so that the ones that had room matching come up first + const sorted = []; + for (const spec of matching) { + if (spec.source) { + sorted.push(spec); + continue; + } + sorted.push(spec); + } + + // Iteration 3: Match permissions for user + const permitted = this.permissionMatcher(msg, sorted); + + // Start executing + for (const spec of permitted) { + const success = await spec.execute(msg, spec, keyword); + if (success) { + break; + } + } + + // Done + } + + public digest(msg: IMessage): void { + if (msg.type !== EMessageType.message) { + return; + } + + const text = msg.data.text ? msg.data.text : msg.data; + const prefixes = this.config.config.prefix; + const keywords = this.config.config.keywords; + + // Attempt to match keywords + if (!keywords && !keywords.length) { + for (const kw of keywords) { + if (text.match(kw)) { + this.handleKeywords(msg, kw).catch(e => + logger.error('[%s] Command handler threw an error:', this.name, e.stack)); + return; + } + } + } + + if (!prefixes) { + return; + } + + // Attempt to match prefixes, prefers room-specific ones + let prefix = '!'; + if (typeof prefixes === 'string') { + prefix = prefixes; + } else if (typeof prefixes === 'object') { + if (msg.fullRoomID) { + for (const idtag in prefixes) { + if (idtag === '*') { + prefix = prefixes[idtag]; + continue; + } + if (fullIDMatcher(msg.fullRoomID, idtag)) { + prefix = prefixes[idtag]; + break; + } + } + } + } + + if (!prefix || text.indexOf(prefix) !== 0) { + return; + } + + this.handlePrefix(msg, prefix).catch(e => + logger.error('[%s] Command handler threw an error:', this.name, e.stack)); + } + + public registerCommand(spec: CommandSpec | CommandSpec[]): boolean { + if (Array.isArray(spec)) { + if (!spec.length) { + return false; + } + + logger.log('[%s] Plugin %s registered commands %s', this.name, + spec[0].plugin || 'unknown', spec.map(x => x.name).join(', ')); + + let success = true; + for (const sp of spec) { + if (!this.registerCommand(sp)) { + success = false; + } + } + + return success; + } else { + logger.log('[%s] Plugin %s registered command %s', this.name, + spec.plugin, spec.name); + } + + if (!spec.name || !spec.execute || !spec.plugin) { + throw new Error('Invalid command specification!'); + } + + for (const cmd of this.commands) { + if (cmd.name === spec.name && cmd.plugin === spec.plugin) { + return false; + } + } + + this.commands.push(spec); + + return true; + } + + public unregisterPlugin(plugin: string): void { + const remaining: CommandSpec[] = []; + const removed: CommandSpec[] = []; + + for (const cmd of this.commands) { + if (cmd.plugin !== plugin) { + remaining.push(cmd); + continue; + } + removed.push(cmd); + } + + if (removed.length) { + logger.log('[%s] Plugin %s unregistered command(s):', this.name, + plugin, removed.map(x => x.name).join(', ')); + this.commands = remaining; + } + } + + private helpCommand(msg: IMessage, prefix: string): void { + // Iteration 1: Resolve commands by name and by aliases + const withAliases = []; + for (const spec of this.commands) { + if (spec.aliases && spec.aliases.length) { + for (const alias of spec.aliases) { + const copy = Object.assign({}, spec); + copy.name = alias; + copy.alias = spec.name; + withAliases.push(copy); + } + } + + withAliases.push(spec); + } + + const matching = this.roomMatcher(msg, withAliases); + + // Iteration 2: Match permissions for user + // TODO: permission matching + + const text = msg.data.text ? msg.data.text : msg.data; + const argv = text.toLowerCase().split(' '); + const b = (t: string) => { + return msg.source.format.format('bold', t); + }; + + if (argv[1]) { + let found: CommandSpec | null = null; + for (const spec of matching) { + if (spec.name === argv[1]) { + found = spec; + break; + } + } + + if (!found) { + msg.resolve('help: No such command "%s"!', argv[1]); + return; + } + + let aliasText = ''; + if (found.alias) { + aliasText = b(`[alias of ${found.alias}]`); + } + + if (found.usage) { + msg.resolve('%s %s -', b(prefix + found.name), found.usage, + found.description || 'No description :(', aliasText); + return; + } + + msg.resolve('%s -', b(prefix + found.name), found.description || 'No description :(', aliasText); + return; + } + + msg.resolve('All commands start with a "%s" prefix!\n%s', prefix, + b(`List of commands in ${msg.target?.name}:`), + matching + .filter(x => x.alias == null && x.hidden !== true) + .map(x => x.name).join(', ') + ); + } + + initialize(): void { + this.registerCommand({ + plugin: this.name, + name: 'help', + aliases: ['commands'], + usage: '[]', + description: 'Show command usage or list all commands', + execute: async (msg: IMessage, spec: CommandSpec, prefix: string): Promise => { + this.helpCommand(msg, prefix); + return true; + } + }); + } + + @DependencyLoad('permissions') + permissionsAdded(plugin: Plugin): void { + this.permissions = plugin; + } + + @DependencyUnload('permissions') + permissionsRemoved(): void { + this.permissions = null; + } + + @EventListener('message') + messageHandler(msg: IMessage): void { + this.digest(msg); + } + + @EventListener('pluginUnload') + unloadEventHandler(plugin: string | Plugin): void { + if (plugin === this.name || plugin === this) { + logger.debug('[%s] shutting down..', this.name); + this.config.save().then(() => + this.emit('pluginUnloaded', this)); + } + } +} + +module.exports = SqueebotCommandsAPIPlugin; diff --git a/squeebot.repo.json b/squeebot.repo.json new file mode 100644 index 0000000..435478f --- /dev/null +++ b/squeebot.repo.json @@ -0,0 +1,14 @@ +{ + "name": "plugins-core", + "plugins": [ + { + "name": "permissions", + "version": "0.0.0" + }, + { + "name": "simplecommands", + "version": "1.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..87fa89d --- /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": false, + "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" + ] + } + } +}