-
-
Notifications
You must be signed in to change notification settings - Fork 87
add WABA support #117
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
add WABA support #117
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -3,15 +3,19 @@ import { getConfig } from '../services/config' | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { SessionStore } from '../services/session_store' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import logger from '../services/logger' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { getAuthHeaderToken } from '../services/security' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { UNOAPI_AUTH_TOKEN } from '../defaults' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { UNOAPI_AUTH_TOKEN , WABA_ID , BUSINESS_ID } from '../defaults' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { setConfig } from '../services/redis' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { Reload } from '../services/reload' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export class PhoneNumberController { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private getConfig: getConfig | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private sessionStore: SessionStore | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private reload: Reload | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| constructor(getConfig: getConfig, sessionStore: SessionStore) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| constructor(getConfig: getConfig, sessionStore: SessionStore, reload: Reload) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| this.getConfig = getConfig | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| this.sessionStore = sessionStore | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| this.reload = reload | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public async get(req: Request, res: Response) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -66,4 +70,340 @@ export class PhoneNumberController { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return res.status(500).json({ status: 'error', message: e.message }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public async accounts(req: Request, res: Response) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| logger.debug('accounts method %s', req.method) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| logger.debug('headers %s', JSON.stringify(req.headers)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| logger.debug('params %s', JSON.stringify(req.params)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| logger.debug('query %s', JSON.stringify(req.query)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| logger.debug('PATH %s', JSON.stringify(req.path)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const token = getAuthHeaderToken(req) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const { fields } = req.query | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (fields && (fields as string).split(',').includes('owned_whatsapp_business_accounts') || req.path.endsWith('/owned_whatsapp_business_accounts')) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| logger.debug('Processing owned_whatsapp_business_accounts request') | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const phones = await this.sessionStore.getPhones() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const accounts: any[] = [] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for (let i = 0; i < phones.length; i++) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const number = phones[i] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const config = await this.getConfig(number) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (token === UNOAPI_AUTH_TOKEN || token === config.authToken) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| accounts.push({ id: WABA_ID }) // id = número | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| break | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Retorna no formato Graph API | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return res.status(200).json({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| id: WABA_ID, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| name: "UNOAPI WABA ACCOUNT", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| timezone_id: "America/Sao_Paulo", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| owned_whatsapp_business_accounts: { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| data: accounts, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (e) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return res.status(500).json({ status: 'error', message: e.message }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public async debugToken(req: Request, res: Response) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| logger.debug('debug_token method %s', req.method) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| logger.debug('headers %s', JSON.stringify(req.headers)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| logger.debug('params %s', JSON.stringify(req.params)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| logger.debug('query %s', JSON.stringify(req.query)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const inputToken = req.query.input_token as string | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const accessToken = req.query.access_token as string | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!inputToken || !accessToken) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return res.status(400).json({ error: 'Missing input_token or access_token' }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const phones = await this.sessionStore.getPhones() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let isValid = false | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let matchedConfig: any = null | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let appId: any | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let label: any | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for (let i = 0; i < phones.length; i++) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const phone = phones[i] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const config = await this.getConfig(phone) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (inputToken === config.authToken && accessToken === config.authToken) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| isValid = true | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| matchedConfig = config | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| label = config.label | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| appId = phone | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| break | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return res.status(200).json({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| data: { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| app_id: appId.replace('+', '') || "APP_ID_NOT_FOUND", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| type: "USER", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| application: "UNOAPI", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| data_access_expires_at: Math.floor(Date.now() / 1000) + 60 * 60 * 24 * 365, // +1 ano | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| expires_at: Math.floor(Date.now() / 1000) + 60 * 60 * 24 * 425, // +1 ano e 1 mês | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| is_valid: isValid, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| issued_at: Math.floor(Date.now() / 1000) - (60 * 60 * 24), // há 1 dia | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| scopes: [ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "whatsapp_business_management", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "whatsapp_business_messaging", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "business_management", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "whatsapp_business_manage_events" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| user_id: matchedConfig ? appId.replace('+', '') || "single_user" : "global_user" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (e: any) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| logger.error('Error in debug_token: ' + e.message) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return res.status(500).json({ status: 'error', message: e.message }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public async waba(req: Request, res: Response) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| logger.debug('headers %s', JSON.stringify(req.headers)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| logger.debug('params %s', JSON.stringify(req.params)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| logger.debug('query %s', JSON.stringify(req.query)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| logger.debug('path %s', req.path) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const token = getAuthHeaderToken(req) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const { waba_id } = req.params | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const phones = await this.sessionStore.getPhones() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const foundConfigs: any[] = [] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for (const number of phones) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const config = await this.getConfig(number) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (token === config.authToken) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| foundConfigs.push({ ...config, number }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (foundConfigs.length === 0) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return res.status(403).json({ error: 'Invalid or unauthorized token' }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+173
to
+194
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Validate waba_id parameter against WABA_ID constant. The method extracts Consider adding validation after line 181: if (waba_id !== WABA_ID) {
return res.status(404).json({ error: 'WABA ID not found' })
}🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let response: any = {} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // 🔹 Caso: rota de listagem de números | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (req.path.endsWith('/phone_numbers')) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| logger.debug('Processing PHONE_NUMBERS request') | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const numbersData = foundConfigs.map(cfg => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const webhookUrl = | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Array.isArray(cfg.webhooks) && cfg.webhooks.length > 0 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ? cfg.webhooks[0].urlAbsolute | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| : null | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| id: cfg.number.replace('+', ''), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| display_phone_number: cfg.number.replace('+', ''), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| verified_name: String(cfg.label || 'WhatsApp Account').toUpperCase(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| quality_rating: 'GREEN', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| code_verification_status: 'VERIFIED', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| new_name_status: 'APPROVED', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| is_pin_enabled: false, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| throughput: {level:'TIER_1'}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| platform_type: 'BUSINESS', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| status: 'CONNECTED', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| webhook_configuration: {application: webhookUrl ? webhookUrl: ''}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| response = { data: numbersData } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // 🔹 Caso: informações gerais do WABA | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| else { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| logger.debug('Processing generic WABA info request') | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const firstCfg = foundConfigs[0] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| response = { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| id: waba_id, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| name: String(firstCfg.label || 'UNOAPI WABA ACCOUNT').toUpperCase(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| currency: 'BRL', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| timezone_id: 42, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| message_template_namespace: firstCfg.label.slice(0, 10), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| primary_business_location: { country: 'BR' }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| creation_time: new Date().toISOString(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| tier: 'TIER_1', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+227
to
+241
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add null safety for label access. Line 236 accesses Apply this diff: - message_template_namespace: firstCfg.label.slice(0, 10),
+ message_template_namespace: (firstCfg.label || 'UNOAPI').slice(0, 10),📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return res.status(200).json(response) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (e: any) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| logger.error('Erro em WABA:', e) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return res.status(500).json({ status: 'error', message: e.message }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public async getsubs(req: Request, res: Response) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| logger.debug('get subscriptions -> headers %s', JSON.stringify(req.headers)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| logger.debug('get subscriptions -> params %s', JSON.stringify(req.params)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| logger.debug('get subscriptions -> query %s', JSON.stringify(req.query)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| logger.debug('get subscriptions -> path %s', req.path) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const { phone } = req.params | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const accessToken = req.query.access_token as string | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Verificação básica | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!accessToken || !accessToken.includes('|')) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return res.status(400).json({ error: 'Access token inválido ou ausente' }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const [appId, userToken] = accessToken.split('|') | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (appId !== phone) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return res.status(403).json({ error: 'appId não corresponde ao número de telefone' }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+262
to
+270
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add safer token parsing with error handling. The token split at line 266 assumes exactly two parts, but doesn't handle cases where the token might contain multiple pipe characters or be malformed in other ways. Apply this diff: // Verificação básica
if (!accessToken || !accessToken.includes('|')) {
return res.status(400).json({ error: 'Access token inválido ou ausente' })
}
const [appId, userToken] = accessToken.split('|')
+
+ if (!appId || !userToken) {
+ return res.status(400).json({ error: 'Access token mal formatado' })
+ }
if (appId !== phone) {📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Obter a configuração do número | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const config = await this.getConfig(phone) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!config) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return res.status(404).json({ error: 'Número não encontrado' }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Validar token | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (userToken !== config.authToken && userToken !== UNOAPI_AUTH_TOKEN) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return res.status(403).json({ error: 'Token inválido para este número' }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Procurar webhook da Meta | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const webhooks = config.webhooks || [] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const metaWebhook = webhooks.find((w: any) => w.id === 'metaId') | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Se não houver webhook "metaId", retorna vazio | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!metaWebhook) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| logger.debug(`Nenhum webhook metaId encontrado para ${phone}`) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return res.status(200).json({ data: [] }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Montar resposta no formato esperado da Graph API | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const response = { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| data: [ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| object: 'whatsapp_business_account', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| id: metaWebhook.id, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| callback_url: metaWebhook.urlAbsolute, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fields: [{name:"UNOAPI",version:"20.0"}], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| active: true, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| verification_token: metaWebhook.token, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| webhook_format: 'json' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return res.status(200).json(response) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (e: any) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| logger.error('Erro em getsubs:', e) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return res.status(500).json({ status: 'error', message: e.message }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public async addsubs(req: Request, res: Response) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| logger.info('POST SUBS -> headers %s', JSON.stringify(req.headers)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| logger.info('POST SUBS -> params %s', JSON.stringify(req.params)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| logger.info('POST SUBS -> body %s', JSON.stringify(req.body)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| logger.info('POST SUBS -> query %s', JSON.stringify(req.query)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| logger.info('POST SUBS -> path %s', req.path) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const { phone } = req.params | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const config = await this.getConfig(phone) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const accessToken = req.query.access_token as string | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const body = req.body || {} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const [appId, userToken] = accessToken.split('|') | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // --- Validações --- | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!config) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return res.status(404).json({ error: 'Número não encontrado' }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!accessToken || !accessToken.includes('|')) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return res.status(400).json({ error: 'Access token inválido ou ausente' }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (appId !== phone || userToken !== config.authToken) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return res.status(403).json({ error: 'appId ou Token não corresponde' }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+326
to
+339
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add safer token parsing and align validation with getsubs. Two issues:
Apply this diff: const accessToken = req.query.access_token as string
const body = req.body || {}
- const [appId, userToken] = accessToken.split('|')
// --- Validações ---
if (!config) {
return res.status(404).json({ error: 'Número não encontrado' })
}
if (!accessToken || !accessToken.includes('|')) {
return res.status(400).json({ error: 'Access token inválido ou ausente' })
}
- if (appId !== phone || userToken !== config.authToken) {
+
+ const [appId, userToken] = accessToken.split('|')
+ if (!appId || !userToken) {
+ return res.status(400).json({ error: 'Access token mal formatado' })
+ }
+ if (appId !== phone || (userToken !== config.authToken && userToken !== UNOAPI_AUTH_TOKEN)) {
return res.status(403).json({ error: 'appId ou Token não corresponde' })
}🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| object, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fields, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| callback_url, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| verify_token | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } = body | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!callback_url || !verify_token) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return res.status(400).json({ error: 'callback_url e verify_token são obrigatórios' }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // --- 🔄 criar ou atualizar webhook "metaId" --- | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const newWebhook = { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| sendNewMessages: true, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| id: 'metaId', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| urlAbsolute: callback_url, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| token: verify_token, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| header: 'Authorization', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| sendGroupMessages: false, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| sendNewsletterMessages: false, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| sendOutgoingMessages: true, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| sendUpdateMessages: true, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| sendIncomingMessages: true, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| sendTranscribeAudio: false, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| url:"http://localhost:9876/webhooks/fake", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| addToBlackListOnOutgoingMessageWithTtl:0, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| timeoutMs:360000 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+353
to
+368
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove hard-coded localhost URL and make webhook configuration more flexible. Line 365 contains a hard-coded At minimum, apply this diff to remove the hard-coded URL: const newWebhook = {
sendNewMessages: true,
id: 'metaId',
urlAbsolute: callback_url,
token: verify_token,
header: 'Authorization',
sendGroupMessages: false,
sendNewsletterMessages: false,
sendOutgoingMessages: true,
sendUpdateMessages: true,
sendIncomingMessages: true,
sendTranscribeAudio: false,
- url:"http://localhost:9876/webhooks/fake",
addToBlackListOnOutgoingMessageWithTtl:0,
timeoutMs:360000
}Consider whether other hard-coded boolean flags should be derived from the 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const webhooks = config.webhooks || [] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const index = webhooks.findIndex((w: any) => w.id === 'metaId') | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (index >= 0) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| webhooks[index] = { ...webhooks[index], ...newWebhook } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| logger.info(`Webhook metaId atualizado para ${phone}`) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| webhooks.push(newWebhook) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| logger.info(`Webhook metaId adicionado para ${phone}`) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Merge config | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const mergedConfig = { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ...config, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| webhooks, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| logger.info('POST SUBS -> MERGED CONFIG ---------------- %s', JSON.stringify(mergedConfig)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // save config updated | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await setConfig(phone, mergedConfig) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| this.reload.run(phone) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return res.status(200).json({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| success: true, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| data: { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| object: object || 'whatsapp_business_account', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| callback_url, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fields: fields || 'messages', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| active: true, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| verify_token, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (e: any) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| logger.error('Erro em addsubs:', e) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return res.status(500).json({ status: 'error', message: e.message }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -67,6 +67,8 @@ export const WEBHOOK_SESSION = process.env.WEBHOOK_SESSION || '' | |
| export const AMQP_URL = process.env.AMQP_URL || 'amqp://guest:guest@localhost:5672' | ||
| export const REDIS_URL = process.env.REDIS_URL || 'redis://localhost:6379' | ||
| export const PROXY_URL = process.env.PROXY_URL | ||
| export const BUSINESS_ID = process.env.FB_ID || 'FB_UNOAPI' | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chainConsider aligning the environment variable name with the constant name. The environment variable
Consider renaming the environment variable to -export const BUSINESS_ID = process.env.FB_ID || 'FB_UNOAPI'
+// Maps to FB_ID environment variable for backward compatibility
+export const BUSINESS_ID = process.env.FB_ID || 'FB_UNOAPI'To verify whether this default value is validated elsewhere in the codebase: 🏁 Script executed: #!/bin/bash
# Search for validation or usage of BUSINESS_ID to confirm if the default is safe
rg -n --type=ts -C3 'BUSINESS_ID' -g '!src/defaults.ts'Length of output: 1666 🏁 Script executed: #!/bin/bash
# Search for validation of these environment variables or constants
rg -n --type=ts 'FB_ID|validate|process.env' src/defaults.ts -A 2 -B 2Length of output: 13763 🏁 Script executed: #!/bin/bash
# Search for any validation or checks on BUSINESS_ID or WABA_ID values in the entire codebase
rg -n --type=ts '(BUSINESS_ID|WABA_ID|FB_ID)' -C 2 | rg -i 'validate|check|if.*BUSINESS_ID|if.*WABA_ID|if.*FB_ID' -C 3Length of output: 0 🏁 Script executed: #!/bin/bash
# Check if there's a config validation file or startup validation
fd -e ts -g '*valid*' -g '*config*' -g '*startup*' -g '*init*' | head -20Length of output: 204 🏁 Script executed: #!/bin/bash
# Look for comments explaining BUSINESS_ID usage
rg -n --type=ts 'BUSINESS_ID.*COMPATIBILITY|BUSINESS.*ID' -B 3 -A 3Length of output: 4612 🏁 Script executed: #!/bin/bash
# Check the entire defaults.ts file to understand the context and patterns
cat src/defaults.tsLength of output: 15456 Add a comment explaining the naming mismatch and compatibility route purpose. The environment variable Suggested change: -export const BUSINESS_ID = process.env.FB_ID || 'FB_UNOAPI'
-export const WABA_ID = process.env.WABA_ID || 'WABA_UNOAPI'
+// Routes identifiers for backward compatibility; FB_ID env var controls BUSINESS_ID for legacy naming reasons
+export const BUSINESS_ID = process.env.FB_ID || 'FB_UNOAPI'
+export const WABA_ID = process.env.WABA_ID || 'WABA_UNOAPI'🤖 Prompt for AI Agents |
||
| export const WABA_ID = process.env.WABA_ID || 'WABA_UNOAPI' | ||
|
|
||
| // behavior of unoapi | ||
| export const UNOAPI_SERVER_NAME = process.env.UNOAPI_SERVER_NAME || 'server_1' | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix operator precedence in condition.
The condition has a precedence issue. The
||operator has lower precedence than the method call, so the current logic evaluates as(fields && fields.split(...).includes(...)) || (req.path.endsWith(...)), but the split could fail iffieldsis not a string.Apply this diff:
📝 Committable suggestion
🤖 Prompt for AI Agents