mirror of
https://github.com/omnivore-app/omnivore.git
synced 2026-03-11 08:54:26 +00:00
fix: email sending and recommendation
* use token in the custom header as the key in rate limiter
This commit is contained in:
parent
e0c59434d7
commit
b7c133d58e
5 changed files with 39 additions and 37 deletions
|
|
@ -2,19 +2,24 @@
|
|||
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||
import cors from 'cors'
|
||||
import express from 'express'
|
||||
import * as jwt from 'jsonwebtoken'
|
||||
import { kx } from '../datalayer/knex_config'
|
||||
import { createPubSubClient } from '../datalayer/pubsub'
|
||||
import { createPage, getPageByParam, updatePage } from '../elastic/pages'
|
||||
import { addRecommendation } from '../elastic/recommendation'
|
||||
import { Recommendation } from '../elastic/types'
|
||||
import { env } from '../env'
|
||||
import {
|
||||
ArticleSavingRequestStatus,
|
||||
PageType,
|
||||
UploadFileStatus,
|
||||
} from '../generated/graphql'
|
||||
import cors from 'cors'
|
||||
import { env } from '../env'
|
||||
import { buildLogger } from '../utils/logger'
|
||||
import * as jwt from 'jsonwebtoken'
|
||||
import { corsConfig } from '../utils/corsConfig'
|
||||
import { Claims } from '../resolvers/types'
|
||||
import { initModels } from '../server'
|
||||
import { kx } from '../datalayer/knex_config'
|
||||
import { getTokenByRequest } from '../utils/auth'
|
||||
import { corsConfig } from '../utils/corsConfig'
|
||||
import {
|
||||
fileNameForFilePath,
|
||||
generateSlug,
|
||||
|
|
@ -22,15 +27,11 @@ import {
|
|||
titleForFilePath,
|
||||
validateUuid,
|
||||
} from '../utils/helpers'
|
||||
import { buildLogger } from '../utils/logger'
|
||||
import {
|
||||
generateUploadFilePathName,
|
||||
generateUploadSignedUrl,
|
||||
} from '../utils/uploads'
|
||||
import { Claims } from '../resolvers/types'
|
||||
import { createPage, getPageByParam, updatePage } from '../elastic/pages'
|
||||
import { createPubSubClient } from '../datalayer/pubsub'
|
||||
import { Recommendation } from '../elastic/types'
|
||||
import { addRecommendation } from '../elastic/recommendation'
|
||||
|
||||
const logger = buildLogger('app.dispatch')
|
||||
|
||||
|
|
@ -157,7 +158,7 @@ export function pageRouter() {
|
|||
'/recommend',
|
||||
cors<express.Request>(corsConfig),
|
||||
async (req, res) => {
|
||||
const token = req?.cookies?.auth || req?.headers?.authorization
|
||||
const token = getTokenByRequest(req)
|
||||
if (!token || !jwt.verify(token, env.server.jwtSecret)) {
|
||||
return res.status(401).send({ errorCode: 'UNAUTHORIZED' })
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import express from 'express'
|
|||
import { User } from '../entity/user'
|
||||
import { getRepository } from '../entity/utils'
|
||||
import { env } from '../env'
|
||||
import { getClaimsByToken } from '../utils/auth'
|
||||
import { getClaimsByToken, getTokenByRequest } from '../utils/auth'
|
||||
import { corsConfig } from '../utils/corsConfig'
|
||||
import { buildLogger } from '../utils/logger'
|
||||
import { sendEmail } from '../utils/sendEmail'
|
||||
|
|
@ -17,10 +17,7 @@ export function userRouter() {
|
|||
|
||||
router.post('/email', cors<express.Request>(corsConfig), async (req, res) => {
|
||||
logger.info('email to-user router')
|
||||
const token =
|
||||
req.header('Omnivore-Authorization') ||
|
||||
req.cookies?.auth ||
|
||||
req.headers?.authorization
|
||||
const token = getTokenByRequest(req)
|
||||
|
||||
let claims
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ import { webhooksServiceRouter } from './routers/svc/webhooks'
|
|||
import { textToSpeechRouter } from './routers/text_to_speech'
|
||||
import { userRouter } from './routers/user_router'
|
||||
import { sentryConfig } from './sentry'
|
||||
import { getClaimsByToken } from './utils/auth'
|
||||
import { getClaimsByToken, getTokenByRequest } from './utils/auth'
|
||||
import { corsConfig } from './utils/corsConfig'
|
||||
import { buildLogger, buildLoggerTransport } from './utils/logger'
|
||||
|
||||
|
|
@ -102,19 +102,12 @@ export const createApp = (): {
|
|||
windowMs: 60 * 1000, // 1 minute
|
||||
max: async (req) => {
|
||||
// 100 RPM for an authenticated request, 5 for a non-authenticated request
|
||||
const token = await getClaimsByToken(
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
||||
req.header('authorization') ?? req.cookies['auth']
|
||||
)
|
||||
return token ? 100 : 5
|
||||
const token = getTokenByRequest(req)
|
||||
const claims = await getClaimsByToken(token)
|
||||
return claims ? 100 : 5
|
||||
},
|
||||
keyGenerator: (req) => {
|
||||
return (
|
||||
req.header('authorization') ||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
||||
(req.cookies['auth'] as string) ||
|
||||
req.ip
|
||||
)
|
||||
return getTokenByRequest(req) || req.ip
|
||||
},
|
||||
// skip preflight requests and test requests
|
||||
skip: (req) => req.method === 'OPTIONS' || env.dev.isLocal,
|
||||
|
|
|
|||
|
|
@ -1,13 +1,15 @@
|
|||
import * as bcrypt from 'bcryptjs'
|
||||
import { v4 as uuidv4 } from 'uuid'
|
||||
import { Claims, ClaimsToSet } from '../resolvers/types'
|
||||
import { getRepository } from '../entity/utils'
|
||||
import { ApiKey } from '../entity/api_key'
|
||||
import crypto from 'crypto'
|
||||
import * as jwt from 'jsonwebtoken'
|
||||
import { env } from '../env'
|
||||
import express from 'express'
|
||||
import * as jwt from 'jsonwebtoken'
|
||||
import { promisify } from 'util'
|
||||
import { v4 as uuidv4 } from 'uuid'
|
||||
import { ApiKey } from '../entity/api_key'
|
||||
import { getRepository } from '../entity/utils'
|
||||
import { env } from '../env'
|
||||
import { Claims, ClaimsToSet } from '../resolvers/types'
|
||||
|
||||
export const OmnivoreAuthorizationHeader = 'Omnivore-Authorization'
|
||||
|
||||
const signToken = promisify(jwt.sign)
|
||||
|
||||
|
|
@ -112,3 +114,12 @@ export const setAuthInCookie = async (
|
|||
expires: new Date(new Date().getTime() + 365 * 24 * 60 * 60 * 1000),
|
||||
})
|
||||
}
|
||||
|
||||
export const getTokenByRequest = (req: express.Request): string | undefined => {
|
||||
return (
|
||||
req.header(OmnivoreAuthorizationHeader) ||
|
||||
req.headers.authorization ||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
||||
(req.cookies?.auth as string)
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import {
|
|||
CreateLabelInput,
|
||||
} from '../generated/graphql'
|
||||
import { signFeatureToken } from '../services/features'
|
||||
import { generateVerificationToken } from './auth'
|
||||
import { generateVerificationToken, OmnivoreAuthorizationHeader } from './auth'
|
||||
import { CreateTaskError } from './errors'
|
||||
import { buildLogger } from './logger'
|
||||
import View = google.cloud.tasks.v2.Task.View
|
||||
|
|
@ -432,7 +432,7 @@ export const enqueueRecommendation = async (
|
|||
}
|
||||
|
||||
const headers = {
|
||||
Cookie: `auth=${authToken}`,
|
||||
[OmnivoreAuthorizationHeader]: authToken,
|
||||
}
|
||||
// If there is no Google Cloud Project Id exposed, it means that we are in local environment
|
||||
if (env.dev.isLocal || !GOOGLE_CLOUD_PROJECT) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue