Эх сурвалжийг харах

Initial config structs and example config, some whatsapp testing

Tulir Asokan 6 жил өмнө
parent
commit
ace08205d9
7 өөрчлөгдсөн 396 нэмэгдсэн , 2 устгасан
  1. 1 0
      .gitignore
  2. 76 0
      config/bridge.go
  3. 81 0
      config/config.go
  4. 62 0
      config/registration.go
  5. 60 0
      example-config.yaml
  6. 95 2
      main.go
  7. 21 0
      matrix.go

+ 1 - 0
.gitignore

@@ -1 +1,2 @@
 .idea
+*.session

+ 76 - 0
config/bridge.go

@@ -0,0 +1,76 @@
+// mautrix-whatsapp - A Matrix-Whatsapp puppeting bridge.
+// Copyright (C) 2018 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
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <https://www.gnu.org/licenses/>.
+
+package config
+
+import (
+	"bytes"
+	"text/template"
+)
+
+type BridgeConfig struct {
+	RawUsernameTemplate    string             `yaml:"username_template"`
+	RawDisplaynameTemplate string             `yaml:"displayname_template"`
+	UsernameTemplate       *template.Template `yaml:"-"`
+	DisplaynameTemplate    *template.Template `yaml:"-"`
+}
+
+func (bc BridgeConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
+	err := unmarshal(bc)
+	if err != nil {
+		return err
+	}
+
+	bc.UsernameTemplate, err = template.New("username").Parse(bc.RawUsernameTemplate)
+	if err != nil {
+		return err
+	}
+
+	bc.DisplaynameTemplate, err = template.New("displayname").Parse(bc.RawDisplaynameTemplate)
+	return err
+}
+
+type DisplaynameTemplateArgs struct {
+	Displayname string
+}
+
+type UsernameTemplateArgs struct {
+	Receiver string
+	UserID   string
+}
+
+func (bc BridgeConfig) FormatDisplayname(displayname string) string {
+	var buf bytes.Buffer
+	bc.DisplaynameTemplate.Execute(&buf, DisplaynameTemplateArgs{
+		Displayname: displayname,
+	})
+	return buf.String()
+}
+
+func (bc BridgeConfig) FormatUsername(receiver, userID string) string {
+	var buf bytes.Buffer
+	bc.UsernameTemplate.Execute(&buf, UsernameTemplateArgs{
+		Receiver: receiver,
+		UserID:   userID,
+	})
+	return buf.String()
+}
+
+func (bc BridgeConfig) MarshalYAML() (interface{}, error) {
+	bc.RawDisplaynameTemplate = bc.FormatDisplayname("{{.Displayname}}")
+	bc.RawUsernameTemplate = bc.FormatUsername("{{.Receiver}}", "{{.UserID}}")
+	return bc, nil
+}

+ 81 - 0
config/config.go

@@ -0,0 +1,81 @@
+// mautrix-whatsapp - A Matrix-Whatsapp puppeting bridge.
+// Copyright (C) 2018 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
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <https://www.gnu.org/licenses/>.
+
+package config
+
+import (
+	"maunium.net/go/mautrix-appservice"
+	"io/ioutil"
+	"gopkg.in/yaml.v2"
+)
+
+type Config struct {
+	Homeserver struct {
+		Address string `yaml:"address"`
+		Domain  string `yaml:"domain"`
+	} `yaml:"homeserver"`
+
+	AppService struct {
+		Address  string `yaml:"address"`
+		Hostname string `yaml:"hostname"`
+		Port     uint16 `yaml:"port"`
+
+		Database string `yaml:"database"`
+
+		ID  string `yaml:"id"`
+		Bot struct {
+			Username    string `yaml:"username"`
+			Displayname string `yaml:"displayname"`
+			Avatar      string `yaml:"avatar"`
+		} `yaml:"bot"`
+
+		ASToken string `yaml:"as_token"`
+		HSToken string `yaml:"hs_token"`
+	} `yaml:"appservice"`
+
+	Bridge BridgeConfig `yaml:"bridge"`
+
+	Logging appservice.LogConfig `yaml:"logging"`
+}
+
+func Load(path string) (*Config, error) {
+	data, err := ioutil.ReadFile(path)
+	if err != nil {
+		return nil, err
+	}
+
+	var config = &Config{}
+	err = yaml.Unmarshal(data, config)
+	return config, err
+}
+
+func (config *Config) Save(path string) error {
+	data, err := yaml.Marshal(config)
+	if err != nil {
+		return err
+	}
+	return ioutil.WriteFile(path, data, 0600)
+}
+
+func (config *Config) Appservice() (*appservice.Config, error) {
+	as := appservice.Create()
+	as.LogConfig = config.Logging
+	as.HomeserverDomain = config.Homeserver.Domain
+	as.HomeserverURL = config.Homeserver.Address
+	var err error
+	as.Registration, err = config.GetRegistration()
+	return as, err
+}

