up
This commit is contained in:
parent
f87b057b85
commit
6c8d22bdec
26
Dockerfile
26
Dockerfile
@ -1,16 +1,20 @@
|
||||
FROM golang:1.20-alpine AS builder
|
||||
# Build stage
|
||||
FROM golang:1.21-alpine AS builder
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY go.mod go.sum ./
|
||||
RUN go mod download
|
||||
|
||||
COPY . .
|
||||
RUN CGO_ENABLED=0 GOOS=linux go build -o sender main.go
|
||||
|
||||
RUN go mod init whatsapp-sender
|
||||
RUN go mod tidy
|
||||
RUN go build -o whatsapp-sender .
|
||||
|
||||
# Runtime stage
|
||||
FROM alpine:latest
|
||||
WORKDIR /root/
|
||||
COPY --from=builder /app/sender .
|
||||
COPY public ./public
|
||||
|
||||
EXPOSE 3000
|
||||
CMD ["./sender"]
|
||||
WORKDIR /app
|
||||
COPY --from=builder /app/whatsapp-sender .
|
||||
COPY --from=builder /app/public ./public
|
||||
|
||||
EXPOSE 8080
|
||||
|
||||
CMD ["./whatsapp-sender"]
|
||||
@ -1,12 +1,17 @@
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
whatsapp-sender:
|
||||
build: .
|
||||
container_name: whatsapp_sender
|
||||
ports:
|
||||
- "3000:3000"
|
||||
volumes:
|
||||
- ./public:/root/public:ro
|
||||
environment:
|
||||
- PORT=3000
|
||||
- "8080:8080"
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- ./public:/app/public
|
||||
environment:
|
||||
- WHATSAPP_SESSION_DIR=/app/sessions
|
||||
volumes:
|
||||
- sessions:/app/sessions
|
||||
|
||||
volumes:
|
||||
sessions:
|
||||
34
go.mod
Normal file
34
go.mod
Normal file
@ -0,0 +1,34 @@
|
||||
module pvnet/whatsapp
|
||||
|
||||
go 1.24.0
|
||||
|
||||
require github.com/Rhymen/go-whatsapp v0.1.1
|
||||
|
||||
require (
|
||||
filippo.io/edwards25519 v1.1.0 // indirect
|
||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||
github.com/golang/protobuf v1.5.0 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/gorilla/mux v1.8.1
|
||||
github.com/gorilla/websocket v1.5.0 // indirect
|
||||
github.com/mattn/go-colorable v0.1.14 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/mattn/go-sqlite3 v1.14.28
|
||||
github.com/ncruces/go-strftime v0.1.9 // indirect
|
||||
github.com/petermattis/goid v0.0.0-20250319124200-ccd6737f222a // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||
github.com/rs/zerolog v1.34.0 // indirect
|
||||
go.mau.fi/libsignal v0.1.2 // indirect
|
||||
go.mau.fi/util v0.8.6 // indirect
|
||||
go.mau.fi/whatsmeow v0.0.0-20250501130609-4c93ee4e6efa // indirect
|
||||
golang.org/x/crypto v0.37.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 // indirect
|
||||
golang.org/x/net v0.39.0 // indirect
|
||||
golang.org/x/sys v0.32.0 // indirect
|
||||
google.golang.org/protobuf v1.36.6 // indirect
|
||||
modernc.org/libc v1.62.1 // indirect
|
||||
modernc.org/mathutil v1.7.1 // indirect
|
||||
modernc.org/memory v1.9.1 // indirect
|
||||
modernc.org/sqlite v1.37.0 // indirect
|
||||
)
|
||||
90
go.sum
Normal file
90
go.sum
Normal file
@ -0,0 +1,90 @@
|
||||
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
|
||||
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
|
||||
github.com/Baozisoftware/qrcode-terminal-go v0.0.0-20170407111555-c0650d8dff0f/go.mod h1:4a58ifQTEe2uwwsaqbh3i2un5/CBPg+At/qHpt18Tmk=
|
||||
github.com/Rhymen/go-whatsapp v0.0.0/go.mod h1:rdQr95g2C1xcOfM7QGOhza58HeI3I+tZ/bbluv7VazA=
|
||||
github.com/Rhymen/go-whatsapp v0.1.1 h1:OK+bCugQcr2YjyYKeDzULqCtM50TPUFM6LvQtszKfcw=
|
||||
github.com/Rhymen/go-whatsapp v0.1.1/go.mod h1:o7jjkvKnigfu432dMbQ/w4PH0Yp5u4Y6ysCNjUlcYCk=
|
||||
github.com/Rhymen/go-whatsapp/examples/echo v0.0.0-20190325075644-cc2581bbf24d/go.mod h1:zgCiQtBtZ4P4gFWvwl9aashsdwOcbb/EHOGRmSzM8ME=
|
||||
github.com/Rhymen/go-whatsapp/examples/restoreSession v0.0.0-20190325075644-cc2581bbf24d/go.mod h1:5sCUSpG616ZoSJhlt9iBNI/KXBqrVLcNUJqg7J9+8pU=
|
||||
github.com/Rhymen/go-whatsapp/examples/sendImage v0.0.0-20190325075644-cc2581bbf24d/go.mod h1:RdiyhanVEGXTam+mZ3k6Y3VDCCvXYCwReOoxGozqhHw=
|
||||
github.com/Rhymen/go-whatsapp/examples/sendTextMessages v0.0.0-20190325075644-cc2581bbf24d/go.mod h1:suwzklatySS3Q0+NCxCDh5hYfgXdQUWU1DNcxwAxStM=
|
||||
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
||||
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.0 h1:kbxbvI4Un1LUWKxufD+BiE6AEExYYgkQLQmLFqA1LFk=
|
||||
github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
|
||||
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
|
||||
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||
github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM=
|
||||
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
|
||||
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
|
||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
|
||||
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
|
||||
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-sqlite3 v1.14.28 h1:ThEiQrnbtumT+QMknw63Befp/ce/nUPgBPMlRFEum7A=
|
||||
github.com/mattn/go-sqlite3 v1.14.28/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
||||
github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
|
||||
github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
|
||||
github.com/petermattis/goid v0.0.0-20250319124200-ccd6737f222a h1:S+AGcmAESQ0pXCUNnRH7V+bOUIgkSX5qVt2cNKCrm0Q=
|
||||
github.com/petermattis/goid v0.0.0-20250319124200-ccd6737f222a/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4=
|
||||
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||
github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0=
|
||||
github.com/rs/zerolog v1.34.0 h1:k43nTLIwcTVQAncfCw4KZ2VY6ukYoZaBPNOE8txlOeY=
|
||||
github.com/rs/zerolog v1.34.0/go.mod h1:bJsvje4Z08ROH4Nhs5iH600c3IkWhwp44iRc54W6wYQ=
|
||||
github.com/skip2/go-qrcode v0.0.0-20190110000554-dc11ecdae0a9/go.mod h1:PLPIyL7ikehBD1OAjmKKiOEhbvWyHGaNDjquXMcYABo=
|
||||
go.mau.fi/libsignal v0.1.2 h1:Vs16DXWxSKyzVtI+EEXLCSy5pVWzzCzp/2eqFGvLyP0=
|
||||
go.mau.fi/libsignal v0.1.2/go.mod h1:JpnLSSJptn/s1sv7I56uEMywvz8x4YzxeF5OzdPb6PE=
|
||||
go.mau.fi/util v0.8.6 h1:AEK13rfgtiZJL2YsNK+W4ihhYCuukcRom8WPP/w/L54=
|
||||
go.mau.fi/util v0.8.6/go.mod h1:uNB3UTXFbkpp7xL1M/WvQks90B/L4gvbLpbS0603KOE=
|
||||
go.mau.fi/whatsmeow v0.0.0-20250501130609-4c93ee4e6efa h1:+bQKfMtnhX2jVoCSaneH4Ctk51IVT1K2gvjyqfFjVW0=
|
||||
go.mau.fi/whatsmeow v0.0.0-20250501130609-4c93ee4e6efa/go.mod h1:NlPtoLdpX3RnltqCTCZQ6kIUfprqLirtSK1gHvwoNx0=
|
||||
golang.org/x/crypto v0.0.0-20190131182504-b8fe1690c613/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE=
|
||||
golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc=
|
||||
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 h1:R84qjqJb5nVJMxqWYb3np9L5ZsaDtB+a39EqjV0JSUM=
|
||||
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0/go.mod h1:S9Xr4PYopiDyqSyp5NjCrhFrqg6A5zA2E/iPHPhqnS8=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY=
|
||||
golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
|
||||
golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
|
||||
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
|
||||
modernc.org/libc v1.62.1 h1:s0+fv5E3FymN8eJVmnk0llBe6rOxCu/DEU+XygRbS8s=
|
||||
modernc.org/libc v1.62.1/go.mod h1:iXhATfJQLjG3NWy56a6WVU73lWOcdYVxsvwCgoPljuo=
|
||||
modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU=
|
||||
modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg=
|
||||
modernc.org/memory v1.9.1 h1:V/Z1solwAVmMW1yttq3nDdZPJqV1rM05Ccq6KMSZ34g=
|
||||
modernc.org/memory v1.9.1/go.mod h1:/JP4VbVC+K5sU2wZi9bHoq2MAkCnrt2r98UGeSK7Mjw=
|
||||
modernc.org/sqlite v1.37.0 h1:s1TMe7T3Q3ovQiK2Ouz4Jwh7dw4ZDqbebSDTlSJdfjI=
|
||||
modernc.org/sqlite v1.37.0/go.mod h1:5YiWv+YviqGMuGw4V+PNplcyaJ5v+vQd7TQOgkACoJM=
|
||||
232
main.go
232
main.go
@ -1,120 +1,142 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"time"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
"context"
|
||||
|
||||
whatsapp "github.com/Rhymen/go-whatsapp"
|
||||
"github.com/Rhymen/go-whatsapp/binary/proto"
|
||||
"github.com/Rhymen/go-whatsapp/binary/proto/text"
|
||||
"github.com/gorilla/mux"
|
||||
"go.mau.fi/whatsmeow"
|
||||
waProto "go.mau.fi/whatsmeow/binary/proto"
|
||||
"go.mau.fi/whatsmeow/store/sqlstore"
|
||||
"go.mau.fi/whatsmeow/types"
|
||||
"go.mau.fi/whatsmeow/types/events"
|
||||
waLog "go.mau.fi/whatsmeow/util/log"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
type interactiveReq struct {
|
||||
Phone string `json:"phone"`
|
||||
Caption string `json:"caption"`
|
||||
URL1 string `json:"url1"`
|
||||
URL2 string `json:"url2"`
|
||||
}
|
||||
var client *whatsmeow.Client
|
||||
|
||||
func main() {
|
||||
wac, err := whatsapp.NewConn(20 * time.Second)
|
||||
if err != nil {
|
||||
log.Fatalf("Error creating connection: %v", err)
|
||||
}
|
||||
// Initialisation du routeur
|
||||
r := mux.NewRouter()
|
||||
|
||||
qrChan := make(chan string)
|
||||
go func() {
|
||||
log.Println("Scan the QR code at http://localhost:3000/login")
|
||||
log.Printf("QR Code: %s", <-qrChan)
|
||||
}()
|
||||
_, err = wac.Login(qrChan)
|
||||
if err != nil {
|
||||
log.Fatalf("Login failed: %v", err)
|
||||
}
|
||||
log.Println("✅ Connected to WhatsApp Web")
|
||||
// Routes
|
||||
r.HandleFunc("/", loginHandler).Methods("GET")
|
||||
r.HandleFunc("/send", sendMessageHandler).Methods("POST")
|
||||
r.HandleFunc("/qr", qrHandler).Methods("GET")
|
||||
|
||||
http.HandleFunc("/login", func(w http.ResponseWriter, r *http.Request) {
|
||||
http.ServeFile(w, r, "public/login.html")
|
||||
})
|
||||
// Serveur de fichiers statiques
|
||||
r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir("public"))))
|
||||
|
||||
http.HandleFunc("/sendInteractive", func(w http.ResponseWriter, r *http.Request) {
|
||||
var req interactiveReq
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
http.Error(w, "Invalid JSON payload", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
// Configuration du serveur
|
||||
srv := &http.Server{
|
||||
Handler: r,
|
||||
Addr: "0.0.0.0:8080",
|
||||
WriteTimeout: 15 * time.Second,
|
||||
ReadTimeout: 15 * time.Second,
|
||||
}
|
||||
|
||||
imageUrl := getBaseURL(r) + "/static/logo-merlo-cs-FR.jpg"
|
||||
header := &proto.InteractiveMessage_Header{
|
||||
HasMediaAttachment: proto.Bool(true),
|
||||
ImageMessage: &proto.ImageMessage{
|
||||
Url: &imageUrl,
|
||||
Mimetype: proto.String("image/jpeg"),
|
||||
},
|
||||
Media: proto.String("imageMessage"),
|
||||
}
|
||||
|
||||
body := &proto.InteractiveMessage_Body{Text: &req.Caption}
|
||||
footer := &proto.InteractiveMessage_Footer{Text: proto.String("Pied de page")}
|
||||
|
||||
buttons := []*proto.InteractiveMessage_ButtonParameters{
|
||||
{
|
||||
Name: proto.String("cta_url"),
|
||||
ButtonParamsJson: proto.String(text.Stringify(&proto.InteractiveMessage_URLButton{
|
||||
DisplayText: proto.String("📄 Proposition"),
|
||||
Url: &req.URL1,
|
||||
})),
|
||||
},
|
||||
{
|
||||
Name: proto.String("cta_url"),
|
||||
ButtonParamsJson: proto.String(text.Stringify(&proto.InteractiveMessage_URLButton{
|
||||
DisplayText: proto.String("🔧 Spécifications"),
|
||||
Url: &req.URL2,
|
||||
})),
|
||||
},
|
||||
}
|
||||
nativeFlow := &proto.InteractiveMessage_NativeFlowMessage{Buttons: buttons}
|
||||
|
||||
interactive := &proto.InteractiveMessage{
|
||||
Header: header,
|
||||
Body: body,
|
||||
Footer: footer,
|
||||
NativeFlowMessage: nativeFlow,
|
||||
}
|
||||
|
||||
wmi := &proto.WebMessageInfo{
|
||||
Key: &proto.MessageKey{RemoteJid: proto.String(req.Phone + "@s.whatsapp.net")},
|
||||
Message: &proto.WebMessageInfo_InteractiveMessage{InteractiveMessage: interactive},
|
||||
}
|
||||
|
||||
if _, err := wac.Send(wmi); err != nil {
|
||||
log.Printf("Error sending message: %v", err)
|
||||
http.Error(w, "Failed to send message", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.Write([]byte(`{"success":true}`))
|
||||
})
|
||||
|
||||
fs := http.FileServer(http.Dir("public"))
|
||||
http.Handle("/static/", http.StripPrefix("/static/", fs))
|
||||
|
||||
port := os.Getenv("PORT")
|
||||
if port == "" {
|
||||
port = "3002"
|
||||
}
|
||||
log.Printf("Server running on :%s", port)
|
||||
log.Fatal(http.ListenAndServe(":"+port, nil))
|
||||
log.Println("Serveur démarré sur http://localhost:8080")
|
||||
log.Fatal(srv.ListenAndServe())
|
||||
}
|
||||
|
||||
func getBaseURL(r *http.Request) string {
|
||||
scheme := "http"
|
||||
if r.TLS != nil {
|
||||
scheme = "https"
|
||||
}
|
||||
return scheme + "://" + r.Host
|
||||
func loginHandler(w http.ResponseWriter, r *http.Request) {
|
||||
http.ServeFile(w, r, "public/login.html")
|
||||
}
|
||||
|
||||
func sendMessageHandler(w http.ResponseWriter, r *http.Request) {
|
||||
phone := r.FormValue("phone")
|
||||
message := r.FormValue("message")
|
||||
|
||||
if client == nil || !client.IsConnected() {
|
||||
http.Error(w, "Client WhatsApp non connecté", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
recipient, err := types.ParseJID(phone)
|
||||
if err != nil {
|
||||
http.Error(w, "Numéro de téléphone invalide", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
msg := &waProto.Message{
|
||||
Conversation: proto.String(message),
|
||||
}
|
||||
|
||||
_, err = client.SendMessage(context.Background(), recipient, msg)
|
||||
if err != nil {
|
||||
http.Error(w, fmt.Sprintf("Erreur d'envoi: %v", err), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Fprintf(w, "Message envoyé avec succès à %s", phone)
|
||||
}
|
||||
|
||||
func qrHandler(w http.ResponseWriter, r *http.Request) {
|
||||
// Initialisation du client WhatsApp si ce n'est pas déjà fait
|
||||
if client == nil {
|
||||
initWhatsAppClient(r.Context(), w)
|
||||
}
|
||||
|
||||
// Ici vous devriez implémenter la logique pour afficher/générer le QR code
|
||||
// Ceci est un exemple simplifié
|
||||
fmt.Fprint(w, "QR code endpoint - à implémenter")
|
||||
}
|
||||
|
||||
func initWhatsAppClient(ctx context.Context, w http.ResponseWriter) {
|
||||
// Configuration du stockage
|
||||
storeDir := "sessions"
|
||||
if os.Getenv("WHATSAPP_SESSION_DIR") != "" {
|
||||
storeDir = os.Getenv("WHATSAPP_SESSION_DIR")
|
||||
}
|
||||
os.MkdirAll(storeDir, os.ModePerm)
|
||||
|
||||
container, err := sqlstore.New("sqlite3", "file:"+filepath.Join(storeDir, "whatsapp.db")+"?_foreign_keys=on", waLog.Noop)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
deviceStore, err := container.GetFirstDevice()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
client = whatsmeow.NewClient(deviceStore, waLog.Noop)
|
||||
client.AddEventHandler(eventHandler)
|
||||
|
||||
if client.Store.ID == nil {
|
||||
// Pas de session enregistrée, besoin de s'authentifier
|
||||
qrChan, _ := client.GetQRChannel(ctx)
|
||||
err = client.Connect()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
for evt := range qrChan {
|
||||
if evt.Event == "code" {
|
||||
// Afficher le QR code à l'utilisateur
|
||||
fmt.Fprintf(w, "QR code: %s", evt.Code)
|
||||
} else {
|
||||
fmt.Fprintf(w, "Événement de connexion: %s", evt.Event)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Déjà connecté
|
||||
err = client.Connect()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func eventHandler(evt interface{}) {
|
||||
switch v := evt.(type) {
|
||||
case *events.Message:
|
||||
fmt.Println("Message reçu de", v.Info.Sender, ":", v.Message.GetConversation())
|
||||
}
|
||||
}
|
||||
@ -1,12 +1,124 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>WhatsApp QR Login</title>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>WhatsApp Sender</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
.container {
|
||||
background-color: white;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
||||
}
|
||||
h1 {
|
||||
color: #075e54;
|
||||
text-align: center;
|
||||
}
|
||||
.form-group {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
label {
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
font-weight: bold;
|
||||
}
|
||||
input, textarea {
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
button {
|
||||
background-color: #075e54;
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 10px 15px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-size: 16px;
|
||||
}
|
||||
button:hover {
|
||||
background-color: #128c7e;
|
||||
}
|
||||
#qr-code {
|
||||
text-align: center;
|
||||
margin: 20px 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Scan QR to Login</h1>
|
||||
<p>Connect to WhatsApp Web from this device.</p>
|
||||
<p>QR will show in terminal output.</p>
|
||||
<div class="container">
|
||||
<h1>WhatsApp Message Sender</h1>
|
||||
|
||||
<div id="qr-code">
|
||||
<p>Scannez le QR code pour vous connecter à WhatsApp</p>
|
||||
<img id="qr-image" src="" alt="QR Code">
|
||||
</div>
|
||||
|
||||
<form id="message-form">
|
||||
<div class="form-group">
|
||||
<label for="phone">Numéro de téléphone (avec indicatif):</label>
|
||||
<input type="text" id="phone" name="phone" placeholder="Ex: 33612345678" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="message">Message:</label>
|
||||
<textarea id="message" name="message" rows="4" required></textarea>
|
||||
</div>
|
||||
|
||||
<button type="submit">Envoyer</button>
|
||||
</form>
|
||||
|
||||
<div id="status"></div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.getElementById('message-form').addEventListener('submit', async function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
const phone = document.getElementById('phone').value;
|
||||
const message = document.getElementById('message').value;
|
||||
const statusDiv = document.getElementById('status');
|
||||
|
||||
try {
|
||||
const response = await fetch('/send', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
},
|
||||
body: `phone=${encodeURIComponent(phone)}&message=${encodeURIComponent(message)}`
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
statusDiv.innerHTML = `<p style="color: green;">${await response.text()}</p>`;
|
||||
} else {
|
||||
statusDiv.innerHTML = `<p style="color: red;">Erreur: ${await response.text()}</p>`;
|
||||
}
|
||||
} catch (error) {
|
||||
statusDiv.innerHTML = `<p style="color: red;">Erreur: ${error.message}</p>`;
|
||||
}
|
||||
});
|
||||
|
||||
// Fonction pour récupérer et afficher le QR code
|
||||
async function fetchQRCode() {
|
||||
const response = await fetch('/qr');
|
||||
const qrData = await response.text();
|
||||
// Ici vous devriez traiter les données du QR code
|
||||
// Cet exemple est simplifié
|
||||
console.log("QR code data:", qrData);
|
||||
}
|
||||
|
||||
// Charger le QR code au démarrage
|
||||
window.onload = fetchQRCode;
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
Loading…
Reference in New Issue
Block a user