2021-02-27 14:57:48 -08:00
|
|
|
package bsignald
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bufio"
|
|
|
|
"net"
|
|
|
|
"encoding/json"
|
|
|
|
"github.com/42wim/matterbridge/bridge"
|
|
|
|
"github.com/42wim/matterbridge/bridge/config"
|
|
|
|
)
|
|
|
|
|
|
|
|
type JSONCMD map[string]interface{}
|
|
|
|
|
|
|
|
const (
|
|
|
|
cfgNumber = "Number"
|
|
|
|
cfgSocket = "UnixSocket"
|
|
|
|
cfgGroupID = "GroupID"
|
|
|
|
)
|
|
|
|
|
2021-02-28 10:18:38 -08:00
|
|
|
type signaldMessage struct {
|
|
|
|
ID string
|
|
|
|
Type string
|
|
|
|
Error json.RawMessage
|
|
|
|
Data json.RawMessage
|
|
|
|
}
|
|
|
|
|
|
|
|
type signaldUnexpectedError struct {
|
|
|
|
Message string
|
|
|
|
}
|
|
|
|
|
|
|
|
type signaldMessageData struct {
|
|
|
|
ID string `json:",omitempty"`
|
|
|
|
Data signaldData `json:",omitempty"`
|
|
|
|
Type string `json:",omitempty"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type signaldData struct {
|
|
|
|
CallMessage json.RawMessage `json:"callMessage,omitempty"`
|
|
|
|
DataMessage *signaldDataMessage `json:"dataMessage,omitempty"`
|
|
|
|
HasContent bool `json:"hasContent,omitempty"`
|
|
|
|
HasLegacyMessage bool `json:"hasLegacyMessage,omitempty"`
|
|
|
|
IsUnidentifiedSender bool `json:"isUnidentifiedSender,omitempty"`
|
|
|
|
Receipt json.RawMessage `json:"receipt,omitempty"`
|
|
|
|
Relay string `json:"relay,omitempty"`
|
|
|
|
ServerDeliveredTimestamp int64 `json:"serverDeliveredTimestamp,omitempty"`
|
|
|
|
ServerTimestamp int64 `json:"serverTimestamp,omitempty"`
|
|
|
|
Source *signaldAccount `json:"source,omitempty"`
|
|
|
|
SourceDevice int32 `json:"sourceDevice,omitempty"`
|
|
|
|
SyncMessage json.RawMessage `json:"syncMessage,omitempty"`
|
|
|
|
Timestamp int64 `json:"timestamp,omitempty"`
|
|
|
|
TimestampISO string `json:"timestampISO,omitempty"`
|
|
|
|
Type string `json:"type,omitempty"`
|
|
|
|
Typing json.RawMessage `json:"typing,omitempty"`
|
|
|
|
Username string `json:"username,omitempty"`
|
|
|
|
UUID string `json:"uuid,omitempty"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type signaldAccount struct {
|
|
|
|
Number string `json:"number,omitempty"`
|
|
|
|
Relay string `json:"relay,omitempty"`
|
|
|
|
UUID string `json:"uuid,omitempty"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type signaldDataMessage struct {
|
|
|
|
Attachments json.RawMessage `json:"attachments,omitempty"`
|
|
|
|
Body string `json:"body,omitempty"`
|
|
|
|
Contacts json.RawMessage `json:"contacts,omitempty"`
|
|
|
|
EndSession bool `json:"endSession,omitempty"`
|
|
|
|
ExpiresInSeconds int32 `json:"expiresInSeconds,omitempty"`
|
|
|
|
Group *signaldGroupInfo `json:"group,omitempty"`
|
|
|
|
GroupV2 *signaldGroupV2Info `json:"groupV2,omitempty"`
|
|
|
|
Mentions json.RawMessage `json:"mentions,omitempty"`
|
|
|
|
Previews json.RawMessage `json:"previews,omitempty"`
|
|
|
|
ProfileKeyUpdate bool `json:"profileKeyUpdate,omitempty"`
|
|
|
|
Quote json.RawMessage `json:"quote,omitempty"`
|
|
|
|
Reaction json.RawMessage `json:"reaction,omitempty"`
|
|
|
|
RemoteDelete json.RawMessage `json:"remoteDelete,omitempty"`
|
|
|
|
Sticker json.RawMessage `json:"sticker,omitempty"`
|
|
|
|
Timestamp int64 `json:"timestamp,omitempty"`
|
|
|
|
ViewOnce bool `json:"viewOnce,omitempty"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type signaldGroupInfo struct {
|
|
|
|
AvatarId int64 `json:"avatarId,omitempty"`
|
|
|
|
GroupId string `json:"groupId,omitempty"`
|
|
|
|
Members json.RawMessage `json:"members,omitempty"`
|
|
|
|
Name string `json:"name,omitempty"`
|
|
|
|
Type string `json:"type,omitempty"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type signaldGroupV2Info struct {
|
|
|
|
AccessControl json.RawMessage `json:"accessControl,omitempty"`
|
|
|
|
Avatar string `json:"avatar,omitempty"`
|
|
|
|
ID string `json:"id,omitempty"`
|
|
|
|
InviteLink string `json:"inviteLink,omitempty"`
|
|
|
|
MemberDetail json.RawMessage `json:"memberDetail,omitempty"`
|
|
|
|
Members json.RawMessage `json:"members,omitempty"`
|
|
|
|
PendingMemberDetail json.RawMessage `json:"pendingMemberDetail,omitempty"`
|
|
|
|
PendingMembers json.RawMessage `json:"pendingMembers,omitempty"`
|
|
|
|
RequestingMembers json.RawMessage `json:"requestingMembers,omitempty"`
|
|
|
|
Revision int32 `json:"revision,omitempty"`
|
|
|
|
Timer int32 `json:"timer,omitempty"`
|
|
|
|
Title string `son:"title,omitempty"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type signaldSendMessage struct {
|
|
|
|
Username string `json:"username,omitempty"`
|
|
|
|
//RecipientAddress signaldAccount `json:"recipientAddress,omitempty"`
|
|
|
|
RecipientGroupId string `json:"recipientGroupId,omitempty"`
|
|
|
|
MessageBody string `json:"messageBody,omitempty"`
|
|
|
|
//Attachments json.RawMessage `json:"attachments,omitempty"`
|
|
|
|
//Quote json.RawMessage `json:"quote,omitempty"`
|
|
|
|
//Timestamp int64 `json:"timestamp,omitempty"`
|
|
|
|
//Mentions json.RawMessage `json:"mentions,omitempty"`
|
2021-02-27 14:57:48 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
type Bsignald struct {
|
|
|
|
*bridge.Config
|
|
|
|
socketpath string
|
|
|
|
socket net.Conn
|
|
|
|
subscribed bool
|
|
|
|
reader *bufio.Scanner
|
|
|
|
//listeners map[string]chan signald.BasicResponse
|
|
|
|
groupid string
|
|
|
|
}
|
|
|
|
|
|
|
|
func New(cfg *bridge.Config) bridge.Bridger {
|
|
|
|
number := cfg.GetString(cfgNumber)
|
|
|
|
if number == "" {
|
|
|
|
cfg.Log.Fatalf("Missing configuration for Signald bridge: Number")
|
|
|
|
}
|
|
|
|
|
|
|
|
socketpath := cfg.GetString(cfgSocket)
|
|
|
|
if socketpath == "" {
|
|
|
|
socketpath = "/var/run/signald/signald.sock"
|
|
|
|
}
|
|
|
|
|
|
|
|
return &Bsignald{
|
|
|
|
Config: cfg,
|
|
|
|
socketpath: socketpath,
|
|
|
|
subscribed: false,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (b *Bsignald) Connect() error {
|
|
|
|
b.Log.Infof("Connecting %s", b.socketpath)
|
|
|
|
|
|
|
|
s, err := net.Dial("unix", b.socketpath)
|
|
|
|
if err != nil {
|
|
|
|
b.Log.Fatalf(err.Error())
|
|
|
|
}
|
|
|
|
//defer s.Close()
|
|
|
|
b.socket = s
|
|
|
|
r := bufio.NewScanner(s)
|
|
|
|
b.reader = r
|
|
|
|
go b.Listen()
|
|
|
|
go b.Login()
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (b *Bsignald) JoinChannel(channel config.ChannelInfo) error {
|
|
|
|
b.groupid = channel.Name
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (b *Bsignald) Listen() {
|
|
|
|
for {
|
|
|
|
for b.reader.Scan() {
|
|
|
|
if err := b.reader.Err(); err != nil {
|
|
|
|
b.Log.Errorf(err.Error())
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
raw := b.reader.Text()
|
|
|
|
|
2021-02-28 10:18:38 -08:00
|
|
|
var msg signaldMessage
|
2021-02-27 14:57:48 -08:00
|
|
|
if err := json.Unmarshal([]byte(raw), &msg); err != nil {
|
|
|
|
b.Log.Errorln("Error unmarshaling raw response:", err.Error())
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
if msg.Type == "unexpected_error" {
|
2021-02-28 10:18:38 -08:00
|
|
|
var errorResponse signaldUnexpectedError
|
2021-02-27 14:57:48 -08:00
|
|
|
if err := json.Unmarshal(msg.Data, &errorResponse); err != nil {
|
2021-02-28 10:18:38 -08:00
|
|
|
b.Log.Errorln("Error unmarshaling error response:", err.Error())
|
2021-02-27 14:57:48 -08:00
|
|
|
continue
|
|
|
|
}
|
2021-02-28 10:18:38 -08:00
|
|
|
b.Log.Errorln("Unexpected error", errorResponse.Message)
|
2021-02-27 14:57:48 -08:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
if msg.Type != "message" {
|
2021-02-28 10:18:38 -08:00
|
|
|
b.Log.Debugln("skipping: not 'message'");
|
2021-02-27 14:57:48 -08:00
|
|
|
continue
|
2021-02-28 10:18:38 -08:00
|
|
|
} else {
|
|
|
|
b.Log.Debugln("FOUND A MESSAGE!", raw);
|
|
|
|
|
2021-02-27 14:57:48 -08:00
|
|
|
}
|
|
|
|
|
2021-02-28 10:18:38 -08:00
|
|
|
response := signaldMessageData{ID: msg.ID, Type: msg.Type}
|
2021-02-27 14:57:48 -08:00
|
|
|
if err := json.Unmarshal(msg.Data, &response.Data); err != nil {
|
2021-02-28 10:18:38 -08:00
|
|
|
b.Log.Errorln("receive error: ", err)
|
2021-02-27 14:57:48 -08:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2021-02-28 10:18:38 -08:00
|
|
|
//b.Log.Debugf("%#v", response);
|
2021-02-27 14:57:48 -08:00
|
|
|
|
|
|
|
if response.Data.DataMessage != nil {
|
|
|
|
if response.Data.DataMessage.GroupV2 != nil {
|
|
|
|
if b.groupid == response.Data.DataMessage.GroupV2.ID {
|
|
|
|
rmsg := config.Message{
|
2021-02-28 10:18:38 -08:00
|
|
|
UserID: response.Data.Source.UUID,
|
|
|
|
Username: response.Data.Source.Number,
|
2021-02-27 14:57:48 -08:00
|
|
|
Text: response.Data.DataMessage.Body,
|
|
|
|
Channel: response.Data.DataMessage.GroupV2.ID,
|
|
|
|
Account: b.Account,
|
|
|
|
Protocol: b.Protocol,
|
|
|
|
}
|
|
|
|
b.Log.Debugf("<= Sending message from %s on %s to gateway", rmsg.Username, b.Account)
|
|
|
|
b.Log.Debugf("<= Message is %#v", rmsg)
|
|
|
|
b.Remote <- rmsg
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//if response.Data.SyncMessage != nil {
|
|
|
|
//if response.Data.SyncMessage.Sent != nil {
|
|
|
|
//if response.Data.SyncMessage.Sent.Message != nil {
|
|
|
|
//if response.Data.SyncMessage.Sent.Message != nil {
|
|
|
|
//if response.Data.SyncMessage.Sent.Message.GroupV2 != nil {
|
|
|
|
//if b.groupid == response.Data.SyncMessage.Sent.Message.GroupV2.id {
|
|
|
|
|
|
|
|
//}
|
|
|
|
//}
|
|
|
|
//}
|
|
|
|
//}
|
|
|
|
//}
|
|
|
|
//}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (b *Bsignald) Login() error {
|
|
|
|
if ! b.subscribed {
|
|
|
|
subscribe := JSONCMD{
|
|
|
|
"type": "subscribe",
|
|
|
|
"username": b.GetString(cfgNumber),
|
|
|
|
}
|
|
|
|
err := json.NewEncoder(b.socket).Encode(subscribe)
|
|
|
|
if err != nil {
|
|
|
|
b.Log.Fatalf(err.Error())
|
|
|
|
}
|
|
|
|
// TODO: this should be done from the listener after the response
|
|
|
|
// was checked
|
|
|
|
b.subscribed = true
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (b *Bsignald) Disconnect() error {
|
|
|
|
b.Log.Debugln("Disconnecting..")
|
|
|
|
b.socket.Close()
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (b *Bsignald) Send(msg config.Message) (string, error) {
|
2021-02-28 10:18:38 -08:00
|
|
|
b.Log.Debugf("message to forward into signal: %#v", msg)
|
2021-02-27 14:57:48 -08:00
|
|
|
|
2021-02-28 10:18:38 -08:00
|
|
|
msgJSON := JSONCMD{
|
|
|
|
"type": "send",
|
|
|
|
"username": b.GetString(cfgNumber),
|
|
|
|
"recipientGroupId": b.groupid,
|
|
|
|
"messageBody": msg.Text,
|
|
|
|
}
|
|
|
|
err := json.NewEncoder(b.socket).Encode(msgJSON)
|
|
|
|
if err != nil {
|
|
|
|
b.Log.Errorln(err.Error())
|
|
|
|
}
|
2021-02-27 14:57:48 -08:00
|
|
|
|
2021-02-28 10:18:38 -08:00
|
|
|
return "", err
|
2021-02-27 14:57:48 -08:00
|
|
|
}
|