forked from MirrorHub/mautrix-whatsapp
Add provisioning API endpoints to list contacts and start chats
This commit is contained in:
parent
1a1fd68812
commit
66d0817081
22
commands.go
22
commands.go
|
@ -1048,26 +1048,14 @@ func (handler *CommandHandler) CommandPM(ce *CommandEvent) {
|
|||
return
|
||||
}
|
||||
|
||||
handler.log.Debugln("Importing", targetUser.JID, "for", user)
|
||||
puppet := user.bridge.GetPuppetByJID(targetUser.JID)
|
||||
puppet.SyncContact(user, true, "manual pm command")
|
||||
portal := user.GetPortalByJID(puppet.JID)
|
||||
if len(portal.MXID) > 0 {
|
||||
ok := portal.ensureUserInvited(user)
|
||||
if !ok {
|
||||
portal.log.Warnfln("ensureUserInvited(%s) returned false, creating new portal", user.MXID)
|
||||
portal.MXID = ""
|
||||
} else {
|
||||
ce.Reply("You already have a private chat portal with +%s at [%s](https://matrix.to/#/%s)", puppet.JID.User, puppet.Displayname, portal.MXID)
|
||||
return
|
||||
}
|
||||
}
|
||||
err = portal.CreateMatrixRoom(user, nil, false)
|
||||
portal, puppet, justCreated, err := user.StartPM(targetUser.JID, "manual PM command")
|
||||
if err != nil {
|
||||
ce.Reply("Failed to create portal room: %v", err)
|
||||
return
|
||||
} else if !justCreated {
|
||||
ce.Reply("You already have a private chat portal with +%s at [%s](https://matrix.to/#/%s)", puppet.JID.User, puppet.Displayname, portal.MXID)
|
||||
} else {
|
||||
ce.Reply("Created portal room with +%s and invited you to it.", puppet.JID.User)
|
||||
}
|
||||
ce.Reply("Created portal room with +%s and invited you to it.", puppet.JID.User)
|
||||
}
|
||||
|
||||
const cmdSyncHelp = `sync <appstate/contacts/groups/space> [--create-portals] - Synchronize data from WhatsApp.`
|
||||
|
|
2
go.mod
2
go.mod
|
@ -10,7 +10,7 @@ require (
|
|||
github.com/prometheus/client_golang v1.11.1
|
||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
|
||||
github.com/tidwall/gjson v1.14.0
|
||||
go.mau.fi/whatsmeow v0.0.0-20220217120518-0bf6c8fb0ce5
|
||||
go.mau.fi/whatsmeow v0.0.0-20220217121823-b7d4c5a8e8cc
|
||||
golang.org/x/image v0.0.0-20211028202545-6944b10bf410
|
||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd
|
||||
google.golang.org/protobuf v1.27.1
|
||||
|
|
4
go.sum
4
go.sum
|
@ -120,8 +120,8 @@ github.com/tidwall/sjson v1.2.4 h1:cuiLzLnaMeBhRmEv00Lpk3tkYrcxpmbU81tAY4Dw0tc=
|
|||
github.com/tidwall/sjson v1.2.4/go.mod h1:098SZ494YoMWPmMO6ct4dcFnqxwj9r/gF0Etp19pSNM=
|
||||
go.mau.fi/libsignal v0.0.0-20211109153248-a67163214910 h1:9FFhG0OmkuMau5UEaTgiUQ+7cSbtbOQ7hiWKdN8OI3I=
|
||||
go.mau.fi/libsignal v0.0.0-20211109153248-a67163214910/go.mod h1:AufGrvVh+00Nc07Jm4hTquh7yleZyn20tKJI2wCPAKg=
|
||||
go.mau.fi/whatsmeow v0.0.0-20220217120518-0bf6c8fb0ce5 h1:hv2cBvttHOiRA/6JUt+yRMAX7CjjER6c+xO2WYqwtA0=
|
||||
go.mau.fi/whatsmeow v0.0.0-20220217120518-0bf6c8fb0ce5/go.mod h1:NNI4Ah/B27mfQNChJMD1iSO8+HS+fQ4WqNuQ8Mh2/XI=
|
||||
go.mau.fi/whatsmeow v0.0.0-20220217121823-b7d4c5a8e8cc h1:nmKmURePfVfpK+qLeAZvJIMbgpAKtfYcqeXwXAaFUls=
|
||||
go.mau.fi/whatsmeow v0.0.0-20220217121823-b7d4c5a8e8cc/go.mod h1:NNI4Ah/B27mfQNChJMD1iSO8+HS+fQ4WqNuQ8Mh2/XI=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// mautrix-whatsapp - A Matrix-WhatsApp puppeting bridge.
|
||||
// Copyright (C) 2021 Tulir Asokan
|
||||
// Copyright (C) 2022 Tulir Asokan
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
|
@ -29,7 +29,9 @@ import (
|
|||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/gorilla/websocket"
|
||||
|
||||
"go.mau.fi/whatsmeow/appstate"
|
||||
"go.mau.fi/whatsmeow/types"
|
||||
|
||||
"go.mau.fi/whatsmeow"
|
||||
|
||||
|
@ -55,6 +57,8 @@ func (prov *ProvisioningAPI) Init() {
|
|||
r.HandleFunc("/disconnect", prov.Disconnect).Methods(http.MethodPost)
|
||||
r.HandleFunc("/reconnect", prov.Reconnect).Methods(http.MethodPost)
|
||||
r.HandleFunc("/sync/appstate/{name}", prov.SyncAppState).Methods(http.MethodPost)
|
||||
r.HandleFunc("/contacts", prov.ListContacts).Methods(http.MethodGet)
|
||||
r.HandleFunc("/pm/{number}", prov.StartPM).Methods(http.MethodPost)
|
||||
prov.bridge.AS.Router.HandleFunc("/_matrix/app/com.beeper.asmux/ping", prov.BridgeStatePing).Methods(http.MethodPost)
|
||||
prov.bridge.AS.Router.HandleFunc("/_matrix/app/com.beeper.bridge_state", prov.BridgeStatePing).Methods(http.MethodPost)
|
||||
|
||||
|
@ -216,6 +220,84 @@ func (prov *ProvisioningAPI) SyncAppState(w http.ResponseWriter, r *http.Request
|
|||
}
|
||||
}
|
||||
|
||||
func (prov *ProvisioningAPI) ListContacts(w http.ResponseWriter, r *http.Request) {
|
||||
if user := r.Context().Value("user").(*User); user.Session == nil {
|
||||
jsonResponse(w, http.StatusBadRequest, Error{
|
||||
Error: "User is not logged into WhatsApp",
|
||||
ErrCode: "no session",
|
||||
})
|
||||
} else if contacts, err := user.Session.Contacts.GetAllContacts(); err != nil {
|
||||
prov.log.Errorfln("Failed to fetch %s's contacts: %v", user.MXID, err)
|
||||
jsonResponse(w, http.StatusInternalServerError, Error{
|
||||
Error: "Internal server error while fetching contact list",
|
||||
ErrCode: "failed to get contacts",
|
||||
})
|
||||
} else {
|
||||
jsonResponse(w, http.StatusOK, contacts)
|
||||
}
|
||||
}
|
||||
|
||||
type OtherUserInfo struct {
|
||||
MXID id.UserID `json:"mxid"`
|
||||
JID types.JID `json:"jid"`
|
||||
Name string `json:"displayname"`
|
||||
Avatar id.ContentURI `json:"avatar_url"`
|
||||
}
|
||||
|
||||
type PortalInfo struct {
|
||||
RoomID id.RoomID `json:"room_id"`
|
||||
OtherUser OtherUserInfo `json:"other_user"`
|
||||
JustCreated bool `json:"just_created"`
|
||||
}
|
||||
|
||||
func (prov *ProvisioningAPI) StartPM(w http.ResponseWriter, r *http.Request) {
|
||||
number, _ := mux.Vars(r)["number"]
|
||||
if strings.HasSuffix(number, "@"+types.DefaultUserServer) {
|
||||
jid, _ := types.ParseJID(number)
|
||||
number = "+" + jid.User
|
||||
}
|
||||
if user := r.Context().Value("user").(*User); !user.IsLoggedIn() {
|
||||
jsonResponse(w, http.StatusBadRequest, Error{
|
||||
Error: "User is not logged into WhatsApp",
|
||||
ErrCode: "no session",
|
||||
})
|
||||
} else if resp, err := user.Client.IsOnWhatsApp([]string{number}); err != nil {
|
||||
jsonResponse(w, http.StatusInternalServerError, Error{
|
||||
Error: fmt.Sprintf("Failed to check if number is on WhatsApp: %v", err),
|
||||
ErrCode: "error checking number",
|
||||
})
|
||||
} else if len(resp) == 0 {
|
||||
jsonResponse(w, http.StatusInternalServerError, Error{
|
||||
Error: "Didn't get a response to checking if the number is on WhatsApp",
|
||||
ErrCode: "error checking number",
|
||||
})
|
||||
} else if !resp[0].IsIn {
|
||||
jsonResponse(w, http.StatusNotFound, Error{
|
||||
Error: fmt.Sprintf("The server said +%s is not on WhatsApp", resp[0].JID.User),
|
||||
ErrCode: "not on whatsapp",
|
||||
})
|
||||
} else if portal, puppet, justCreated, err := user.StartPM(resp[0].JID, "provisioning API PM"); err != nil {
|
||||
jsonResponse(w, http.StatusInternalServerError, Error{
|
||||
Error: fmt.Sprintf("Failed to create portal: %v", err),
|
||||
})
|
||||
} else {
|
||||
status := http.StatusOK
|
||||
if justCreated {
|
||||
status = http.StatusCreated
|
||||
}
|
||||
jsonResponse(w, status, PortalInfo{
|
||||
RoomID: portal.MXID,
|
||||
OtherUser: OtherUserInfo{
|
||||
JID: puppet.JID,
|
||||
MXID: puppet.MXID,
|
||||
Name: puppet.Displayname,
|
||||
Avatar: puppet.AvatarURL,
|
||||
},
|
||||
JustCreated: justCreated,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (prov *ProvisioningAPI) Ping(w http.ResponseWriter, r *http.Request) {
|
||||
user := r.Context().Value("user").(*User)
|
||||
wa := map[string]interface{}{
|
||||
|
|
18
user.go
18
user.go
|
@ -1035,3 +1035,21 @@ func (user *User) handlePictureUpdate(evt *events.Picture) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (user *User) StartPM(jid types.JID, reason string) (*Portal, *Puppet, bool, error) {
|
||||
user.log.Debugln("Starting PM with", jid, "from", reason)
|
||||
puppet := user.bridge.GetPuppetByJID(jid)
|
||||
puppet.SyncContact(user, true, reason)
|
||||
portal := user.GetPortalByJID(puppet.JID)
|
||||
if len(portal.MXID) > 0 {
|
||||
ok := portal.ensureUserInvited(user)
|
||||
if !ok {
|
||||
portal.log.Warnfln("ensureUserInvited(%s) returned false, creating new portal", user.MXID)
|
||||
portal.MXID = ""
|
||||
} else {
|
||||
return portal, puppet, false, nil
|
||||
}
|
||||
}
|
||||
err := portal.CreateMatrixRoom(user, nil, false)
|
||||
return portal, puppet, true, err
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue