First version with multisessions

This commit is contained in:
allburov committed 2022-08-18 18:44:37 +03:00
1 parent ebf5532f27
commit aff6e78b36
14 files changed
+12656 -164

No files matched your search

+23 -23
View File
@@ -1,25 +1,25 @@
module.exports = {
parser: '@typescript-eslint/parser',
parserOptions: {
project: 'tsconfig.json',
sourceType: 'module',
},
plugins: ['@typescript-eslint/eslint-plugin'],
extends: [
'plugin:@typescript-eslint/eslint-recommended',
'plugin:@typescript-eslint/recommended',
'prettier',
'prettier/@typescript-eslint',
],
root: true,
env: {
node: true,
jest: true,
},
rules: {
'@typescript-eslint/interface-name-prefix': 'off',
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/no-explicit-any': 'off',
},
parser: '@typescript-eslint/parser',
parserOptions: {
project: 'tsconfig.json',
sourceType: 'module',
},
plugins: ['@typescript-eslint/eslint-plugin'],
extends: [
'plugin:@typescript-eslint/eslint-recommended',
'plugin:@typescript-eslint/recommended',
'prettier',
'prettier/@typescript-eslint',
],
root: true,
env: {
node: true,
jest: true,
},
rules: {
'@typescript-eslint/interface-name-prefix': 'off',
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/no-explicit-any': 'off',
},
};
+6 -2
View File
@@ -2,13 +2,17 @@
**NOTE**
If you have any problem with docker version of API - try to use the fork https://github.com/diazzaid/whatsapp-api-venom. It uses the latest Venom and probably works better. I haven't updated the venom here for a long time...
If you have any problem with docker version of API - try to use the fork https://github.com/diazzaid/whatsapp-api-venom.
It uses the latest Venom and probably works better. I haven't updated the venom here for a long time...
----------
WhatsApp HTTP API that you can configure in a click! It's really Free! :)
> The article [Make a WhatsApp Bot Via HTTP API For Free And Fun!](https://allburov.medium.com/make-a-whatsapp-bot-for-free-and-fun-via-http-api-b3e6afcdf395) on Medium about this repository.
> The
>
article [Make a WhatsApp Bot Via HTTP API For Free And Fun!](https://allburov.medium.com/make-a-whatsapp-bot-for-free-and-fun-via-http-api-b3e6afcdf395)
> on Medium about this repository.
You can go [through currently supported methods in Swagger](https://allburov.github.io/whatsapp-http-api/)
The project is an HTTP wrapper around https://github.com/orkestral/venom, so we can also support these methods:
+43 -46
View File
@@ -1,60 +1,57 @@
<!-- HTML for static distribution bundle build -->
<!DOCTYPE html>
<html lang="en">
<head>
<head>
<meta charset="UTF-8">
<title>allburov/whatsapp-http-api</title>
<link rel="stylesheet" type="text/css" href="./swagger-ui.css" >
<link rel="icon" type="image/png" href="./favicon-32x32.png" sizes="32x32" />
<link rel="icon" type="image/png" href="./favicon-16x16.png" sizes="16x16" />
<link href="./swagger-ui.css" rel="stylesheet" type="text/css">
<link href="./favicon-32x32.png" rel="icon" sizes="32x32" type="image/png"/>
<link href="./favicon-16x16.png" rel="icon" sizes="16x16" type="image/png"/>
<style>
html
{
box-sizing: border-box;
overflow: -moz-scrollbars-vertical;
overflow-y: scroll;
}
html {
box-sizing: border-box;
overflow: -moz-scrollbars-vertical;
overflow-y: scroll;
}
*,
*:before,
*:after
{
box-sizing: inherit;
}
*,
*:before,
*:after {
box-sizing: inherit;
}
body
{
margin:0;
background: #fafafa;
}
body {
margin: 0;
background: #fafafa;
}
</style>
</head>
</head>
<body>
<div id="swagger-ui"></div>
<body>
<div id="swagger-ui"></div>
<script src="./swagger-ui-bundle.js" charset="UTF-8"> </script>
<script src="./swagger-ui-standalone-preset.js" charset="UTF-8"> </script>
<script>
window.onload = function() {
// Begin Swagger UI call region
const ui = SwaggerUIBundle({
url: "openapi.json",
dom_id: '#swagger-ui',
deepLinking: true,
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIStandalonePreset
],
plugins: [
SwaggerUIBundle.plugins.DownloadUrl
],
layout: "StandaloneLayout"
})
// End Swagger UI call region
<script charset="UTF-8" src="./swagger-ui-bundle.js"></script>
<script charset="UTF-8" src="./swagger-ui-standalone-preset.js"></script>
<script>
window.onload = function () {
// Begin Swagger UI call region
const ui = SwaggerUIBundle({
url: "openapi.json",
dom_id: '#swagger-ui',
deepLinking: true,
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIStandalonePreset
],
plugins: [
SwaggerUIBundle.plugins.DownloadUrl
],
layout: "StandaloneLayout"
})
// End Swagger UI call region
window.ui = ui
window.ui = ui
}
</script>
</body>
</script>
</body>
</html>
+14 -11
View File
@@ -8,7 +8,8 @@
</html>
<script>
'use strict';
function run () {
function run() {
var oauth2 = window.opener.swaggerUIRedirectOauth2;
var sentState = oauth2.state;
var redirectUrl = oauth2.redirectUrl;
@@ -21,18 +22,20 @@
}
arr = qp.split("&")
arr.forEach(function (v,i,_arr) { _arr[i] = '"' + v.replace('=', '":"') + '"';})
arr.forEach(function (v, i, _arr) {
_arr[i] = '"' + v.replace('=', '":"') + '"';
})
qp = qp ? JSON.parse('{' + arr.join() + '}',
function (key, value) {
return key === "" ? value : decodeURIComponent(value)
}
function (key, value) {
return key === "" ? value : decodeURIComponent(value)
}
) : {}
isValid = qp.state === sentState
if ((
oauth2.auth.schema.get("flow") === "accessCode"||
oauth2.auth.schema.get("flow") === "authorizationCode"
oauth2.auth.schema.get("flow") === "accessCode" ||
oauth2.auth.schema.get("flow") === "authorizationCode"
) && !oauth2.auth.code) {
if (!isValid) {
oauth2.errCb({
@@ -50,9 +53,9 @@
} else {
let oauthErrorMsg
if (qp.error) {
oauthErrorMsg = "["+qp.error+"]: " +
(qp.error_description ? qp.error_description+ ". " : "no accessCode received from the server. ") +
(qp.error_uri ? "More info: "+qp.error_uri : "");
oauthErrorMsg = "[" + qp.error + "]: " +
(qp.error_description ? qp.error_description + ". " : "no accessCode received from the server. ") +
(qp.error_uri ? "More info: " + qp.error_uri : "");
}
oauth2.errCb({
@@ -69,6 +72,6 @@
}
window.addEventListener('DOMContentLoaded', function () {
run();
run();
});
</script>
+660 -1
View File
@@ -1 +1,660 @@
{"openapi":"3.0.0","info":{"title":"WhatsApp HTTP API","description":"WhatsApp HTTP API that you can configure in a click!","version":"1.0","contact":{}},"tags":[{"name":"device","description":"Device information"},{"name":"chatting","description":"Chat methods"}],"servers":[],"components":{"securitySchemes":{"api_key":{"type":"apiKey","in":"header","name":"X-VENOM-TOKEN","description":"Your secret key"}},"schemas":{"MessageContactVcard":{"type":"object","properties":{"chatId":{"type":"string","example":"791231234567@c.us"},"contactsId":{"type":"string"},"name":{"type":"string"}},"required":["chatId","contactsId","name"]},"MessageText":{"type":"object","properties":{"chatId":{"type":"string","example":"791231234567@c.us"},"text":{"type":"string"}},"required":["chatId","text"]},"MessageLocation":{"type":"object","properties":{"chatId":{"type":"string","example":"791231234567@c.us"},"latitude":{"type":"string"},"longitude":{"type":"string"},"title":{"type":"string"}},"required":["chatId","latitude","longitude","title"]},"MessageLinkPreview":{"type":"object","properties":{"chatId":{"type":"string","example":"791231234567@c.us"},"url":{"type":"string"},"title":{"type":"string"}},"required":["chatId","url","title"]},"MessageImage":{"type":"object","properties":{"chatId":{"type":"string","example":"791231234567@c.us"},"path":{"type":"string"},"filename":{"type":"string"},"caption":{"type":"string"}},"required":["chatId","path","filename","caption"]},"MessageFile":{"type":"object","properties":{"chatId":{"type":"string","example":"791231234567@c.us"},"path":{"type":"string"},"filename":{"type":"string"},"caption":{"type":"string"}},"required":["chatId","path","filename","caption"]},"MessageReply":{"type":"object","properties":{"chatId":{"type":"string","example":"791231234567@c.us"},"reply_to":{"type":"string","example":"message.id"},"text":{"type":"string"}},"required":["chatId","reply_to","text"]},"Chat":{"type":"object","properties":{"chatId":{"type":"string","example":"791231234567@c.us"}},"required":["chatId"]}}},"externalDocs":{"description":"Github WhatsApp HTTP API","url":"https://github.com/allburov/whatsapp-http-api"},"paths":{"/api/sendContactVcard":{"post":{"operationId":"ChattingController_sendContactVcard","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageContactVcard"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"tags":["chatting"]}},"/api/sendText":{"post":{"operationId":"ChattingController_sendText","summary":"Send a text message","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageText"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"tags":["chatting"]}},"/api/sendLocation":{"post":{"operationId":"ChattingController_sendLocation","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageLocation"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"tags":["chatting"]}},"/api/sendLinkPreview":{"post":{"operationId":"ChattingController_sendLinkPreview","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageLinkPreview"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"tags":["chatting"]}},"/api/sendImage":{"post":{"operationId":"ChattingController_sendImage","summary":"NOT IMPLEMENTED YET","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageImage"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"tags":["chatting"]}},"/api/sendFile":{"post":{"operationId":"ChattingController_sendFile","summary":"NOT IMPLEMENTED YET","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageFile"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"tags":["chatting"]}},"/api/reply":{"post":{"operationId":"ChattingController_reply","summary":"Reply to a text message","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageReply"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"tags":["chatting"]}},"/api/sendSeen":{"post":{"operationId":"ChattingController_sendSeen","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Chat"}}}},"responses":{"201":{"description":""}},"tags":["chatting"]}},"/api/startTyping":{"post":{"operationId":"ChattingController_startTyping","parameters":[],"requestBody":{"required":trLine truncated
{
"openapi": "3.0.0",
"info": {
"title": "WhatsApp HTTP API",
"description": "WhatsApp HTTP API that you can configure in a click!",
"version": "1.0",
"contact": {}
},
"tags": [
{
"name": "device",
"description": "Device information"
},
{
"name": "chatting",
"description": "Chat methods"
}
],
"servers": [],
"components": {
"securitySchemes": {
"api_key": {
"type": "apiKey",
"in": "header",
"name": "X-VENOM-TOKEN",
"description": "Your secret key"
}
},
"schemas": {
"MessageContactVcard": {
"type": "object",
"properties": {
"chatId": {
"type": "string",
"example": "791231234567@c.us"
},
"contactsId": {
"type": "string"
},
"name": {
"type": "string"
}
},
"required": [
"chatId",
"contactsId",
"name"
]
},
"MessageText": {
"type": "object",
"properties": {
"chatId": {
"type": "string",
"example": "791231234567@c.us"
},
"text": {
"type": "string"
}
},
"required": [
"chatId",
"text"
]
},
"MessageLocation": {
"type": "object",
"properties": {
"chatId": {
"type": "string",
"example": "791231234567@c.us"
},
"latitude": {
"type": "string"
},
"longitude": {
"type": "string"
},
"title": {
"type": "string"
}
},
"required": [
"chatId",
"latitude",
"longitude",
"title"
]
},
"MessageLinkPreview": {
"type": "object",
"properties": {
"chatId": {
"type": "string",
"example": "791231234567@c.us"
},
"url": {
"type": "string"
},
"title": {
"type": "string"
}
},
"required": [
"chatId",
"url",
"title"
]
},
"MessageImage": {
"type": "object",
"properties": {
"chatId": {
"type": "string",
"example": "791231234567@c.us"
},
"path": {
"type": "string"
},
"filename": {
"type": "string"
},
"caption": {
"type": "string"
}
},
"required": [
"chatId",
"path",
"filename",
"caption"
]
},
"MessageFile": {
"type": "object",
"properties": {
"chatId": {
"type": "string",
"example": "791231234567@c.us"
},
"path": {
"type": "string"
},
"filename": {
"type": "string"
},
"caption": {
"type": "string"
}
},
"required": [
"chatId",
"path",
"filename",
"caption"
]
},
"MessageReply": {
"type": "object",
"properties": {
"chatId": {
"type": "string",
"example": "791231234567@c.us"
},
"reply_to": {
"type": "string",
"example": "message.id"
},
"text": {
"type": "string"
}
},
"required": [
"chatId",
"reply_to",
"text"
]
},
"Chat": {
"type": "object",
"properties": {
"chatId": {
"type": "string",
"example": "791231234567@c.us"
}
},
"required": [
"chatId"
]
}
}
},
"externalDocs": {
"description": "Github WhatsApp HTTP API",
"url": "https://github.com/allburov/whatsapp-http-api"
},
"paths": {
"/api/sendContactVcard": {
"post": {
"operationId": "ChattingController_sendContactVcard",
"parameters": [],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/MessageContactVcard"
}
}
}
},
"responses": {
"201": {
"description": "",
"content": {
"application/json": {
"schema": {
"type": "object"
}
}
}
}
},
"tags": [
"chatting"
]
}
},
"/api/sendText": {
"post": {
"operationId": "ChattingController_sendText",
"summary": "Send a text message",
"parameters": [],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/MessageText"
}
}
}
},
"responses": {
"201": {
"description": "",
"content": {
"application/json": {
"schema": {
"type": "object"
}
}
}
}
},
"tags": [
"chatting"
]
}
},
"/api/sendLocation": {
"post": {
"operationId": "ChattingController_sendLocation",
"parameters": [],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/MessageLocation"
}
}
}
},
"responses": {
"201": {
"description": "",
"content": {
"application/json": {
"schema": {
"type": "object"
}
}
}
}
},
"tags": [
"chatting"
]
}
},
"/api/sendLinkPreview": {
"post": {
"operationId": "ChattingController_sendLinkPreview",
"parameters": [],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/MessageLinkPreview"
}
}
}
},
"responses": {
"201": {
"description": "",
"content": {
"application/json": {
"schema": {
"type": "object"
}
}
}
}
},
"tags": [
"chatting"
]
}
},
"/api/sendImage": {
"post": {
"operationId": "ChattingController_sendImage",
"summary": "NOT IMPLEMENTED YET",
"parameters": [],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/MessageImage"
}
}
}
},
"responses": {
"201": {
"description": "",
"content": {
"application/json": {
"schema": {
"type": "object"
}
}
}
}
},
"tags": [
"chatting"
]
}
},
"/api/sendFile": {
"post": {
"operationId": "ChattingController_sendFile",
"summary": "NOT IMPLEMENTED YET",
"parameters": [],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/MessageFile"
}
}
}
},
"responses": {
"201": {
"description": "",
"content": {
"application/json": {
"schema": {
"type": "object"
}
}
}
}
},
"tags": [
"chatting"
]
}
},
"/api/reply": {
"post": {
"operationId": "ChattingController_reply",
"summary": "Reply to a text message",
"parameters": [],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/MessageReply"
}
}
}
},
"responses": {
"201": {
"description": "",
"content": {
"application/json": {
"schema": {
"type": "object"
}
}
}
}
},
"tags": [
"chatting"
]
}
},
"/api/sendSeen": {
"post": {
"operationId": "ChattingController_sendSeen",
"parameters": [],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Chat"
}
}
}
},
"responses": {
"201": {
"description": ""
}
},
"tags": [
"chatting"
]
}
},
"/api/startTyping": {
"post": {
"operationId": "ChattingController_startTyping",
"parameters": [],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Chat"
}
}
}
},
"responses": {
"201": {
"description": "",
"content": {
"application/json": {
"schema": {
"type": "boolean"
}
}
}
}
},
"tags": [
"chatting"
]
}
},
"/api/stopTyping": {
"post": {
"operationId": "ChattingController_stopTyping",
"parameters": [],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Chat"
}
}
}
},
"responses": {
"201": {
"description": "",
"content": {
"application/json": {
"schema": {
"type": "boolean"
}
}
}
}
},
"tags": [
"chatting"
]
}
},
"/api/killServiceWorker": {
"post": {
"operationId": "DeviceController_killServiceWorker",
"parameters": [],
"responses": {
"201": {
"description": "",
"content": {
"application/json": {
"schema": {
"type": "boolean"
}
}
}
}
},
"tags": [
"device"
]
}
},
"/api/restartService": {
"post": {
"operationId": "DeviceController_restartService",
"parameters": [],
"responses": {
"201": {
"description": "",
"content": {
"application/json": {
"schema": {
"type": "boolean"
}
}
}
}
},
"tags": [
"device"
]
}
},
"/api/getHostDevice": {
"get": {
"operationId": "DeviceController_getHostDevice",
"parameters": [],
"responses": {
"200": {
"description": "",
"content": {
"application/json": {
"schema": {
"type": "object"
}
}
}
}
},
"tags": [
"device"
]
}
},
"/api/getConnectionState": {
"get": {
"operationId": "DeviceController_getConnectionState",
"parameters": [],
"responses": {
"200": {
"description": ""
}
},
"tags": [
"device"
]
}
},
"/api/getBatteryLevel": {
"get": {
"operationId": "DeviceController_getBatteryLevel",
"parameters": [],
"responses": {
"200": {
"description": "",
"content": {
"application/json": {
"schema": {
"type": "number"
}
}
}
}
},
"tags": [
"device"
]
}
},
"/api/isConnected": {
"get": {
"operationId": "DeviceController_isConnected",
"parameters": [],
"responses": {
"200": {
"description": "",
"content": {
"application/json": {
"schema": {
"type": "boolean"
}
}
}
}
},
"tags": [
"device"
]
}
},
"/api/getWAVersion": {
"get": {
"operationId": "DeviceController_getWAVersion",
"parameters": [],
"responses": {
"200": {
"description": "",
"content": {
"application/json": {
"schema": {
"type": "string"
}
}
}
}
},
"tags": [
"device"
]
}
},
"/api/screenshot": {
"get": {
"operationId": "ScreenshotController_screenshot",
"parameters": [],
"responses": {
"200": {
"description": ""
}
},
"tags": [
"screenshot"
]
}
}
}
}
+11056 -3
View File
File diff suppressed because it is too large. Load diff
+19 -10
View File
@@ -1,29 +1,38 @@
import {ApiProperty} from "@nestjs/swagger";
const chatId = ApiProperty({
const chatIdProperty = ApiProperty({
example: '791231234567@c.us'
})
const sessionNameProperty = ApiProperty({
default: "default",
example: 'default',
})
export class Session {
@sessionNameProperty
sessionName: string;
}
export class Chat {
@chatId
@chatIdProperty
chatId: string;
}
export class MessageContactVcard {
@chatId
@chatIdProperty
chatId: string;
contactsId: string;
name: string
}
export class MessageText {
@chatId
@chatIdProperty
chatId: string;
text: string;
}
export class MessageReply {
@chatId
@chatIdProperty
chatId: string;
text: string;
@ApiProperty({
@@ -33,7 +42,7 @@ export class MessageReply {
}
export class MessageLocation {
@chatId
@chatIdProperty
chatId: string;
latitude: string;
longitude: string;
@@ -41,7 +50,7 @@ export class MessageLocation {
}
export class MessageImage {
@chatId
@chatIdProperty
chatId: string;
path: string;
filename: string;
@@ -49,7 +58,7 @@ export class MessageImage {
}
export class MessageFile {
@chatId
@chatIdProperty
chatId: string;
path: string;
filename: string;
@@ -57,8 +66,8 @@ export class MessageFile {
}
export class MessageLinkPreview {
@chatId
@chatIdProperty
chatId: string;
url: string;
title: string;
}
}
+9 -5
View File
@@ -1,19 +1,23 @@
import {Controller, Get, Inject, Res} from '@nestjs/common';
import {Controller, Get, Query, Res} from '@nestjs/common';
import {ApiTags} from "@nestjs/swagger";
import {Whatsapp} from "venom-bot";
import {Readable} from "stream";
import {Response} from 'express';
import {WhatsappSessionManager} from "../whatsapp.service";
@Controller('api')
@ApiTags('screenshot')
export class ScreenshotController {
constructor(@Inject('WHATSAPP') private whatsapp: Whatsapp) {
constructor(private whatsappSessionManager: WhatsappSessionManager) {
}
@Get('/screenshot')
async screenshot(@Res() res: Response,) {
const buffer = await this.whatsapp.page.screenshot();
async screenshot(
@Res() res: Response,
@Query('sessionName') sessionName: string,
) {
const whatsapp = this.whatsappSessionManager.getSession(sessionName)
const buffer = await whatsapp.page.screenshot();
const stream = new Readable();
stream.push(buffer);
stream.push(null);
+50
View File
@@ -0,0 +1,50 @@
import {Body, Controller, Get, Post, Query, Res} from '@nestjs/common';
import {ApiTags} from "@nestjs/swagger";
import {Readable} from "stream";
import {Response} from 'express';
import {WhatsappSessionManager} from "../whatsapp.service";
import {Session} from "./all.dto";
@Controller('api/sessions')
@ApiTags('sessions')
export class SessionsController {
constructor(private whatsappSessionManager: WhatsappSessionManager) {
}
@Post('/start/')
async start(@Body() query: Session) {
this.whatsappSessionManager.startSession(query.sessionName)
return
}
@Post('/stop/')
async stop(@Body() query: Session) {
this.whatsappSessionManager.stopSession(query.sessionName)
return
}
@Get('/qr')
async qr(
@Res() res: Response,
@Query('sessionName') sessionName: string,
) {
const buffer = this.whatsappSessionManager.getQR(sessionName)
const stream = new Readable();
stream.push(buffer);
stream.push(null);
res.set({
'Content-Type': 'image/png',
'Content-Length': buffer.length,
});
stream.pipe(res)
}
@Get('/')
async list() {
return this.whatsappSessionManager.getAllSessions()
}
}
+11 -6
View File
@@ -1,11 +1,10 @@
import {ConsoleLogger, Logger, Module} from '@nestjs/common';
import {ChattingController} from './api/chatting.controller';
import {DeviceController} from "./api/device.controller";
import {whatsappProvider, WhatsappService} from "./whatsapp.service";
import {ConsoleLogger, Module} from '@nestjs/common';
import {WhatsappSessionManager} from "./whatsapp.service";
import {ScreenshotController} from "./api/screenshot.controller";
import {ConfigModule} from "@nestjs/config";
import {WhatsappConfigService} from "./config.service";
import {ServeStaticModule} from "@nestjs/serve-static";
import {SessionsController} from "./api/sessions.controller";
@Module({
imports: [
@@ -24,8 +23,14 @@ import {ServeStaticModule} from "@nestjs/serve-static";
},
}),
],
controllers: [ChattingController, DeviceController, ScreenshotController],
providers: [whatsappProvider, WhatsappService, ConsoleLogger, WhatsappConfigService],
controllers: [
SessionsController,
// TODO: Uncomment them back
// ChattingController,
// DeviceController,
ScreenshotController,
],
providers: [WhatsappSessionManager, ConsoleLogger, WhatsappConfigService],
})
export class AppModule {
}
+3 -1
View File
@@ -15,8 +15,10 @@ async function bootstrap() {
.setDescription('WhatsApp HTTP API that you can configure in a click!')
.setExternalDoc("Github WhatsApp HTTP API", "https://github.com/allburov/whatsapp-http-api")
.setVersion('1.0')
.addTag('device', 'Device information')
.addTag('sessions', 'Control your WhatsApp sessions')
.addTag('screenshot', 'Get QR code or the screenshot of WhatsApp')
.addTag('chatting', 'Chat methods')
.addTag('device', 'Device information')
.addApiKey({
type: 'apiKey',
description: 'Your secret key',
+100 -54
View File
@@ -1,6 +1,5 @@
import {create, Message, Whatsapp} from "venom-bot";
import {ConsoleLogger, Inject, Injectable, OnApplicationShutdown} from "@nestjs/common";
import {ConfigService} from "@nestjs/config";
import {ConsoleLogger, Injectable, OnApplicationShutdown} from "@nestjs/common";
import * as path from "path";
import {WhatsappConfigService} from "./config.service";
import request = require('requestretry');
@@ -15,28 +14,6 @@ const writeFileAsync = promisify(fs.writeFile)
const SECOND = 1000;
export const whatsappProvider = {
provide: 'WHATSAPP',
useFactory: async (config: ConfigService) => create('sessionName',
(base64Qr, asciiQR) => {
console.log(asciiQR);
},
undefined,
{
headless: true,
devtools: false,
useChrome: true,
debug: false,
logQR: true,
browserArgs: ["--no-sandbox"],
autoClose: 60000,
createPathFileToken: true,
puppeteerOptions: {},
multidevice: false,
}
)
}
const ONMESSAGE_HOOK = "onMessage"
const HOOKS = [
ONMESSAGE_HOOK,
@@ -50,26 +27,23 @@ const HOOKS = [
const ENV_PREFIX = "WHATSAPP_HOOK_"
@Injectable()
export class WhatsappService implements OnApplicationShutdown {
// TODO: Use environment variables
export class WhatsappService {
readonly filesFolder: string
readonly mimetypes: string[] | null
readonly filesLifetime: number
private RETRY_DELAY = 15
private RETRY_ATTEMPTS = 3;
readonly FILES_FOLDER: string
readonly mimetypes: string[] | null
readonly files_lifetime: number
private log: ConsoleLogger;
constructor(
@Inject('WHATSAPP') private whatsapp: Whatsapp,
public whatsapp: Whatsapp,
private config: WhatsappConfigService,
private log: ConsoleLogger,
) {
this.log = new ConsoleLogger()
this.log.setContext('WhatsappService')
this.FILES_FOLDER = this.config.filesFolder
this.cleanDownloadsFolder()
this.filesFolder = this.config.filesFolder
this.mimetypes = this.config.mimetypes
this.files_lifetime = this.config.filesLifetime * SECOND
this.filesLifetime = this.config.filesLifetime * SECOND
this.log.log('Configuring webhooks...')
for (const hook of HOOKS) {
@@ -90,17 +64,6 @@ export class WhatsappService implements OnApplicationShutdown {
this.log.log('Webhooks were configured.')
}
private cleanDownloadsFolder() {
if (fs.existsSync(this.FILES_FOLDER)) {
del([`${this.FILES_FOLDER}/*`], {force: true}).then((paths) =>
console.log('Deleted files and directories:\n', paths.join('\n'))
)
} else {
fs.mkdirSync(this.FILES_FOLDER)
this.log.log(`Directory '${this.FILES_FOLDER}' created from scratch`)
}
}
private callWebhook(data, url) {
this.log.log(`Sending POST to ${url}...`)
@@ -146,7 +109,7 @@ export class WhatsappService implements OnApplicationShutdown {
this.log.log(`The message ${message.id} has media, downloading it...`);
const fileName = `${message.id}.${mime.extension(message.mimetype)}`;
const filePath = path.resolve(`${this.FILES_FOLDER}/${fileName}`)
const filePath = path.resolve(`${this.filesFolder}/${fileName}`)
this.log.verbose(`Writing file to ${filePath}...`)
await writeFileAsync(filePath, buffer);
this.log.log(`The file from ${message.id} has been saved to ${filePath}`);
@@ -157,16 +120,99 @@ export class WhatsappService implements OnApplicationShutdown {
});
}
onApplicationShutdown(signal ?: string): any {
this.log.log('Close a browser...')
return this.whatsapp.close()
}
private removeFile(file: string) {
setTimeout(() => fs.unlink(file, () => {
this.log.log(`File ${file} was removed`)
}), this.files_lifetime)
}), this.filesLifetime)
}
}
@Injectable()
export class WhatsappSessionManager implements OnApplicationShutdown {
readonly filesFolder: string
private readonly sessions: Record<string, WhatsappService>;
private sessionsQR: Record<string, string>;
constructor(
private config: WhatsappConfigService,
private log: ConsoleLogger,
) {
this.log.setContext('WhatsappSessionManager')
this.filesFolder = this.config.filesFolder
this.cleanDownloadsFolder()
this.sessions = {}
this.sessionsQR = {}
}
async startSession(name: string) {
this.log.log(`Starting ${name} session...`)
const whatsapp = await create('sessionName',
(base64Qrimg, asciiQR, attempts, urlCode) => {
this.saveQR(name, base64Qrimg)
console.log('Number of attempts to read the qrcode: ', attempts);
console.log('Terminal qrcode: ', asciiQR);
},
undefined,
{
headless: true,
devtools: false,
useChrome: true,
debug: false,
logQR: true,
browserArgs: ["--no-sandbox"],
autoClose: 60000,
createPathFileToken: true,
puppeteerOptions: {},
multidevice: false,
}
)
this.sessions[name] = new WhatsappService(whatsapp, this.config)
this.deleteQR(name)
}
getQR(name: string) {
let qrBase64 = this.sessionsQR[name]
qrBase64 = qrBase64.replace(/^data:image\/png;base64,/, '');
return Buffer.from(qrBase64, "base64")
}
saveQR(name, base64Qrimg) {
this.sessionsQR[name] = base64Qrimg
console.log('base64 image string qrcode: ', base64Qrimg);
}
deleteQR(name) {
delete this.sessionsQR[name]
}
getSession(name: string): Whatsapp {
// TODO: Check session exists
return this.sessions[name].whatsapp
}
stopSession(name: string) {
this.log.log(`Stopping ${name} session...`)
this.log.log(`"${name}" has been stopped.`)
}
getAllSessions() {
return Object.keys(this.sessions) as Array<string>
}
onApplicationShutdown(signal ?: string): any {
this.log.log('Close a browser...')
// TODO: Stop all sessions
}
private cleanDownloadsFolder() {
if (fs.existsSync(this.filesFolder)) {
del([`${this.filesFolder}/*`], {force: true}).then((paths) =>
console.log('Deleted files and directories:\n', paths.join('\n'))
)
} else {
fs.mkdirSync(this.filesFolder)
this.log.log(`Directory '${this.filesFolder}' created from scratch`)
}
}
}
+656 -1
View File
@@ -1 +1,656 @@
{"openapi":"3.0.0","info":{"title":"WhatsApp HTTP API","description":"WhatsApp HTTP API that you can configure in a click","version":"1.0","contact":{}},"tags":[{"name":"device","description":"Device information"},{"name":"chatting","description":"Chat methods"}],"servers":[],"components":{"securitySchemes":{"api_key":{"type":"apiKey","in":"header","name":"X-VENOM-TOKEN","description":"Your secret key"}},"schemas":{"MessageContactVcard":{"type":"object","properties":{"chatId":{"type":"string","example":"791231234567@c.us"},"contactsId":{"type":"string"},"name":{"type":"string"}},"required":["chatId","contactsId","name"]},"MessageText":{"type":"object","properties":{"chatId":{"type":"string","example":"791231234567@c.us"},"text":{"type":"string"}},"required":["chatId","text"]},"MessageLocation":{"type":"object","properties":{"chatId":{"type":"string","example":"791231234567@c.us"},"latitude":{"type":"string"},"longitude":{"type":"string"},"title":{"type":"string"}},"required":["chatId","latitude","longitude","title"]},"MessageLinkPreview":{"type":"object","properties":{"chatId":{"type":"string","example":"791231234567@c.us"},"url":{"type":"string"},"title":{"type":"string"}},"required":["chatId","url","title"]},"MessageImage":{"type":"object","properties":{"chatId":{"type":"string","example":"791231234567@c.us"},"path":{"type":"string"},"filename":{"type":"string"},"caption":{"type":"string"}},"required":["chatId","path","filename","caption"]},"MessageFile":{"type":"object","properties":{"chatId":{"type":"string","example":"791231234567@c.us"},"path":{"type":"string"},"filename":{"type":"string"},"caption":{"type":"string"}},"required":["chatId","path","filename","caption"]},"MessageReply":{"type":"object","properties":{"chatId":{"type":"string","example":"791231234567@c.us"},"reply_to":{"type":"string","example":"message.id"},"text":{"type":"string"}},"required":["chatId","reply_to","text"]},"Chat":{"type":"object","properties":{"chatId":{"type":"string","example":"791231234567@c.us"}},"required":["chatId"]}}},"paths":{"/api/sendContactVcard":{"post":{"operationId":"ChattingController_sendContactVcard","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageContactVcard"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"tags":["chatting"]}},"/api/sendText":{"post":{"operationId":"ChattingController_sendText","summary":"Send a text message","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageText"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"tags":["chatting"]}},"/api/sendLocation":{"post":{"operationId":"ChattingController_sendLocation","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageLocation"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"tags":["chatting"]}},"/api/sendLinkPreview":{"post":{"operationId":"ChattingController_sendLinkPreview","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageLinkPreview"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"tags":["chatting"]}},"/api/sendImage":{"post":{"operationId":"ChattingController_sendImage","summary":"NOT IMPLEMENTED YET","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageImage"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"tags":["chatting"]}},"/api/sendFile":{"post":{"operationId":"ChattingController_sendFile","summary":"NOT IMPLEMENTED YET","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageFile"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"tags":["chatting"]}},"/api/reply":{"post":{"operationId":"ChattingController_reply","summary":"Reply to a text message","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageReply"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"tags":["chatting"]}},"/api/sendSeen":{"post":{"operationId":"ChattingController_sendSeen","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Chat"}}}},"responses":{"201":{"description":""}},"tags":["chatting"]}},"/api/startTyping":{"post":{"operationId":"ChattingController_startTyping","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Chat"}}}},"responses":{"201":{"descriptiLine truncated
{
"openapi": "3.0.0",
"info": {
"title": "WhatsApp HTTP API",
"description": "WhatsApp HTTP API that you can configure in a click",
"version": "1.0",
"contact": {}
},
"tags": [
{
"name": "device",
"description": "Device information"
},
{
"name": "chatting",
"description": "Chat methods"
}
],
"servers": [],
"components": {
"securitySchemes": {
"api_key": {
"type": "apiKey",
"in": "header",
"name": "X-VENOM-TOKEN",
"description": "Your secret key"
}
},
"schemas": {
"MessageContactVcard": {
"type": "object",
"properties": {
"chatId": {
"type": "string",
"example": "791231234567@c.us"
},
"contactsId": {
"type": "string"
},
"name": {
"type": "string"
}
},
"required": [
"chatId",
"contactsId",
"name"
]
},
"MessageText": {
"type": "object",
"properties": {
"chatId": {
"type": "string",
"example": "791231234567@c.us"
},
"text": {
"type": "string"
}
},
"required": [
"chatId",
"text"
]
},
"MessageLocation": {
"type": "object",
"properties": {
"chatId": {
"type": "string",
"example": "791231234567@c.us"
},
"latitude": {
"type": "string"
},
"longitude": {
"type": "string"
},
"title": {
"type": "string"
}
},
"required": [
"chatId",
"latitude",
"longitude",
"title"
]
},
"MessageLinkPreview": {
"type": "object",
"properties": {
"chatId": {
"type": "string",
"example": "791231234567@c.us"
},
"url": {
"type": "string"
},
"title": {
"type": "string"
}
},
"required": [
"chatId",
"url",
"title"
]
},
"MessageImage": {
"type": "object",
"properties": {
"chatId": {
"type": "string",
"example": "791231234567@c.us"
},
"path": {
"type": "string"
},
"filename": {
"type": "string"
},
"caption": {
"type": "string"
}
},
"required": [
"chatId",
"path",
"filename",
"caption"
]
},
"MessageFile": {
"type": "object",
"properties": {
"chatId": {
"type": "string",
"example": "791231234567@c.us"
},
"path": {
"type": "string"
},
"filename": {
"type": "string"
},
"caption": {
"type": "string"
}
},
"required": [
"chatId",
"path",
"filename",
"caption"
]
},
"MessageReply": {
"type": "object",
"properties": {
"chatId": {
"type": "string",
"example": "791231234567@c.us"
},
"reply_to": {
"type": "string",
"example": "message.id"
},
"text": {
"type": "string"
}
},
"required": [
"chatId",
"reply_to",
"text"
]
},
"Chat": {
"type": "object",
"properties": {
"chatId": {
"type": "string",
"example": "791231234567@c.us"
}
},
"required": [
"chatId"
]
}
}
},
"paths": {
"/api/sendContactVcard": {
"post": {
"operationId": "ChattingController_sendContactVcard",
"parameters": [],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/MessageContactVcard"
}
}
}
},
"responses": {
"201": {
"description": "",
"content": {
"application/json": {
"schema": {
"type": "object"
}
}
}
}
},
"tags": [
"chatting"
]
}
},
"/api/sendText": {
"post": {
"operationId": "ChattingController_sendText",
"summary": "Send a text message",
"parameters": [],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/MessageText"
}
}
}
},
"responses": {
"201": {
"description": "",
"content": {
"application/json": {
"schema": {
"type": "object"
}
}
}
}
},
"tags": [
"chatting"
]
}
},
"/api/sendLocation": {
"post": {
"operationId": "ChattingController_sendLocation",
"parameters": [],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/MessageLocation"
}
}
}
},
"responses": {
"201": {
"description": "",
"content": {
"application/json": {
"schema": {
"type": "object"
}
}
}
}
},
"tags": [
"chatting"
]
}
},
"/api/sendLinkPreview": {
"post": {
"operationId": "ChattingController_sendLinkPreview",
"parameters": [],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/MessageLinkPreview"
}
}
}
},
"responses": {
"201": {
"description": "",
"content": {
"application/json": {
"schema": {
"type": "object"
}
}
}
}
},
"tags": [
"chatting"
]
}
},
"/api/sendImage": {
"post": {
"operationId": "ChattingController_sendImage",
"summary": "NOT IMPLEMENTED YET",
"parameters": [],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/MessageImage"
}
}
}
},
"responses": {
"201": {
"description": "",
"content": {
"application/json": {
"schema": {
"type": "object"
}
}
}
}
},
"tags": [
"chatting"
]
}
},
"/api/sendFile": {
"post": {
"operationId": "ChattingController_sendFile",
"summary": "NOT IMPLEMENTED YET",
"parameters": [],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/MessageFile"
}
}
}
},
"responses": {
"201": {
"description": "",
"content": {
"application/json": {
"schema": {
"type": "object"
}
}
}
}
},
"tags": [
"chatting"
]
}
},
"/api/reply": {
"post": {
"operationId": "ChattingController_reply",
"summary": "Reply to a text message",
"parameters": [],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/MessageReply"
}
}
}
},
"responses": {
"201": {
"description": "",
"content": {
"application/json": {
"schema": {
"type": "object"
}
}
}
}
},
"tags": [
"chatting"
]
}
},
"/api/sendSeen": {
"post": {
"operationId": "ChattingController_sendSeen",
"parameters": [],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Chat"
}
}
}
},
"responses": {
"201": {
"description": ""
}
},
"tags": [
"chatting"
]
}
},
"/api/startTyping": {
"post": {
"operationId": "ChattingController_startTyping",
"parameters": [],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Chat"
}
}
}
},
"responses": {
"201": {
"description": "",
"content": {
"application/json": {
"schema": {
"type": "boolean"
}
}
}
}
},
"tags": [
"chatting"
]
}
},
"/api/stopTyping": {
"post": {
"operationId": "ChattingController_stopTyping",
"parameters": [],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Chat"
}
}
}
},
"responses": {
"201": {
"description": "",
"content": {
"application/json": {
"schema": {
"type": "boolean"
}
}
}
}
},
"tags": [
"chatting"
]
}
},
"/api/killServiceWorker": {
"post": {
"operationId": "DeviceController_killServiceWorker",
"parameters": [],
"responses": {
"201": {
"description": "",
"content": {
"application/json": {
"schema": {
"type": "boolean"
}
}
}
}
},
"tags": [
"device"
]
}
},
"/api/restartService": {
"post": {
"operationId": "DeviceController_restartService",
"parameters": [],
"responses": {
"201": {
"description": "",
"content": {
"application/json": {
"schema": {
"type": "boolean"
}
}
}
}
},
"tags": [
"device"
]
}
},
"/api/getHostDevice": {
"get": {
"operationId": "DeviceController_getHostDevice",
"parameters": [],
"responses": {
"200": {
"description": "",
"content": {
"application/json": {
"schema": {
"type": "object"
}
}
}
}
},
"tags": [
"device"
]
}
},
"/api/getConnectionState": {
"get": {
"operationId": "DeviceController_getConnectionState",
"parameters": [],
"responses": {
"200": {
"description": ""
}
},
"tags": [
"device"
]
}
},
"/api/getBatteryLevel": {
"get": {
"operationId": "DeviceController_getBatteryLevel",
"parameters": [],
"responses": {
"200": {
"description": "",
"content": {
"application/json": {
"schema": {
"type": "number"
}
}
}
}
},
"tags": [
"device"
]
}
},
"/api/isConnected": {
"get": {
"operationId": "DeviceController_isConnected",
"parameters": [],
"responses": {
"200": {
"description": "",
"content": {
"application/json": {
"schema": {
"type": "boolean"
}
}
}
}
},
"tags": [
"device"
]
}
},
"/api/getWAVersion": {
"get": {
"operationId": "DeviceController_getWAVersion",
"parameters": [],
"responses": {
"200": {
"description": "",
"content": {
"application/json": {
"schema": {
"type": "string"
}
}
}
}
},
"tags": [
"device"
]
}
},
"/api/screenshot": {
"get": {
"operationId": "ScreenshotController_screenshot",
"parameters": [],
"responses": {
"200": {
"description": ""
}
},
"tags": [
"screenshot"
]
}
}
}
}
+6 -1
View File
@@ -1,4 +1,9 @@
{
"extends": "./tsconfig.json",
"exclude": ["node_modules", "test", "dist", "**/*spec.ts"]
"exclude": [
"node_modules",
"test",
"dist",
"**/*spec.ts"
]
}