Verify api key for routers too

This commit is contained in:
Hongbo Wu 2022-05-28 22:00:01 +08:00
parent 6e16631f3b
commit c0bb67a6b5
4 changed files with 42 additions and 27 deletions

View file

@ -5,7 +5,7 @@
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
/* eslint-disable @typescript-eslint/require-await */
import { ContextFunction } from 'apollo-server-core'
import { Claims, ClaimsToSet, ResolverContext } from './resolvers/types'
import { ClaimsToSet, ResolverContext } from './resolvers/types'
import { SetClaimsRole } from './utils/dictionary'
import Knex, { Transaction } from 'knex'
import { ExpressContext } from 'apollo-server-express/dist/ApolloServer'
@ -24,7 +24,7 @@ import ScalarResolvers from './scalars'
import * as Sentry from '@sentry/node'
import { createPubSubClient } from './datalayer/pubsub'
import { initModels } from './server'
import { claimsFromApiKey } from './utils/auth'
import { getClaimsByToken } from './utils/auth'
const signToken = promisify(jwt.sign)
const logger = buildLogger('app.dispatch')
@ -39,28 +39,13 @@ const contextFunc: ContextFunction<ExpressContext, ResolverContext> = async ({
req,
res,
}) => {
let claims: Claims | undefined
const token = req?.cookies?.auth || req?.headers?.authorization
logger.info(`handling gql request`, {
query: req.body.query,
variables: req.body.variables,
})
if (token) {
try {
jwt.verify(token, env.server.jwtSecret) &&
(claims = jwt.decode(token) as Claims)
} catch (e) {
if (e instanceof jwt.JsonWebTokenError) {
logger.info(`not a jwt token, checking api key`, { token })
claims = await claimsFromApiKey(token)
} else {
throw e
}
}
}
const token = req?.cookies?.auth || req?.headers?.authorization
const claims = await getClaimsByToken(token)
async function setClaims(
tx: Transaction,

View file

@ -6,13 +6,12 @@ import express from 'express'
import { CreateArticleErrorCode } from './../generated/graphql'
import { isSiteBlockedForParse } from './../utils/blocked'
import cors from 'cors'
import { env } from './../env'
import { buildLogger } from './../utils/logger'
import * as jwt from 'jsonwebtoken'
import { corsConfig } from '../utils/corsConfig'
import { createPageSaveRequest } from '../services/create_page_save_request'
import { initModels } from '../server'
import { kx } from '../datalayer/knex_config'
import { getClaimsByToken } from '../utils/auth'
const logger = buildLogger('app.dispatch')
@ -26,11 +25,12 @@ export function articleRouter() {
}
const token = req?.cookies?.auth || req?.headers?.authorization
if (!token || !jwt.verify(token, env.server.jwtSecret)) {
return res.status(401).send({ errorCode: 'UNAUTHORIZED' })
const claims = await getClaimsByToken(token)
if (!claims) {
return res.status(401).send('UNAUTHORIZED')
}
const { uid } = (jwt.decode(token) || {}) as { uid: string }
const { uid } = claims
logger.info('Article saving request', {
body: req.body,

View file

@ -1,6 +1,5 @@
import express from 'express'
import { env } from '../../env'
import * as jwt from 'jsonwebtoken'
import { PageType, UploadFileStatus } from '../../generated/graphql'
import {
generateUploadFilePathName,
@ -17,6 +16,7 @@ import { generateSlug } from '../../utils/helpers'
import { createPubSubClient } from '../../datalayer/pubsub'
import { ArticleSavingRequestStatus, Page } from '../../elastic/types'
import { createPage } from '../../elastic/pages'
import { getClaimsByToken } from '../../utils/auth'
export function pdfAttachmentsRouter() {
const router = express.Router()
@ -31,7 +31,7 @@ export function pdfAttachmentsRouter() {
}
const token = req?.headers?.authorization
if (!token || !jwt.verify(token, env.server.jwtSecret)) {
if (!(await getClaimsByToken(token))) {
return res.status(401).send('UNAUTHORIZED')
}
@ -94,7 +94,7 @@ export function pdfAttachmentsRouter() {
}
const token = req?.headers?.authorization
if (!token || !jwt.verify(token, env.server.jwtSecret)) {
if (!(await getClaimsByToken(token))) {
return res.status(401).send('UNAUTHORIZED')
}

View file

@ -4,6 +4,8 @@ import { Claims } 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'
export const hashPassword = async (password: string, salt = 10) => {
return bcrypt.hash(password, salt)
@ -49,3 +51,31 @@ export const claimsFromApiKey = async (key: string): Promise<Claims> => {
exp,
}
}
// verify jwt token first
// if valid then decode and return claims
// if expired then throw error
// if not valid then verify api key
export const getClaimsByToken = async (
token: string | undefined
): Promise<Claims | undefined> => {
let claims: Claims | undefined
if (!token) {
return undefined
}
try {
jwt.verify(token, env.server.jwtSecret) &&
(claims = jwt.decode(token) as Claims)
} catch (e) {
if (e instanceof jwt.JsonWebTokenError) {
console.log(`not a jwt token, checking api key`, { token })
claims = await claimsFromApiKey(token)
} else {
throw e
}
}
return claims
}