From 28a6aef9b999541e6cacc64a0b26aafa10432b2c Mon Sep 17 00:00:00 2001 From: Dwayne Harris Date: Wed, 30 Oct 2019 01:12:39 -0400 Subject: [PATCH] WIP --- package-lock.json | 422 +++--------------------------- package.json | 3 +- src/lib/collections.ts | 54 +++- src/lib/crypto.ts | 6 +- src/plugins/api/authentication.ts | 27 +- src/plugins/api/groups.ts | 8 +- src/plugins/api/posts.ts | 114 ++++++-- src/plugins/api/users.ts | 53 ++-- src/schemas.ts | 7 +- src/types/collections.ts | 15 +- 10 files changed, 220 insertions(+), 489 deletions(-) diff --git a/package-lock.json b/package-lock.json index ff07d1a..0e819c7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -54,13 +54,11 @@ "integrity": "sha512-1dVNHT76Uu5N3eJNTYcvxee+jzX4Z9lfciqRRHCU27ihbUcYi+iSc2iml5Ke1LXe1SyJCLA0+14Jh4tXJgOppA==", "dev": true }, - "@phc/format": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/@phc/format/-/format-0.5.0.tgz", - "integrity": "sha512-JWtZ5P1bfXU0bAtTzCpOLYHDXuxSVdtL/oqz4+xa97h8w9E5IlVN333wugXVFv8vZ1hbXObKQf1ptXmFFcMByg==", - "requires": { - "safe-buffer": "^5.1.2" - } + "@types/bcryptjs": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@types/bcryptjs/-/bcryptjs-2.4.2.tgz", + "integrity": "sha512-LiMQ6EOPob/4yUL66SZzu6Yh77cbzJFYll+ZfaPiPPFswtIlA/Fs1MzdKYA7JApHU49zQTbJGX3PDmCpIdDBRQ==", + "dev": true }, "@types/debug": { "version": "4.1.5", @@ -124,7 +122,8 @@ "abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true }, "abort-controller": { "version": "3.0.0", @@ -162,7 +161,8 @@ "ansi-regex": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true }, "ansi-styles": { "version": "3.2.1", @@ -194,59 +194,11 @@ } } }, - "aproba": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" - }, "archy": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=" }, - "are-we-there-yet": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", - "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", - "requires": { - "delegates": "^1.0.0", - "readable-stream": "^2.0.6" - }, - "dependencies": { - "readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "requires": { - "safe-buffer": "~5.1.0" - } - } - } - }, - "argon2": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/argon2/-/argon2-0.25.0.tgz", - "integrity": "sha512-Kvj6nb4qrvLi1yen9UZ69hbpRiA47qm6eZNhaQwTtfhahjq3S0GV/K78yrvIWnJOoTQTPxrDglbGGBitdbvM3w==", - "requires": { - "@phc/format": "^0.5.0", - "node-addon-api": "^1.7.1", - "node-pre-gyp": "^0.13.0" - } - }, "args": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/args/-/args-5.0.1.tgz", @@ -335,7 +287,8 @@ "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true }, "base": { "version": "0.11.2", @@ -392,6 +345,11 @@ } } }, + "bcryptjs": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz", + "integrity": "sha1-mrVie5PmBiH/fNrF2pczAn3x0Ms=" + }, "binary-extensions": { "version": "1.13.1", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", @@ -422,6 +380,7 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -526,11 +485,6 @@ "upath": "^1.1.1" } }, - "chownr": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.3.tgz", - "integrity": "sha512-i70fVHhmV3DtTl6nqvZOnIjbY0Pe4kAUjwHj8z0zAdgBtYrJyYwLKCCuRBQ5ppkyL0AkN7HKRnETdmdp1zqNXw==" - }, "ci-info": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-1.6.0.tgz", @@ -566,11 +520,6 @@ "integrity": "sha1-T6kXw+WclKAEzWH47lCdplFocUM=", "dev": true }, - "code-point-at": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" - }, "collection-visit": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", @@ -648,7 +597,8 @@ "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true }, "configstore": { "version": "3.1.2", @@ -664,11 +614,6 @@ "xdg-basedir": "^3.0.0" } }, - "console-control-strings": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" - }, "content-security-policy-builder": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/content-security-policy-builder/-/content-security-policy-builder-2.1.0.tgz", @@ -740,7 +685,8 @@ "deep-extend": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true }, "deepmerge": { "version": "4.2.1", @@ -801,21 +747,11 @@ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" }, - "delegates": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=" - }, "depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" }, - "detect-libc": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", - "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=" - }, "diagnostics": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/diagnostics/-/diagnostics-1.1.1.tgz", @@ -1288,19 +1224,6 @@ "resolved": "https://registry.npmjs.org/frameguard/-/frameguard-3.1.0.tgz", "integrity": "sha512-TxgSKM+7LTA6sidjOiSZK9wxY0ffMPY3Wta//MqwmX0nZuEHc8QrkV8Fh3ZhMJeiH+Uyh/tcaarImRy8u77O7g==" }, - "fs-minipass": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz", - "integrity": "sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==", - "requires": { - "minipass": "^2.6.0" - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" - }, "fsevents": { "version": "1.2.9", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.9.tgz", @@ -1854,54 +1777,6 @@ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" }, - "gauge": { - "version": "2.7.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", - "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", - "requires": { - "aproba": "^1.0.3", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.0", - "object-assign": "^4.1.0", - "signal-exit": "^3.0.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wide-align": "^1.1.0" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "requires": { - "ansi-regex": "^2.0.0" - } - } - } - }, "get-stream": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", @@ -1916,19 +1791,6 @@ "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", "dev": true }, - "glob": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", - "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", - "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" - } - }, "glob-parent": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", @@ -2011,11 +1873,6 @@ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=" }, - "has-unicode": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=" - }, "has-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", @@ -2088,14 +1945,6 @@ "depd": "2.0.0" } }, - "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" - } - }, "ienoopen": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/ienoopen/-/ienoopen-1.1.0.tgz", @@ -2107,14 +1956,6 @@ "integrity": "sha1-SMptcvbGo68Aqa1K5odr44ieKwk=", "dev": true }, - "ignore-walk": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.2.tgz", - "integrity": "sha512-EXyErtpHbn75ZTsOADsfx6J/FPo6/5cjev46PXrcTpd8z3BoRkXgYu9/JVqrI7tusjmwCZutGeRJeU0Wo1e4Cw==", - "requires": { - "minimatch": "^3.0.4" - } - }, "import-lazy": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", @@ -2127,15 +1968,6 @@ "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", "dev": true }, - "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", @@ -2144,7 +1976,8 @@ "ini": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", - "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==" + "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", + "dev": true }, "ip-regex": { "version": "2.1.0", @@ -2269,7 +2102,8 @@ "is-fullwidth-code-point": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true }, "is-glob": { "version": "4.0.1", @@ -2648,6 +2482,7 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, "requires": { "brace-expansion": "^1.1.7" } @@ -2655,31 +2490,8 @@ "minimist": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" - }, - "minipass": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", - "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", - "requires": { - "safe-buffer": "^5.1.2", - "yallist": "^3.0.0" - }, - "dependencies": { - "yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" - } - } - }, - "minizlib": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz", - "integrity": "sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==", - "requires": { - "minipass": "^2.9.0" - } + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true }, "mixin-deep": { "version": "1.3.2", @@ -2702,21 +2514,6 @@ } } }, - "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "requires": { - "minimist": "0.0.8" - }, - "dependencies": { - "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" - } - } - }, "moment": { "version": "2.24.0", "resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz", @@ -2759,26 +2556,6 @@ "to-regex": "^3.0.1" } }, - "needle": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/needle/-/needle-2.4.0.tgz", - "integrity": "sha512-4Hnwzr3mi5L97hMYeNl8wRW/Onhy4nUKR/lVemJ8gJedxxUyBLm9kkrDColJvoSfwi0jCNhD+xCdOtiGDQiRZg==", - "requires": { - "debug": "^3.2.6", - "iconv-lite": "^0.4.4", - "sax": "^1.2.4" - }, - "dependencies": { - "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", - "requires": { - "ms": "^2.1.1" - } - } - } - }, "nice-try": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", @@ -2794,44 +2571,11 @@ "resolved": "https://registry.npmjs.org/node-abort-controller/-/node-abort-controller-1.0.4.tgz", "integrity": "sha512-7cNtLKTAg0LrW3ViS2C7UfIzbL3rZd8L0++5MidbKqQVJ8yrH6+1VRSHl33P0ZjBTbOJd37d9EYekvHyKkB0QQ==" }, - "node-addon-api": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-1.7.1.tgz", - "integrity": "sha512-2+DuKodWvwRTrCfKOeR24KIc5unKjOh8mz17NCzVnHWfjAdDqbfbjqh7gUT+BkXBRQM52+xCHciKWonJ3CbJMQ==" - }, "node-fetch": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz", "integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==" }, - "node-pre-gyp": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.13.0.tgz", - "integrity": "sha512-Md1D3xnEne8b/HGVQkZZwV27WUi1ZRuZBij24TNaZwUPU3ZAFtvT6xxJGaUVillfmMKnn5oD1HoGsp2Ftik7SQ==", - "requires": { - "detect-libc": "^1.0.2", - "mkdirp": "^0.5.1", - "needle": "^2.2.1", - "nopt": "^4.0.1", - "npm-packlist": "^1.1.6", - "npmlog": "^4.0.2", - "rc": "^1.2.7", - "rimraf": "^2.6.1", - "semver": "^5.3.0", - "tar": "^4" - }, - "dependencies": { - "nopt": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz", - "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", - "requires": { - "abbrev": "1", - "osenv": "^0.1.4" - } - } - } - }, "nodemon": { "version": "1.19.4", "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-1.19.4.tgz", @@ -2894,20 +2638,6 @@ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "dev": true }, - "npm-bundled": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.0.6.tgz", - "integrity": "sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g==" - }, - "npm-packlist": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.4.tgz", - "integrity": "sha512-zTLo8UcVYtDU3gdeaFu2Xu0n0EvelfHDGuqtNIn5RO7yQj4H1TqNdBc/yZjxnWA0PVB8D3Woyp0i5B43JwQ6Vw==", - "requires": { - "ignore-walk": "^3.0.1", - "npm-bundled": "^1.0.1" - } - }, "npm-run-all": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/npm-run-all/-/npm-run-all-4.1.5.tgz", @@ -2933,27 +2663,6 @@ "path-key": "^2.0.0" } }, - "npmlog": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", - "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", - "requires": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" - } - }, - "number-is-nan": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" - }, "object-copy": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", @@ -3030,11 +2739,6 @@ "resolved": "https://registry.npmjs.org/one-time/-/one-time-0.0.4.tgz", "integrity": "sha1-+M33eISCb+Tf+T46nMN7HkSAdC4=" }, - "os-homedir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" - }, "os-name": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/os-name/-/os-name-3.1.0.tgz", @@ -3044,20 +2748,6 @@ "windows-release": "^3.1.0" } }, - "os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" - }, - "osenv": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", - "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", - "requires": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.0" - } - }, "p-finally": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", @@ -3100,7 +2790,8 @@ "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=" + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true }, "path-is-inside": { "version": "1.0.2", @@ -3266,6 +2957,7 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, "requires": { "deep-extend": "^0.6.0", "ini": "~1.3.0", @@ -3413,14 +3105,6 @@ "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.1.4.tgz", "integrity": "sha512-5C9HXdzK8EAqN7JDif30jqsBzavB7wLpaubisuQIGHWf2gUXSpzy6ArX/+Da8RjFpagWsCn+pIgxTMAmKw9Zug==" }, - "rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "requires": { - "glob": "^7.1.3" - } - }, "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", @@ -3451,11 +3135,6 @@ "ret": "~0.2.0" } }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, "sax": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", @@ -3490,11 +3169,6 @@ "resolved": "https://registry.npmjs.org/semver-store/-/semver-store-0.3.0.tgz", "integrity": "sha512-TcZvGMMy9vodEFSse30lWinkj+JgOBvPn8wRItpQRSayhc+4ssDs335uklkfvQQJgL/WvmHLVj4Ycv2s7QCQMg==" }, - "set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" - }, "set-value": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", @@ -3785,6 +3459,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, "requires": { "is-fullwidth-code-point": "^2.0.0", "strip-ansi": "^4.0.0" @@ -3813,6 +3488,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, "requires": { "ansi-regex": "^3.0.0" } @@ -3831,7 +3507,8 @@ "strip-json-comments": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "dev": true }, "supports-color": { "version": "5.5.0", @@ -3842,27 +3519,6 @@ "has-flag": "^3.0.0" } }, - "tar": { - "version": "4.4.13", - "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.13.tgz", - "integrity": "sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA==", - "requires": { - "chownr": "^1.1.1", - "fs-minipass": "^1.2.5", - "minipass": "^2.8.6", - "minizlib": "^1.2.1", - "mkdirp": "^0.5.0", - "safe-buffer": "^5.1.2", - "yallist": "^3.0.3" - }, - "dependencies": { - "yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" - } - } - }, "term-size": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/term-size/-/term-size-1.2.0.tgz", @@ -4200,14 +3856,6 @@ "isexe": "^2.0.0" } }, - "wide-align": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", - "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", - "requires": { - "string-width": "^1.0.2 || 2" - } - }, "widest-line": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-2.0.1.tgz", diff --git a/package.json b/package.json index 17a489f..d6d7cf8 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "watch": "run-p watch-typescript watch-server" }, "devDependencies": { + "@types/bcryptjs": "^2.4.2", "@types/dotenv": "^6.1.1", "@types/jsonwebtoken": "^8.3.5", "@types/lodash": "^4.14.144", @@ -23,7 +24,7 @@ "dependencies": { "@azure/cosmos": "^3.3.6", "@azure/storage-blob": "^10.5.0", - "argon2": "^0.25.0", + "bcryptjs": "^2.4.3", "dotenv": "^8.2.0", "fastify": "^2.10.0", "fastify-cors": "^2.1.3", diff --git a/src/lib/collections.ts b/src/lib/collections.ts index 4a3838f..d627a4b 100644 --- a/src/lib/collections.ts +++ b/src/lib/collections.ts @@ -1,22 +1,58 @@ import { CosmosClient } from '@azure/cosmos' import { Logger } from 'fastify' +import compact from 'lodash/compact' import uniq from 'lodash/uniq' import { DatabaseItem } from '../types' import { containerFor, createQuerySpec, queryItems, getItem } from './database' -import { User, UserSubscription, UserBlock, GroupMembership, UserItemType, GroupItemType } from '../types/collections' +import { User, UserSubscription, UserBlock, Group, GroupMembership, UserItemType, GroupItemType } from '../types/collections' +export async function getUser(client: CosmosClient, id: string): Promise { + const user = await getItem({ + container: containerFor(client, 'Users'), + id, + }) + + if (!user) return + + const getGroup = async (id: string) => { + return await getItem({ + container: containerFor(client, 'Groups'), + id, + }) + } + + return { + ...user, + group: user.groupId ? await getGroup(user.groupId) : undefined, + } +} export async function getUsers(client: CosmosClient, ids: string[], logger?: Logger): Promise { - return await queryItems({ + const users = await queryItems({ container: containerFor(client, 'Users'), query: createQuerySpec( - `SELECT u.id, u.name, u.imageUrl, u.coverImageUrl, u['group'], u.created FROM Users u WHERE ARRAY_CONTAINS(@ids, u.id)`, - { - ids: uniq(ids), - } + 'SELECT u.id, u.name, u.imageUrl, u.coverImageUrl, u.groupId, u.created FROM Users u WHERE ARRAY_CONTAINS(@ids, u.id)', + { ids: uniq(ids) } ), logger, }) + + const groups = await queryItems({ + container: containerFor(client, 'Groups'), + query: createQuerySpec( + 'SELECT g.id, g.name, g.imageUrl, g.coverImageUrl, g.iconImageUrl, g.created FROM Groups g WHERE ARRAY_CONTAINS(@ids, g.id)', + { ids: uniq(compact(users.map(u => u.groupId))) } + ), + logger, + }) + + return users.map(user => { + return { + ...user, + group: groups.find(group => group.id === user.groupId), + groupId: undefined + } + }) } export async function getUsersFromItems(client: CosmosClient, items: T[], logger?: Logger): Promise { @@ -28,7 +64,7 @@ export async function getApprovedSubscriptions(client: CosmosClient, from: strin container: containerFor(client, 'Users'), query: createQuerySpec( `SELECT u.id FROM Users u WHERE - u.subscriberId = @to + u.id = @to u.pk = @from AND u.t = @type AND u.pending = false`, @@ -59,7 +95,7 @@ export async function getUserMembership(client: CosmosClient, userId: string, lo }) if (!user) return - if (!user.group) return + if (!user.groupId) return const memberships = await queryItems({ container: containerFor(client, 'Groups'), @@ -70,7 +106,7 @@ export async function getUserMembership(client: CosmosClient, userId: string, lo g.userId = @user `, { - pk: user.group.id, + pk: user.groupId, type: GroupItemType.Membership, user: user.id, } diff --git a/src/lib/crypto.ts b/src/lib/crypto.ts index 1531235..a2bf82d 100644 --- a/src/lib/crypto.ts +++ b/src/lib/crypto.ts @@ -1,13 +1,13 @@ -import argon2 from 'argon2' +import { hash, compare } from 'bcryptjs' import { randomBytes } from 'crypto' import jwt, { SignOptions, VerifyOptions } from 'jsonwebtoken' export async function hashPassword(password: string): Promise { - return await argon2.hash(password) + return await hash(password, 8) } export async function verifyPassword(hash: string, password: string): Promise { - return await argon2.verify(hash, password) + return await compare(hash, password) } export const generateString = (length: number) => randomBytes(Math.max(Math.round(length / 2), 5)).toString('hex') diff --git a/src/plugins/api/authentication.ts b/src/plugins/api/authentication.ts index 1866617..db778c8 100644 --- a/src/plugins/api/authentication.ts +++ b/src/plugins/api/authentication.ts @@ -13,6 +13,7 @@ import { Server, IncomingMessage, ServerResponse } from 'http' import { MIN_ID_LENGTH, MAX_ID_LENGTH, MAX_NAME_LENGTH, MIN_PASSWORD_LENGTH, INSTALLATION_PARTITION_KEY } from '../../constants' import { tokenResponseSchema, selfSchema, errorSchema } from '../../schemas' import { createAccessToken, createRefreshToken } from '../../lib/authentication' +import { getUser } from '../../lib/collections' import { hashPassword, verifyPassword, JWT } from '../../lib/crypto' import { containerFor, getItem, queryItems, normalize, createQuerySpec } from '../../lib/database' import { badRequestError, badRequestFormError, unauthorizedError, serverError } from '../../lib/errors' @@ -25,7 +26,6 @@ import { UserToken, Group, GroupInvitation, - GroupPartial, GroupMembership, UserItemType, UserPrivacyType, @@ -109,7 +109,6 @@ function registerRoute(server: FastifyInstance({ container: groupContainer, id: request.body.group }) @@ -141,12 +140,6 @@ function registerRoute(server: FastifyInstance({ - container: containerFor(server.database.client, 'Users'), - id: request.viewer.id, - }) - + const viewer = await getUser(server.database.client, request.viewer.id) if (!viewer) return unauthorizedError(reply) - const group = viewer.group ? await getItem({ - container: containerFor(server.database.client, 'Groups'), - id: viewer.group.id, - }) : undefined - - return { - ...viewer, - group, - } + return viewer }) } diff --git a/src/plugins/api/groups.ts b/src/plugins/api/groups.ts index 93e0104..78633fc 100644 --- a/src/plugins/api/groups.ts +++ b/src/plugins/api/groups.ts @@ -137,7 +137,7 @@ function createRoute(server: FastifyInstance({ ...viewer, - group: { - id: group.id, - name: group.name, - iconImageUrl: group.iconImageUrl, - }, + groupId: group.id, }) await groupContainer.items.create({ diff --git a/src/plugins/api/posts.ts b/src/plugins/api/posts.ts index 91c3b86..ec43091 100644 --- a/src/plugins/api/posts.ts +++ b/src/plugins/api/posts.ts @@ -18,7 +18,7 @@ import { SHORT_TEXT_LENGTH, SUBSCRIBER_MAX_SIZE, INSTALLATION_PARTITION_KEY, APP import { userSchema, postSchema, errorSchema } from '../../schemas' import { unauthorizedError, serverError, badRequestError, badRequestFormError, notFoundError } from '../../lib/errors' import { trimContent, createPostId } from '../../lib/utils' -import { getUsers, getApprovedSubscriptions, getUserBlocks } from '../../lib/collections' +import { getUsers, getApprovedSubscriptions, getUserBlocks, getUser } from '../../lib/collections' import { containerFor, createQuerySpec, queryItems, getItem, normalize } from '../../lib/database' import { @@ -106,7 +106,7 @@ async function createPost(client: CosmosClient, userId: string, body: PostBody, if (!viewer) return serverError(reply) if (viewer.pending) return badRequestError(reply, 'User requires approval') - if (!viewer.group) return badRequestError(reply, 'User must belong to a group') + if (!viewer.groupId) return badRequestError(reply, 'User must belong to a group') const postId = createPostId() @@ -167,15 +167,13 @@ async function createPost(client: CosmosClient, userId: string, body: PostBody, logger, }) - if (subscribers.length < SUBSCRIBER_MAX_SIZE) { - for (const subscriber of subscribers) { - await userContainer.items.create({ - postId, - pk: subscriber.id!, - t: UserItemType.Timeline, - created: Date.now(), - }) - } + for (const uid of [userId, ...subscribers.map(s => s.id)]) { + await userContainer.items.create({ + id: postId, + pk: uid, + t: UserItemType.Timeline, + created: Date.now(), + }) } return { @@ -305,10 +303,10 @@ function postsByUserRoute(server: FastifyInstance({ container: userContainer, id }) + const user = await getUser(server.database.client, id) if (!user) return notFoundError(reply) - if (!user.group) return notFoundError(reply) + if (!user.groupId) return notFoundError(reply) switch (user.privacy) { case UserPrivacyType.Private: @@ -326,10 +324,10 @@ function postsByUserRoute(server: FastifyInstance({ container: userContainer, id: request.viewer.id }) if (!viewer) return serverError(reply) - if (!viewer.group) return unauthorizedError(reply) + if (!viewer.groupId) return unauthorizedError(reply) const subscriptions = await getApprovedSubscriptions(server.database.client, user.id, request.viewer.id, request.log) - if (viewer.group.id !== user.group.id && subscriptions.length === 0) return unauthorizedError(reply) + if (viewer.groupId !== user.groupId && subscriptions.length === 0) return unauthorizedError(reply) break } @@ -338,9 +336,9 @@ function postsByUserRoute(server: FastifyInstance({ container: userContainer, id: request.viewer.id }) if (!viewer) return serverError(reply) - if (!viewer.group) return unauthorizedError(reply) + if (!viewer.groupId) return unauthorizedError(reply) - const blocks = await getUserBlocks(server.database.client, user.id, [viewer.id, viewer.group.id], request.log) + const blocks = await getUserBlocks(server.database.client, user.id, [viewer.id, viewer.groupId], request.log) if (blocks.length > 0) return unauthorizedError(reply) } @@ -359,18 +357,82 @@ function postsByUserRoute(server: FastifyInstance({ container: containerFor(server.database.client, 'Groups'), id: user.group.id }) - return { - user: { - ...user, - group, - }, + user, posts, } }) } +function timelineRoute(server: FastifyInstance) { + interface Query { + continuation?: string + } + + const options: RouteShorthandOptions = { + schema: { + querystring: { + type: 'object', + properties: { + continuation: { type: 'string' }, + }, + }, + response: { + 200: { + type: 'object', + properties: { + posts: { + type: 'array', + items: postSchema, + }, + }, + }, + 400: errorSchema, + }, + }, + } + + server.get('/api/timeline', options, async (request, reply) => { + if (!server.database) return serverError(reply) + if (!request.viewer) return unauthorizedError(reply) + + const userContainer = containerFor(server.database.client, 'Users') + const postContainer = containerFor(server.database.client, 'Posts') + + const { resources: timelinePosts, requestCharge, continuation } = await userContainer.items.query( + createQuerySpec('SELECT * FROM Users u WHERE u.pk = @pk AND u.t = @type ORDER BY u.created', { + pk: request.viewer.id, + type: UserItemType.Timeline, + }), + { + maxItemCount: 40, + continuation: request.query.continuation, + } + ).fetchAll() + + request.log.trace('Query: %d', requestCharge) + + const posts = await queryItems({ + container: postContainer, + query: createQuerySpec('SELECT * FROM Posts p WHERE ARRAY_CONTAINS(@posts, p.id) ORDER BY p.created DESC', { + posts: timelinePosts.map(p => p.id), + }), + logger: request.log + }) + + const users = await getUsers(server.database.client, posts.map(p => p.userId)) + + return { + posts: posts.map(post => ({ + ...post, + user: users.find(u => u.id === post.userId), + userId: undefined, + })), + continuation, + } + }) +} + function postRoute(server: FastifyInstance) { interface Params { id: string @@ -455,7 +517,7 @@ function postRoute(server: FastifyInstance({ container: containerFor(server.database.client, 'Users'), id: request.viewer.id }) if (!viewer) return serverError(reply) - if (!viewer.group) return unauthorizedError(reply) + if (!viewer.groupId) return unauthorizedError(reply) const blockQuery = createQuerySpec(` SELECT g.userId FROM Groups g WHERE @@ -465,7 +527,7 @@ function postRoute(server: FastifyInstance = async server => { createPostRoute(server) + createAppPostRoute(server) postsByUserRoute(server) + timelineRoute(server) postRoute(server) } diff --git a/src/plugins/api/users.ts b/src/plugins/api/users.ts index 2e99084..bbbc359 100644 --- a/src/plugins/api/users.ts +++ b/src/plugins/api/users.ts @@ -11,7 +11,7 @@ import { import { Server, IncomingMessage, ServerResponse } from 'http' import { unauthorizedError, serverError, notFoundError, badRequestError } from '../../lib/errors' -import { getUserBlocks } from '../../lib/collections' +import { getUserBlocks, getUser } from '../../lib/collections' import { containerFor, createQuerySpec, queryItems, getItem, normalize } from '../../lib/database' import { deleteMedia, attachMedia } from '../../lib/media' @@ -187,26 +187,37 @@ function getRoute(server: FastifyInstance({ container: userContainer, id: request.params.id }) + const user = await getUser(server.database.client, request.params.id) if (!user) return notFoundError(reply) + let subscribed = false + let subscribedToYou = false + if (request.viewer) { const viewer = await getItem({ container: userContainer, id: request.viewer.id }) if (!viewer) return serverError(reply) - if (!viewer.group) return unauthorizedError(reply) + if (!viewer.groupId) return unauthorizedError(reply) - const blocks = await getUserBlocks(server.database.client, user.id, [viewer.id, viewer.group.id], request.log) + const blocks = await getUserBlocks(server.database.client, user.id, [viewer.id, viewer.groupId], request.log) if (blocks.length > 0) return unauthorizedError(reply) - } - const group = user.group ? await getItem({ - container: containerFor(server.database.client, 'Groups'), - id: user.group.id, - }) : undefined + subscribed = !!(await getItem({ + container: userContainer, + id: user.id, + partitionKey: viewer.id, + })) + + subscribedToYou = !!(await getItem({ + container: userContainer, + id: viewer.id, + partitionKey: user.id, + })) + } return { ...user, - group, + subscribed, + subscribedToYou, } }) } @@ -242,9 +253,9 @@ function subscribeRoute(server: FastifyInstance 0) return badRequestError(reply, 'Invalid operation') await userContainer.items.create({ - subscriberId: user.id, + id: user.id, pk: request.viewer.id, t: UserItemType.Subscription, pending, @@ -324,7 +335,7 @@ function unsubscribeRoute(server: FastifyInstance({ container: userContainer, id: request.params.id }) if (!user) return notFoundError(reply) - if (!user.group) return badRequestError(reply) + if (!user.groupId) return badRequestError(reply) await userContainer.items.create({ blockedId: user.id, @@ -387,7 +398,7 @@ function blockRoute(server: FastifyInstance({ - pk: user.group.id, + pk: user.groupId, t: GroupItemType.Block, blockedId: user.id, userId: request.viewer.id, @@ -423,7 +434,7 @@ function unblockRoute(server: FastifyInstance({ container: userContainer, id: request.params.id }) if (!user) return notFoundError(reply) - if (!user.group) return badRequestError(reply, 'Invalid operation') + if (!user.groupId) return badRequestError(reply, 'Invalid operation') const userBlockQuery = createQuerySpec(`SELECT u.id FROM Users u WHERE u.pk = @pk AND u.blockedId = @blocked AND u.t = @type`, { pk: request.viewer.id, @@ -444,7 +455,7 @@ function unblockRoute(server: FastifyInstance