From 9e07fbb247123eaf096e8d0e6e96e9116eeaf651 Mon Sep 17 00:00:00 2001 From: Tom Snelling Date: Wed, 21 Feb 2024 09:31:16 +0000 Subject: [PATCH 1/5] readme translation updates --- README.md | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index ca1314c..7d33c8f 100644 --- a/README.md +++ b/README.md @@ -116,16 +116,20 @@ To add a new translation in your own language, create a new JSON file with your The best place to start is to copy the `en.json` file and work through it, translating each English string. +There is also an [inlang project](https://fink.inlang.com/github.com/tdjsnelling/sqtracker) to aid with translation. + ### Existing translations -| Language | Complete (estimate) | Contributed by | -|--------------------|---------------------|----------------------------------------------------| -| English | 100% | | -| Russian | 100% | [@smlinux](https://github.com/smlinux) | -| Esperanto | 100% | [@smlinux](https://github.com/smlinux) | -| German | 100% | [@EchterAlsFake](https://github.com/EchterAlsFake) | -| Simplified Chinese | 95% | [@0EAC](https://github.com/0EAC) | -| French | 100% | [@Klaiment](https://github.com/Klaiment) | +| Language | Contributed by | +|--------------------|------------------------------------------------------| +| English | | +| Russian | [@smlinux](https://github.com/smlinux) | +| Esperanto | [@smlinux](https://github.com/smlinux) | +| German | [@EchterAlsFake](https://github.com/EchterAlsFake) | +| Simplified Chinese | [@0EAC](https://github.com/0EAC) | +| French | [@Klaiment](https://github.com/Klaiment) | +| Spanish | [@CerealKillerjs](https://github.com/CerealKillerjs) | +| Italian | [@NotLugozzi](https://github.com/NotLugozzi) | ## Screenshots From 41155da91e3faf68bb4daea86e3b8599a896ed8a Mon Sep 17 00:00:00 2001 From: Tom Snelling Date: Wed, 21 Feb 2024 09:48:08 +0000 Subject: [PATCH 2/5] adds default locale setting --- api/src/utils/validateConfig.js | 11 + client/pages/_app.js | 4 +- config.example.js | 3 + yarn.lock | 481 ++++++++++++++------------------ 4 files changed, 221 insertions(+), 278 deletions(-) diff --git a/api/src/utils/validateConfig.js b/api/src/utils/validateConfig.js index 096a15a..5ccf91c 100644 --- a/api/src/utils/validateConfig.js +++ b/api/src/utils/validateConfig.js @@ -1,4 +1,12 @@ import * as yup from "yup"; +import en from "@sqtracker/client/locales/en.json"; +import es from "@sqtracker/client/locales/es.json"; +import it from "@sqtracker/client/locales/it.json"; +import ru from "@sqtracker/client/locales/ru.json"; +import de from "@sqtracker/client/locales/de.json"; +import zh from "@sqtracker/client/locales/zh.json"; +import eo from "@sqtracker/client/locales/eo.json"; +import fr from "@sqtracker/client/locales/fr.json"; const httpRegex = /http(s)?:\/\/.*/; const mongoRegex = /mongodb:\/\/.*/; @@ -50,6 +58,9 @@ const configSchema = yup grey: yup.string().matches(hexRegex), }), SQ_EXTENSION_BLACKLIST: yup.array().of(yup.string()).min(0), + SQ_SITE_DEFAULT_LOCALE: yup + .string() + .oneOf(["en", "es", "it", "ru", "de", "zh", "eo", "fr"]), SQ_BASE_URL: yup.string().matches(httpRegex).required(), SQ_API_URL: yup.string().matches(httpRegex).required(), SQ_MONGO_URL: yup.string().matches(mongoRegex).required(), diff --git a/client/pages/_app.js b/client/pages/_app.js index 4dc7070..8950ac3 100644 --- a/client/pages/_app.js +++ b/client/pages/_app.js @@ -164,7 +164,6 @@ const SqTracker = ({ Component, pageProps, initialTheme }) => { const [isServer, setIsServer] = useState(true); const [loading, setLoading] = useState(false); const [userStats, setUserStats] = useState(); - const [locale, setLocale] = useState("en"); const router = useRouter(); @@ -181,9 +180,12 @@ const SqTracker = ({ Component, pageProps, initialTheme }) => { SQ_API_URL, SQ_MINIMUM_RATIO, SQ_MAXIMUM_HIT_N_RUNS, + SQ_SITE_DEFAULT_LOCALE, }, } = getConfig(); + const [locale, setLocale] = useState(SQ_SITE_DEFAULT_LOCALE ?? "en"); + const allowThemeToggle = !Object.keys(SQ_CUSTOM_THEME ?? {}).some( (key) => key !== "primary" ); diff --git a/config.example.js b/config.example.js index a4344f2..ce2f57a 100644 --- a/config.example.js +++ b/config.example.js @@ -73,6 +73,9 @@ module.exports = { // An array of blacklisted file extensions. Torrents containing files with these extensions will fail to upload. SQ_EXTENSION_BLACKLIST: ["exe"], + // Default site locale. See `client/locales/index.js` for available options. + SQ_SITE_DEFAULT_LOCALE: "en", + // The URL of your tracker site. SQ_BASE_URL: "https://sqtracker.dev", diff --git a/yarn.lock b/yarn.lock index d44a97f..65c29f2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10,13 +10,6 @@ "@jridgewell/gen-mapping" "^0.1.0" "@jridgewell/trace-mapping" "^0.3.9" -"@babel/code-frame@^7.18.6": - version "7.18.6" - resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz" - integrity sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q== - dependencies: - "@babel/highlight" "^7.18.6" - "@babel/code-frame@7.12.11": version "7.12.11" resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz" @@ -24,12 +17,19 @@ dependencies: "@babel/highlight" "^7.10.4" +"@babel/code-frame@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz" + integrity sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q== + dependencies: + "@babel/highlight" "^7.18.6" + "@babel/compat-data@^7.17.7", "@babel/compat-data@^7.20.1", "@babel/compat-data@^7.20.5": version "7.20.14" resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.14.tgz" integrity sha512-0YpKHD6ImkWMEINCyDAD0HLLUH/lPCefG8ld9it8DJB2wnApraKuhgYTvTY1z7UFIfBTGy5LwncZ+5HWWGbhFw== -"@babel/core@^7.0.0", "@babel/core@^7.0.0-0", "@babel/core@^7.12.0", "@babel/core@^7.13.0", "@babel/core@^7.14.6", "@babel/core@^7.4.0-0": +"@babel/core@^7.14.6": version "7.20.12" resolved "https://registry.npmjs.org/@babel/core/-/core-7.20.12.tgz" integrity sha512-XsMfHovsUYHFMdrIHkZphTN/2Hzzi78R08NuHfDBehym2VsPDL6Zn/JAD/JQdnRvbSsbQc4mVaU1m6JgtTEElg== @@ -1017,7 +1017,7 @@ resolved "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz" integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== -"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.13", "@jridgewell/sourcemap-codec@1.4.14": +"@jridgewell/sourcemap-codec@1.4.14", "@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.13": version "1.4.14" resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz" integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== @@ -1057,6 +1057,66 @@ dependencies: glob "7.1.7" +"@next/swc-android-arm-eabi@12.2.5": + version "12.2.5" + resolved "https://registry.yarnpkg.com/@next/swc-android-arm-eabi/-/swc-android-arm-eabi-12.2.5.tgz#903a5479ab4c2705d9c08d080907475f7bacf94d" + integrity sha512-cPWClKxGhgn2dLWnspW+7psl3MoLQUcNqJqOHk2BhNcou9ARDtC0IjQkKe5qcn9qg7I7U83Gp1yh2aesZfZJMA== + +"@next/swc-android-arm64@12.2.5": + version "12.2.5" + resolved "https://registry.yarnpkg.com/@next/swc-android-arm64/-/swc-android-arm64-12.2.5.tgz#2f9a98ec4166c7860510963b31bda1f57a77c792" + integrity sha512-vMj0efliXmC5b7p+wfcQCX0AfU8IypjkzT64GiKJD9PgiA3IILNiGJr1fw2lyUDHkjeWx/5HMlMEpLnTsQslwg== + +"@next/swc-darwin-arm64@12.2.5": + version "12.2.5" + resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-12.2.5.tgz#31b1c3c659d54be546120c488a1e1bad21c24a1d" + integrity sha512-VOPWbO5EFr6snla/WcxUKtvzGVShfs302TEMOtzYyWni6f9zuOetijJvVh9CCTzInnXAZMtHyNhefijA4HMYLg== + +"@next/swc-darwin-x64@12.2.5": + version "12.2.5" + resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-12.2.5.tgz#2e44dd82b2b7fef88238d1bc4d3bead5884cedfd" + integrity sha512-5o8bTCgAmtYOgauO/Xd27vW52G2/m3i5PX7MUYePquxXAnX73AAtqA3WgPXBRitEB60plSKZgOTkcpqrsh546A== + +"@next/swc-freebsd-x64@12.2.5": + version "12.2.5" + resolved "https://registry.yarnpkg.com/@next/swc-freebsd-x64/-/swc-freebsd-x64-12.2.5.tgz#e24e75d8c2581bfebc75e4f08f6ddbd116ce9dbd" + integrity sha512-yYUbyup1JnznMtEBRkK4LT56N0lfK5qNTzr6/DEyDw5TbFVwnuy2hhLBzwCBkScFVjpFdfiC6SQAX3FrAZzuuw== + +"@next/swc-linux-arm-gnueabihf@12.2.5": + version "12.2.5" + resolved "https://registry.yarnpkg.com/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-12.2.5.tgz#46d8c514d834d2b5f67086013f0bd5e3081e10b9" + integrity sha512-2ZE2/G921Acks7UopJZVMgKLdm4vN4U0yuzvAMJ6KBavPzqESA2yHJlm85TV/K9gIjKhSk5BVtauIUntFRP8cg== + +"@next/swc-linux-arm64-gnu@12.2.5": + version "12.2.5" + resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-12.2.5.tgz#91f725ac217d3a1f4f9f53b553615ba582fd3d9f" + integrity sha512-/I6+PWVlz2wkTdWqhlSYYJ1pWWgUVva6SgX353oqTh8njNQp1SdFQuWDqk8LnM6ulheVfSsgkDzxrDaAQZnzjQ== + +"@next/swc-linux-arm64-musl@12.2.5": + version "12.2.5" + resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-12.2.5.tgz#e627e8c867920995810250303cd9b8e963598383" + integrity sha512-LPQRelfX6asXyVr59p5sTpx5l+0yh2Vjp/R8Wi4X9pnqcayqT4CUJLiHqCvZuLin3IsFdisJL0rKHMoaZLRfmg== + +"@next/swc-linux-x64-gnu@12.2.5": + version "12.2.5" + resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-12.2.5.tgz#83a5e224fbc4d119ef2e0f29d0d79c40cc43887e" + integrity sha512-0szyAo8jMCClkjNK0hknjhmAngUppoRekW6OAezbEYwHXN/VNtsXbfzgYOqjKWxEx3OoAzrT3jLwAF0HdX2MEw== + +"@next/swc-linux-x64-musl@12.2.5": + version "12.2.5" + resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-12.2.5.tgz#be700d48471baac1ec2e9539396625584a317e95" + integrity sha512-zg/Y6oBar1yVnW6Il1I/08/2ukWtOG6s3acdJdEyIdsCzyQi4RLxbbhkD/EGQyhqBvd3QrC6ZXQEXighQUAZ0g== + +"@next/swc-win32-arm64-msvc@12.2.5": + version "12.2.5" + resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-12.2.5.tgz#a93e958133ad3310373fda33a79aa10af2a0aa97" + integrity sha512-3/90DRNSqeeSRMMEhj4gHHQlLhhKg5SCCoYfE3kBjGpE63EfnblYUqsszGGZ9ekpKL/R4/SGB40iCQr8tR5Jiw== + +"@next/swc-win32-ia32-msvc@12.2.5": + version "12.2.5" + resolved "https://registry.yarnpkg.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-12.2.5.tgz#4f5f7ba0a98ff89a883625d4af0125baed8b2e19" + integrity sha512-hGLc0ZRAwnaPL4ulwpp4D2RxmkHQLuI8CFOEEHdzZpS63/hMVzv81g8jzYA0UXbb9pus/iTc3VRbVbAM03SRrw== + "@next/swc-win32-x64-msvc@12.2.5": version "12.2.5" resolved "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-12.2.5.tgz" @@ -1070,7 +1130,7 @@ "@nodelib/fs.stat" "2.0.5" run-parallel "^1.1.9" -"@nodelib/fs.stat@^2.0.2", "@nodelib/fs.stat@2.0.5": +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": version "2.0.5" resolved "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz" integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== @@ -1191,7 +1251,7 @@ stacktrace-parser "^0.1.10" tslib "^2.4.1 || ^1.9.3" -"@sentry/node@^7.36.0", "@sentry/node@7.73.0": +"@sentry/node@7.73.0", "@sentry/node@^7.36.0": version "7.73.0" resolved "https://registry.npmjs.org/@sentry/node/-/node-7.73.0.tgz" integrity sha512-i50bRfmgkRRx0XXUbg9jGD/RuznDJxJXc4rBILhoJuhl+BjRIaoXA3ayplfJn8JLZxsNh75uJaCq4IUK70SORw== @@ -1279,68 +1339,6 @@ "@sentry/cli" "^1.74.6" webpack-sources "^2.0.0 || ^3.0.0" -"@sqtracker/api@file:C:\\sqt\\sqtracker\\api": - version "1.4.0" - resolved "file:api" - dependencies: - "@babel/core" "^7.14.6" - "@babel/node" "^7.14.7" - "@babel/preset-env" "^7.14.7" - "@sentry/node" "^7.36.0" - "@sentry/tracing" "^7.36.0" - bcrypt "^5.0.1" - bencode "^2.0.1" - bittorrent-tracker "9.19.0" - body-parser "^1.19.0" - chalk "^4.1.1" - content-disposition "^0.5.4" - cookie-parser "^1.4.6" - cors "^2.8.5" - dotenv "^10.0.0" - express "^4.17.1" - express-rate-limit "^6.7.0" - jsonwebtoken "^8.5.1" - memoizee "^0.4.15" - mongoose "^5.13.2" - mongoose-fuzzy-searching "^2.0.2" - morgan "^1.10.0" - multer "^1.4.2" - node-fetch "^2.6.1" - nodemailer "^6.7.8" - qrcode "^1.5.1" - qs "^6.11.0" - slugify "^1.6.5" - speakeasy "^2.0.0" - yup "^0.32.11" - -"@sqtracker/client@file:C:\\sqt\\sqtracker\\client": - version "1.4.0" - resolved "file:client" - dependencies: - "@sentry/nextjs" "^7.36.0" - "@styled-icons/boxicons-regular" "^10.38.0" - "@styled-icons/boxicons-solid" "^10.38.0" - "@styled-system/css" "^5.1.5" - copy-to-clipboard "^3.3.1" - dotenv "^10.0.0" - jsonwebtoken "^8.5.1" - lodash "^4.17.21" - moment "^2.29.1" - next "12.2.5" - pluralize "^8.0.0" - polished "^4.1.3" - pretty-bytes "^5.6.0" - qs "^6.11.0" - react "17.0.2" - react-cookie "^4.1.1" - react-dom "17.0.2" - react-dropzone "^14.2.3" - react-markdown "^7.1.2" - remark-gfm "^3.0.1" - slugify "^1.6.5" - styled-components "^5.3.3" - styled-system "^5.1.5" - "@styled-icons/boxicons-regular@^10.38.0": version "10.47.0" resolved "https://registry.npmjs.org/@styled-icons/boxicons-regular/-/boxicons-regular-10.47.0.tgz" @@ -1545,7 +1543,7 @@ resolved "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz" integrity sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w== -"@types/react@*", "@types/react@>=16": +"@types/react@*": version "18.2.27" resolved "https://registry.npmjs.org/@types/react/-/react-18.2.27.tgz" integrity sha512-Wfv7B7FZiR2r3MIqbAlXoY1+tXm4bOqfz4oRr+nyXdBqapDBZ0l/IGcSlAfvxIHEEJjkPU0MYAc/BlFPOcrgLw== @@ -1626,7 +1624,7 @@ acorn-jsx@^5.3.1: resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz" integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== -"acorn@^6.0.0 || ^7.0.0 || ^8.0.0", acorn@^7.4.0: +acorn@^7.4.0: version "7.4.1" resolved "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz" integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== @@ -1962,7 +1960,7 @@ bn.js@^5.2.0: resolved "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz" integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ== -body-parser@^1.19.0, body-parser@1.20.1: +body-parser@1.20.1, body-parser@^1.19.0: version "1.20.1" resolved "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz" integrity sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw== @@ -2002,7 +2000,7 @@ braces@^3.0.2, braces@~3.0.2: dependencies: fill-range "^7.0.1" -browserslist@^4.21.3, browserslist@^4.21.5, "browserslist@>= 4.21.0": +browserslist@^4.21.3, browserslist@^4.21.5: version "4.21.5" resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz" integrity sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w== @@ -2035,7 +2033,7 @@ buffer@^6.0.3: base64-js "^1.3.1" ieee754 "^1.2.1" -bufferutil@^4.0.1, bufferutil@^4.0.3: +bufferutil@^4.0.3: version "4.0.7" resolved "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.7.tgz" integrity sha512-kukuqc39WOHtdxtw4UScxF/WVnMFVSQVKhtx3AjZJzhd0RGZZldcrfSEbVsWWe6KNH253574cq5F+wpv0G9pJw== @@ -2088,16 +2086,15 @@ ccount@^2.0.0: resolved "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz" integrity sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg== -chalk@^2.0.0: - version "2.4.2" - resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz" - integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== +chalk@3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz" + integrity sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg== dependencies: - ansi-styles "^3.2.1" - escape-string-regexp "^1.0.5" - supports-color "^5.3.0" + ansi-styles "^4.1.0" + supports-color "^7.1.0" -chalk@^2.4.1: +chalk@^2.0.0, chalk@^2.4.1: version "2.4.2" resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz" integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== @@ -2114,14 +2111,6 @@ chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.1: ansi-styles "^4.1.0" supports-color "^7.1.0" -chalk@3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz" - integrity sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - character-entities@^2.0.0: version "2.0.2" resolved "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz" @@ -2201,16 +2190,16 @@ color-convert@^2.0.1: dependencies: color-name "~1.1.4" -color-name@~1.1.4: - version "1.1.4" - resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" - integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== - color-name@1.1.3: version "1.1.3" resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz" integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + color-support@^1.1.2: version "1.1.3" resolved "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz" @@ -2273,7 +2262,7 @@ console-control-strings@^1.0.0, console-control-strings@^1.1.0: resolved "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz" integrity sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ== -content-disposition@^0.5.4, content-disposition@0.5.4: +content-disposition@0.5.4, content-disposition@^0.5.4: version "0.5.4" resolved "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz" integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ== @@ -2303,20 +2292,20 @@ cookie-signature@1.0.6: resolved "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz" integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ== -cookie@^0.4.0: - version "0.4.2" - resolved "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz" - integrity sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA== +cookie@0.4.1: + version "0.4.1" + resolved "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz" + integrity sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA== -cookie@^0.5.0, cookie@0.5.0: +cookie@0.5.0, cookie@^0.5.0: version "0.5.0" resolved "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz" integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw== -cookie@0.4.1: - version "0.4.1" - resolved "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz" - integrity sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA== +cookie@^0.4.0: + version "0.4.2" + resolved "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz" + integrity sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA== copy-to-clipboard@^3.3.1: version "3.3.3" @@ -2389,7 +2378,7 @@ csstype@^3.0.2: resolved "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz" integrity sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw== -d@^1.0.1, d@1: +d@1, d@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/d/-/d-1.0.1.tgz" integrity sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA== @@ -2407,20 +2396,6 @@ date-fns@^2.29.1: resolved "https://registry.npmjs.org/date-fns/-/date-fns-2.29.3.tgz" integrity sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA== -debug@^3.2.7: - version "3.2.7" - resolved "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz" - integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== - dependencies: - ms "^2.1.1" - -debug@^4.0.0, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@4: - version "4.3.4" - resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz" - integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== - dependencies: - ms "2.1.2" - debug@2.6.9: version "2.6.9" resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz" @@ -2435,6 +2410,20 @@ debug@3.1.0: dependencies: ms "2.0.0" +debug@4, debug@^4.0.0, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4: + version "4.3.4" + resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + +debug@^3.2.7: + version "3.2.7" + resolved "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz" + integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== + dependencies: + ms "^2.1.1" + decamelize@^1.2.0: version "1.2.0" resolved "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz" @@ -2500,7 +2489,7 @@ denque@^1.4.1: resolved "https://registry.npmjs.org/denque/-/denque-1.5.1.tgz" integrity sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw== -depd@~2.0.0, depd@2.0.0: +depd@2.0.0, depd@~2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz" integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== @@ -2812,7 +2801,7 @@ eslint-module-utils@^2.7.4: dependencies: debug "^3.2.7" -eslint-plugin-import@*, eslint-plugin-import@^2.22.1: +eslint-plugin-import@^2.22.1: version "2.27.5" resolved "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.27.5.tgz" integrity sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow== @@ -2913,7 +2902,7 @@ eslint-visitor-keys@^2.0.0: resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz" integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== -eslint@*, "eslint@^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8", "eslint@^3 || ^4 || ^5 || ^6 || ^7 || ^8", "eslint@^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0", "eslint@^5.0.0 || ^6.0.0 || ^7.0.0", eslint@^7.23.0, eslint@^7.30.0, eslint@>=5.0.0, eslint@>=7.0.0, eslint@7: +eslint@7, eslint@^7.30.0: version "7.32.0" resolved "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz" integrity sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA== @@ -3025,7 +3014,7 @@ express-rate-limit@^6.7.0: resolved "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-6.7.0.tgz" integrity sha512-vhwIdRoqcYB/72TK3tRZI+0ttS8Ytrk24GfmsxDXK9o9IhHNO5bXRiXQSExPQ4GbaE5tvIS7j1SGrxsuWs+sGA== -"express@^4 || ^5", express@^4.17.1: +express@^4.17.1: version "4.18.2" resolved "https://registry.npmjs.org/express/-/express-4.18.2.tgz" integrity sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ== @@ -3212,6 +3201,11 @@ fs.realpath@^1.0.0: resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== +fsevents@~2.3.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== + function-bind@^1.1.1: version "1.1.1" resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz" @@ -3291,6 +3285,18 @@ glob-parent@^5.1.2, glob-parent@~5.1.2: dependencies: is-glob "^4.0.1" +glob@7.1.7: + version "7.1.7" + resolved "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz" + integrity sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ== + dependencies: + 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@^7.1.3, glob@^7.2.0: version "7.2.3" resolved "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz" @@ -3314,31 +3320,12 @@ glob@^8.0.3: minimatch "^5.0.1" once "^1.3.0" -glob@7.1.7: - version "7.1.7" - resolved "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz" - integrity sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ== - dependencies: - 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" - globals@^11.1.0: version "11.12.0" resolved "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz" integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== -globals@^13.6.0: - version "13.20.0" - resolved "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz" - integrity sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ== - dependencies: - type-fest "^0.20.2" - -globals@^13.9.0: +globals@^13.6.0, globals@^13.9.0: version "13.20.0" resolved "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz" integrity sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ== @@ -3523,7 +3510,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3, inherits@2, inherits@2.0.4: +inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3: version "2.0.4" resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -3552,16 +3539,16 @@ ip@^2.0.0: resolved "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz" integrity sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ== -ipaddr.js@^2.0.0, "ipaddr.js@>= 0.1.5": - version "2.0.1" - resolved "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.0.1.tgz" - integrity sha512-1qTgH9NG+IIJ4yfKs2e6Pp1bZg8wbDbKHT21HrLIeYBTRLgMYKnMTPAuI3Lcs61nfx5h1xlXnbJtH1kX5/d/ng== - ipaddr.js@1.9.1: version "1.9.1" resolved "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz" integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== +"ipaddr.js@>= 0.1.5", ipaddr.js@^2.0.0: + version "2.0.1" + resolved "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.0.1.tgz" + integrity sha512-1qTgH9NG+IIJ4yfKs2e6Pp1bZg8wbDbKHT21HrLIeYBTRLgMYKnMTPAuI3Lcs61nfx5h1xlXnbJtH1kX5/d/ng== + is-arguments@^1.1.1: version "1.1.1" resolved "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz" @@ -3758,6 +3745,11 @@ is-weakset@^2.0.1: call-bind "^1.0.2" get-intrinsic "^1.1.1" +isarray@0.0.1: + version "0.0.1" + resolved "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz" + integrity sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ== + isarray@^2.0.5: version "2.0.5" resolved "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz" @@ -3768,11 +3760,6 @@ isarray@~1.0.0: resolved "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz" integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== -isarray@0.0.1: - version "0.0.1" - resolved "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz" - integrity sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ== - isexe@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz" @@ -4025,11 +4012,6 @@ loose-envify@^1.1.0, loose-envify@^1.4.0: dependencies: js-tokens "^3.0.0 || ^4.0.0" -lru_map@^0.3.3: - version "0.3.3" - resolved "https://registry.npmjs.org/lru_map/-/lru_map-0.3.3.tgz" - integrity sha512-Pn9cox5CsMYngeDbmChANltQl+5pi6XmTrraMSzhPmMBbmgcxmqWry0U3PGapCU1yB4/LqCcom7qhHZiF/jGfQ== - lru-cache@^5.1.1: version "5.1.1" resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz" @@ -4058,6 +4040,11 @@ lru@^3.1.0: dependencies: inherits "^2.0.1" +lru_map@^0.3.3: + version "0.3.3" + resolved "https://registry.npmjs.org/lru_map/-/lru_map-0.3.3.tgz" + integrity sha512-Pn9cox5CsMYngeDbmChANltQl+5pi6XmTrraMSzhPmMBbmgcxmqWry0U3PGapCU1yB4/LqCcom7qhHZiF/jGfQ== + magic-string@^0.27.0: version "0.27.0" resolved "https://registry.npmjs.org/magic-string/-/magic-string-0.27.0.tgz" @@ -4657,7 +4644,7 @@ mongoose-legacy-pluralize@1.0.2: resolved "https://registry.npmjs.org/mongoose-legacy-pluralize/-/mongoose-legacy-pluralize-1.0.2.tgz" integrity sha512-Yo/7qQU4/EyIS8YDFSeenIvXxZN+ld7YdV9LqFVQJzTLye8unujAWPZ4NWKfFA+RNjh+wvTWKY9Z3E5XM6ZZiQ== -mongoose@*, mongoose@^5.13.2, mongoose@5.10.x: +mongoose@^5.13.2: version "5.13.15" resolved "https://registry.npmjs.org/mongoose/-/mongoose-5.13.15.tgz" integrity sha512-cxp1Gbb8yUWkaEbajdhspSaKzAvsIvOtRlYD87GN/P2QEUhpd6bIvebi36T6M0tIVAMauNaK9SPA055N3PwF8Q== @@ -4709,16 +4696,16 @@ mri@^1.1.0: resolved "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz" integrity sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA== -ms@^2.1.1, ms@2.1.2: - version "2.1.2" - resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" - integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== - ms@2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz" integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== +ms@2.1.2, ms@^2.1.1: + version "2.1.2" + resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + ms@2.1.3: version "2.1.3" resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz" @@ -4758,12 +4745,12 @@ negotiator@0.6.3: resolved "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz" integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== -next-tick@^1.1.0, next-tick@1: +next-tick@1, next-tick@^1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz" integrity sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ== -"next@^10.0.8 || ^11.0 || ^12.0 || ^13.0", next@>=10.2.0, next@12.2.5: +next@12.2.5: version "12.2.5" resolved "https://registry.npmjs.org/next/-/next-12.2.5.tgz" integrity sha512-tBdjqX5XC/oFs/6gxrZhjmiq90YWizUYU6qOWAfat7zJwrwapJ+BYgX2PmiacunXMaRpeVT4vz5MSPSLgNkrpA== @@ -4977,7 +4964,7 @@ object.values@^1.1.6: define-properties "^1.1.4" es-abstract "^1.20.4" -on-finished@^2.3.0, on-finished@2.4.1: +on-finished@2.4.1, on-finished@^2.3.0: version "2.4.1" resolved "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz" integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg== @@ -5003,6 +4990,11 @@ once@^1.3.0, once@^1.3.1, once@^1.4.0: dependencies: wrappy "1" +optional-require@1.0.x: + version "1.0.3" + resolved "https://registry.npmjs.org/optional-require/-/optional-require-1.0.3.tgz" + integrity sha512-RV2Zp2MY2aeYK5G+B/Sps8lW5NHAzE5QClbFP15j+PWmP+T9PxlJXBOOLoSAdgwFvS4t0aMR4vpedMkbHfh0nA== + optional-require@^1.1.8: version "1.1.8" resolved "https://registry.npmjs.org/optional-require/-/optional-require-1.1.8.tgz" @@ -5010,11 +5002,6 @@ optional-require@^1.1.8: dependencies: require-at "^1.0.6" -optional-require@1.0.x: - version "1.0.3" - resolved "https://registry.npmjs.org/optional-require/-/optional-require-1.0.3.tgz" - integrity sha512-RV2Zp2MY2aeYK5G+B/Sps8lW5NHAzE5QClbFP15j+PWmP+T9PxlJXBOOLoSAdgwFvS4t0aMR4vpedMkbHfh0nA== - optionator@^0.9.1: version "0.9.1" resolved "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz" @@ -5205,7 +5192,7 @@ prettier-linter-helpers@^1.0.0: dependencies: fast-diff "^1.1.2" -prettier@^2.3.2, prettier@>=1.13.0: +prettier@^2.3.2: version "2.8.4" resolved "https://registry.npmjs.org/prettier/-/prettier-2.8.4.tgz" integrity sha512-vIS4Rlc2FNh0BySk3Wkd6xmwxB0FpOndW5fisM5H8hsZSxU2VWVB5CWIkIjWvrHjIhxk2g3bfMKM87zNTrZddw== @@ -5277,7 +5264,7 @@ qrcode@^1.5.1: pngjs "^5.0.0" yargs "^15.3.1" -qs@^6.11.0, qs@6.11.0: +qs@6.11.0, qs@^6.11.0: version "6.11.0" resolved "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz" integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q== @@ -5325,7 +5312,7 @@ react-cookie@^4.1.1: hoist-non-react-statics "^3.0.0" universal-cookie "^4.0.0" -"react-dom@^17.0.2 || ^18.0.0-0", "react-dom@>= 16.8.0", react-dom@17.0.2: +react-dom@17.0.2: version "17.0.2" resolved "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz" integrity sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA== @@ -5343,7 +5330,7 @@ react-dropzone@^14.2.3: file-selector "^0.6.0" prop-types "^15.8.1" -react-is@^16.13.1, react-is@^16.7.0, "react-is@>= 16.8.0": +react-is@^16.13.1, react-is@^16.7.0: version "16.13.1" resolved "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== @@ -5373,7 +5360,7 @@ react-markdown@^7.1.2: unist-util-visit "^4.0.0" vfile "^5.0.0" -react@*, "react@^16.8.0 || ^17.0.0 || ^18.0.0", "react@^17.0.2 || ^18.0.0-0", "react@>= 16.3.0", "react@>= 16.8 || 18.0.0", "react@>= 16.8.0", "react@>= 16.8.0 || 17.x.x || ^18.0.0-0", react@>=16, "react@15.x || 16.x || 17.x || 18.x", "react@16.x || 17.x || 18.x", react@17.0.2: +react@17.0.2: version "17.0.2" resolved "https://registry.npmjs.org/react/-/react-17.0.2.tgz" integrity sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA== @@ -5390,20 +5377,17 @@ read-pkg@^3.0.0: normalize-package-data "^2.3.2" path-type "^3.0.0" -readable-stream@^2.2.2: - version "2.3.7" - resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz" - integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== +readable-stream@1.1.x: + version "1.1.14" + resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz" + integrity sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ== dependencies: 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" + inherits "~2.0.1" + isarray "0.0.1" + string_decoder "~0.10.x" -readable-stream@^2.3.5: +readable-stream@^2.2.2, readable-stream@^2.3.5: version "2.3.7" resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz" integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== @@ -5425,16 +5409,6 @@ readable-stream@^3.6.0: string_decoder "^1.1.1" util-deprecate "^1.0.1" -readable-stream@1.1.x: - version "1.1.14" - resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz" - integrity sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ== - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.1" - isarray "0.0.1" - string_decoder "~0.10.x" - readdirp@~3.6.0: version "3.6.0" resolved "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz" @@ -5466,7 +5440,7 @@ regenerator-transform@^0.15.1: dependencies: "@babel/runtime" "^7.8.4" -regexp-clone@^1.0.0, regexp-clone@1.0.0: +regexp-clone@1.0.0, regexp-clone@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/regexp-clone/-/regexp-clone-1.0.0.tgz" integrity sha512-TuAasHQNamyyJ2hb97IuBEif4qBHGjPHBS64sZwytpLEqtBQ1gPJTnOaQ6qmpET16cK14kkjbazl6+p0RRv0yw== @@ -5588,7 +5562,7 @@ rimraf@^3.0.2: dependencies: glob "^7.1.3" -rollup@^1.20.0||^2.0.0||^3.0.0, rollup@^2.68.0||^3.0.0, rollup@2.78.0: +rollup@2.78.0: version "2.78.0" resolved "https://registry.npmjs.org/rollup/-/rollup-2.78.0.tgz" integrity sha512-4+YfbQC9QEVvKTanHhIAFVUFSRsezvQF8vFOJwtGfb9Bb+r014S+qryr9PSmw8x6sMnPkmFBGAvIFVQxvJxjtg== @@ -5621,25 +5595,15 @@ sade@^1.7.3: dependencies: mri "^1.1.0" -safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@5.2.1: - version "5.2.1" - resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz" - integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== - -safe-buffer@~5.1.0: - version "5.1.2" - resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz" - integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== - -safe-buffer@~5.1.1: +safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.2" resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== -safe-buffer@5.1.2: - version "5.1.2" - resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz" - integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== +safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2: + version "5.2.1" + resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== safe-regex-test@^1.0.0: version "1.0.0" @@ -5670,44 +5634,17 @@ scheduler@^0.20.2: loose-envify "^1.1.0" object-assign "^4.1.1" -semver@^5.5.0: +"semver@2 || 3 || 4 || 5", semver@^5.5.0, semver@^5.6.0, semver@^5.7.0, semver@^5.7.1: version "5.7.1" resolved "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== -semver@^5.6.0: - version "5.7.1" - resolved "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz" - integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== - -semver@^5.7.0: - version "5.7.1" - resolved "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz" - integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== - -semver@^5.7.1: - version "5.7.1" - resolved "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz" - integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== - -semver@^6.0.0: +semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.3.0: version "6.3.0" resolved "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== -semver@^6.1.1, semver@^6.1.2, semver@^6.3.0: - version "6.3.0" - resolved "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz" - integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== - -semver@^7.2.1: - version "7.3.8" - resolved "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz" - integrity sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A== - dependencies: - lru-cache "^6.0.0" - -semver@^7.3.5: +semver@^7.2.1, semver@^7.3.5: version "7.3.8" resolved "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz" integrity sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A== @@ -5719,11 +5656,6 @@ semver@~7.0.0: resolved "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz" integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A== -"semver@2 || 3 || 4 || 5": - version "5.7.1" - resolved "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz" - integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== - send@0.18.0: version "0.18.0" resolved "https://registry.npmjs.org/send/-/send-0.18.0.tgz" @@ -6002,18 +5934,6 @@ streamsearch@0.1.2: resolved "https://registry.npmjs.org/streamsearch/-/streamsearch-0.1.2.tgz" integrity sha512-jos8u++JKm0ARcSUTAZXOVC0mSox7Bhn6sBgty73P1f3JGf7yG2clTbBNHUdde/kdvP2FESam+vM6l8jBrNxHA== -string_decoder@^1.1.1, string_decoder@~1.1.1: - version "1.1.1" - resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz" - integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== - dependencies: - safe-buffer "~5.1.0" - -string_decoder@~0.10.x: - version "0.10.31" - resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz" - integrity sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ== - "string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" @@ -6072,6 +5992,18 @@ string2compact@^1.3.0: addr-to-ip-port "^1.0.1" ipaddr.js "^2.0.0" +string_decoder@^1.1.1, string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + +string_decoder@~0.10.x: + version "0.10.31" + resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz" + integrity sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ== + strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" @@ -6096,7 +6028,7 @@ style-to-object@^0.3.0: dependencies: inline-style-parser "0.1.1" -styled-components@*, styled-components@^5.3.3, "styled-components@>= 2", "styled-components@>=4.1.0 <6": +styled-components@^5.3.3: version "5.3.6" resolved "https://registry.npmjs.org/styled-components/-/styled-components-5.3.6.tgz" integrity sha512-hGTZquGAaTqhGWldX7hhfzjnIYBZ0IXQXkCYdvF1Sq3DsUaLx6+NTHC5Jj1ooM2F68sBiVz3lvhfwQs/S3l6qg== @@ -6262,12 +6194,7 @@ tslib@^1.8.1, tslib@^1.9.3, "tslib@^2.4.1 || ^1.9.3": resolved "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== -tslib@^2.1.0: - version "2.5.0" - resolved "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz" - integrity sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg== - -tslib@^2.4.0: +tslib@^2.1.0, tslib@^2.4.0: version "2.5.0" resolved "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz" integrity sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg== @@ -6440,7 +6367,7 @@ unordered-array-remove@^1.0.2: resolved "https://registry.npmjs.org/unordered-array-remove/-/unordered-array-remove-1.0.2.tgz" integrity sha512-45YsfD6svkgaCBNyvD+dFHm4qFX9g3wRSIVgWVPtm2OCnphvPxzJoe20ATsiNpNJrmzHifnxm+BN5F7gFT/4gw== -unpipe@~1.0.0, unpipe@1.0.0: +unpipe@1.0.0, unpipe@~1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz" integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== @@ -6465,7 +6392,7 @@ use-sync-external-store@1.2.0: resolved "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz" integrity sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA== -utf-8-validate@^5.0.2, utf-8-validate@^5.0.5: +utf-8-validate@^5.0.5: version "5.0.10" resolved "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.10.tgz" integrity sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ== From e2ba154eda84c67f15d3727829c465b6b08516f3 Mon Sep 17 00:00:00 2001 From: Tom Snelling Date: Wed, 21 Feb 2024 11:32:06 +0000 Subject: [PATCH 3/5] adds setting to disable email/smtp --- api/src/controllers/user.js | 76 ++++++++++++++++++-------------- api/src/index.js | 22 +++++---- api/src/setup/createAdminUser.js | 29 ++++++------ api/src/utils/validateConfig.js | 41 ++++++++++++++--- client/locales/en.json | 9 ++-- client/pages/account.js | 26 +++++++++-- config.example.js | 10 +++++ 7 files changed, 144 insertions(+), 69 deletions(-) diff --git a/api/src/controllers/user.js b/api/src/controllers/user.js index 9491498..7fba1b5 100644 --- a/api/src/controllers/user.js +++ b/api/src/controllers/user.js @@ -110,7 +110,7 @@ export const register = (mail) => async (req, res, next) => { role, invitedBy: invite?.invitingUser, remainingInvites: 0, - emailVerified: false, + emailVerified: process.env.SQ_DISABLE_EMAIL, bonusPoints: 0, totp: { enabled: false, @@ -125,19 +125,21 @@ export const register = (mail) => async (req, res, next) => { const createdUser = await newUser.save(); - const emailVerificationValidUntil = created + 48 * 60 * 60 * 1000; - const emailVerificationToken = jwt.sign( - { - user: req.body.email, - validUntil: emailVerificationValidUntil, - }, - process.env.SQ_JWT_SECRET - ); - await sendVerificationEmail( - mail, - req.body.email, - emailVerificationToken - ); + if (!process.env.SQ_DISABLE_EMAIL) { + const emailVerificationValidUntil = created + 48 * 60 * 60 * 1000; + const emailVerificationToken = jwt.sign( + { + user: req.body.email, + validUntil: emailVerificationValidUntil, + }, + process.env.SQ_JWT_SECRET + ); + await sendVerificationEmail( + mail, + req.body.email, + emailVerificationToken + ); + } if (createdUser) { if (req.body.invite) { @@ -293,14 +295,16 @@ export const generateInvite = (mail) => async (req, res, next) => { const createdInvite = await invite.save(); if (createdInvite) { - await mail.sendMail({ - from: `"${process.env.SQ_SITE_NAME}" <${process.env.SQ_MAIL_FROM_ADDRESS}>`, - to: email, - subject: "Invite", - text: `You have been invited to join ${process.env.SQ_SITE_NAME}. Please follow the link below to register. + if (!process.env.SQ_DISABLE_EMAIL) { + await mail.sendMail({ + from: `"${process.env.SQ_SITE_NAME}" <${process.env.SQ_MAIL_FROM_ADDRESS}>`, + to: email, + subject: "Invite", + text: `You have been invited to join ${process.env.SQ_SITE_NAME}. Please follow the link below to register. ${process.env.SQ_BASE_URL}/register?token=${createdInvite.token}`, - }); + }); + } res.send(createdInvite); } } else { @@ -343,18 +347,20 @@ export const changePassword = (mail) => async (req, res, next) => { { $set: { password: hash } } ); - await mail.sendMail({ - from: `"${process.env.SQ_SITE_NAME}" <${process.env.SQ_MAIL_FROM_ADDRESS}>`, - to: user.email, - subject: "Your password was changed", - text: `Your password was updated successfully at ${new Date().toISOString()} from ${ - req.ip - }. + if (!process.env.SQ_DISABLE_EMAIL) { + await mail.sendMail({ + from: `"${process.env.SQ_SITE_NAME}" <${process.env.SQ_MAIL_FROM_ADDRESS}>`, + to: user.email, + subject: "Your password was changed", + text: `Your password was updated successfully at ${new Date().toISOString()} from ${ + req.ip + }. If you did not perform this action, follow the link below immediately to reset your password. If this was you, no action is required. ${process.env.SQ_BASE_URL}/reset-password/initiate`, - }); + }); + } res.sendStatus(200); } catch (e) { @@ -388,14 +394,16 @@ export const initiatePasswordReset = (mail) => async (req, res, next) => { process.env.SQ_JWT_SECRET ); - await mail.sendMail({ - from: `"${process.env.SQ_SITE_NAME}" <${process.env.SQ_MAIL_FROM_ADDRESS}>`, - to: user.email, - subject: "Password reset", - text: `Please follow the link below to reset your password. + if (!process.env.SQ_DISABLE_EMAIL) { + await mail.sendMail({ + from: `"${process.env.SQ_SITE_NAME}" <${process.env.SQ_MAIL_FROM_ADDRESS}>`, + to: user.email, + subject: "Password reset", + text: `Please follow the link below to reset your password. ${process.env.SQ_BASE_URL}/reset-password/finalise?token=${token}`, - }); + }); + } res.sendStatus(200); } catch (e) { diff --git a/api/src/index.js b/api/src/index.js index ad9fc33..09968e5 100644 --- a/api/src/index.js +++ b/api/src/index.js @@ -52,15 +52,19 @@ validateConfig(config).then(() => { }); } - const mail = nodemailer.createTransport({ - host: process.env.SQ_SMTP_HOST, - port: process.env.SQ_SMTP_PORT, - secure: process.env.SQ_SMTP_SECURE, - auth: { - user: process.env.SQ_SMTP_USER, - pass: process.env.SQ_SMTP_PASS, - }, - }); + let mail; + + if (!process.env.SQ_DISABLE_EMAIL) { + mail = nodemailer.createTransport({ + host: process.env.SQ_SMTP_HOST, + port: process.env.SQ_SMTP_PORT, + secure: process.env.SQ_SMTP_SECURE, + auth: { + user: process.env.SQ_SMTP_USER, + pass: process.env.SQ_SMTP_PASS, + }, + }); + } const connectToDb = () => { console.log("[sq] initiating db connection..."); diff --git a/api/src/setup/createAdminUser.js b/api/src/setup/createAdminUser.js index 63b9dc0..5b0dfb6 100644 --- a/api/src/setup/createAdminUser.js +++ b/api/src/setup/createAdminUser.js @@ -18,6 +18,7 @@ const createAdminUser = async (mail) => { password: hash, created, remainingInvites: Number.MAX_SAFE_INTEGER, + emailVerified: process.env.SQ_DISABLE_EMAIL, }); adminUser.uid = crypto .createHash("sha256") @@ -35,19 +36,21 @@ const createAdminUser = async (mail) => { await adminUser.save(); - const emailVerificationValidUntil = created + 48 * 60 * 60 * 1000; - const emailVerificationToken = jwt.sign( - { - user: process.env.SQ_ADMIN_EMAIL, - validUntil: emailVerificationValidUntil, - }, - process.env.SQ_JWT_SECRET - ); - await sendVerificationEmail( - mail, - process.env.SQ_ADMIN_EMAIL, - emailVerificationToken - ); + if (!process.env.SQ_DISABLE_EMAIL) { + const emailVerificationValidUntil = created + 48 * 60 * 60 * 1000; + const emailVerificationToken = jwt.sign( + { + user: process.env.SQ_ADMIN_EMAIL, + validUntil: emailVerificationValidUntil, + }, + process.env.SQ_JWT_SECRET + ); + await sendVerificationEmail( + mail, + process.env.SQ_ADMIN_EMAIL, + emailVerificationToken + ); + } console.log("[sq] created initial admin user"); } diff --git a/api/src/utils/validateConfig.js b/api/src/utils/validateConfig.js index 5ccf91c..38cc5c1 100644 --- a/api/src/utils/validateConfig.js +++ b/api/src/utils/validateConfig.js @@ -64,10 +64,31 @@ const configSchema = yup SQ_BASE_URL: yup.string().matches(httpRegex).required(), SQ_API_URL: yup.string().matches(httpRegex).required(), SQ_MONGO_URL: yup.string().matches(mongoRegex).required(), - SQ_MAIL_FROM_ADDRESS: yup.string().email().required(), - SQ_SMTP_HOST: yup.string().required(), - SQ_SMTP_PORT: yup.number().integer().min(1).max(65535).required(), - SQ_SMTP_SECURE: yup.boolean().required(), + SQ_DISABLE_EMAIL: yup.boolean(), + SQ_MAIL_FROM_ADDRESS: yup + .string() + .email() + .when("SQ_DISABLE_EMAIL", { + is: (val) => val !== true, + then: (schema) => schema.required(), + }), + SQ_SMTP_HOST: yup.string().when("SQ_DISABLE_EMAIL", { + is: (val) => val !== true, + then: (schema) => schema.required(), + }), + SQ_SMTP_PORT: yup + .number() + .integer() + .min(1) + .max(65535) + .when("SQ_DISABLE_EMAIL", { + is: (val) => val !== true, + then: (schema) => schema.required(), + }), + SQ_SMTP_SECURE: yup.boolean().when("SQ_DISABLE_EMAIL", { + is: (val) => val !== true, + then: (schema) => schema.required(), + }), }) .strict() .noUnknown() @@ -77,8 +98,16 @@ const configSchema = yup SQ_JWT_SECRET: yup.string().required(), SQ_SERVER_SECRET: yup.string().required(), SQ_ADMIN_EMAIL: yup.string().email().required(), - SQ_SMTP_USER: yup.string().required(), - SQ_SMTP_PASS: yup.string().required(), + SQ_SMTP_USER: yup.string(), + SQ_SMTP_PASS: yup.string(), + }) + .when("envs.SQ_DISABLE_EMAIL", { + is: (val) => val !== true, + then: (schema) => { + schema.fields.SQ_SMTP_USER = yup.string().required(); + schema.fields.SQ_SMTP_PASS = yup.string().required(); + return schema; + }, }) .strict() .noUnknown() diff --git a/client/locales/en.json b/client/locales/en.json index c839a33..646f16b 100644 --- a/client/locales/en.json +++ b/client/locales/en.json @@ -31,14 +31,16 @@ "accEnable2FA": "Enable 2FA", "accEveryRequestYouFulfill": "for every request you fulfill, or", "accForEveryGBYouUpload": "for every GB you upload", - "accIfYouAreAlsUploaderAcceptTorrent": "if you are als the uploader of the accepted torrent", + "accIfYouAreAlsUploaderAcceptTorrent": "if you are also the uploader of the accepted torrent", "accInviteLinkCopiedClipboard": "Invite link copied to clipboard", "accInvites": "Invites", "accRemaining": "remaining", "accRoleUser": "Role: user", "accRoleAdmin": "Role: admin", "accInviteSentSuccess": "Invite sent successfully", + "accInviteSentSuccessNoEmail": "Invite created successfully", "accInviteText1": "Enter an email address to send an invite. The invited user will need to sign up with the same email address. Once the invite is generated, you can also copy a direct invite link.", + "accInviteText1NoEmail": "Enter an email address to generate an invite. The invited user will need to sign up with the same email address. This tracker has email sending disabled, so you will need to copy and send the invite link yourself.", "accItemsPurchasedSuccess": "Items purchased successfully", "accMyAccount": "My account", "accPassChangedSuccess": "Password changed successfully", @@ -46,6 +48,7 @@ "accPurchaseUpload1GB": "Purchase upload (1 GB)", "accRole": "Role", "accSendInvite": "Send invite", + "accSendInviteNoEmail": "Create invite", "accThisIsAdminAcc": "This is an admin account.", "accValidUntil": "Valid until", "accYouCurrentlyHave": "You currently have", @@ -279,8 +282,8 @@ "userUploaded": "Uploaded", "userMyUploads": "My uploads", "usernameRules": "Can only consist of letters, numbers, and “.”", - "userUnban": "unban", - "userBan": "ban", + "userUnban": "Unban", + "userBan": "Ban", "userUnbanned": "unbanned", "userBanned": "banned", "userAdmin": "Admin", diff --git a/client/pages/account.js b/client/pages/account.js index e725081..8335c0e 100644 --- a/client/pages/account.js +++ b/client/pages/account.js @@ -98,6 +98,7 @@ const Account = ({ token, invites = [], user, userRole }) => { SQ_BP_COST_PER_INVITE, SQ_BP_COST_PER_GB, SQ_ALLOW_REGISTER, + SQ_DISABLE_EMAIL, }, } = getConfig(); @@ -133,7 +134,14 @@ const Account = ({ token, invites = [], user, userRole }) => { return currentInvitesList; }); - addNotification("success", `${getLocaleString("accInviteSentSuccess")}`); + addNotification( + "success", + `${getLocaleString( + SQ_DISABLE_EMAIL + ? "accInviteSentSuccessNoEmail" + : "accInviteSentSuccess" + )}` + ); setRemainingInvites((r) => r - 1); @@ -425,7 +433,9 @@ const Account = ({ token, invites = [], user, userRole }) => { onClick={() => setShowInviteModal(true)} disabled={remainingInvites < 1} > - {getLocaleString("accSendInvite")} + {getLocaleString( + SQ_DISABLE_EMAIL ? "accSendInviteNoEmail" : "accSendInvite" + )} @@ -650,7 +660,11 @@ const Account = ({ token, invites = [], user, userRole }) => { )} {showInviteModal && ( setShowInviteModal(false)}> - {getLocaleString("accInviteText1")} + + {getLocaleString( + SQ_DISABLE_EMAIL ? "accInviteText1NoEmail" : "accInviteText1" + )} +
{ > {getLocaleString("accCancel")} - +
diff --git a/config.example.js b/config.example.js index ce2f57a..8fbd1e1 100644 --- a/config.example.js +++ b/config.example.js @@ -85,18 +85,26 @@ module.exports = { // The URL of your MongoDB server. Under the recommended setup, it should be `mongodb://sq_mongodb/sqtracker`. SQ_MONGO_URL: "mongodb://sq_mongodb/sqtracker", + // Disables sending of any emails and removes the need for an SMTP server. + // Fine for testing, not recommended in production as users will not be able to reset their passwords. + SQ_DISABLE_EMAIL: false, + // The email address that mail will be sent from. + // Not required if SQ_DISABLE_EMAIL=true. SQ_MAIL_FROM_ADDRESS: "mail@sqtracker.dev", // The hostname of your SMTP server. + // Not required if SQ_DISABLE_EMAIL=true. SQ_SMTP_HOST: "smtp.example.com", // The port of your SMTP server. + // Not required if SQ_DISABLE_EMAIL=true. SQ_SMTP_PORT: 587, // Whether to force SMTP TLS: if true the connection will use TLS when connecting to server. // If false (the default) then TLS is used if server supports the STARTTLS extension. // In most cases set this value to true if you are connecting to port 465. For port 587 or 25 keep it false. + // Not required if SQ_DISABLE_EMAIL=true. SQ_SMTP_SECURE: false, }, secrets: { @@ -111,9 +119,11 @@ module.exports = { SQ_ADMIN_EMAIL: "admin@example.com", // The username to authenticate with your SMTP server with. + // Not required if SQ_DISABLE_EMAIL=true. SQ_SMTP_USER: "smtp_username", // The password to authenticate with your SMTP server with. + // Not required if SQ_DISABLE_EMAIL=true. SQ_SMTP_PASS: "smtp_password", }, }; From 5e1e955508d2c4103050e403b2eb3a9942af57b9 Mon Sep 17 00:00:00 2001 From: Tom Snelling Date: Wed, 21 Feb 2024 13:47:48 +0000 Subject: [PATCH 4/5] update dockerfiles, add nginx config --- README.md | 2 ++ api/Dockerfile | 2 +- api/src/utils/validateConfig.js | 8 -------- client/Dockerfile | 2 +- docker-compose.dev.yml | 10 +++++++-- docker-compose.yml | 8 ++++++++ nginx.conf | 36 +++++++++++++++++++++++++++++++++ 7 files changed, 56 insertions(+), 12 deletions(-) create mode 100644 nginx.conf diff --git a/README.md b/README.md index 7d33c8f..a49d947 100644 --- a/README.md +++ b/README.md @@ -89,6 +89,8 @@ The sqtracker client service provides the modern, responsive web interface that The HTTP proxy allows the client, API, and BitTorrent tracker to all be accessible via a single endpoint. +Traefik is recommended and is configured by default. An Nginx config file is also provided for those that prefer it and the `docker-compose.yml` file contains an Nginx block that can be enabled. + ### Deploying with Docker compose The sqtracker platform is designed to be deployed via Docker. Once a configuration file is created, deploying is as simple as running `docker compose up -d` at the root of the project. diff --git a/api/Dockerfile b/api/Dockerfile index 9cd92df..1cfed1d 100644 --- a/api/Dockerfile +++ b/api/Dockerfile @@ -1,4 +1,4 @@ -FROM node:16-alpine +FROM node:16 ENV NODE_ENV=production ENV SENTRY_DSN="https://9b9761216607428180ea3b32bd1c8e58@o140996.ingest.sentry.io/4504645996576768" LABEL org.opencontainers.image.source=https://github.com/tdjsnelling/sqtracker diff --git a/api/src/utils/validateConfig.js b/api/src/utils/validateConfig.js index 38cc5c1..554b4c3 100644 --- a/api/src/utils/validateConfig.js +++ b/api/src/utils/validateConfig.js @@ -1,12 +1,4 @@ import * as yup from "yup"; -import en from "@sqtracker/client/locales/en.json"; -import es from "@sqtracker/client/locales/es.json"; -import it from "@sqtracker/client/locales/it.json"; -import ru from "@sqtracker/client/locales/ru.json"; -import de from "@sqtracker/client/locales/de.json"; -import zh from "@sqtracker/client/locales/zh.json"; -import eo from "@sqtracker/client/locales/eo.json"; -import fr from "@sqtracker/client/locales/fr.json"; const httpRegex = /http(s)?:\/\/.*/; const mongoRegex = /mongodb:\/\/.*/; diff --git a/client/Dockerfile b/client/Dockerfile index 0b19958..d76cb29 100644 --- a/client/Dockerfile +++ b/client/Dockerfile @@ -1,4 +1,4 @@ -FROM node:16-alpine AS builder +FROM node:16 AS builder ARG SENTRY_AUTH_TOKEN ENV NODE_ENV=production ENV SENTRY_ORG=tdjsnelling diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index 8874d31..c676757 100644 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -17,11 +17,17 @@ services: volumes: - "/var/run/docker.sock:/var/run/docker.sock:ro" - ./traefik.yml:/config/traefik.yml +# nginx: +# image: "nginx:latest" +# container_name: "sq_nginx" +# restart: always +# ports: +# - "80:80" +# volumes: +# - ./nginx.conf:/etc/nginx/nginx.conf database: container_name: sq_mongodb image: mongo:6.0 - ports: - - "127.0.0.1:27017:27017" volumes: - ./data:/data/db api: diff --git a/docker-compose.yml b/docker-compose.yml index 245287d..ca4737a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -23,6 +23,14 @@ services: - "/var/run/docker.sock:/var/run/docker.sock:ro" - ./letsencrypt:/letsencrypt - ./traefik.yml:/config/traefik.yml +# nginx: +# image: "nginx:latest" +# container_name: "sq_nginx" +# restart: always +# ports: +# - "80:80" +# volumes: +# - ./nginx.conf:/etc/nginx/nginx.conf database: container_name: sq_mongodb image: mongo:6.0 diff --git a/nginx.conf b/nginx.conf new file mode 100644 index 0000000..b93617a --- /dev/null +++ b/nginx.conf @@ -0,0 +1,36 @@ +events {} + +http { + server { + listen 80; + resolver 127.0.0.11; + + location / { + proxy_pass http://sq_client:3000; + proxy_redirect off; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Host $server_name; + } + + location /api/ { + rewrite /api/(.*) /$1 break; + proxy_pass http://sq_api:3001; + proxy_redirect off; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Host $server_name; + } + + location /sq/ { + proxy_pass http://sq_api:3001; + proxy_redirect off; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Host $server_name; + } + } +} From f8bced481d52e1c8c3dd4fccf458382f2d9651d1 Mon Sep 17 00:00:00 2001 From: Tom Snelling Date: Tue, 18 Jun 2024 13:53:02 +0100 Subject: [PATCH 5/5] include development URLs in config.example.js --- config.example.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/config.example.js b/config.example.js index 8fbd1e1..cd1e816 100644 --- a/config.example.js +++ b/config.example.js @@ -77,12 +77,15 @@ module.exports = { SQ_SITE_DEFAULT_LOCALE: "en", // The URL of your tracker site. + // For local development, this should be `http://127.0.0.1:3000`. SQ_BASE_URL: "https://sqtracker.dev", // The URL of your API. Under the recommended setup, it should be `${SQ_BASE_URL}/api`. + // For local development, this should be `http://127.0.0.1:3001`. SQ_API_URL: "https://sqtracker.dev/api", // The URL of your MongoDB server. Under the recommended setup, it should be `mongodb://sq_mongodb/sqtracker`. + // For local development, this should be `mongodb://127.0.0.1/sqtracker`. SQ_MONGO_URL: "mongodb://sq_mongodb/sqtracker", // Disables sending of any emails and removes the need for an SMTP server.