Skip to content
This repository was archived by the owner on Nov 7, 2023. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
26f1b5d
configure and create phone-number-auth route
Jean1dev Sep 28, 2023
3f789dc
feat: send registration code to number and login with mobile number
Jean1dev Oct 9, 2023
58538fd
update postman collection
Jean1dev Oct 23, 2023
b686213
Delete yarn.lock
Jean1dev Nov 16, 2023
7b89d0e
Merge branch 'salman0ansari:main' into main
Jean1dev Nov 20, 2023
30a44dd
Update instance.controller.js
Jean1dev Feb 19, 2024
3c9d486
v1 auditoria
Jean1dev Mar 19, 2024
46019c9
auditoria controller
Jean1dev Mar 20, 2024
51dc33b
Merge branch 'main' into auditoria-de-mensagens
Jean1dev Mar 20, 2024
d877464
Merge pull request #1 from Jean1dev/auditoria-de-mensagens
Jean1dev Mar 20, 2024
6786320
Update mongoAuthState.js
Jean1dev Mar 20, 2024
8007d90
crud ok, implementacao logica
Jean1dev Jul 10, 2024
ce990ea
mais typebot types
Jean1dev Jul 11, 2024
55302d3
Update instance.controller.js
Jean1dev Jul 12, 2024
3c77598
Merge pull request #2 from Jean1dev/typebot-integracao
Jean1dev Jul 17, 2024
a1d4e7f
Update package.json
Jean1dev Sep 17, 2024
a190d1e
Add handling for phone number input in TypeBot
Jean1dev Jan 15, 2025
aae9961
Enhance WhatsAppInstance to handle location messages and improve erro…
Jean1dev Jan 16, 2025
7f1d916
Refactor Dockerfile and enhance TypeBot error handling and message pr…
Jean1dev Jan 16, 2025
ee8a06e
Merge pull request #3 from Jean1dev/racli
Jean1dev Jan 31, 2025
1428c59
Add Swagger documentation setup and update dependencies
Jean1dev Feb 3, 2025
7d3ecc9
Update swagger.js
Jean1dev Feb 3, 2025
bcb85ac
Add Swagger security definitions and contact information to API docum…
Jean1dev Feb 6, 2025
b7a8ad1
Merge pull request #4 from Jean1dev/swagger
Jean1dev Feb 6, 2025
67da444
Add CORS middleware to Express configuration
Jean1dev May 14, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ CLIENT_VERSION='4.0.0'
# INSTANCE CONFIGURATION
# ==================================
INSTANCE_MAX_RETRY_QR=2
NATIVE_MOBILE_AUTH=false

# ==================================
# DATABASE CONFIGURATION
Expand Down
8 changes: 3 additions & 5 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,14 @@ FROM node:19-alpine

ARG _WORKDIR=/home/node/app
ARG PORT=3333

USER root
RUN apk add git
ENV MONGODB_URL=mongodb://mongo:27017/whatsapp_api

WORKDIR ${_WORKDIR}

ADD . ${_WORKDIR}
RUN yarn install
RUN npm install

USER node
EXPOSE ${PORT}

CMD yarn start
CMD ["npm", "start"]
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
# Maintained by Jeanlucafp
This API is a forked from @salman0ansari and maintained by me.

# Archive Notice 🔒
After three years, I've decided to archive this open-source WhatsApp API project. Your support and contributions have been incredible!

Expand Down
16 changes: 6 additions & 10 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ services:
mongodb:
container_name: mongodb
image: mongo:latest
restart: unless-stopped
ports:
- 27017:27017
volumes:
Expand All @@ -15,21 +14,18 @@ services:
context: .
dockerfile: Dockerfile
args:
- PORT=${PORT}
- PORT=3333
depends_on:
- mongodb
restart: unless-stopped
env_file: .env
ports:
- ${PORT}:${PORT}
- 3333:3333
environment:
- TOKEN=${TOKEN}
- PORT=${PORT}
- MONGODB_ENABLED=${MONGODB_ENABLED}
- PORT=3333
- MONGODB_ENABLED=true
- MONGODB_URL=mongodb://mongodb:27017
- WEBHOOK_ENABLED=${WEBHOOK_ENABLED}
- WEBHOOK_URL=${WEBHOOK_URL}
- WEBHOOK_BASE64=${WEBHOOK_BASE64}
- WEBHOOK_ENABLED=false
- LOG_LEVEL=trace
volumes:
- ./:/home/node/app
- /home/node/app/node_modules/
Expand Down
12 changes: 8 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,20 +32,24 @@
"author": "Mohd Salman Ansari <[email protected]>",
"license": "MIT",
"dependencies": {
"@whiskeysockets/baileys": "^6.1.0",
"@adiwajshing/keyed-db": "^0.2.4",
"@whiskeysockets/baileys": "^6.7.7",
"axios": "^1.1.3",
"cors": "^2.8.5",
"dotenv": "^16.0.3",
"ejs": "^3.1.7",
"express": "^4.18.2",
"express": "^4.21.0",
"express-exception-handler": "^1.3.23",
"libphonenumber-js": "^1.10.45",
"link-preview-js": "^3.0.0",
"mongodb": "^4.12.1",
"mongoose": "^6.7.4",
"multer": "^1.4.5-lts.1",
"pino": "^8.7.0",
"qrcode": "^1.5.1",
"sharp": "^0.30.5",
"sharp": "^0.32.6",
"swagger-jsdoc": "^6.2.8",
"swagger-ui-express": "^5.0.1",
"uuid": "^9.0.0"
},
"devDependencies": {
Expand All @@ -54,7 +58,7 @@
"husky": "^8.0.2",
"lint-staged": "^13.0.4",
"mocha": "^10.1.0",
"nodemon": "^2.0.20",
"nodemon": "^3.1.4",
"prettier": "^2.8.0",
"supertest": "^6.3.1"
}
Expand Down
100 changes: 100 additions & 0 deletions src/api/class/audit.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
const useMongoDBAuthState = require('../helper/mongoAuthState');
const logger = require('pino')()

