🔥 Remove streamer Pages API endpoint
This commit is contained in:
@ -6,7 +6,7 @@ import {
|
||||
StripeCredentials,
|
||||
} from '@typebot.io/schemas'
|
||||
import Stripe from 'stripe'
|
||||
import { decrypt } from '@typebot.io/lib/api/encryption'
|
||||
import { decrypt } from '@typebot.io/lib/api/encryption/decrypt'
|
||||
import { parseVariables } from '../../../variables/parseVariables'
|
||||
import prisma from '@typebot.io/lib/prisma'
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { TRPCError } from '@trpc/server'
|
||||
import { env } from '@typebot.io/env'
|
||||
import { decrypt, encrypt } from '@typebot.io/lib/api/encryption'
|
||||
import { encrypt } from '@typebot.io/lib/api/encryption/encrypt'
|
||||
import { decrypt } from '@typebot.io/lib/api/encryption/decrypt'
|
||||
import { isDefined } from '@typebot.io/lib/utils'
|
||||
import { GoogleSheetsCredentials } from '@typebot.io/schemas/features/blocks/integrations/googleSheets/schemas'
|
||||
import { Credentials as CredentialsFromDb } from '@typebot.io/prisma'
|
||||
|
@ -1,6 +1,7 @@
|
||||
import {
|
||||
Block,
|
||||
BubbleBlockType,
|
||||
Credentials,
|
||||
SessionState,
|
||||
TypebotInSession,
|
||||
} from '@typebot.io/schemas'
|
||||
@ -10,7 +11,7 @@ import {
|
||||
chatCompletionMessageRoles,
|
||||
} from '@typebot.io/schemas/features/blocks/integrations/openai'
|
||||
import { byId, isEmpty } from '@typebot.io/lib'
|
||||
import { decrypt, isCredentialsV2 } from '@typebot.io/lib/api/encryption'
|
||||
import { decrypt } from '@typebot.io/lib/api/encryption/decrypt'
|
||||
import { resumeChatCompletion } from './resumeChatCompletion'
|
||||
import { parseChatCompletionMessages } from './parseChatCompletionMessages'
|
||||
import { executeChatCompletionOpenAIRequest } from './executeChatCompletionOpenAIRequest'
|
||||
@ -167,3 +168,6 @@ const getNextBlock =
|
||||
)
|
||||
: connectedGroup?.blocks.at(0)
|
||||
}
|
||||
|
||||
const isCredentialsV2 = (credentials: Pick<Credentials, 'iv'>) =>
|
||||
credentials.iv.length === 24
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Connection } from '@planetscale/database'
|
||||
import { decrypt } from '@typebot.io/lib/api/encryption'
|
||||
import { decryptV2 } from '@typebot.io/lib/api/encryption/decryptV2'
|
||||
import { isNotEmpty } from '@typebot.io/lib/utils'
|
||||
import {
|
||||
ChatCompletionOpenAIOptions,
|
||||
@ -27,7 +27,7 @@ export const getChatCompletionStream =
|
||||
console.error('Could not find credentials in database')
|
||||
return
|
||||
}
|
||||
const { apiKey } = (await decrypt(
|
||||
const { apiKey } = (await decryptV2(
|
||||
credentials.data,
|
||||
credentials.iv
|
||||
)) as OpenAICredentials['data']
|
||||
|
@ -13,7 +13,7 @@ import { createTransport } from 'nodemailer'
|
||||
import Mail from 'nodemailer/lib/mailer'
|
||||
import { byId, isDefined, isEmpty, isNotDefined, omit } from '@typebot.io/lib'
|
||||
import { getDefinedVariables, parseAnswers } from '@typebot.io/lib/results'
|
||||
import { decrypt } from '@typebot.io/lib/api'
|
||||
import { decrypt } from '@typebot.io/lib/api/encryption/decrypt'
|
||||
import { defaultFrom, defaultTransportOptions } from './constants'
|
||||
import { findUniqueVariableValue } from '../../../variables/findUniqueVariableValue'
|
||||
import { env } from '@typebot.io/env'
|
||||
|
@ -5,7 +5,7 @@ import {
|
||||
ZemanticAiResponse,
|
||||
} from '@typebot.io/schemas/features/blocks/integrations/zemanticAi'
|
||||
import got from 'got'
|
||||
import { decrypt } from '@typebot.io/lib/api/encryption'
|
||||
import { decrypt } from '@typebot.io/lib/api/encryption/decrypt'
|
||||
import { byId, isDefined, isEmpty } from '@typebot.io/lib'
|
||||
import { getDefinedVariables, parseAnswers } from '@typebot.io/lib/results'
|
||||
import prisma from '@typebot.io/lib/prisma'
|
||||
|
@ -8,7 +8,7 @@ import { sendChatReplyToWhatsApp } from './sendChatReplyToWhatsApp'
|
||||
import { startWhatsAppSession } from './startWhatsAppSession'
|
||||
import { getSession } from '../queries/getSession'
|
||||
import { continueBotFlow } from '../continueBotFlow'
|
||||
import { decrypt } from '@typebot.io/lib/api'
|
||||
import { decrypt } from '@typebot.io/lib/api/encryption/decrypt'
|
||||
import { saveStateToDatabase } from '../saveStateToDatabase'
|
||||
import prisma from '@typebot.io/lib/prisma'
|
||||
import { isDefined } from '@typebot.io/lib/utils'
|
||||
|
@ -1,76 +0,0 @@
|
||||
import { Credentials } from '@typebot.io/schemas/features/credentials'
|
||||
import { decryptV1 } from './encryptionV1'
|
||||
import { env } from '@typebot.io/env'
|
||||
|
||||
const algorithm = 'AES-GCM'
|
||||
const secretKey = env.ENCRYPTION_SECRET
|
||||
|
||||
export const encrypt = async (
|
||||
data: object
|
||||
): Promise<{ encryptedData: string; iv: string }> => {
|
||||
if (!secretKey) throw new Error('ENCRYPTION_SECRET is not in environment')
|
||||
const iv = crypto.getRandomValues(new Uint8Array(12))
|
||||
const encodedData = new TextEncoder().encode(JSON.stringify(data))
|
||||
|
||||
const key = await crypto.subtle.importKey(
|
||||
'raw',
|
||||
new TextEncoder().encode(secretKey),
|
||||
algorithm,
|
||||
false,
|
||||
['encrypt']
|
||||
)
|
||||
|
||||
const encryptedBuffer = await crypto.subtle.encrypt(
|
||||
{ name: algorithm, iv },
|
||||
key,
|
||||
encodedData
|
||||
)
|
||||
|
||||
const encryptedData = btoa(
|
||||
String.fromCharCode.apply(null, Array.from(new Uint8Array(encryptedBuffer)))
|
||||
)
|
||||
|
||||
const ivHex = Array.from(iv)
|
||||
.map((byte) => byte.toString(16).padStart(2, '0'))
|
||||
.join('')
|
||||
|
||||
return {
|
||||
encryptedData,
|
||||
iv: ivHex,
|
||||
}
|
||||
}
|
||||
|
||||
export const decrypt = async (
|
||||
encryptedData: string,
|
||||
ivHex: string
|
||||
): Promise<object> => {
|
||||
if (ivHex.length !== 24) return decryptV1(encryptedData, ivHex)
|
||||
if (!secretKey) throw new Error('ENCRYPTION_SECRET is not in environment')
|
||||
const iv = new Uint8Array(
|
||||
ivHex.match(/.{1,2}/g)?.map((byte) => parseInt(byte, 16)) ?? []
|
||||
)
|
||||
|
||||
const key = await crypto.subtle.importKey(
|
||||
'raw',
|
||||
new TextEncoder().encode(secretKey),
|
||||
algorithm,
|
||||
false,
|
||||
['decrypt']
|
||||
)
|
||||
|
||||
const encryptedBuffer = new Uint8Array(
|
||||
Array.from(atob(encryptedData)).map((char) => char.charCodeAt(0))
|
||||
)
|
||||
|
||||
const decryptedBuffer = await crypto.subtle.decrypt(
|
||||
{ name: algorithm, iv },
|
||||
key,
|
||||
encryptedBuffer
|
||||
)
|
||||
|
||||
const decryptedData = new TextDecoder().decode(decryptedBuffer)
|
||||
return JSON.parse(decryptedData)
|
||||
}
|
||||
|
||||
export const isCredentialsV2 = (credentials: Pick<Credentials, 'iv'>) =>
|
||||
credentials.iv.length === 24
|
10
packages/lib/api/encryption/decrypt.ts
Normal file
10
packages/lib/api/encryption/decrypt.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import { decryptV1 } from './decryptV1'
|
||||
import { decryptV2 } from './decryptV2'
|
||||
|
||||
export const decrypt = async (
|
||||
encryptedData: string,
|
||||
ivHex: string
|
||||
): Promise<object> => {
|
||||
if (ivHex.length !== 24) return decryptV1(encryptedData, ivHex)
|
||||
return decryptV2(encryptedData, ivHex)
|
||||
}
|
35
packages/lib/api/encryption/decryptV2.ts
Normal file
35
packages/lib/api/encryption/decryptV2.ts
Normal file
@ -0,0 +1,35 @@
|
||||
import { env } from '@typebot.io/env'
|
||||
|
||||
const algorithm = 'AES-GCM'
|
||||
const secretKey = env.ENCRYPTION_SECRET
|
||||
|
||||
export const decryptV2 = async (
|
||||
encryptedData: string,
|
||||
ivHex: string
|
||||
): Promise<object> => {
|
||||
if (!secretKey) throw new Error('ENCRYPTION_SECRET is not in environment')
|
||||
const iv = new Uint8Array(
|
||||
ivHex.match(/.{1,2}/g)?.map((byte) => parseInt(byte, 16)) ?? []
|
||||
)
|
||||
|
||||
const key = await crypto.subtle.importKey(
|
||||
'raw',
|
||||
new TextEncoder().encode(secretKey),
|
||||
algorithm,
|
||||
false,
|
||||
['decrypt']
|
||||
)
|
||||
|
||||
const encryptedBuffer = new Uint8Array(
|
||||
Array.from(atob(encryptedData)).map((char) => char.charCodeAt(0))
|
||||
)
|
||||
|
||||
const decryptedBuffer = await crypto.subtle.decrypt(
|
||||
{ name: algorithm, iv },
|
||||
key,
|
||||
encryptedBuffer
|
||||
)
|
||||
|
||||
const decryptedData = new TextDecoder().decode(decryptedBuffer)
|
||||
return JSON.parse(decryptedData)
|
||||
}
|
39
packages/lib/api/encryption/encrypt.ts
Normal file
39
packages/lib/api/encryption/encrypt.ts
Normal file
@ -0,0 +1,39 @@
|
||||
import { env } from '@typebot.io/env'
|
||||
|
||||
const algorithm = 'AES-GCM'
|
||||
const secretKey = env.ENCRYPTION_SECRET
|
||||
|
||||
export const encrypt = async (
|
||||
data: object
|
||||
): Promise<{ encryptedData: string; iv: string }> => {
|
||||
if (!secretKey) throw new Error('ENCRYPTION_SECRET is not in environment')
|
||||
const iv = crypto.getRandomValues(new Uint8Array(12))
|
||||
const encodedData = new TextEncoder().encode(JSON.stringify(data))
|
||||
|
||||
const key = await crypto.subtle.importKey(
|
||||
'raw',
|
||||
new TextEncoder().encode(secretKey),
|
||||
algorithm,
|
||||
false,
|
||||
['encrypt']
|
||||
)
|
||||
|
||||
const encryptedBuffer = await crypto.subtle.encrypt(
|
||||
{ name: algorithm, iv },
|
||||
key,
|
||||
encodedData
|
||||
)
|
||||
|
||||
const encryptedData = btoa(
|
||||
String.fromCharCode.apply(null, Array.from(new Uint8Array(encryptedBuffer)))
|
||||
)
|
||||
|
||||
const ivHex = Array.from(iv)
|
||||
.map((byte) => byte.toString(16).padStart(2, '0'))
|
||||
.join('')
|
||||
|
||||
return {
|
||||
encryptedData,
|
||||
iv: ivHex,
|
||||
}
|
||||
}
|
@ -1,2 +1 @@
|
||||
export * from './utils'
|
||||
export * from './encryption'
|
||||
|
@ -4,7 +4,7 @@ import {
|
||||
PrismaClient,
|
||||
WorkspaceRole,
|
||||
} from '@typebot.io/prisma'
|
||||
import { encrypt } from '../api'
|
||||
import { encrypt } from '../api/encryption/encrypt'
|
||||
|
||||
const prisma = new PrismaClient()
|
||||
|
||||
|
Reference in New Issue
Block a user