+ 62 - 0
config/registration.go

@@ -0,0 +1,62 @@
+// mautrix-whatsapp - A Matrix-Whatsapp puppeting bridge.
+// Copyright (C) 2018 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
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <https://www.gnu.org/licenses/>.
+
+package config
+
+import (
+	"maunium.net/go/mautrix-appservice"
+	"regexp"
+)
+
+func (config *Config) NewRegistration() (*appservice.Registration, error) {
+	registration := appservice.CreateRegistration("mautrix-whatsapp")
+
+	err := config.copyToRegistration(registration)
+	if err != nil {
+		return nil, err
+	}
+
+	config.AppService.ASToken = registration.AppToken
+	config.AppService.HSToken = registration.ServerToken
+	return registration, nil
+}
+
+func (config *Config) GetRegistration() (*appservice.Registration, error) {
+	registration := appservice.CreateRegistration("mautrix-whatsapp")
+
+	err := config.copyToRegistration(registration)
+	if err != nil {
+		return nil, err
+	}
+
+	registration.AppToken = config.AppService.ASToken
+	registration.ServerToken = config.AppService.HSToken
+	return registration, nil
+}
+
+func (config *Config) copyToRegistration(registration *appservice.Registration) error {
+	registration.ID = config.AppService.ID
+	registration.URL = config.AppService.Address
+	registration.RateLimited = false
+	registration.SenderLocalpart = config.AppService.Bot.Username
+
+	userIDRegex, err := regexp.Compile(config.Bridge.FormatUsername("[0-9]+", "[0-9]+"))
+	if err != nil {
+		return err
+	}
+	registration.Namespaces.RegisterUserIDs(userIDRegex, true)
+	return nil
+}

+ 60 - 0
example-config.yaml