function statusHandler(numberStatus) {
switch (numberStatus) {
case 1:
return 'pending'
case 3:
return 'played'
default:
return 'unknown'
}
}

class AuditMessageType {
constructor(data) {
this.key = data.key;
this.remoteJid = data.key.remoteJid;
this.identificator = data.id;
this.id = data.key.id;
this.messag = data.message;
this.status = statusHandler(data.status);
this.messageTimestamp = data.messageTimestamp;
}
}

class AuditMessages {
constructor(id) {
this.messages = [];
this.collectionName = 'audit_messages';
this.id = id;
}

find(query) {
const collection = mongoClient.db('whatsapp-api').collection(this.collectionName)
return useMongoDBAuthState(collection)
.then(({ find }) => {
return find(query)
})
}

findHistory(remoteJid) {
const findes = this.messages.filter(message => message.remoteJid === remoteJid)
if (findes.length > 0) {
return new Promise(resolve => resolve(findes))
}

const collection = mongoClient.db('whatsapp-api').collection(this.collectionName)
return useMongoDBAuthState(collection)
.then(({ find }) => {
return find({ remoteJid })
})
}

append(message) {
const messageStruct = new AuditMessageType({
key: message.key,
message: message.message,
status: message.status,
messageTimestamp: message.messageTimestamp,
id: this.id,
remoteJid: message.key.remoteJid,
});

const collection = mongoClient.db('whatsapp-api').collection(this.collectionName)
useMongoDBAuthState(collection)
.then(({ insertData }) => {
insertData(messageStruct)
.then((result) => {
logger.info('Audit message requested save saved', result)
this.messages.push(messageStruct);
})
})
}

update(message) {
const remoteJid = message?.key?.remoteJid
if (remoteJid) {
this.findHistory(remoteJid)
.then(entities => {
const collection = mongoClient.db('whatsapp-api').collection(this.collectionName)
const id = message.key.id;
entities.forEach(entitie => {
if (entitie.id === id) {
useMongoDBAuthState(collection).then(({ updateOne }) => {
updateOne(
{ id: entitie.id, remoteJid: entitie.remoteJid },
{ $set: { status: statusHandler(message.update.status), updateAt: new Date() } }
)
})

}

})
})
}
}
}

exports.AuditMessages = new AuditMessages();
104 changes: 96 additions & 8 deletions src/api/class/instance.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,9 @@ const pino = require('pino')
const {
default: makeWASocket,
DisconnectReason,
PHONENUMBER_MCC
} = require('@whiskeysockets/baileys')
const { unlinkSync } = require('fs')
const { v4: uuidv4 } = require('uuid')
const path = require('path')
const processButton = require('../helper/processbtn')
const generateVC = require('../helper/genVc')
const Chat = require('../models/chat.model')
Expand All @@ -16,11 +15,15 @@ const config = require('../../config/config')
const downloadMessage = require('../helper/downloadMsg')
const logger = require('pino')()
const useMongoDBAuthState = require('../helper/mongoAuthState')
const { AuditMessages } = require('./audit')
const libPhonenumber = require('libphonenumber-js')
const TypeBot = require('./typebot')

