refactor: Provide pubKey in context to avoid API calls

This commit is contained in:
Moriz Wahl 2021-09-27 19:04:27 +02:00
parent 9211f52d7f
commit d86a3dee42
9 changed files with 35 additions and 23 deletions

View File

@ -15,7 +15,8 @@ export const isAuthorized: AuthChecker<any> = async ({ root, args, context, info
`${CONFIG.LOGIN_API_URL}checkSessionState?session_id=${decoded.sessionId}`,
)
context.sessionId = decoded.sessionId
context.setHeaders.push({ key: 'token', value: encode(decoded.sessionId) })
context.pubKey = decoded.pubKey
context.setHeaders.push({ key: 'token', value: encode(decoded.sessionId, decoded.pubKey) })
return result.success
}
}

View File

@ -2,9 +2,7 @@
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
import { Resolver, Query, Ctx, Authorized } from 'type-graphql'
import CONFIG from '../../config'
import { Balance } from '../models/Balance'
import { apiGet } from '../../apis/HttpRequest'
import { User as dbUser } from '../../typeorm/entity/User'
import { Balance as dbBalance } from '../../typeorm/entity/Balance'
import calculateDecay from '../../util/decay'
@ -15,20 +13,14 @@ export class BalanceResolver {
@Authorized()
@Query(() => Balance)
async balance(@Ctx() context: any): Promise<Balance> {
// get public key for current logged in user
const result = await apiGet(CONFIG.LOGIN_API_URL + 'login?session_id=' + context.sessionId)
if (!result.success) throw new Error(result.data)
// load user and balance
const userEntity = await dbUser.findByPubkeyHex(result.data.user.public_hex)
const userEntity = await dbUser.findByPubkeyHex(context.pubKey)
const balanceEntity = await dbBalance.findByUser(userEntity.id)
const now = new Date()
const balance = new Balance({
return new Balance({
balance: roundFloorFrom4(balanceEntity.amount),
decay: roundFloorFrom4(calculateDecay(balanceEntity.amount, balanceEntity.recordDate, now)),
decay_date: now.toString(),
})
return balance
}
}

View File

@ -18,18 +18,14 @@ export class GdtResolver {
{ currentPage = 1, pageSize = 5, order = 'DESC' }: GdtTransactionSessionIdInput,
@Ctx() context: any,
): Promise<GdtEntryList> {
// get public key for current logged in user
const result = await apiGet(CONFIG.LOGIN_API_URL + 'login?session_id=' + context.sessionId)
if (!result.success) throw new Error(result.data)
// load user
const userEntity = await dbUser.findByPubkeyHex(result.data.user.public_hex)
const userEntity = await dbUser.findByPubkeyHex(context.pubKey)
const resultGDT = await apiGet(
`${CONFIG.GDT_API_URL}/GdtEntries/listPerEmailApi/${userEntity.email}/${currentPage}/${pageSize}/${order}`,
)
if (!resultGDT.success) {
throw new Error(result.data)
throw new Error(resultGDT.data)
}
return new GdtEntryList(resultGDT.data)

View File

@ -22,6 +22,7 @@ import {
klicktippNewsletterStateMiddleware,
} from '../../middleware/klicktippMiddleware'
import { CheckEmailResponse } from '../models/CheckEmailResponse'
@Resolver()
export class UserResolver {
@Query(() => User)
@ -35,7 +36,10 @@ export class UserResolver {
throw new Error(result.data)
}
context.setHeaders.push({ key: 'token', value: encode(result.data.session_id) })
context.setHeaders.push({
key: 'token',
value: encode(result.data.session_id, result.data.user.public_hex),
})
return new User(result.data.user)
}

View File

@ -1,18 +1,26 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
import jwt from 'jsonwebtoken'
import jwt, { JwtPayload } from 'jsonwebtoken'
import CONFIG from '../config/'
interface CustomJwtPayload extends JwtPayload {
sessionId: number
pubKey: Buffer
}
export default (token: string): any => {
if (!token) return new Error('401 Unauthorized')
let sessionId = null
let pubKey = null
try {
const decoded = jwt.verify(token, CONFIG.JWT_SECRET)
sessionId = decoded.sub
const decoded = <CustomJwtPayload>jwt.verify(token, CONFIG.JWT_SECRET)
sessionId = decoded.sessionId
pubKey = decoded.pubKey
return {
token,
sessionId,
pubKey,
}
} catch (err) {
throw new Error('403.13 - Client certificate revoked')

View File

@ -5,8 +5,8 @@ import jwt from 'jsonwebtoken'
import CONFIG from '../config/'
// Generate an Access Token
export default function encode(sessionId: string): string {
const token = jwt.sign({ sessionId }, CONFIG.JWT_SECRET, {
export default function encode(sessionId: number, pubKey: Buffer): string {
const token = jwt.sign({ sessionId, pubKey }, CONFIG.JWT_SECRET, {
expiresIn: CONFIG.JWT_EXPIRES_IN,
subject: sessionId.toString(),
})

View File

@ -1,3 +1,6 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
const context = (args: any) => {
const authorization = args.req.headers.authorization
let token = null

View File

@ -1,3 +1,6 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
const plugins = [
{
requestDidStart() {

View File

@ -1,6 +1,8 @@
import { BaseEntity, Entity, PrimaryGeneratedColumn, Column } from 'typeorm'
// import { Group } from "./Group"
// Moriz: I do not like the idea of having two user tables
@Entity('state_users')
export class User extends BaseEntity {
@PrimaryGeneratedColumn()
@ -27,6 +29,9 @@ export class User extends BaseEntity {
@Column()
disabled: boolean
// Moriz: I am voting for the data mapper implementation.
// see: https://typeorm.io/#/active-record-data-mapper/what-is-the-data-mapper-pattern
// We should discuss this ASAP
static findByPubkeyHex(pubkeyHex: string): Promise<User> {
return this.createQueryBuilder('user')
.where('hex(user.pubkey) = :pubkeyHex', { pubkeyHex })