@@ -0,0 +1,60 @@
+# Homeserver details.
+homeserver:
+  # The address that this appservice can use to connect to the homeserver.
+  address: https://matrix.org
+  # The domain of the homeserver (for MXIDs, etc).
+  domain: matrix.org
+
+# Application service host/registration related details.
+# Changing these values requires regeneration of the registration.
+appservice:
+  # The address that the homeserver can use to connect to this appservice.
+  address: http://localhost:8080
+
+  # The hostname and port where this appservice should listen.
+  hostname: 0.0.0.0
+  port: 8080
+
+  # The full URI to the database. Only SQLite is currently supported.
+  database: sqlite:///mautrix-whatsapp.db
+
+  # The unique ID of this appservice.
+  id: whatsapp
+  # Appservice bot details.
+  bot:
+    # Username of the appservice bot.
+    username: whatsappbot
+    # Display name and avatar for bot. Set to "remove" to remove display name/avatar, leave empty
+    # to leave display name/avatar as-is.
+    displayname: WhatsApp bridge bot
+    avatar: mxc://maunium.net/NeXNQarUbrlYBiPCpprYsRqr
+
+  # Authentication tokens for AS <-> HS communication. Autogenerated; do not modify.
+  as_token: "This value is generated when generating the registration"
+  hs_token: "This value is generated when generating the registration"
+
+# Bridge config. Currently unused.
+bridge:
+  # Localpart template of MXIDs for Whatsapp users.
+  # {{.receiver}} is replaced with the Whatsapp user ID of the Matrix user receiving messages.
+  # {{.userid}} is replaced with the user ID of the Whatsapp user.
+  username_template: "whatsapp_{{.Receiver}}_{{.UserID}}"
+  # Displayname template for Whatsapp users.
+  # {{.displayname}} is replaced with the display name of the Whatsapp user.
+  displayname_template: "{{.Displayname}}"
+
+# Logging config.
+logging:
+  # The directory for log files. Will be created if not found.
+  directory: ./logs
+  # Available variables: .date for the file date and .index for different log files on the same day.
+  file_name_format: {{.date}}-{{.index}.log
+  # Date format for file names in the Go time format: https://golang.org/pkg/time/#pkg-constants
+  file_date_format: 2006-01-02
+  # Log file permissions.
+  file_mode: 0600
+  # Timestamp format for log entries in the Go time format.
+  timestamp_format: Jan _2, 2006 15:04:05
+  # Minimum severity for log messages.
+  # Options: debug, info, warn, error, fatal
+  print_level: info

+ 95 - 2
main.go

@@ -1,4 +1,4 @@
-// mautrix-whatsapp - A puppeting Matrix-Whatsapp bridge.
+// mautrix-whatsapp - A Matrix-Whatsapp puppeting bridge.
 // Copyright (C) 2018 Tulir Asokan
 //
 // This program is free software: you can redistribute it and/or modify
@@ -16,6 +16,99 @@
 
 package main
 
+import (
+	"github.com/Rhymen/go-whatsapp"
+	"time"
+	"fmt"
+	"os"
+	"bufio"
+	"encoding/gob"
+	"github.com/mdp/qrterminal"
+)
+
 func main() {
-	
+	wac, err := whatsapp.NewConn(20 * time.Second)
+	if err != nil {
+		panic(err)
+	}
+
+	wac.AddHandler(myHandler{})
+
+	sess, err := LoadSession("whatsapp.session")
+	if err != nil {
+		fmt.Println(err)
+		sess, err = Login(wac)
+	} else {
+		sess, err = wac.RestoreSession(sess)
+	}
+	if err != nil {
+		panic(err)
+	}
+	SaveSession(sess, "whatsapp.session")
+
+	reader := bufio.NewReader(os.Stdin)
+	for {
+		fmt.Print("receiver> ")
+		receiver, _ := reader.ReadString('\n')
+		fmt.Print("message> ")
+		message, _ := reader.ReadString('\n')
+		wac.Send(whatsapp.TextMessage{
+			Info: whatsapp.MessageInfo{
+				RemoteJid: fmt.Sprintf("%s@s.whatsapp.net", receiver),
+			},
+			Text: message,
+		})
+		fmt.Println(receiver, message)
+	}
+}
+
+func Login(wac *whatsapp.Conn) (whatsapp.Session, error) {
+	qrChan := make(chan string)
+	go func() {
+		qrterminal.Generate(<-qrChan, qrterminal.L, os.Stdout)
+	}()
+	return wac.Login(qrChan)
+}
+
+func SaveSession(session whatsapp.Session, fileName string) {
+	file, err := os.OpenFile(fileName, os.O_WRONLY|os.O_CREATE, 0600)
+	if err != nil {
+		panic(err)
+	}
+
+	enc := gob.NewEncoder(file)
+	enc.Encode(session)
+}
+
+func LoadSession(fileName string) (sess whatsapp.Session, err error) {
+	file, err := os.OpenFile(fileName, os.O_RDONLY, 0600)
+	if err != nil {
+		return sess, err
+	}
+
+	dec := gob.NewDecoder(file)
+	dec.Decode(sess)
+	return
+}
+
+type myHandler struct{}
+
+func (myHandler) HandleError(err error) {
+	fmt.Fprintf(os.Stderr, "%v", err)
+}
+
+func (myHandler) HandleTextMessage(message whatsapp.TextMessage) {
+	fmt.Println(message)
+}
+
+func (myHandler) HandleImageMessage(message whatsapp.ImageMessage) {
+	fmt.Println(message)
+}
+
+func (myHandler) HandleVideoMessage(message whatsapp.VideoMessage) {
+	fmt.Println(message)
+}
+
+func (myHandler) HandleJsonMessage(message string) {
+	fmt.Println(message)
 }

+ 21 - 0
matrix.go

@@ -0,0 +1,21 @@
+// mautrix-whatsapp - A Matrix-Whatsapp puppeting bridge.
+// Copyright (C) 2018 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
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <https://www.gnu.org/licenses/>.
+
+package main
+
+func InitMatrix() {
+
+}