cleaned dht-node of ballast

This commit is contained in:
Ulf Gebhardt 2023-01-10 12:27:47 +01:00
parent 904003377a
commit 10008fa682
Signed by: ulfgebhardt
GPG Key ID: DA6B843E748679C9
23 changed files with 62 additions and 715 deletions

View File

@ -1,11 +1,8 @@
CONFIG_VERSION=v14.2022-12-22
CONFIG_VERSION=v14.2022-11-22
# Server
PORT=4000
JWT_SECRET=secret123
JWT_EXPIRES_IN=10m
PORT=5000
GRAPHIQL=false
GDT_API_URL=https://gdt.gradido.net
# Database
DB_HOST=localhost
@ -13,47 +10,7 @@ DB_PORT=3306
DB_USER=root
DB_PASSWORD=
DB_DATABASE=gradido_community
TYPEORM_LOGGING_RELATIVE_PATH=typeorm.backend.log
# Klicktipp
KLICKTIPP=false
KLICKTTIPP_API_URL=https://api.klicktipp.com
KLICKTIPP_USER=gradido_test
KLICKTIPP_PASSWORD=secret321
KLICKTIPP_APIKEY_DE=SomeFakeKeyDE
KLICKTIPP_APIKEY_EN=SomeFakeKeyEN
# Community
COMMUNITY_NAME=Gradido Entwicklung
COMMUNITY_URL=http://localhost/
COMMUNITY_REGISTER_URL=http://localhost/register
COMMUNITY_REDEEM_URL=http://localhost/redeem/{code}
COMMUNITY_REDEEM_CONTRIBUTION_URL=http://localhost/redeem/CL-{code}
COMMUNITY_DESCRIPTION=Die lokale Entwicklungsumgebung von Gradido.
COMMUNITY_SUPPORT_MAIL=support@supportmail.com
# Login Server
LOGIN_APP_SECRET=21ffbbc616fe
LOGIN_SERVER_KEY=a51ef8ac7ef1abf162fb7a65261acd7a
# EMail
EMAIL=false
EMAIL_TEST_MODUS=false
EMAIL_TEST_RECEIVER=stage1@gradido.net
EMAIL_USERNAME=gradido_email
EMAIL_SENDER=info@gradido.net
EMAIL_PASSWORD=xxx
EMAIL_SMTP_URL=gmail.com
EMAIL_SMTP_PORT=587
EMAIL_LINK_VERIFICATION=http://localhost/checkEmail/{optin}{code}
EMAIL_LINK_SETPASSWORD=http://localhost/reset-password/{optin}
EMAIL_LINK_FORGOTPASSWORD=http://localhost/forgot-password
EMAIL_LINK_OVERVIEW=http://localhost/overview
EMAIL_CODE_VALID_TIME=1440
EMAIL_CODE_REQUEST_TIME=10
# Webhook
WEBHOOK_ELOPAGE_SECRET=secret
TYPEORM_LOGGING_RELATIVE_PATH=typeorm.dht-node.log
# EventProtocol
EVENT_PROTOCOL_DISABLED=false
@ -65,5 +22,5 @@ EVENT_PROTOCOL_DISABLED=false
# Federation
# if you set the value of FEDERATION_DHT_TOPIC, the DHT hyperswarm will start to announce and listen
# on an hash created from this topic
# FEDERATION_DHT_TOPIC=GRADIDO_HUB
FEDERATION_DHT_TOPIC=GRADIDO_HUB
# FEDERATION_DHT_SEED=64ebcb0e3ad547848fef4197c6e2332f

View File

