deps: update outdated and critical dependencies (#532)

* deps: bump critical deps version

* chore: specify sentry and dd debug mode

* chore: enable SwcMinify

* chore: casing

* deps: bump mongoose version to 6.8.3

* Revert "deps: bump mongoose version to 6.8.3"

This reverts commit d5b90b5c0909545d4d21553d50c5681bd93a57a4.

* deps: change mongoose version to 5.13.15

* fix: typing

* deps: update audited deps

* deps: update next-pwa and dd-trace@2

* deps: update dd-trace@3 and sentry

* fix: redirects

* fix: style

* feat: redirect using next config

* deps: update mongoose to 6.9.0

* chore: change next version in package.json

* chore: change next version to 12.3.2

* fix: model compile issue

* chore: lint

* chore: remove any

* deps: update jest version to 29

* deps: resolve remaining vulnerabilities

---------

Co-authored-by: skinmaker1345 <me@skinmaker.dev>
This commit is contained in:
Eunwoo Choi 2023-02-01 01:34:30 +09:00 committed by GitHub
parent 5a28ac284c
commit 2d68f7aadd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 3132 additions and 2877 deletions

View File

@ -18,4 +18,7 @@ DISCORD_CLIENT_INTENTS=32767
GITHUB_CLIENT_ID=GH_CLIENT_ID GITHUB_CLIENT_ID=GH_CLIENT_ID
GITHUB_CLIENT_SECRET=GH_CLIENT_SECRET GITHUB_CLIENT_SECRET=GH_CLIENT_SECRET
CSRF_SECRET=CSRF_SECRET CSRF_SECRET=CSRF_SECRET
DD_TRACE_DEBUG=true
DD_TRACE_ENABLED=true

View File

@ -1,8 +1,6 @@
// eslint-disable-next-line @typescript-eslint/no-var-requires // eslint-disable-next-line @typescript-eslint/no-var-requires
const tracer = require('dd-trace') const tracer = require('dd-trace')
tracer.init({ tracer.init()
debug: true
})
module.exports = tracer module.exports = tracer

View File

@ -1,7 +1,7 @@
module.exports = { module.exports = {
preset: 'ts-jest', preset: 'ts-jest',
testEnvironment: 'node', testEnvironment: 'node',
moduleDirectories: ['node_modules', '.'], moduleDirectories: ['node_modules', __dirname],
moduleNameMapper: { moduleNameMapper: {
'@types': '<rootDir>/types', '@types': '<rootDir>/types',
'^@utils/(.*)$': '<rootDir>/utils/$1', '^@utils/(.*)$': '<rootDir>/utils/$1',

1
next-env.d.ts vendored
View File

@ -1,5 +1,4 @@
/// <reference types="next" /> /// <reference types="next" />
/// <reference types="next/types/global" />
/// <reference types="next/image-types/global" /> /// <reference types="next/image-types/global" />
// NOTE: This file should not be edited // NOTE: This file should not be edited

View File

@ -1,8 +1,14 @@
/* eslint-disable @typescript-eslint/no-var-requires */ /* eslint-disable @typescript-eslint/no-var-requires */
const { withSentryConfig } = require('@sentry/nextjs') const { withSentryConfig } = require('@sentry/nextjs')
const withPWA = require('next-pwa') const withPWA = require('next-pwa')({
disable: process.env.NODE_ENV !== 'production',
register: false
})
const VERSION = require('./package.json').version const VERSION = require('./package.json').version
/**
* @type {import('next').NextConfig}
*/
const NextConfig = { const NextConfig = {
webpack: (config, { isServer }) => { webpack: (config, { isServer }) => {
if (!isServer) { if (!isServer) {
@ -10,10 +16,6 @@ const NextConfig = {
} }
return config return config
}, },
pwa: {
disable: process.env.NODE_ENV !== 'production',
register: false
},
env: { env: {
NEXT_PUBLIC_RELEASE_VERSION: VERSION, NEXT_PUBLIC_RELEASE_VERSION: VERSION,
SENTRY_SKIP_AUTO_RELEASE: true SENTRY_SKIP_AUTO_RELEASE: true
@ -21,6 +23,21 @@ const NextConfig = {
future: {}, future: {},
experimental: { experimental: {
scrollRestoration: true scrollRestoration: true
},
swcMinify: true,
redirects: async () => {
return [
{
source: '/developers',
destination: '/developers/applications',
permanent: true
},
{
source: '/developers/docs',
destination: '/developers/docs/시작하기',
permanent: true
}
]
} }
} }
module.exports = withSentryConfig(withPWA(NextConfig)) module.exports = withSentryConfig(withPWA(NextConfig))

View File

@ -16,10 +16,7 @@
"dependencies": { "dependencies": {
"@fortawesome/fontawesome-free": "5.15.3", "@fortawesome/fontawesome-free": "5.15.3",
"@hcaptcha/react-hcaptcha": "0.3.6", "@hcaptcha/react-hcaptcha": "0.3.6",
"@sentry/nextjs": "6.10.0", "@sentry/nextjs": "^7.31.1",
"@sentry/node": "6.10.0",
"@sentry/react": "^6.10.0",
"@sentry/tracing": "6.10.0",
"abort-controller": "3.0.0", "abort-controller": "3.0.0",
"autoprefixer": "^10.3.1", "autoprefixer": "^10.3.1",
"badgen": "3.2.2", "badgen": "3.2.2",
@ -27,7 +24,7 @@
"csrf": "3.1.0", "csrf": "3.1.0",
"dataloader": "2.0.0", "dataloader": "2.0.0",
"dayjs": "^1.10.6", "dayjs": "^1.10.6",
"dd-trace": "^1.1.0", "dd-trace": "^3.11.0",
"difflib": "0.2.4", "difflib": "0.2.4",
"discord.js": "^14.2.0", "discord.js": "^14.2.0",
"emoji-mart": "3.0.1", "emoji-mart": "3.0.1",
@ -36,13 +33,13 @@
"formik": "2.2.9", "formik": "2.2.9",
"generate-license-file": "1.1.0", "generate-license-file": "1.1.0",
"josa": "3.0.1", "josa": "3.0.1",
"jsonwebtoken": "8.5.1", "jsonwebtoken": "^9.0.0",
"knex": "^0.95.8", "knex": "^2.4.0",
"mongoose": "^5.13.4", "mongoose": "6.9.0",
"mysql": "2.18.1", "mysql": "2.18.1",
"next": "^11.1.3", "next": "^12.3.2",
"next-connect": "0.10.1", "next-connect": "0.10.1",
"next-pwa": "^5.2.24", "next-pwa": "^5.6.0",
"next-seo": "^4.26.0", "next-seo": "^4.26.0",
"next-session": "3.4.0", "next-session": "3.4.0",
"node-emoji": "1.10.0", "node-emoji": "1.10.0",
@ -60,7 +57,7 @@
"react-showdown": "2.3.0", "react-showdown": "2.3.0",
"react-sortable-hoc": "2.0.0", "react-sortable-hoc": "2.0.0",
"react-use-clipboard": "1.0.7", "react-use-clipboard": "1.0.7",
"sanitize-html": "2.4.0", "sanitize-html": "^2.8.1",
"tailwindcss": "2.2.7", "tailwindcss": "2.2.7",
"tlru": "1.0.2", "tlru": "1.0.2",
"twemoji": "13.1.0", "twemoji": "13.1.0",
@ -76,7 +73,7 @@
"@types/express-rate-limit": "^5.1.3", "@types/express-rate-limit": "^5.1.3",
"@types/jest": "^26.0.24", "@types/jest": "^26.0.24",
"@types/josa": "3.0.2", "@types/josa": "3.0.2",
"@types/jsonwebtoken": "^8.5.4", "@types/jsonwebtoken": "^9.0.1",
"@types/node": "16.4.3", "@types/node": "16.4.3",
"@types/node-emoji": "1.8.1", "@types/node-emoji": "1.8.1",
"@types/node-fetch": "^2.5.12", "@types/node-fetch": "^2.5.12",
@ -84,7 +81,7 @@
"@types/rc-tooltip": "^3.7.4", "@types/rc-tooltip": "^3.7.4",
"@types/react": "^17.0.15", "@types/react": "^17.0.15",
"@types/react-select": "^4.0.17", "@types/react-select": "^4.0.17",
"@types/sanitize-html": "^2.3.2", "@types/sanitize-html": "^2.8.0",
"@types/twemoji": "^12.1.2", "@types/twemoji": "^12.1.2",
"@types/url-regex-safe": "1.0.0", "@types/url-regex-safe": "1.0.0",
"@typescript-eslint/eslint-plugin": "4.28.5", "@typescript-eslint/eslint-plugin": "4.28.5",
@ -96,10 +93,10 @@
"eslint-plugin-prettier": "3.4.0", "eslint-plugin-prettier": "3.4.0",
"eslint-plugin-react": "7.24.0", "eslint-plugin-react": "7.24.0",
"eslint-plugin-react-hooks": "4.2.0", "eslint-plugin-react-hooks": "4.2.0",
"jest": "27.0.6", "jest": "^29.4.1",
"prettier": "^2.3.2", "prettier": "^2.3.2",
"prettier-plugin-tailwind": "^2.2.12", "prettier-plugin-tailwind": "^2.2.12",
"ts-jest": "27.0.4", "ts-jest": "^29.0.5",
"typescript": "4.6.4" "typescript": "4.6.4"
}, },
"license": "AGPL-3.0" "license": "AGPL-3.0"

View File

@ -346,9 +346,11 @@ export const getServerSideProps = async (ctx: Context) => {
const desc = await get.botDescSafe(data.id) const desc = await get.botDescSafe(data.id)
const user = await get.Authorization(parsed?.token) const user = await get.Authorization(parsed?.token)
if((checkBotFlag(data.flags, 'trusted') || checkBotFlag(data.flags, 'partnered')) && data.vanity && data.vanity !== ctx.query.id) { if((checkBotFlag(data.flags, 'trusted') || checkBotFlag(data.flags, 'partnered')) && data.vanity && data.vanity !== ctx.query.id) {
ctx.res.statusCode = 301
ctx.res.setHeader('Location', `/bots/${data.vanity}`)
return { return {
redirect: {
destination: `/bots/${data.vanity}`,
permanent: true
},
props: {} props: {}
} }
} }

View File

@ -9,7 +9,7 @@ export const getServerSideProps: GetServerSideProps = async (ctx) => {
const data = await get.bot.load(ctx.query.id as string) const data = await get.bot.load(ctx.query.id as string)
if(!data) return { props: {} } if(!data) return { props: {} }
const record = await Bots.updateOne({ _id: data.id, 'inviteMetrix.day': getYYMMDD() }, { $inc: { 'inviteMetrix.$.count': 1 } }) const record = await Bots.updateOne({ _id: data.id, 'inviteMetrix.day': getYYMMDD() }, { $inc: { 'inviteMetrix.$.count': 1 } })
if(record.n === 0) await Bots.findByIdAndUpdate(data.id, { $push: { inviteMetrix: { count: 1 } } }, { upsert: true }) if(record.matchedCount === 0) await Bots.findByIdAndUpdate(data.id, { $push: { inviteMetrix: { count: 1 } } }, { upsert: true })
ctx.res.statusCode = 307 ctx.res.statusCode = 307
ctx.res.setHeader('Location', data.url || `https://discordapp.com/oauth2/authorize?client_id=${data.id}&scope=bot&permissions=0`) ctx.res.setHeader('Location', data.url || `https://discordapp.com/oauth2/authorize?client_id=${data.id}&scope=bot&permissions=0`)
return { return {

View File

@ -52,9 +52,13 @@ const Search:NextPage<SearchProps> = ({ botData, query }) => {
export const getServerSideProps = async(ctx: Context) => { export const getServerSideProps = async(ctx: Context) => {
if(ctx.query.query && !ctx.query.q) ctx.query.q = ctx.query.query if(ctx.query.query && !ctx.query.q) ctx.query.q = ctx.query.query
if(!ctx.query?.q) { if(!ctx.query?.q) {
ctx.res.statusCode = 301 return {
ctx.res.setHeader('Location', '/') redirect: {
return { props: {} } destination: '/',
permanent: true
},
props: {}
}
} }
if(!ctx.query.page) ctx.query.page = '1' if(!ctx.query.page) ctx.query.page = '1'
const validate = await SearchQuerySchema.validate(ctx.query).then(el => el).catch(() => null) const validate = await SearchQuerySchema.validate(ctx.query).then(el => el).catch(() => null)

View File

@ -1,15 +0,0 @@
import { GetServerSideProps, NextPage } from 'next'
const Docs: NextPage = () => {
return <></>
}
export const getServerSideProps: GetServerSideProps = async (ctx) => {
ctx.res.statusCode = 301
ctx.res.setHeader('Location', encodeURI('/developers/docs/시작하기'))
return {
props: {}
}
}
export default Docs

View File

@ -1,15 +0,0 @@
import { GetServerSideProps, NextPage } from 'next'
const Developers: NextPage = () => {
return <></>
}
export const getServerSideProps: GetServerSideProps = async (ctx) => {
ctx.res.statusCode = 301
ctx.res.setHeader('Location', '/developers/applications')
return {
props: {}
}
}
export default Developers

View File

@ -57,9 +57,13 @@ const Search:NextPage<SearchProps> = ({ botData, serverData, priority, query })
export const getServerSideProps = async(ctx: Context) => { export const getServerSideProps = async(ctx: Context) => {
if(ctx.query.query && !ctx.query.q) ctx.query.q = ctx.query.query if(ctx.query.query && !ctx.query.q) ctx.query.q = ctx.query.query
if(!ctx.query?.q) { if(!ctx.query?.q) {
ctx.res.statusCode = 301 return {
ctx.res.setHeader('Location', '/') redirect: {
return { props: {} } destination: '/',
permanent: true
},
props: {}
}
} }
if(!ctx.query.page) ctx.query.page = '1' if(!ctx.query.page) ctx.query.page = '1'
const validate = await SearchQuerySchema.validate(ctx.query).then(el => el).catch(() => null) const validate = await SearchQuerySchema.validate(ctx.query).then(el => el).catch(() => null)

View File

@ -281,9 +281,11 @@ export const getServerSideProps = async (ctx: Context) => {
const desc = safeImageHost(data.desc) const desc = safeImageHost(data.desc)
const user = await get.Authorization(parsed?.token) const user = await get.Authorization(parsed?.token)
if((checkServerFlag(data.flags, 'trusted') || checkServerFlag(data.flags, 'partnered')) && data.vanity && data.vanity !== ctx.query.id) { if((checkServerFlag(data.flags, 'trusted') || checkServerFlag(data.flags, 'partnered')) && data.vanity && data.vanity !== ctx.query.id) {
ctx.res.statusCode = 301
ctx.res.setHeader('Location', `/servers/${data.vanity}`)
return { return {
redirect: {
destination: `/servers/${data.vanity}`,
permanent: true
},
props: {} props: {}
} }
} }

View File

@ -52,9 +52,13 @@ const Search:NextPage<SearchProps> = ({ serverData, query }) => {
export const getServerSideProps = async(ctx: Context) => { export const getServerSideProps = async(ctx: Context) => {
if(ctx.query.query && !ctx.query.q) ctx.query.q = ctx.query.query if(ctx.query.query && !ctx.query.q) ctx.query.q = ctx.query.query
if(!ctx.query?.q) { if(!ctx.query?.q) {
ctx.res.statusCode = 301 return {
ctx.res.setHeader('Location', '/') redirect: {
return { props: {} } destination: '/',
permanent: true
},
props: {}
}
} }
if(!ctx.query.page) ctx.query.page = '1' if(!ctx.query.page) ctx.query.page = '1'
const validate = await SearchQuerySchema.validate(ctx.query).then(el => el).catch(() => null) const validate = await SearchQuerySchema.validate(ctx.query).then(el => el).catch(() => null)

View File

@ -8,7 +8,7 @@ const SENTRY_DSN = process.env.NEXT_PUBLIC_SENTRY_DSN
Sentry.init({ Sentry.init({
dsn: SENTRY_DSN, dsn: SENTRY_DSN,
debug: true, debug: process.env.SENTRY_DEBUG === 'true',
enabled: process.env.NODE_ENV === 'production' enabled: process.env.NODE_ENV === 'production'
// Note: if you want to override the automatic release value, do not set a // Note: if you want to override the automatic release value, do not set a
// `release` value here - use the environment variable `SENTRY_RELEASE`, so // `release` value here - use the environment variable `SENTRY_RELEASE`, so

View File

@ -8,7 +8,7 @@ const SENTRY_DSN = process.env.SENTRY_DSN
Sentry.init({ Sentry.init({
dsn: SENTRY_DSN, dsn: SENTRY_DSN,
debug: true, debug: process.env.SENTRY_DEBUG === 'true',
enabled: process.env.NODE_ENV=== 'production' enabled: process.env.NODE_ENV=== 'production'
// Note: if you want to override the automatic release value, do not set a // Note: if you want to override the automatic release value, do not set a
// `release` value here - use the environment variable `SENTRY_RELEASE`, so // `release` value here - use the environment variable `SENTRY_RELEASE`, so

View File

@ -1,25 +1,42 @@
{ {
"compilerOptions": { "compilerOptions": {
"baseUrl": ".", "baseUrl": ".",
"paths": { "paths": {
"@components/*": ["components/*"], "@components/*": [
"@utils/*": ["utils/*"], "components/*"
"@types": ["types/index.ts"] ],
}, "@utils/*": [
"target": "es5", "utils/*"
"lib": ["dom", "dom.iterable", "esnext"], ],
"allowJs": true, "@types": [
"skipLibCheck": true, "types/index.ts"
"strict": false, ]
"forceConsistentCasingInFileNames": true, },
"noEmit": true, "target": "es5",
"esModuleInterop": true, "lib": [
"module": "esnext", "dom",
"moduleResolution": "node", "dom.iterable",
"resolveJsonModule": true, "esnext"
"isolatedModules": true, ],
"jsx": "preserve" "allowJs": true,
}, "skipLibCheck": true,
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], "strict": false,
"exclude": ["node_modules"] "forceConsistentCasingInFileNames": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true
},
"include": [
"next-env.d.ts",
"**/*.ts",
"**/*.tsx"
],
"exclude": [
"node_modules"
]
} }

View File

@ -5,14 +5,15 @@ const privateKey = process.env.PRIVATE_KEY?.replace(/\\n/g, '\n')
export function sign(payload: string | Record<string, unknown>, options?: JWTSignOption): string | null { export function sign(payload: string | Record<string, unknown>, options?: JWTSignOption): string | null {
try { try {
return jwt.sign(payload, privateKey, options ? { ...options, algorithm: 'RS256' } : { algorithm: 'RS256' }) return jwt.sign(payload, privateKey, options ? { ...options, algorithm: 'RS256', allowInsecureKeySizes: true } : { algorithm: 'RS256', allowInsecureKeySizes: true })
} catch { } catch {
return null return null
} }
} }
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
export function verify(token: string): any | null { export function verify(token?: string): any | null {
if(!token) return null
try { try {
return jwt.verify(token, publicPem) return jwt.verify(token, publicPem)
} catch(e) { } catch(e) {

View File

@ -1,4 +1,4 @@
import mongoose from 'mongoose' import mongoose, { InferSchemaType, Model, ObtainSchemaGeneric, Schema } from 'mongoose'
import { getYYMMDD } from './Tools' import { getYYMMDD } from './Tools'
mongoose.connect(`mongodb://${process.env.MONGO_USER}:${process.env.MONGO_PASSWORD}@${process.env.MONGO_HOST || 'localhost'}/${process.env.MONGO_DATABASE}`) mongoose.connect(`mongodb://${process.env.MONGO_USER}:${process.env.MONGO_PASSWORD}@${process.env.MONGO_HOST || 'localhost'}/${process.env.MONGO_DATABASE}`)
@ -25,5 +25,14 @@ const serverSchema = new mongoose.Schema({
data: {} data: {}
}) })
export const Bots = mongoose.models.bots || mongoose.model('bots', botSchema) type ModelType<TSchema extends Schema> = Model<
export const Servers = mongoose.models.servers || mongoose.model('servers', serverSchema) InferSchemaType<TSchema>,
ObtainSchemaGeneric<TSchema, 'TQueryHelpers'>,
ObtainSchemaGeneric<TSchema, 'TInstanceMethods'>,
ObtainSchemaGeneric<TSchema, 'TVirtuals'>,
TSchema
> &
ObtainSchemaGeneric<TSchema, 'TStaticMethods'>
export const Bots = (mongoose.models.bots as ModelType<typeof botSchema>) || mongoose.model('bots', botSchema)
export const Servers = (mongoose.models.servers as ModelType<typeof serverSchema>) || mongoose.model('servers', serverSchema)

View File

@ -376,7 +376,7 @@ async function voteBot(userID: string, botID: string): Promise<number|boolean> {
await knex('bots').where({ id: botID }).increment('votes', 1) await knex('bots').where({ id: botID }).increment('votes', 1)
await knex('users').where({ id: userID }).update({ votes: JSON.stringify(data) }) await knex('users').where({ id: userID }).update({ votes: JSON.stringify(data) })
const record = await Bots.updateOne({ _id: botID, 'voteMetrix.day': getYYMMDD() }, { $inc: { 'voteMetrix.$.increasement': 1, 'voteMetrix.$.count': 1 } }) const record = await Bots.updateOne({ _id: botID, 'voteMetrix.day': getYYMMDD() }, { $inc: { 'voteMetrix.$.increasement': 1, 'voteMetrix.$.count': 1 } })
if(record.n === 0) await Bots.findByIdAndUpdate(botID, { $push: { voteMetrix: { count: (await knex('bots').where({ id: botID }))[0].votes } } }, { upsert: true }) if(record.matchedCount === 0) await Bots.findByIdAndUpdate(botID, { $push: { voteMetrix: { count: (await knex('bots').where({ id: botID }))[0].votes } } }, { upsert: true })
return true return true
} }
@ -705,7 +705,7 @@ export function safeImageHost(text: string) {
async function viewBot(id: string) { async function viewBot(id: string) {
const record = await Bots.updateOne({ _id: id, 'viewMetrix.day': getYYMMDD() }, { $inc: { 'viewMetrix.$.count': 1 } }) const record = await Bots.updateOne({ _id: id, 'viewMetrix.day': getYYMMDD() }, { $inc: { 'viewMetrix.$.count': 1 } })
if(record.n === 0) await Bots.findByIdAndUpdate(id, { $push: { viewMetrix: { count: 0 } } }, { upsert: true }) if(record.matchedCount === 0) await Bots.findByIdAndUpdate(id, { $push: { viewMetrix: { count: 0 } } }, { upsert: true })
} }
export const get = { export const get = {

5778
yarn.lock

File diff suppressed because it is too large Load Diff