Files
botpress--botpress/integrations/dropbox/src/setup.ts
T
2026-07-13 13:34:48 +08:00

141 lines
4.8 KiB
TypeScript

import * as sdk from '@botpress/sdk'
import { DropboxClient } from './dropbox-api'
import { getAuthorizationCode } from './dropbox-api/oauth-client'
import * as bp from '.botpress'
type RegisterProps = Parameters<bp.IntegrationProps['register']>[0]
export const register: bp.IntegrationProps['register'] = async (props) => {
if (await _isAlreadyAuthenticatedWithSameCredentials(props)) {
return
}
await _authenticate(props)
await _saveRegistrationDate(props)
}
export const unregister: bp.IntegrationProps['unregister'] = async () => {}
const _isAlreadyAuthenticatedWithSameCredentials = async (props: RegisterProps): Promise<boolean> => {
try {
const dropboxClient = await DropboxClient.create(props)
const authenticationSucceeded = await dropboxClient.isProperlyAuthenticated()
if (!authenticationSucceeded) {
return false
}
if (props.ctx.configurationType !== 'manual') {
return true
}
// For manual configurations, compare the authorization code from context with the one in state
const { state } = await props.client.getState({
type: 'integration',
id: props.ctx.integrationId,
name: 'authorization',
})
const currentAuthorizationCode = getAuthorizationCode({ ctx: props.ctx })
return state.payload.authorizationCode === currentAuthorizationCode
} catch {}
return false
}
const _authenticateWithRefreshToken = async (props: RegisterProps): Promise<boolean> => {
const dropboxClient = await DropboxClient.create(props)
return dropboxClient.isProperlyAuthenticated()
}
const _authenticateWithAuthorizationCode = async (props: RegisterProps): Promise<boolean> => {
const { logger } = props
await DropboxClient.processAuthorizationCode(props)
const dropboxClient = await DropboxClient.create(props)
const authenticated = await dropboxClient.isProperlyAuthenticated()
if (authenticated) {
logger.forBot().info('Successfully created Dropbox client from authorization code')
}
return authenticated
}
const _authenticateManual = async (props: RegisterProps): Promise<boolean> => {
const { ctx, logger } = props
const authorizationCode = getAuthorizationCode({ ctx })
if (!authorizationCode) {
logger.forBot().info('No authorization code provided, using existing refresh token from state')
return _authenticateWithRefreshToken(props).catch((err) => {
logger.forBot().warn({ err }, 'Failed to authenticate with existing refresh token')
return false
})
}
logger.forBot().info('Using authorization code from context')
let isAuthenticated = false
isAuthenticated = await _authenticateWithAuthorizationCode(props).catch((err) => {
logger?.forBot().warn({ err }, 'Failed to create Dropbox client from authorization code; falling back')
return false
})
if (!isAuthenticated) {
isAuthenticated = await _authenticateWithAuthorizationCode(props).catch((err) => {
logger.forBot().error({ err }, 'Failed to authenticate with fallback')
return false
})
}
return isAuthenticated
}
const _authenticateOAuth = async (props: RegisterProps): Promise<boolean> => {
const { logger } = props
logger.forBot().info('Using refresh token from state')
return _authenticateWithRefreshToken(props).catch((err) => {
logger.forBot().warn({ err }, 'Failed to authenticate with existing refresh token')
return false
})
}
const _getAuthFailureMessage = (configurationType: string): string => {
if (configurationType === 'manual') {
return (
'Dropbox authentication failed. ' +
'Please note that the Access Code is only valid for a few minutes. ' +
'You may need to reauthorize your Dropbox application by navigating ' +
"to the authorization URL and update the integration's config accordingly."
)
}
return (
'Dropbox authentication failed. ' +
'Please use the OAuth wizard to re-authenticate your Dropbox application. ' +
'You can access the wizard through the integration configuration page.'
)
}
const _authenticate = async (props: RegisterProps): Promise<void> => {
const { ctx, logger } = props
if (ctx.configurationType !== 'manual') {
const authenticationSucceeded = await _authenticateOAuth(props)
if (!authenticationSucceeded) {
logger.forBot().info('No existing OAuth credentials found. Please complete the OAuth wizard to authenticate.')
}
return
}
const authenticationSucceeded = await _authenticateManual(props)
if (!authenticationSucceeded) {
throw new sdk.RuntimeError(_getAuthFailureMessage(ctx.configurationType ?? ''))
}
}
const _saveRegistrationDate = async (props: RegisterProps): Promise<void> => {
await props.client.setState({
id: props.ctx.integrationId,
type: 'integration',
name: 'setupMeta',
payload: {
integrationRegisteredAt: new Date().toISOString(),
},
})
}