mirror of
https://github.com/farcasclaudiu/Flowise.git
synced 2026-06-28 09:00:52 +03:00
Chore/refractor (#4454)
* markdown files and env examples cleanup * components update * update jsonlines description * server refractor * update telemetry * add execute custom node * add ui refractor * add username and password authenticate * correctly retrieve past images in agentflowv2 * disable e2e temporarily * add existing username and password authenticate * update migration to default workspace * update todo * blob storage migrating * throw error on agent tool call error * add missing execution import * add referral * chore: add error message when importData is undefined * migrate api keys to db * fix: data too long for column executionData * migrate api keys from json to db at init * add info on account setup * update docstore missing fields --------- Co-authored-by: chungyau97 <chungyau97@gmail.com>
This commit is contained in:
@@ -1,10 +1,14 @@
|
||||
import { randomBytes, scryptSync, timingSafeEqual } from 'crypto'
|
||||
import { ICommonObject } from 'flowise-components'
|
||||
import moment from 'moment'
|
||||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
import logger from './logger'
|
||||
import { appConfig } from '../AppConfig'
|
||||
import { DataSource } from 'typeorm'
|
||||
import { ApiKey } from '../database/entities/ApiKey'
|
||||
import { Workspace } from '../enterprise/database/entities/workspace.entity'
|
||||
import { v4 as uuidv4 } from 'uuid'
|
||||
import { ChatFlow } from '../database/entities/ChatFlow'
|
||||
import { addChatflowsCount } from './addChatflowsCount'
|
||||
import { Platform } from '../Interface'
|
||||
|
||||
/**
|
||||
* Returns the api key path
|
||||
@@ -51,94 +55,14 @@ export const compareKeys = (storedKey: string, suppliedKey: string): boolean =>
|
||||
* @returns {Promise<ICommonObject[]>}
|
||||
*/
|
||||
export const getAPIKeys = async (): Promise<ICommonObject[]> => {
|
||||
if (appConfig.apiKeys.storageType !== 'json') {
|
||||
return []
|
||||
}
|
||||
try {
|
||||
const content = await fs.promises.readFile(getAPIKeyPath(), 'utf8')
|
||||
return JSON.parse(content)
|
||||
} catch (error) {
|
||||
const keyName = 'DefaultKey'
|
||||
const apiKey = generateAPIKey()
|
||||
const apiSecret = generateSecretHash(apiKey)
|
||||
const content = [
|
||||
{
|
||||
keyName,
|
||||
apiKey,
|
||||
apiSecret,
|
||||
createdAt: moment().format('DD-MMM-YY'),
|
||||
id: randomBytes(16).toString('hex')
|
||||
}
|
||||
]
|
||||
await fs.promises.writeFile(getAPIKeyPath(), JSON.stringify(content), 'utf8')
|
||||
return content
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add new API key
|
||||
* @param {string} keyName
|
||||
* @returns {Promise<ICommonObject[]>}
|
||||
*/
|
||||
export const addAPIKey = async (keyName: string): Promise<ICommonObject[]> => {
|
||||
const existingAPIKeys = await getAPIKeys()
|
||||
const apiKey = generateAPIKey()
|
||||
const apiSecret = generateSecretHash(apiKey)
|
||||
const content = [
|
||||
...existingAPIKeys,
|
||||
{
|
||||
keyName,
|
||||
apiKey,
|
||||
apiSecret,
|
||||
createdAt: moment().format('DD-MMM-YY'),
|
||||
id: randomBytes(16).toString('hex')
|
||||
}
|
||||
]
|
||||
await fs.promises.writeFile(getAPIKeyPath(), JSON.stringify(content), 'utf8')
|
||||
return content
|
||||
}
|
||||
|
||||
/**
|
||||
* import API keys
|
||||
* @param {[]} keys
|
||||
* @returns {Promise<ICommonObject[]>}
|
||||
*/
|
||||
export const importKeys = async (keys: any[], importMode: string): Promise<ICommonObject[]> => {
|
||||
const allApiKeys = await getAPIKeys()
|
||||
// if importMode is errorIfExist, check for existing keys and raise error before any modification to the file
|
||||
if (importMode === 'errorIfExist') {
|
||||
for (const key of keys) {
|
||||
const keyNameExists = allApiKeys.find((k) => k.keyName === key.keyName)
|
||||
if (keyNameExists) {
|
||||
throw new Error(`Key with name ${key.keyName} already exists`)
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const key of keys) {
|
||||
// Check if keyName already exists, if overwrite is false, raise an error else overwrite the key
|
||||
const keyNameExists = allApiKeys.find((k) => k.keyName === key.keyName)
|
||||
if (keyNameExists) {
|
||||
const keyIndex = allApiKeys.findIndex((k) => k.keyName === key.keyName)
|
||||
switch (importMode) {
|
||||
case 'overwriteIfExist':
|
||||
allApiKeys[keyIndex] = key
|
||||
continue
|
||||
case 'ignoreIfExist':
|
||||
// ignore this key and continue
|
||||
continue
|
||||
case 'errorIfExist':
|
||||
// should not reach here as we have already checked for existing keys
|
||||
throw new Error(`Key with name ${key.keyName} already exists`)
|
||||
default:
|
||||
throw new Error(`Unknown overwrite option ${importMode}`)
|
||||
}
|
||||
}
|
||||
allApiKeys.push(key)
|
||||
}
|
||||
await fs.promises.writeFile(getAPIKeyPath(), JSON.stringify(allApiKeys), 'utf8')
|
||||
return allApiKeys
|
||||
}
|
||||
|
||||
/**
|
||||
* Get API Key details
|
||||
* @param {string} apiKey
|
||||
@@ -151,42 +75,82 @@ export const getApiKey = async (apiKey: string) => {
|
||||
return existingAPIKeys[keyIndex]
|
||||
}
|
||||
|
||||
/**
|
||||
* Update existing API key
|
||||
* @param {string} keyIdToUpdate
|
||||
* @param {string} newKeyName
|
||||
* @returns {Promise<ICommonObject[]>}
|
||||
*/
|
||||
export const updateAPIKey = async (keyIdToUpdate: string, newKeyName: string): Promise<ICommonObject[]> => {
|
||||
const existingAPIKeys = await getAPIKeys()
|
||||
const keyIndex = existingAPIKeys.findIndex((key) => key.id === keyIdToUpdate)
|
||||
if (keyIndex < 0) return []
|
||||
existingAPIKeys[keyIndex].keyName = newKeyName
|
||||
await fs.promises.writeFile(getAPIKeyPath(), JSON.stringify(existingAPIKeys), 'utf8')
|
||||
return existingAPIKeys
|
||||
}
|
||||
export const migrateApiKeysFromJsonToDb = async (appDataSource: DataSource, platformType: Platform) => {
|
||||
if (platformType === Platform.CLOUD) {
|
||||
return
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete API key
|
||||
* @param {string} keyIdToDelete
|
||||
* @returns {Promise<ICommonObject[]>}
|
||||
*/
|
||||
export const deleteAPIKey = async (keyIdToDelete: string): Promise<ICommonObject[]> => {
|
||||
const existingAPIKeys = await getAPIKeys()
|
||||
const result = existingAPIKeys.filter((key) => key.id !== keyIdToDelete)
|
||||
await fs.promises.writeFile(getAPIKeyPath(), JSON.stringify(result), 'utf8')
|
||||
return result
|
||||
}
|
||||
if (!process.env.APIKEY_STORAGE_TYPE || process.env.APIKEY_STORAGE_TYPE === 'json') {
|
||||
const keys = await getAPIKeys()
|
||||
if (keys.length > 0) {
|
||||
try {
|
||||
// Get all available workspaces
|
||||
const workspaces = await appDataSource.getRepository(Workspace).find()
|
||||
|
||||
/**
|
||||
* Replace all api keys
|
||||
* @param {ICommonObject[]} content
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
export const replaceAllAPIKeys = async (content: ICommonObject[]): Promise<void> => {
|
||||
try {
|
||||
await fs.promises.writeFile(getAPIKeyPath(), JSON.stringify(content), 'utf8')
|
||||
} catch (error) {
|
||||
logger.error(error)
|
||||
for (const key of keys) {
|
||||
const existingKey = await appDataSource.getRepository(ApiKey).findOneBy({
|
||||
apiKey: key.apiKey
|
||||
})
|
||||
|
||||
// Only add if key doesn't already exist in DB
|
||||
if (!existingKey) {
|
||||
// Create a new API key for each workspace
|
||||
if (workspaces.length > 0) {
|
||||
for (const workspace of workspaces) {
|
||||
const newKey = new ApiKey()
|
||||
newKey.id = uuidv4()
|
||||
newKey.apiKey = key.apiKey
|
||||
newKey.apiSecret = key.apiSecret
|
||||
newKey.keyName = key.keyName
|
||||
newKey.workspaceId = workspace.id
|
||||
|
||||
const keyEntity = appDataSource.getRepository(ApiKey).create(newKey)
|
||||
await appDataSource.getRepository(ApiKey).save(keyEntity)
|
||||
|
||||
const chatflows = await appDataSource.getRepository(ChatFlow).findBy({
|
||||
apikeyid: key.id,
|
||||
workspaceId: workspace.id
|
||||
})
|
||||
|
||||
for (const chatflow of chatflows) {
|
||||
chatflow.apikeyid = newKey.id
|
||||
await appDataSource.getRepository(ChatFlow).save(chatflow)
|
||||
}
|
||||
|
||||
await addChatflowsCount(chatflows)
|
||||
}
|
||||
} else {
|
||||
// If no workspaces exist, create the key without a workspace ID and later will be updated by setNullWorkspaceId
|
||||
const newKey = new ApiKey()
|
||||
newKey.id = uuidv4()
|
||||
newKey.apiKey = key.apiKey
|
||||
newKey.apiSecret = key.apiSecret
|
||||
newKey.keyName = key.keyName
|
||||
|
||||
const keyEntity = appDataSource.getRepository(ApiKey).create(newKey)
|
||||
await appDataSource.getRepository(ApiKey).save(keyEntity)
|
||||
|
||||
const chatflows = await appDataSource.getRepository(ChatFlow).findBy({
|
||||
apikeyid: key.id
|
||||
})
|
||||
|
||||
for (const chatflow of chatflows) {
|
||||
chatflow.apikeyid = newKey.id
|
||||
await appDataSource.getRepository(ChatFlow).save(chatflow)
|
||||
}
|
||||
|
||||
await addChatflowsCount(chatflows)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Delete the JSON file
|
||||
if (fs.existsSync(getAPIKeyPath())) {
|
||||
fs.unlinkSync(getAPIKeyPath())
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error migrating API keys from JSON to DB', error)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user