1
0
Fork 0
mirror of https://github.com/maybe-finance/maybe.git synced 2025-08-09 07:25:19 +02:00

fix failing integration tests

This commit is contained in:
Tyler Myracle 2024-01-18 01:53:00 -06:00
parent 2eed43f6e0
commit 6dd3110bb1
11 changed files with 53 additions and 64 deletions

View file

@ -85,7 +85,6 @@ export const authOptions = {
strategy: 'jwt' as SessionStrategy,
maxAge: 1 * 24 * 60 * 60, // 1 Day
},
providers: [
CredentialsProvider({
name: 'Credentials',

View file

@ -9,7 +9,6 @@ import {
} from '@maybe-finance/server/features'
import { InMemoryQueueFactory, PgService, type IQueueFactory } from '@maybe-finance/server/shared'
import { createLogger, transports } from 'winston'
import isCI from 'is-ci'
import nock from 'nock'
import Decimal from 'decimal.js'
import { startServer, stopServer } from './utils/server'
@ -27,7 +26,7 @@ const prisma = new PrismaClient()
// For TypeScript support
const plaid = jest.mocked(_plaid) // eslint-disable-line
const auth0Id = isCI ? 'auth0|61afd38f678a0c006895f046' : 'auth0|61afd340678a0c006895f000'
const authId = '__TEST_USER_ID__'
let axios: AxiosInstance
let user: User
@ -38,7 +37,7 @@ if (process.env.IS_VSCODE_DEBUG === 'true') {
beforeEach(async () => {
// Clears old user and data, creates new user
user = await resetUser(auth0Id)
user = await resetUser(authId)
})
describe('/v1/accounts API', () => {

View file

@ -2,7 +2,6 @@ import type { AxiosInstance } from 'axios'
import type { SharedType } from '@maybe-finance/shared'
import type { Prisma, AccountConnection, AccountSyncStatus, User } from '@prisma/client'
import type { ItemRemoveResponse } from 'plaid'
import isCI from 'is-ci'
import { startServer, stopServer } from './utils/server'
import { getAxiosClient } from './utils/axios'
import prisma from '../lib/prisma'
@ -18,7 +17,7 @@ jest.mock('plaid')
// For TypeScript support
const plaid = jest.mocked(_plaid)
const auth0Id = isCI ? 'auth0|61afd38f678a0c006895f046' : 'auth0|61afd340678a0c006895f000'
const authId = '__TEST_USER_ID__'
let axios: AxiosInstance
let user: User | null
let connection: AccountConnection
@ -45,7 +44,7 @@ afterAll(async () => {
})
beforeEach(async () => {
user = await resetUser(auth0Id)
user = await resetUser(authId)
connectionData = {
data: {

View file

@ -1,38 +1,37 @@
import type { AxiosResponse } from 'axios'
import type { SharedType } from '@maybe-finance/shared'
import { superjson } from '@maybe-finance/shared'
import env from '../../../env'
import isCI from 'is-ci'
import Axios from 'axios'
import { encode } from 'next-auth/jwt'
// Fetches Auth0 access token (JWT) and prepares Axios client to use it on each request
export async function getAxiosClient() {
const tenantUrl = isCI
? 'REPLACE_THIS-staging.us.auth0.com'
: 'REPLACE_THIS-development.us.auth0.com'
const {
data: { access_token: token },
} = await Axios.request({
method: 'POST',
url: `https://${tenantUrl}/oauth/token`,
headers: { 'content-type': 'application/json' },
data: {
grant_type: 'password',
username: 'REPLACE_THIS',
password: 'REPLACE_THIS',
audience: 'https://maybe-finance-api/v1',
scope: '',
client_id: isCI ? 'REPLACE_THIS' : 'REPLACE_THIS',
const baseUrl = 'http://127.0.0.1:53333/v1'
const jwt = await encode({
maxAge: 1 * 24 * 60 * 60,
secret: process.env.NEXTAUTH_SECRET || 'CHANGE_ME',
token: {
sub: '__TEST_USER_ID__',
user: '__TEST_USER_ID__',
'https://maybe.co/email': 'REPLACE_THIS',
firstName: 'REPLACE_THIS',
lastName: 'REPLACE_THIS',
name: 'REPLACE_THIS',
},
})
const defaultHeaders = {
'Content-Type': 'application/json',
'Access-Control-Allow-Credentials': true,
Authorization: `Bearer ${jwt}`,
}
const axiosOptions = {
baseURL: baseUrl,
headers: defaultHeaders,
}
const axios = Axios.create({
baseURL: 'http://127.0.0.1:53333/v1',
...axiosOptions,
validateStatus: () => true, // Tests should determine whether status is correct, not Axios
headers: {
Authorization: `Bearer ${token}`,
},
})
axios.interceptors.response.use((response: AxiosResponse<SharedType.BaseResponse>) => {

View file

@ -2,17 +2,20 @@ import cookieParser from 'cookie-parser'
import { decode } from 'next-auth/jwt'
const SECRET = process.env.NEXTAUTH_SECRET ?? 'REPLACE_THIS'
export const validateAuthJwt = async (req, res, next) => {
cookieParser(SECRET)(req, res, async (err) => {
if (err) {
return res.status(500).json({ message: 'Internal Server Error' })
}
if (req.cookies && 'next-auth.session-token' in req.cookies) {
const cookieName = req.secure
? '__Secure-next-auth.session-token'
: 'next-auth.session-token'
if (req.cookies && cookieName in req.cookies) {
try {
const token = await decode({
token: req.cookies['next-auth.session-token'],
token: req.cookies[cookieName],
secret: SECRET,
})
@ -26,6 +29,18 @@ export const validateAuthJwt = async (req, res, next) => {
console.error('Error in token validation', error)
return res.status(500).json({ message: 'Internal Server Error' })
}
} else if (req.headers.authorization) {
const token = req.headers.authorization.split(' ')[1]
const decoded = await decode({
token,
secret: SECRET,
})
if (decoded) {
req.user = decoded
return next()
} else {
return res.status(401).json({ message: 'Unauthorized' })
}
} else {
return res.status(401).json({ message: 'Unauthorized' })
}

View file

@ -48,8 +48,6 @@ const envSchema = z.object({
NX_SENTRY_DSN: z.string().optional(),
NX_SENTRY_ENV: z.string().optional(),
NX_LD_SDK_KEY: z.string().default('REPLACE_THIS'),
NX_POLYGON_API_KEY: z.string().default(''),
NX_PORT: z.string().default('3333'),

View file

@ -68,8 +68,8 @@ describe('Finicity', () => {
userId: user.id,
name: 'TEST_FINICITY',
type: 'finicity',
finicityInstitutionId: 'REPLACE_THIS',
finicityInstitutionLoginId: 'REPLACE_THIS',
finicityInstitutionId: '101732',
finicityInstitutionLoginId: '6000483842',
},
})

View file

@ -22,8 +22,6 @@ const envSchema = z.object({
NX_SENTRY_DSN: z.string().optional(),
NX_SENTRY_ENV: z.string().optional(),
NX_LD_SDK_KEY: z.string().default('REPLACE_THIS'),
NX_REDIS_URL: z.string().default('redis://localhost:6379'),
NX_POLYGON_API_KEY: z.string().default(''),

View file

@ -1,4 +1,4 @@
import crypto from 'crypto'
import CryptoJS from 'crypto-js'
export interface ICryptoService {
encrypt(plainText: string): string
@ -6,32 +6,13 @@ export interface ICryptoService {
}
export class CryptoService implements ICryptoService {
private key: Buffer
private ivLength = 16 // Initialization vector length. For AES, this is always 16
constructor(private readonly secret: string) {
// Ensure the key length is suitable for AES-256
this.key = crypto.createHash('sha256').update(String(this.secret)).digest()
}
constructor(private readonly secret: string) {}
encrypt(plainText: string) {
const iv = crypto.randomBytes(this.ivLength)
const cipher = crypto.createCipheriv('aes-256-cbc', this.key, iv)
let encrypted = cipher.update(plainText, 'utf8', 'hex')
encrypted += cipher.final('hex')
// Include the IV at the start of the encrypted result
return iv.toString('hex') + ':' + encrypted
return CryptoJS.AES.encrypt(plainText, this.secret).toString()
}
decrypt(encrypted: string) {
const textParts = encrypted.split(':')
const iv = Buffer.from(textParts.shift()!, 'hex')
const encryptedText = textParts.join(':')
const decipher = crypto.createDecipheriv('aes-256-cbc', this.key, iv)
let decrypted = decipher.update(encryptedText, 'hex', 'utf8')
decrypted += decipher.final('utf8')
return decrypted
return CryptoJS.AES.decrypt(encrypted, this.secret).toString(CryptoJS.enc.Utf8)
}
}

View file

@ -89,6 +89,7 @@
"bcrypt": "^5.1.1",
"bull": "^4.10.2",
"classnames": "^2.3.1",
"cookie": "^0.6.0",
"cookie-parser": "^1.4.6",
"core-js": "^3.6.5",
"cors": "^2.8.5",

View file

@ -7988,7 +7988,7 @@ cookie@0.5.0, cookie@^0.5.0:
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.5.0.tgz#d1f5d71adec6558c58f389987c366aa47e994f8b"
integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==
cookie@0.6.0:
cookie@0.6.0, cookie@^0.6.0:
version "0.6.0"
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.6.0.tgz#2798b04b071b0ecbff0dbb62a505a8efa4e19051"
integrity sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==