class WhatsAppInstance {
socketConfig = {
defaultQueryTimeoutMs: undefined,
printQRInTerminal: false,
mobile: config.instance.useMobileAuth,
logger: pino({
level: config.log.level,
}),
Expand All @@ -37,6 +40,7 @@ class WhatsAppInstance {
messages: [],
qrRetry: 0,
customWebhook: '',
typebot: null
}

axiosInstance = axios.create({
Expand Down Expand Up @@ -66,20 +70,27 @@ class WhatsAppInstance {
body,
instanceKey: key,
})
.catch(() => {})
.catch(() => { })
}

async init() {
this.collection = mongoClient.db('whatsapp-api').collection(this.key)
const { state, saveCreds } = await useMongoDBAuthState(this.collection)
this.authState = { state: state, saveCreds: saveCreds }
const { state, saveCreds, writeData } = await useMongoDBAuthState(this.collection)
this.authState = { state: state, saveCreds: saveCreds, writeData }
this.socketConfig.auth = this.authState.state
this.socketConfig.browser = Object.values(config.browser)
this.instance.sock = makeWASocket(this.socketConfig)
this.setHandler()
return this
}

async activeTypeBot(apiHost, typebotname, saveData = true) {
const typebot = new TypeBot(apiHost, typebotname, this)
this.instance.typebot = typebot
if (saveData)
await this.authState.writeData(typebot.getObjectToSave(), 'typebot')
}

setHandler() {
const sock = this.instance.sock
// on credentials update save state
Expand Down Expand Up @@ -302,13 +313,48 @@ class WhatsAppInstance {
)
)
await this.SendWebhook('message', webhookData, this.key)

if (this.instance.typebot) {
// extendedTextMessage quando recebe mensagem do web-whatsapp
if (messageType === 'extendedTextMessage') {
await this.instance.typebot.startTypebot({
message: msg.message.extendedTextMessage.text,
remoteJid: msg.key.remoteJid
})
}

// conversation quando recebe mensagem do celular
if (messageType === 'conversation') {
await this.instance.typebot.startTypebot({
message: msg.message.conversation,
remoteJid: msg.key.remoteJid
})
}

if (messageType === 'templateButtonReplyMessage') {
await this.instance.typebot.startTypebot({
message: TypeBot.giveMeTextButtonAndIGiveUId(msg.message.templateButtonReplyMessage.selectedDisplayText),
remoteJid: msg.key.remoteJid
})
}

if (messageType === 'locationMessage') {
const locationString = `${msg.message.locationMessage.degreesLatitude},${msg.message.locationMessage.degreesLongitude}`
await this.instance.typebot.startTypebot({
message: locationString,
remoteJid: msg.key.remoteJid
})
}
}
})
})

sock?.ev.on('messages.update', async (messages) => {
//console.log('messages.update')
//console.dir(messages);
messages.forEach(element => {
AuditMessages.update(element)
})
})

sock?.ws.on('CB:call', async (data) => {
if (data.content) {
if (data.content.find((e) => e.tag === 'offer')) {
Expand Down Expand Up @@ -429,6 +475,10 @@ class WhatsAppInstance {
phone_connected: this.instance?.online,
webhookUrl: this.instance.customWebhook,
user: this.instance?.online ? this.instance.sock?.user : {},
typebot: this.instance?.typebot ? {
apiHost: this.instance.typebot.apiHost,
typebotName: this.instance.typebot.typebotName,
} : {},
}
}

Expand Down Expand Up @@ -471,8 +521,9 @@ class WhatsAppInstance {
async sendUrlMediaFile(to, url, type, mimeType, caption = '') {
await this.verifyId(this.getWhatsAppId(to))

const receiver = this.getWhatsAppId(to)
const data = await this.instance.sock?.sendMessage(
this.getWhatsAppId(to),
receiver,
{
[type]: {
url: url,
Expand Down Expand Up @@ -1000,6 +1051,43 @@ class WhatsAppInstance {
logger.error('Error react message failed')
}
}

async enterRegistrationCode(code) {
const response = await this.instance.sock?.register(code.replace(/["']/g, '').trim().toLowerCase())
logger.info('Successfully registered your phone number.')
return response
}

async sendCodeRegistrationToWhatsappNumber(phoneNumber) {
const parsedNumber = libPhonenumber.parsePhoneNumberWithError(phoneNumber)
if (!parsedNumber.isValid()) {
throw new Error('Invalid phone number: ' + phoneNumber)
}

const registration = {}
registration.phoneNumber = parsedNumber.format('E.164')
registration.phoneNumberCountryCode = parsedNumber.countryCallingCode
registration.phoneNumberNationalNumber = parsedNumber.nationalNumber
const mcc = PHONENUMBER_MCC[parsedNumber.countryCallingCode]
if (!mcc) {
throw new Error('Could not find MCC for phone number: ' + phoneNumber + '\nPlease specify the MCC manually.')
}

registration.phoneNumberMobileCountryCode = mcc
registration.identityId = Buffer.from(registration.phoneNumber, 'utf-8')
registration.backupToken = Buffer.from('1243', 'utf-8')
await this.instance.sock?.requestRegistrationCode(registration)
}

async requestMobileAuthCode(phoneNumber) {
if (!config.instance.useMobileAuth) {
throw new Error('Cannot use pairing code with mobile api')
}
logger.info(`request pairing code for : ${phoneNumber}`)
const _code = await this.instance.sock?.requestPairingCode(phoneNumber)
logger.info(`Pairing code: ${_code}`)
return _code
}
}

exports.WhatsAppInstance = WhatsAppInstance
Loading