chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,140 @@
|
||||
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(),
|
||||
},
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user