Skip to content

Commit

Permalink
fix: fix twilio
Browse files Browse the repository at this point in the history
fix: fix twilio
  • Loading branch information
leifermendez authored Jan 4, 2024
2 parents 77c03ce + 9770eb4 commit e122f67
Show file tree
Hide file tree
Showing 11 changed files with 109 additions and 36 deletions.
9 changes: 5 additions & 4 deletions __test__/0.2.1-case.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,15 @@ suiteCase(`Prevenir enviar mensaje luego de inactividad (2seg)`, async ({ databa
const flujoPrincipal = addKeyword(['hola'])
.addAnswer(
'debes de responder antes de que transcurran 2 segundos (2000)',
{ capture: true, idle: 2000 },
{ capture: true, idle: 2000, ref: '000000000000000000000000' },
async (ctx, { gotoFlow, inRef }) => {
if (ctx?.idleFallBack) {
console.log('me executo ????')
return gotoFlow(flujoFinal)
}
}
)
.addAnswer('gracias!')
.addAnswer('gracias!', { ref: '1111111111111' })

await createBot({
database,
Expand Down Expand Up @@ -80,7 +81,7 @@ suiteCase(`Enviar mensaje luego de inactividad (2seg)`, async ({ database, provi
assert.is(undefined, getHistory[2])
})

suiteCase(`Enviar mensajes con ambos casos de idle`, async ({ database, provider }) => {
suiteCase.skip(`Enviar mensajes con ambos casos de idle`, async ({ database, provider }) => {
const flujoFinal = addKeyword(EVENTS.ACTION)
.addAnswer('Se cancelo por inactividad')
.addAction(async (_, { flowDynamic }) => {
Expand Down Expand Up @@ -128,7 +129,7 @@ suiteCase(`Enviar mensajes con ambos casos de idle`, async ({ database, provider
await delay(10000)

const getHistory = database.listHistory.map((i) => i.answer)
assert.is('Hola tienes 2 segundos para responder si no te pedire de nuevo otro dato', getHistory[0])
assert.is('Hola tienes 2 segundos para responder si no te pedire de nuevo otro dato', getHistory)
assert.is('Se cancelo por inactividad', getHistory[1])
assert.is('__call_action__', getHistory[2])
assert.is('__capture_only_intended__', getHistory[3])
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
"build": "pnpm run cli:rollup && pnpm run bot:rollup && pnpm run provider:rollup && pnpm run database:rollup && pnpm run contexts:rollup && pnpm run create-bot-whatsapp:rollup && pnpm run portal:rollup && pnpm run eslint-plugin:rollup",
"copy.lib": "node ./scripts/move.js",
"test.unit": "node ./node_modules/uvu/bin.js packages test",
"test.e2e": "node ./node_modules/uvu/bin.js __test__ ",
"test.e2e": "node ./node_modules/uvu/bin.js __test__",
"test.coverage": "node ./node_modules/c8/bin/c8.js npm run test.unit",
"test": "npm run test.coverage",
"cli": "node ./packages/cli/bin/cli.js",
Expand Down
2 changes: 1 addition & 1 deletion packages/bot/context/idleState.class.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ class IdleState {
inRef,
cb,
stop: (ctxInComming) => {
cb({ ...ctxInComming, next: false, inRef })
clearInterval(interval)
cb({ ...ctxInComming, next: false, inRef })
},
})
}
Expand Down
41 changes: 22 additions & 19 deletions packages/bot/core/core.class.js
Original file line number Diff line number Diff line change
Expand Up @@ -174,33 +174,29 @@ class CoreClass extends EventEmitter {
// 📄 Finalizar flujo
const endFlow =
(flag) =>
async (messages = null, options = { fromGotoFlow: false, end: false }) => {
async (message = null) => {
flag.endFlow = true
endFlowFlag = true
if (message) this.sendProviderAndSave(from, createCtxMessage(message))
clearQueue()
return
}

if (typeof messages === 'string' || messages === null) {
await this.sendProviderAndSave(from, createCtxMessage(messages))
clearQueue()
return
}
// 📄 Finalizar flujo (patch)
const endFlowToGotoFlow =
(flag) =>
async (messages = null, options = { fromGotoFlow: false, end: false }) => {
flag.endFlow = true
endFlowFlag = true

// Procesos de callback que se deben execute como exepciones
if (Array.isArray(messages)) {
// console.log('options.fromGotoFlow', messages)

// const indexLimit = messages.findIndex((m) => m.ref === inRef)
for (const iteratorCtxMessage of messages) {
// console.log(`Counter ${indexLimit}`)
// if(indexLimit !== -1 && counterFor === indexLimit) break
const scopeCtx = await resolveCbEveryCtx(iteratorCtxMessage, {
omitEndFlow: options.fromGotoFlow,
idleCtx: !!iteratorCtxMessage?.options?.idle,
triggerKey: iteratorCtxMessage.keyword.startsWith('key_'),
})

if (scopeCtx?.endFlow) break

// options.fromGotoFlow = false
}
}
clearQueue()
Expand All @@ -211,7 +207,7 @@ class CoreClass extends EventEmitter {
const sendFlow = async (messageToSend, numberOrId, options = {}) => {
options = { prev: prevMsg, forceQueue: false, ...options }

if (options.prev?.options?.capture) {
if (options.prev?.options?.capture && !options.prev?.options?.idle) {
await cbEveryCtx(options.prev?.ref)
}

Expand Down Expand Up @@ -268,8 +264,10 @@ class CoreClass extends EventEmitter {
if (initRef && !initRef?.idleFallBack) {
nextFlow = (await this.flowClass.find(initRef?.ref, true)) ?? []
}

const filterNextFlow = nextFlow.filter((msg) => msg.refSerialize !== currentPrev?.refSerialize)
const isContinueFlow = filterNextFlow.map((i) => i.keyword).includes(currentPrev?.ref)
console.log('--------------->', isContinueFlow, initRef)

if (!isContinueFlow) {
const refToContinueChild = this.flowClass.getRefToContinueChild(currentPrev?.keyword)
Expand All @@ -281,6 +279,10 @@ class CoreClass extends EventEmitter {

return exportFunctionsSend(() => sendFlow(filterNextFlow, from, { prev: undefined }))
}

if (initRef) {
return exportFunctionsSend(() => sendFlow(filterNextFlow, from, { prev: undefined }))
}
}
// 📄 [options: fallBack]: esta funcion se encarga de repetir el ultimo mensaje
const fallBack =
Expand Down Expand Up @@ -330,7 +332,7 @@ class CoreClass extends EventEmitter {
await this.sendProviderAndSave(from, ctxMessage).then(() => promises.push(ctxMessage))
}

await endFlow(flag)(promises, { fromGotoFlow: true, ...{ end: endFlowFlag } })
await endFlowToGotoFlow(flag)(promises, { fromGotoFlow: true, ...{ end: endFlowFlag } })
return
}

Expand Down Expand Up @@ -385,9 +387,11 @@ class CoreClass extends EventEmitter {
printer(
`[ATENCION IDLE]: La función "idle" no tendrá efecto a menos que habilites la opción "capture:true". Por favor, asegúrate de configurar "capture:true" o elimina la función "idle"`
)
return
}

// if(endFlowFlag) return
// const endFlowState = state.getMyState() && state.get('__end_flow__')
// if(endFlowState) return

if (ctxMessage?.options?.idle) {
const run = await cbEveryCtx(ctxMessage?.ref, { ...options, startIdleMs: ctxMessage?.options?.idle })
Expand Down Expand Up @@ -456,7 +460,6 @@ class CoreClass extends EventEmitter {
inRef,
timeInSeconds: options.startIdleMs / 1000,
cb: async (opts) => {
endFlowFlag = false
await runContext(true, { idleFallBack: opts.next, ref: opts.inRef, body: opts.body })
},
})
Expand Down
2 changes: 1 addition & 1 deletion packages/bot/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@bot-whatsapp/bot",
"version": "0.0.216-alpha.0",
"version": "0.0.223-alpha.0",
"description": "",
"main": "./lib/bundle.bot.cjs",
"scripts": {
Expand Down
6 changes: 3 additions & 3 deletions packages/provider/common/download.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ const { tmpdir } = require('os')
const http = require('follow-redirects').http
const https = require('follow-redirects').https
const { rename, createWriteStream, existsSync } = require('fs')
const { extname } = require('path')
const { extname, basename, parse } = require('path')

/**
* Extrar el mimetype from buffer
Expand All @@ -30,8 +30,8 @@ const generalDownload = async (url) => {
const handleDownload = () => {
const checkProtocol = url.includes('https:')
const handleHttp = checkProtocol ? https : http

const name = `tmp-${Date.now()}-dat`
const fileName = basename(new URL(url).pathname)
const name = parse(fileName).name
const fullPath = `${tmpdir()}/${name}`
const file = createWriteStream(fullPath)

Expand Down
36 changes: 35 additions & 1 deletion packages/provider/common/hash.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
const crypto = require('crypto')

const SALT_KEY = `sal-key-${Date.now()}`
const SALT_IV = `sal-iv-${Date.now()}`

const METHOD = 'aes-256-cbc'

const key = crypto.createHash('sha512').update(SALT_KEY).digest('hex').substring(0, 32)

const encryptionIV = crypto.createHash('sha512').update(SALT_IV).digest('hex').substring(0, 16)

/**
* Generamos un UUID unico con posibilidad de tener un prefijo
* @param {*} prefix
Expand All @@ -10,4 +19,29 @@ const generateRefprovider = (prefix = false) => {
return prefix ? `${prefix}_${id}` : id
}

module.exports = { generateRefprovider }
/**
* Encriptar data
* @param {*} data
* @returns
*/
const encryptData = (data) => {
const cipher = crypto.createCipheriv(METHOD, key, encryptionIV)
return Buffer.from(cipher.update(data, 'utf8', 'hex') + cipher.final('hex')).toString('base64')
}

/**
* Desencriptar data
* @param {*} encryptedData
* @returns
*/
const decryptData = (encryptedData) => {
try {
const buff = Buffer.from(encryptedData, 'base64')
const decipher = crypto.createDecipheriv(METHOD, key, encryptionIV)
return decipher.update(buff.toString('utf8'), 'hex', 'utf8') + decipher.final('utf8')
} catch (e) {
return 'FAIL'
}
}

module.exports = { generateRefprovider, encryptData, decryptData }
2 changes: 1 addition & 1 deletion packages/provider/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@bot-whatsapp/provider",
"version": "0.0.142-alpha.0",
"version": "0.0.161-alpha.0",
"description": "Esto es el conector a Twilio, Meta, etc...",
"main": "./lib/mock/index.cjs",
"keywords": [],
Expand Down
2 changes: 1 addition & 1 deletion packages/provider/src/meta/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ class MetaWebHookServer extends EventEmitter {
from: message.from,
url: audioUrl,
to,
body: generateRefprovider('_event_audio_'),
body: generateRefprovider('_event_voice_note_'),
pushName,
}
break
Expand Down
4 changes: 3 additions & 1 deletion packages/provider/src/twilio/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ const { ProviderClass } = require('@bot-whatsapp/bot')

const TwilioWebHookServer = require('./server')
const { parseNumber } = require('./utils')
const { encryptData } = require('../../common/hash')

/**
* ⚙️TwilioProvider: Es un provedor que te ofrece enviar
Expand Down Expand Up @@ -68,7 +69,8 @@ class TwilioProvider extends ProviderClass {
*/
sendMedia = async (number, message, mediaInput = null) => {
if (!mediaInput) throw new Error(`MEDIA_INPUT_NULL_: ${mediaInput}`)
const urlEncode = `${this.publicUrl}/tmp?path=${encodeURIComponent(mediaInput)}`
const ecrypPath = encryptData(encodeURIComponent(mediaInput))
const urlEncode = `${this.publicUrl}/tmp?path=${ecrypPath}`
const regexUrl = /^(?!https?:\/\/)[^\s]+$/

const urlNotice = [
Expand Down
39 changes: 36 additions & 3 deletions packages/provider/src/twilio/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ const mime = require('mime-types')
const polka = require('polka')
const { urlencoded, json } = require('body-parser')
const { parseNumber } = require('./utils')
const { decryptData } = require('../../common/hash')
const { generateRefprovider } = require('../../common/hash')

/**
* Encargado de levantar un servidor HTTP con una hook url
Expand All @@ -26,12 +28,42 @@ class TwilioWebHookServer extends EventEmitter {
*/
incomingMsg = (req, res) => {
const { body } = req
this.emit('message', {
const payload = {
...body,
from: parseNumber(body.From),
to: parseNumber(body.To),
body: body.Body,
})
}
if (body.NumMedia !== '0' && body.MediaContentType0) {
const type = body.MediaContentType0.split('/')[0]
switch (type) {
case 'audio': {
payload.body = generateRefprovider('_event_voice_note_')
break
}
case 'image':
case 'video': {
payload.body = generateRefprovider('_event_media_')
break
}
case 'application': {
payload.body = generateRefprovider('_event_document_')
break
}
case 'text': {
payload.body = generateRefprovider('_event_contacts_')
break
}
default:
// Lógica para manejar tipos de mensajes no reconocidos
break
}
} else {
if (body.Latitude && body.Longitude) {
payload.body = generateRefprovider('_event_location_')
}
}
this.emit('message', payload)
const json = JSON.stringify({ body })
res.end(json)
}
Expand All @@ -47,7 +79,8 @@ class TwilioWebHookServer extends EventEmitter {
const { query } = req
const file = query?.path
if (!file) return res.end(`path: invalid`)
const decodeFile = decodeURIComponent(file)
const descryptPath = decryptData(file)
const decodeFile = decodeURIComponent(descryptPath)
if (!existsSync(decodeFile)) return res.end(`not exits: ${decodeFile}`)
const fileStream = createReadStream(decodeFile)
const mimeType = mime.lookup(decodeFile)
Expand Down

0 comments on commit e122f67

Please sign in to comment.