@ -3,7 +3,7 @@
"version": "1.0.0",
"description": "Gradido dht-node module",
"main": "src/index.ts",
"repository": "https://github.com/gradido/gradido/federation",
"repository": "https://github.com/gradido/gradido/",
"author": "Claus-Peter Huebner",
"license": "Apache-2.0",
"private": false,
@ -17,12 +17,6 @@
},
"dependencies": {
"@hyperswarm/dht": "^6.3.3",
"@types/dotenv": "^8.2.0",
"@types/i18n": "^0.13.6",
"@types/jest": "^27.0.2",
"@types/jsonwebtoken": "^8.5.9",
"@types/lodash.clonedeep": "^4.5.7",
"@types/node": "^18.11.18",
"apollo-server-express": "2.25.2",
"class-validator": "^0.13.2",
"cross-env": "^7.0.3",
@ -30,9 +24,6 @@
"dotenv": "10.0.0",
"express": "4.17.1",
"graphql": "15.5.1",
"i18n": "0.15.1",
"jsonwebtoken": "^8.5.1",
"lodash.clonedeep": "^4.5.0",
"log4js": "^6.7.1",
"nodemon": "^2.0.20",
"reflect-metadata": "^0.1.13",
@ -44,6 +35,10 @@
"devDependencies": {
"@typescript-eslint/eslint-plugin": "^5.48.0",
"@typescript-eslint/parser": "^5.48.0",
"@types/dotenv": "^8.2.0",
"@types/jest": "^27.0.2",
"@types/lodash.clonedeep": "^4.5.7",
"@types/node": "^18.11.18",
"eslint": "^8.31.0",
"eslint-config-prettier": "^8.3.0",
"eslint-config-standard": "^17.0.0",

View File

@ -1,5 +0,0 @@
import { JwtPayload } from 'jsonwebtoken'
export interface CustomJwtPayload extends JwtPayload {
pubKey: Buffer
}

View File

@ -1,12 +0,0 @@
import { RIGHTS } from './RIGHTS'
export const INALIENABLE_RIGHTS = [
RIGHTS.LOGIN,
RIGHTS.GET_COMMUNITY_INFO,
RIGHTS.COMMUNITIES,
RIGHTS.CREATE_USER,
RIGHTS.SEND_RESET_PASSWORD_EMAIL,
RIGHTS.SET_PASSWORD,
RIGHTS.QUERY_TRANSACTION_LINK,
RIGHTS.QUERY_OPT_IN,
]

View File

@ -1,19 +0,0 @@
import jwt from 'jsonwebtoken'
import CONFIG from '@/config/'
import { CustomJwtPayload } from './CustomJwtPayload'
export const decode = (token: string): CustomJwtPayload | null => {
if (!token) throw new Error('401 Unauthorized')
try {
return <CustomJwtPayload>jwt.verify(token, CONFIG.JWT_SECRET)
} catch (err) {
return null
}
}
export const encode = (pubKey: Buffer): string => {
const token = jwt.sign({ pubKey }, CONFIG.JWT_SECRET, {
expiresIn: CONFIG.JWT_EXPIRES_IN,
})
return token
}

View File

@ -1,56 +0,0 @@
export enum RIGHTS {
LOGIN = 'LOGIN',
VERIFY_LOGIN = 'VERIFY_LOGIN',
BALANCE = 'BALANCE',
GET_COMMUNITY_INFO = 'GET_COMMUNITY_INFO',
COMMUNITIES = 'COMMUNITIES',
LIST_GDT_ENTRIES = 'LIST_GDT_ENTRIES',
EXIST_PID = 'EXIST_PID',
GET_KLICKTIPP_USER = 'GET_KLICKTIPP_USER',
GET_KLICKTIPP_TAG_MAP = 'GET_KLICKTIPP_TAG_MAP',
UNSUBSCRIBE_NEWSLETTER = 'UNSUBSCRIBE_NEWSLETTER',
SUBSCRIBE_NEWSLETTER = 'SUBSCRIBE_NEWSLETTER',
TRANSACTION_LIST = 'TRANSACTION_LIST',
SEND_COINS = 'SEND_COINS',
LOGOUT = 'LOGOUT',
CREATE_USER = 'CREATE_USER',
SEND_RESET_PASSWORD_EMAIL = 'SEND_RESET_PASSWORD_EMAIL',
SET_PASSWORD = 'SET_PASSWORD',
QUERY_OPT_IN = 'QUERY_OPT_IN',
UPDATE_USER_INFOS = 'UPDATE_USER_INFOS',
HAS_ELOPAGE = 'HAS_ELOPAGE',
CREATE_TRANSACTION_LINK = 'CREATE_TRANSACTION_LINK',
DELETE_TRANSACTION_LINK = 'DELETE_TRANSACTION_LINK',
QUERY_TRANSACTION_LINK = 'QUERY_TRANSACTION_LINK',
REDEEM_TRANSACTION_LINK = 'REDEEM_TRANSACTION_LINK',
LIST_TRANSACTION_LINKS = 'LIST_TRANSACTION_LINKS',
GDT_BALANCE = 'GDT_BALANCE',
CREATE_CONTRIBUTION = 'CREATE_CONTRIBUTION',
DELETE_CONTRIBUTION = 'DELETE_CONTRIBUTION',
LIST_CONTRIBUTIONS = 'LIST_CONTRIBUTIONS',
LIST_ALL_CONTRIBUTIONS = 'LIST_ALL_CONTRIBUTIONS',
UPDATE_CONTRIBUTION = 'UPDATE_CONTRIBUTION',
LIST_CONTRIBUTION_LINKS = 'LIST_CONTRIBUTION_LINKS',
COMMUNITY_STATISTICS = 'COMMUNITY_STATISTICS',
SEARCH_ADMIN_USERS = 'SEARCH_ADMIN_USERS',
CREATE_CONTRIBUTION_MESSAGE = 'CREATE_CONTRIBUTION_MESSAGE',
LIST_ALL_CONTRIBUTION_MESSAGES = 'LIST_ALL_CONTRIBUTION_MESSAGES',
// Admin
SEARCH_USERS = 'SEARCH_USERS',
SET_USER_ROLE = 'SET_USER_ROLE',
DELETE_USER = 'DELETE_USER',
UNDELETE_USER = 'UNDELETE_USER',
ADMIN_CREATE_CONTRIBUTION = 'ADMIN_CREATE_CONTRIBUTION',
ADMIN_CREATE_CONTRIBUTIONS = 'ADMIN_CREATE_CONTRIBUTIONS',
ADMIN_UPDATE_CONTRIBUTION = 'ADMIN_UPDATE_CONTRIBUTION',
ADMIN_DELETE_CONTRIBUTION = 'ADMIN_DELETE_CONTRIBUTION',
LIST_UNCONFIRMED_CONTRIBUTIONS = 'LIST_UNCONFIRMED_CONTRIBUTIONS',
CONFIRM_CONTRIBUTION = 'CONFIRM_CONTRIBUTION',
SEND_ACTIVATION_EMAIL = 'SEND_ACTIVATION_EMAIL',
CREATION_TRANSACTION_LIST = 'CREATION_TRANSACTION_LIST',
LIST_TRANSACTION_LINKS_ADMIN = 'LIST_TRANSACTION_LINKS_ADMIN',
CREATE_CONTRIBUTION_LINK = 'CREATE_CONTRIBUTION_LINK',
DELETE_CONTRIBUTION_LINK = 'DELETE_CONTRIBUTION_LINK',
UPDATE_CONTRIBUTION_LINK = 'UPDATE_CONTRIBUTION_LINK',
ADMIN_CREATE_CONTRIBUTION_MESSAGE = 'ADMIN_CREATE_CONTRIBUTION_MESSAGE',
}

View File

@ -1,40 +0,0 @@
import { INALIENABLE_RIGHTS } from './INALIENABLE_RIGHTS'
import { RIGHTS } from './RIGHTS'
import { Role } from './Role'
export const ROLE_UNAUTHORIZED = new Role('unauthorized', INALIENABLE_RIGHTS)
export const ROLE_USER = new Role('user', [
...INALIENABLE_RIGHTS,
RIGHTS.VERIFY_LOGIN,
RIGHTS.BALANCE,
RIGHTS.LIST_GDT_ENTRIES,
RIGHTS.EXIST_PID,
RIGHTS.GET_KLICKTIPP_USER,
RIGHTS.GET_KLICKTIPP_TAG_MAP,
RIGHTS.UNSUBSCRIBE_NEWSLETTER,
RIGHTS.SUBSCRIBE_NEWSLETTER,
RIGHTS.TRANSACTION_LIST,
RIGHTS.SEND_COINS,
RIGHTS.LOGOUT,
RIGHTS.UPDATE_USER_INFOS,
RIGHTS.HAS_ELOPAGE,
RIGHTS.CREATE_TRANSACTION_LINK,
RIGHTS.DELETE_TRANSACTION_LINK,
RIGHTS.REDEEM_TRANSACTION_LINK,
RIGHTS.LIST_TRANSACTION_LINKS,
RIGHTS.GDT_BALANCE,
RIGHTS.CREATE_CONTRIBUTION,
RIGHTS.DELETE_CONTRIBUTION,
RIGHTS.LIST_CONTRIBUTIONS,
RIGHTS.LIST_ALL_CONTRIBUTIONS,
RIGHTS.UPDATE_CONTRIBUTION,
RIGHTS.SEARCH_ADMIN_USERS,
RIGHTS.LIST_CONTRIBUTION_LINKS,
RIGHTS.COMMUNITY_STATISTICS,
RIGHTS.CREATE_CONTRIBUTION_MESSAGE,
RIGHTS.LIST_ALL_CONTRIBUTION_MESSAGES,
])
export const ROLE_ADMIN = new Role('admin', Object.values(RIGHTS)) // all rights
// TODO from database
export const ROLES = [ROLE_UNAUTHORIZED, ROLE_USER, ROLE_ADMIN]

View File

@ -1,15 +0,0 @@
import { RIGHTS } from './RIGHTS'
export class Role {
id: string
rights: RIGHTS[]
constructor(id: string, rights: RIGHTS[]) {
this.id = id
this.rights = rights
}
hasRight = (right: RIGHTS): boolean => {
return this.rights.includes(right)
}
}

View File

@ -25,10 +25,7 @@ const constants = {
const server = {
PORT: process.env.PORT || 5000,
JWT_SECRET: process.env.JWT_SECRET || 'secret123',
JWT_EXPIRES_IN: process.env.JWT_EXPIRES_IN || '10m',
GRAPHIQL: process.env.GRAPHIQL === 'true' || false,
GDT_API_URL: process.env.GDT_API_URL || 'https://gdt.gradido.net',
PRODUCTION: process.env.NODE_ENV === 'production' || false,
}
@ -38,18 +35,8 @@ const database = {
DB_USER: process.env.DB_USER || 'root',
DB_PASSWORD: process.env.DB_PASSWORD || '',
DB_DATABASE: process.env.DB_DATABASE || 'gradido_community',
TYPEORM_LOGGING_RELATIVE_PATH: process.env.TYPEORM_LOGGING_RELATIVE_PATH || 'typeorm.backend.log',
}
const community = {
COMMUNITY_NAME: process.env.COMMUNITY_NAME || 'Gradido Entwicklung',
COMMUNITY_URL: process.env.COMMUNITY_URL || 'http://localhost/',
COMMUNITY_REGISTER_URL: process.env.COMMUNITY_REGISTER_URL || 'http://localhost/register',
COMMUNITY_REDEEM_URL: process.env.COMMUNITY_REDEEM_URL || 'http://localhost/redeem/{code}',
COMMUNITY_REDEEM_CONTRIBUTION_URL:
process.env.COMMUNITY_REDEEM_CONTRIBUTION_URL || 'http://localhost/redeem/CL-{code}',
COMMUNITY_DESCRIPTION:
process.env.COMMUNITY_DESCRIPTION || 'Die lokale Entwicklungsumgebung von Gradido.',
TYPEORM_LOGGING_RELATIVE_PATH:
process.env.TYPEORM_LOGGING_RELATIVE_PATH || 'typeorm.dht-node.log',
}
const eventProtocol = {
@ -57,8 +44,11 @@ const eventProtocol = {
EVENT_PROTOCOL_DISABLED: process.env.EVENT_PROTOCOL_DISABLED === 'true' || false,
}
// This is needed by graphql-directive-auth
process.env.APP_SECRET = server.JWT_SECRET
const federation = {
FEDERATION_DHT_TOPIC: process.env.FEDERATION_DHT_TOPIC || null,
FEDERATION_DHT_SEED: process.env.FEDERATION_DHT_SEED || null,
FEDERATION_COMMUNITY_URL: process.env.FEDERATION_COMMUNITY_URL || null,
}
// Check config version
constants.CONFIG_VERSION.CURRENT = process.env.CONFIG_VERSION || constants.CONFIG_VERSION.DEFAULT
@ -72,24 +62,11 @@ if (
)
}
const federation = {
FEDERATION_DHT_TOPIC: process.env.FEDERATION_DHT_TOPIC || null,
FEDERATION_DHT_SEED: process.env.FEDERATION_DHT_SEED || null,
FEDERATION_PORT: process.env.FEDERATION_PORT || 5000,
FEDERATION_API: process.env.FEDERATION_API || '1_0',
FEDERATION_COMMUNITY_URL: process.env.FEDERATION_COMMUNITY_URL || null,
}
const CONFIG = {
...constants,
...server,
...database,
// ...klicktipp,
...community,
// ...email,
// ...loginServer,
// ...webhook,
// ...eventProtocol,
...eventProtocol,
...federation,
}

View File

@ -155,7 +155,9 @@ export const startDHT = async (topic: string): Promise<void> => {
})
}
logger.info(`Found new peers: ${collectedPubKeys}`)
if(collectedPubKeys.length){
logger.info(`Found new peers: ${collectedPubKeys}`)
}
collectedPubKeys.forEach((remotePubKey) => {
const socket = node.connect(Buffer.from(remotePubKey, 'hex'))

View File

@ -1,21 +0,0 @@
import { Field, ObjectType, Query, Resolver } from 'type-graphql'
import { federationLogger as logger } from '@/server/logger'
@ObjectType()
class GetTestApiResult {
constructor(apiVersion: string) {
this.api = `${apiVersion}`
}
@Field(() => String)
api: string
}
@Resolver()
export class TestResolver {
@Query(() => GetTestApiResult)
async test(): Promise<GetTestApiResult> {
logger.info(`test api 1_0`)
return new GetTestApiResult('1_0')
}
}

View File

@ -1,9 +0,0 @@
import path from 'path'
// config
import CONFIG from '../../config'
import { federationLogger as logger } from '@/server/logger'
export const getApiResolvers = () => {
logger.info(`getApiResolvers...${CONFIG.FEDERATION_API}`)
return path.join(__dirname, `./${CONFIG.FEDERATION_API}/resolver/*Resolver.{ts,js}`)
}

View File

@ -1,55 +0,0 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { AuthChecker } from 'type-graphql'
import { decode, encode } from '@/auth/JWT'
import { ROLE_UNAUTHORIZED, ROLE_USER, ROLE_ADMIN } from '@/auth/ROLES'
import { RIGHTS } from '@/auth/RIGHTS'
import { getCustomRepository } from '@dbTools/typeorm'
import { UserRepository } from '@repository/User'
import { INALIENABLE_RIGHTS } from '@/auth/INALIENABLE_RIGHTS'
const isAuthorized: AuthChecker<any> = async ({ context }, rights) => {
context.role = ROLE_UNAUTHORIZED // unauthorized user
// is rights an inalienable right?
if ((<RIGHTS[]>rights).reduce((acc, right) => acc && INALIENABLE_RIGHTS.includes(right), true))
return true
// Do we have a token?
if (!context.token) {
throw new Error('401 Unauthorized')
}
// Decode the token
const decoded = decode(context.token)
if (!decoded) {
throw new Error('403.13 - Client certificate revoked')
}
// Set context pubKey
context.pubKey = Buffer.from(decoded.pubKey).toString('hex')
// TODO - load from database dynamically & admin - maybe encode this in the token to prevent many database requests
// TODO this implementation is bullshit - two database queries cause our user identifiers are not aligned and vary between email, id and pubKey
const userRepository = getCustomRepository(UserRepository)
try {
const user = await userRepository.findByPubkeyHex(context.pubKey)
context.user = user
context.role = user.isAdmin ? ROLE_ADMIN : ROLE_USER
} catch {
// in case the database query fails (user deleted)
throw new Error('401 Unauthorized')
}
// check for correct rights
const missingRights = (<RIGHTS[]>rights).filter((right) => !context.role.hasRight(right))
if (missingRights.length !== 0) {
throw new Error('401 Unauthorized')
}
// set new header token
context.setHeaders.push({ key: 'token', value: encode(decoded.pubKey) })
return true
}
export default isAuthorized

View File

@ -0,0 +1,9 @@
import { Query, Resolver } from 'type-graphql'
@Resolver()
export class TestResolver {
@Query(() => Boolean)
async test(): Promise<boolean> {
return true
}
}

View File

@ -1,15 +1,13 @@
import { GraphQLSchema } from 'graphql'
import { buildSchema } from 'type-graphql'
import path from 'path'
import isAuthorized from './directive/isAuthorized'
import DecimalScalar from './scalar/Decimal'
import Decimal from 'decimal.js-light'
import { getApiResolvers } from './api/schema'
const schema = async (): Promise<GraphQLSchema> => {
return await buildSchema({
resolvers: [getApiResolvers()],
authChecker: isAuthorized,
resolvers: [path.join(__dirname, `./resolver/*Resolver.{ts,js}`)],
scalarsMap: [{ type: Decimal, scalar: DecimalScalar }],
})
}

View File

@ -7,30 +7,32 @@ import { startDHT } from '@/dht_node/index'
import CONFIG from './config'
async function main() {
// eslint-disable-next-line no-console
console.log(`FEDERATION_PORT=${CONFIG.FEDERATION_PORT}`)
console.log(`FEDERATION_API=${CONFIG.FEDERATION_API}`)
console.log(`configured: FEDERATION_DHT_TOPIC=${CONFIG.FEDERATION_DHT_TOPIC}`)
const { app } = await createServer()
app.listen(CONFIG.FEDERATION_PORT, () => {
// die when there is no FEDERATION_DHT_TOPIC defined
if (!CONFIG.FEDERATION_DHT_TOPIC) {
throw new Error(
'You have to configure a `FEDERATION_DHT_TOPIC` in the config to run this service.',
)
}
// eslint-disable-next-line no-console
console.log(
`starting Federation on ${CONFIG.FEDERATION_DHT_TOPIC} ${
CONFIG.FEDERATION_DHT_SEED ? 'with seed...' : 'without seed...'
}`,
)
await startDHT(CONFIG.FEDERATION_DHT_TOPIC)
// management interface
app.listen(CONFIG.PORT, () => {
// eslint-disable-next-line no-console
console.log(`Server is running at http://localhost:${CONFIG.FEDERATION_PORT}`)
console.log(`Server is running at http://localhost:${CONFIG.PORT}`)
if (CONFIG.GRAPHIQL) {
// eslint-disable-next-line no-console
console.log(`GraphIQL available at http://localhost:${CONFIG.FEDERATION_PORT}`)
console.log(`GraphIQL available at http://localhost:${CONFIG.PORT}`)
}
})
// start DHT hyperswarm when DHT_TOPIC is set in .env
if (CONFIG.FEDERATION_DHT_TOPIC) {
// eslint-disable-next-line no-console
console.log(
`starting Federation on ${CONFIG.FEDERATION_DHT_TOPIC} ${
CONFIG.FEDERATION_DHT_SEED ? 'with seed...' : 'without seed...'
}`,
)
await startDHT(CONFIG.FEDERATION_DHT_TOPIC) // con,
}
}
main().catch((e) => {

View File

@ -1,51 +0,0 @@
import { Role } from '@/auth/Role'
import { User as dbUser } from '@entity/User'
import { Transaction as dbTransaction } from '@entity/Transaction'
import Decimal from 'decimal.js-light'
import { ExpressContext } from 'apollo-server-express'
export interface Context {
token: string | null
setHeaders: { key: string; value: string }[]
role?: Role
user?: dbUser
clientTimezoneOffset?: number
// hack to use less DB calls for Balance Resolver
lastTransaction?: dbTransaction
transactionCount?: number
linkCount?: number
sumHoldAvailableAmount?: Decimal
}
const context = (args: ExpressContext): Context => {
const authorization = args.req.headers.authorization
const clientTimezoneOffset = args.req.headers.clienttimezoneoffset
const context: Context = {
token: null,
setHeaders: [],
}
if (authorization) {
context.token = authorization.replace(/^Bearer /, '')
}
if (clientTimezoneOffset && typeof clientTimezoneOffset === 'string') {
context.clientTimezoneOffset = Number(clientTimezoneOffset)
}
return context
}
export const getUser = (context: Context): dbUser => {
if (context.user) return context.user
throw new Error('No user given in context!')
}
export const getClientTimezoneOffset = (context: Context): number => {
if (
(context.clientTimezoneOffset || context.clientTimezoneOffset === 0) &&
Math.abs(context.clientTimezoneOffset) <= 27 * 60
) {
return context.clientTimezoneOffset
}
throw new Error('No valid client time zone offset in context!')
}
export default context

View File

@ -6,40 +6,16 @@ import express, { Express } from 'express'
// database
import connection from '@/typeorm/connection'
import { checkDBVersion } from '@/typeorm/DBVersion'
// server
import cors from './cors'
// import serverContext from './context'
// import plugins from './plugins'
// config
import CONFIG from '@/config'
// graphql
import schema from '@/graphql/schema'
// webhooks
// import { elopageWebhook } from '@/webhook/elopage'
import { Connection } from '@dbTools/typeorm'
import { apolloLogger } from './logger'
import { Logger } from 'log4js'
// i18n
import { i18n } from './localization'
// TODO implement
// import queryComplexity, { simpleEstimator, fieldConfigEstimator } from "graphql-query-complexity";
type ServerDef = { apollo: ApolloServer; app: Express; con: Connection }
const createServer = async (
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// context: any = serverContext,
logger: Logger = apolloLogger,
localization: i18n.I18n = i18n,
): Promise<ServerDef> => {
logger.addContext('user', 'unknown')
const createServer = async (logger: Logger = apolloLogger): Promise<ServerDef> => {
logger.debug('createServer...')
// open mysql connection
@ -62,24 +38,11 @@ const createServer = async (
// cors
app.use(cors)
// bodyparser json
app.use(express.json())
// bodyparser urlencoded for elopage
app.use(express.urlencoded({ extended: true }))
// i18n
app.use(localization.init)
// Elopage Webhook
// app.post('/hook/elopage/' + CONFIG.WEBHOOK_ELOPAGE_SECRET, elopageWebhook)
// Apollo Server
const apollo = new ApolloServer({
schema: await schema(),
// playground: CONFIG.GRAPHIQL,
// introspection: CONFIG.GRAPHIQL,
// context,
// plugins,
playground: CONFIG.GRAPHIQL,
introspection: CONFIG.GRAPHIQL,
logger,
})
apollo.applyMiddleware({ app, path: '/' })

View File

@ -1,28 +0,0 @@
import path from 'path'
import { federationLogger as logger } from './logger'
import i18n from 'i18n'
i18n.configure({
locales: ['en', 'de'],
defaultLocale: 'en',
retryInDefaultLocale: false,
directory: path.join(__dirname, '..', 'locales'),
// autoReload: true, // if this is activated the seeding hangs at the very end
updateFiles: false,
objectNotation: true,
logDebugFn: (msg) => logger.debug(msg),
logWarnFn: (msg) => logger.info(msg),
logErrorFn: (msg) => logger.error(msg),
// this api is needed for email-template pug files
api: {
__: 't', // now req.__ becomes req.t
__n: 'tn', // and req.__n can be called as req.tn
},
register: global,
mustacheConfig: {
tags: ['{', '}'],
disable: false,
},
})
export { i18n }

View File

@ -11,20 +11,18 @@ let filename: string = options.appenders.federation.filename
if (CONFIG.FEDERATION_DHT_TOPIC) {
options.appenders.federation.filename = filename
.replace('apiversion-%v', 'dht-' + CONFIG.FEDERATION_DHT_TOPIC)
.replace('%p', CONFIG.FEDERATION_PORT.toString())
.replace('%p', CONFIG.PORT.toString())
} else {
options.appenders.federation.filename = filename
.replace('%v', CONFIG.FEDERATION_API)
.replace('%p', CONFIG.FEDERATION_PORT.toString())
options.appenders.federation.filename = filename.replace('%p', CONFIG.PORT.toString())
}
filename = options.appenders.access.filename
options.appenders.access.filename = filename.replace('%p', CONFIG.FEDERATION_PORT.toString())
options.appenders.access.filename = filename.replace('%p', CONFIG.PORT.toString())
filename = options.appenders.apollo.filename
options.appenders.apollo.filename = filename.replace('%p', CONFIG.FEDERATION_PORT.toString())
options.appenders.apollo.filename = filename.replace('%p', CONFIG.PORT.toString())
filename = options.appenders.backend.filename
options.appenders.backend.filename = filename.replace('%p', CONFIG.FEDERATION_PORT.toString())
options.appenders.backend.filename = filename.replace('%p', CONFIG.PORT.toString())
filename = options.appenders.errorFile.filename
options.appenders.errorFile.filename = filename.replace('%p', CONFIG.FEDERATION_PORT.toString())
options.appenders.errorFile.filename = filename.replace('%p', CONFIG.PORT.toString())
log4js.configure(options)

View File

@ -1,61 +0,0 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
import clonedeep from 'lodash.clonedeep'
const setHeadersPlugin = {
requestDidStart() {
return {
willSendResponse(requestContext: any) {
const { setHeaders = [] } = requestContext.context
setHeaders.forEach(({ key, value }: { [key: string]: string }) => {
if (requestContext.response.http.headers.get(key)) {
requestContext.response.http.headers.set(key, value)
} else {
requestContext.response.http.headers.append(key, value)
}
})
return requestContext
},
}
},
}
const filterVariables = (variables: any) => {
const vars = clonedeep(variables)
if (vars.password) vars.password = '***'
if (vars.passwordNew) vars.passwordNew = '***'
return vars
}
const logPlugin = {
requestDidStart(requestContext: any) {
const { logger } = requestContext
const { query, mutation, variables, operationName } = requestContext.request
if (operationName !== 'IntrospectionQuery') {
logger.info(`Request:
${mutation || query}variables: ${JSON.stringify(filterVariables(variables), null, 2)}`)
}
return {
willSendResponse(requestContext: any) {
if (operationName !== 'IntrospectionQuery') {
if (requestContext.context.user) logger.info(`User ID: ${requestContext.context.user.id}`)
if (requestContext.response.data) {
logger.info('Response Success!')
logger.trace(`Response-Data:
${JSON.stringify(requestContext.response.data, null, 2)}`)
}
if (requestContext.response.errors)
logger.error(`Response-Errors:
${JSON.stringify(requestContext.response.errors, null, 2)}`)
}
return requestContext
},
}
},
}
const plugins =
process.env.NODE_ENV === 'development' ? [setHeadersPlugin] : [setHeadersPlugin, logPlugin]
export default plugins

View File

@ -15,7 +15,7 @@ const checkDBVersion = async (DB_VERSION: string): Promise<boolean> => {
const dbVersion = await getDBVersion()
if (!dbVersion || dbVersion.indexOf(DB_VERSION) === -1) {
logger.error(
`Wrong database version detected - the backend requires '${DB_VERSION}' but found '${
`Wrong database version detected - the dht-node requires '${DB_VERSION}' but found '${
dbVersion || 'None'
}`,
)

View File

@ -650,42 +650,6 @@
"@jridgewell/resolve-uri" "3.1.0"
"@jridgewell/sourcemap-codec" "1.4.14"
"@messageformat/core@^3.0.0":
version "3.0.1"
resolved "https://registry.yarnpkg.com/@messageformat/core/-/core-3.0.1.tgz#191e12cf9643704d1fd32e592a3fbdc194dd588e"
integrity sha512-yxj2+0e46hcZqJfNf0ZYbC2q6WlcGoh4g11mCyRtTueR0AD8F9z4JMYAS1aOiFG8Vl1LZg/h5hZHKmWTAyZq8g==
dependencies:
"@messageformat/date-skeleton" "^1.0.0"
"@messageformat/number-skeleton" "^1.0.0"
"@messageformat/parser" "^5.0.0"
"@messageformat/runtime" "^3.0.1"
make-plural "^7.0.0"
safe-identifier "^0.4.1"
"@messageformat/date-skeleton@^1.0.0":
version "1.0.1"
resolved "https://registry.yarnpkg.com/@messageformat/date-skeleton/-/date-skeleton-1.0.1.tgz#980b8babe21a11433b6e1e8f6dc8c4cae4f5f56b"
integrity sha512-jPXy8fg+WMPIgmGjxSlnGJn68h/2InfT0TNSkVx0IGXgp4ynnvYkbZ51dGWmGySEK+pBiYUttbQdu5XEqX5CRg==
"@messageformat/number-skeleton@^1.0.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@messageformat/number-skeleton/-/number-skeleton-1.1.0.tgz#eb636738da8abbd35ccbeb84f7d84d63302aeb61"
integrity sha512-F0Io+GOSvFFxvp9Ze3L5kAoZ2NnOAT0Mr/jpGNd3fqo8A0t4NxNIAcCdggtl2B/gN2ErkIKSBVPrF7xcW1IGvA==
"@messageformat/parser@^5.0.0":
version "5.0.0"
resolved "https://registry.yarnpkg.com/@messageformat/parser/-/parser-5.0.0.tgz#5737e69d7d4a469998b527710f1891174fc1b262"
integrity sha512-WiDKhi8F0zQaFU8cXgqq69eYFarCnTVxKcvhAONufKf0oUxbqLMW6JX6rV4Hqh+BEQWGyKKKHY4g1XA6bCLylA==
dependencies:
moo "^0.5.1"
"@messageformat/runtime@^3.0.1":
version "3.0.1"
resolved "https://registry.yarnpkg.com/@messageformat/runtime/-/runtime-3.0.1.tgz#94d1f6c43265c28ef7aed98ecfcc0968c6c849ac"
integrity sha512-6RU5ol2lDtO8bD9Yxe6CZkl0DArdv0qkuoZC+ZwowU+cdRlVE1157wjCmlA5Rsf1Xc/brACnsZa5PZpEDfTFFg==
dependencies:
make-plural "^7.0.0"
"@nodelib/fs.scandir@2.1.5":
version "2.1.5"
resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5"
@ -940,11 +904,6 @@
resolved "https://registry.yarnpkg.com/@types/http-errors/-/http-errors-2.0.1.tgz#20172f9578b225f6c7da63446f56d4ce108d5a65"
integrity sha512-/K3ds8TRAfBvi5vfjuz8y6+GiAYBZ0x4tXv1Av6CWBWn0IlADc+ZX9pMq7oU0fNQPnBwIZl3rmeLp6SBApbxSQ==
"@types/i18n@^0.13.6":
version "0.13.6"
resolved "https://registry.yarnpkg.com/@types/i18n/-/i18n-0.13.6.tgz#54199ca55c7b25cb45040ac566e90c94a57fdfa8"
integrity sha512-LLbimAA0oQilgP4PJBFH7sRdBUjWLo6R1rf46SUgVzsUZeXH3PT1piXj4LNX5ECDi0bLg9RmQMmY1K2qawqJqA==
"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1":
version "2.0.4"
resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz#8467d4b3c087805d63580480890791277ce35c44"
@ -982,13 +941,6 @@
resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee"
integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==
"@types/jsonwebtoken@^8.5.9":
version "8.5.9"
resolved "https://registry.yarnpkg.com/@types/jsonwebtoken/-/jsonwebtoken-8.5.9.tgz#2c064ecb0b3128d837d2764aa0b117b0ff6e4586"
integrity sha512-272FMnFGzAVMGtu9tkr29hRL6bZj4Zs1KZNeHLnKqAvp06tAIcarTMwOh8/8bz4FmKRcMxZhZNeUAQsNLoiPhg==
dependencies:
"@types/node" "*"
"@types/keygrip@*":
version "1.0.2"
resolved "https://registry.yarnpkg.com/@types/keygrip/-/keygrip-1.0.2.tgz#513abfd256d7ad0bf1ee1873606317b33b1b2a72"
@ -1680,11 +1632,6 @@ bogon@^1.0.0:
compact-encoding "^2.11.0"
compact-encoding-net "^1.2.0"
boolean@^3.1.4:
version "3.2.0"
resolved "https://registry.yarnpkg.com/boolean/-/boolean-3.2.0.tgz#9e5294af4e98314494cbb17979fa54ca159f116b"
integrity sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw==
brace-expansion@^1.1.7:
version "1.1.11"
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
@ -1729,11 +1676,6 @@ bser@2.1.1:
dependencies:
node-int64 "^0.4.0"
buffer-equal-constant-time@1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819"
integrity sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==
buffer-from@^1.0.0:
version "1.1.2"
resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5"
@ -2043,7 +1985,7 @@ debug@2.6.9, debug@^2.6.9:
dependencies:
ms "2.0.0"
debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.2, debug@^4.3.3, debug@^4.3.4:
debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.2, debug@^4.3.4:
version "4.3.4"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
@ -2204,13 +2146,6 @@ dotenv@10.0.0:
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-10.0.0.tgz#3d4227b8fb95f81096cdd2b66653fb2c7085ba81"
integrity sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==
ecdsa-sig-formatter@1.0.11:
version "1.0.11"
resolved "https://registry.yarnpkg.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz#ae0f0fa2d85045ef14a817daa3ce9acd0489e5bf"
integrity sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==
dependencies:
safe-buffer "^5.0.1"
ee-first@1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
@ -2697,13 +2632,6 @@ fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.6:
resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==
fast-printf@^1.6.9:
version "1.6.9"
resolved "https://registry.yarnpkg.com/fast-printf/-/fast-printf-1.6.9.tgz#212f56570d2dc8ccdd057ee93d50dd414d07d676"
integrity sha512-FChq8hbz65WMj4rstcQsFB0O7Cy++nmbNfLYnD9cYv2cRn8EG6k/MGn9kO/tjO66t09DLDugj3yL+V2o6Qftrg==
dependencies:
boolean "^3.1.4"
fastq@^1.6.0:
version "1.15.0"
resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.15.0.tgz#d04d07c6a2a68fe4599fea8d2e103a937fae6b3a"
@ -3144,18 +3072,6 @@ hypercore-crypto@^3.3.0:
compact-encoding "^2.5.1"
sodium-universal "^3.0.0"
i18n@0.15.1:
version "0.15.1"
resolved "https://registry.yarnpkg.com/i18n/-/i18n-0.15.1.tgz#68fb8993c461cc440bc2485d82f72019f2b92de8"
integrity sha512-yue187t8MqUPMHdKjiZGrX+L+xcUsDClGO0Cz4loaKUOK9WrGw5pgan4bv130utOwX7fHE9w2iUeHFalVQWkXA==
dependencies:
"@messageformat/core" "^3.0.0"
debug "^4.3.3"
fast-printf "^1.6.9"
make-plural "^7.0.0"
math-interval-parser "^2.0.1"
mustache "^4.2.0"
iconv-lite@0.4.24:
version "0.4.24"
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
@ -3921,39 +3837,6 @@ jsonfile@^4.0.0:
optionalDependencies:
graceful-fs "^4.1.6"
jsonwebtoken@^8.5.1:
version "8.5.1"
resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz#00e71e0b8df54c2121a1f26137df2280673bcc0d"
integrity sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==
dependencies:
jws "^3.2.2"
lodash.includes "^4.3.0"
lodash.isboolean "^3.0.3"
lodash.isinteger "^4.0.4"
lodash.isnumber "^3.0.3"
lodash.isplainobject "^4.0.6"
lodash.isstring "^4.0.1"
lodash.once "^4.0.0"
ms "^2.1.1"
semver "^5.6.0"
jwa@^1.4.1:
version "1.4.1"
resolved "https://registry.yarnpkg.com/jwa/-/jwa-1.4.1.tgz#743c32985cb9e98655530d53641b66c8645b039a"
integrity sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==
dependencies:
buffer-equal-constant-time "1.0.1"
ecdsa-sig-formatter "1.0.11"
safe-buffer "^5.0.1"
jws@^3.2.2:
version "3.2.2"
resolved "https://registry.yarnpkg.com/jws/-/jws-3.2.2.tgz#001099f3639468c9414000e99995fa52fb478304"
integrity sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==
dependencies:
jwa "^1.4.1"
safe-buffer "^5.0.1"
kademlia-routing-table@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/kademlia-routing-table/-/kademlia-routing-table-1.0.1.tgz#6f18416f612e885a8d4df128f04c490a90d772f6"
@ -4009,46 +3892,11 @@ locate-path@^6.0.0:
dependencies:
p-locate "^5.0.0"
lodash.clonedeep@^4.5.0:
version "4.5.0"
resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef"
integrity sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==
lodash.get@^4.4.2:
version "4.4.2"
resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99"
integrity sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==
lodash.includes@^4.3.0:
version "4.3.0"
resolved "https://registry.yarnpkg.com/lodash.includes/-/lodash.includes-4.3.0.tgz#60bb98a87cb923c68ca1e51325483314849f553f"
integrity sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==
lodash.isboolean@^3.0.3:
version "3.0.3"
resolved "https://registry.yarnpkg.com/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz#6c2e171db2a257cd96802fd43b01b20d5f5870f6"
integrity sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==
lodash.isinteger@^4.0.4:
version "4.0.4"
resolved "https://registry.yarnpkg.com/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz#619c0af3d03f8b04c31f5882840b77b11cd68343"
integrity sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==
lodash.isnumber@^3.0.3:
version "3.0.3"
resolved "https://registry.yarnpkg.com/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz#3ce76810c5928d03352301ac287317f11c0b1ffc"
integrity sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==
lodash.isplainobject@^4.0.6:
version "4.0.6"
resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb"
integrity sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==
lodash.isstring@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451"
integrity sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==
lodash.memoize@4.x:
version "4.1.2"
resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe"
@ -4059,11 +3907,6 @@ lodash.merge@^4.6.2:
resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a"
integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==
lodash.once@^4.0.0:
version "4.1.1"
resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac"
integrity sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==
lodash.sortby@^4.7.0:
version "4.7.0"
resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438"
@ -4121,11 +3964,6 @@ make-error@1.x, make-error@^1.1.1:
resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2"
integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==
make-plural@^7.0.0:
version "7.2.0"
resolved "https://registry.yarnpkg.com/make-plural/-/make-plural-7.2.0.tgz#93174b1419672a48a2340db6c1d3fb217530c684"
integrity sha512-WkdI+iaWaBCFM2wUXwos8Z7spg5Dt64Xe/VI6NpRaly21cDtD76N6S97K//UtzV0dHOiXX+E90TnszdXHG0aMg==
makeerror@1.0.12:
version "1.0.12"
resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.12.tgz#3e5dd2079a82e812e983cc6610c4a2cb0eaa801a"
@ -4133,11 +3971,6 @@ makeerror@1.0.12:
dependencies:
tmpl "1.0.5"
math-interval-parser@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/math-interval-parser/-/math-interval-parser-2.0.1.tgz#e22cd6d15a0a7f4c03aec560db76513da615bed4"
integrity sha512-VmlAmb0UJwlvMyx8iPhXUDnVW1F9IrGEd9CIOmv+XL8AErCUUuozoDMrgImvnYt2A+53qVX/tPW6YJurMKYsvA==
media-typer@0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
@ -4205,11 +4038,6 @@ minimist@^1.2.0, minimist@^1.2.6:
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.7.tgz#daa1c4d91f507390437c6a8bc01078e7000c4d18"
integrity sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==
moo@^0.5.1:
version "0.5.2"
resolved "https://registry.yarnpkg.com/moo/-/moo-0.5.2.tgz#f9fe82473bc7c184b0d32e2215d3f6e67278733c"
integrity sha512-iSAJLHYKnX41mKcJKjqvnAN9sf0LMDTXDEvFv+ffuRR9a1MIuXLjMNL6EsnDHSkKLTWNqQQ5uo61P4EbU4NU+Q==
ms@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
@ -4230,11 +4058,6 @@ ms@2.1.3, ms@^2.1.1:
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"
integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
mustache@^4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/mustache/-/mustache-4.2.0.tgz#e5892324d60a12ec9c2a73359edca52972bf6f64"
integrity sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==
nanoassert@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/nanoassert/-/nanoassert-1.1.0.tgz#4f3152e09540fde28c76f44b19bbcd1d5a42478d"
@ -4796,11 +4619,6 @@ safe-buffer@5.2.1, safe-buffer@^5.0.1:
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
safe-identifier@^0.4.1:
version "0.4.2"
resolved "https://registry.yarnpkg.com/safe-identifier/-/safe-identifier-0.4.2.tgz#cf6bfca31c2897c588092d1750d30ef501d59fcb"
integrity sha512-6pNbSMW6OhAi9j+N8V+U715yBQsaWJ7eyEUaOrawX+isg5ZxhUlV1NipNtgaKHmFGiABwt+ZF04Ii+3Xjkg+8w==
safe-regex-test@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.0.0.tgz#793b874d524eb3640d1873aad03596db2d4f2295"
@ -4834,7 +4652,7 @@ semver@7.x, semver@^7.0.0, semver@^7.3.2, semver@^7.3.7, semver@^7.3.8:
dependencies:
lru-cache "^6.0.0"
semver@^5.6.0, semver@^5.7.1:
semver@^5.7.1:
version "5.7.1"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==