Browse Source

Add some documentation

Brendan Abolivier 2 years ago
parent
commit
d22266b26b
Signed by: Brendan Abolivier <contact@brendanabolivier.com> GPG key ID: 8EF1500759F70623
4 changed files with 107 additions and 10 deletions
  1. 50
    0
      README.md
  2. 11
    0
      config.sample.yaml
  3. 15
    3
      src/config/config.go
  4. 31
    7
      src/fixer/main.go

+ 50
- 0
README.md View File

@@ -0,0 +1,50 @@
1
+# Fixer for Matrix's Facebook Messenger puppet bridge
2
+
3
+I'm using the [Matrix↔️Facebook Messenger puppet bridge](https://github.com/matrix-hacks/matrix-puppet-facebook) to talk with my friends on Facebook using [Riot](https://riot.im) plugged to my [Matrix](https://matrix.org) homeserver.
4
+
5
+When I'm having a 1:1 chat with a Facebook friend, the bridge creates a with the friend, the appservice's bot and myself. Because of that, and also because it doesn't automatically set the room's avatar and name, I have troubles identifying what's happening in that room.
6
+
7
+This small tool will take the local part of the room ID created by the Matrix↔️Facebook Messenger bot once the friend has joined it, identify the friend, and grab their avatar and display name to set the room's.
8
+
9
+**Note: I'm not shaming anyone here, as the bridge is currently still in development. This is totally a temporary solution.**
10
+
11
+## Install
12
+
13
+You'll first need a Go install, and [gb](https://getgb.io/):
14
+
15
+```
16
+go get github.com/constabulary/gb/...
17
+```
18
+
19
+Then clone this repo on your computer (or server), walk into it, install its dependencies and build it:
20
+
21
+```
22
+git clone https://github.com/babolivier/matrix-puppet-facebook-1to1-fixer
23
+cd matrix-puppet-facebook-1to1-fixer
24
+gb vendor restore
25
+gb build
26
+```
27
+
28
+## Configure
29
+
30
+An example configuration is located in the [config.sample.yaml](config.sample.yaml) file.
31
+
32
+Copy it somewhere, and edit it accordingly with the key's comments.
33
+
34
+## Run
35
+
36
+You have to run this tool manually for each room you want to edit.
37
+
38
+You can run this tool by typing
39
+
40
+```
41
+./bin/fixer --room-id-localpart ROOM_ID_LOCALPART
42
+```
43
+
44
+where `ROOM_ID_LOCALPART` is the room's ID's localpart (which usually looks like something like `ZUFHhmRzEyUdzljKRz`).
45
+
46
+If you moved your configuration file to a different path than `./config.yaml`, you can specify the configuration file's path by appending the `--config CONFIG_PATH` to your command, where `CONFIG_PATH` is the path to your configuration file.
47
+
48
+## Stuff it doesn't do
49
+
50
+Because it's not supported by [gomatrix](https://github.com/matrix-org/gomatrix) yet, this tool won't set the room as direct chat, nor will it change its push notification settings. These features will be added as soon as gomatrix supports them.

+ 11
- 0
config.sample.yaml View File

@@ -0,0 +1,11 @@
1
+# Matrix-related settings
2
+matrix:
3
+  # The full URL of the homeserver to contact.
4
+  homeserver_url: https://matrix.org
5
+  # The server name of the homeserver to contact.
6
+  server_name: matrix.org
7
+  # The local part from the bridge user's Matrix ID. In the example shown in this
8
+  # sample file, the user's Matrix ID is @Alice:matrix.org.
9
+  localpart: Alice
10
+  # The bridge user's access token.
11
+  access_token: ACCESS_TOKEN

+ 15
- 3
src/config/config.go View File

@@ -6,25 +6,37 @@ import (
6 6
 	"gopkg.in/yaml.v2"
7 7
 )
8 8
 
9
+// Config represents the full configuration.
9 10
 type Config struct {
10 11
 	Matrix MatrixConfig `yaml:"matrix"`
11 12
 }
12 13
 
14
+// MatrixConfig represents the Matrix part of the configuration.
13 15
 type MatrixConfig struct {
16
+	// HomeserverURL is the full URL of the homeserver to contact
17
+	// (e.g. https://matrix.org/).
14 18
 	HomeserverURL string `yaml:"homeserver_url"`
15
-	ServerName    string `yaml:"server_name"`
16
-	Localpart     string `yaml:"localpart"`
17
-	AccessToken   string `yaml:"access_token"`
19
+	// ServerName is the server name of the homeserver to contact
20
+	// (e.g. matrix.org)0.
21
+	ServerName string `yaml:"server_name"`
22
+	// Localpart is the local part from the bridge user's Matrix ID (e.g. Alice).
23
+	Localpart string `yaml:"localpart"`
24
+	// AccessToken is the bridge user's access token.
25
+	AccessToken string `yaml:"access_token"`
18 26
 }
19 27
 
28
+// Parse reads the file located at the provided path then proceeds to create and
29
+// fill in a Config instance.
20 30
 func Parse(path string) (cfg *Config, err error) {
21 31
 	cfg = new(Config)
22 32
 
33
+	// Load the content from the configuration file.
23 34
 	content, err := ioutil.ReadFile(path)
24 35
 	if err != nil {
25 36
 		return
26 37
 	}
27 38
 
39
+	// Parse the YAML content from the configuration file.
28 40
 	err = yaml.Unmarshal(content, cfg)
29 41
 	return
30 42
 }

+ 31
- 7
src/fixer/main.go View File

@@ -4,6 +4,7 @@ import (
4 4
 	"flag"
5 5
 	"fmt"
6 6
 	"os"
7
+	"regexp"
7 8
 
8 9
 	"config"
9 10
 
@@ -13,9 +14,9 @@ import (
13 14
 
14 15
 // Fixed variables
15 16
 var (
16
-	// ErrEmptyRoomID is fired if no room ID localpart has been provided, and is
17
-	// followed by the command's usage.
18
-	ErrEmptyRoomID = fmt.Errorf("The room ID localpart cannot be empty")
17
+	// ErrRoomIDEmptyOrInvalid is fired if no room ID localpart has been provided
18
+	// or is invalid, and is followed by the command's usage.
19
+	ErrRoomIDEmptyOrInvalid = fmt.Errorf("The room ID localpart is either empty or invalid")
19 20
 	// ErrInvalidRoomMembersNb is fired if the number of joined members in the
20 21
 	// room isn't 3 (i.e.: the user, their friend, and the Facebook bot).
21 22
 	ErrInvalidRoomMembersNb = fmt.Errorf("Invalid number of members in the room: either the friend hasn't joined yet, or there's more than one friend in the room")
@@ -29,12 +30,12 @@ var (
29 30
 	InfoNameUpdated = "Room's name updated"
30 31
 	// InfoProcessIsOver is displayed once the whole process is over, just before
31 32
 	// exiting.
32
-	InfoProcessIsOver = "The room has been fully updated. Don't forget to mark it as direct chat in Riot, and to edit its push rules."
33
+	InfoProcessIsOver = "The room has been fully updated. Don't forget to mark it as direct chat in Riot, and to edit its notification rules."
33 34
 )
34 35
 
35 36
 // Command line flags
36 37
 var (
37
-	localpart  = flag.String("room-id-localpart", "", "Room ID localpart")
38
+	localpart  = flag.String("room-id-localpart", "", "Room ID localpart (i.e. 'ZUFHhmRzEyUdzljKRz')")
38 39
 	configFile = flag.String("config", "config.yaml", "Configuration file")
39 40
 )
40 41
 
@@ -55,44 +56,57 @@ func main() {
55 56
 
56 57
 	flag.Parse()
57 58
 
58
-	if len(*localpart) == 0 {
59
-		logrus.Error(ErrEmptyRoomID)
59
+	// We need the room ID's localpart to be non-empty and only composed of letters.
60
+	roomIDLocalpartRgxp := regexp.MustCompile("^[a-zA-Z]+")
61
+	if len(*localpart) == 0 || !roomIDLocalpartRgxp.Match([]byte(*localpart)) {
62
+		logrus.Error(ErrRoomIDEmptyOrInvalid)
60 63
 		flag.Usage()
61 64
 		os.Exit(1)
62 65
 	}
63 66
 
67
+	// Load the configuration from the configuration file.
64 68
 	cfg, err := config.Parse(*configFile)
65 69
 	if err != nil {
66 70
 		panic(err)
67 71
 	}
68 72
 
73
+	// Compute the room's ID along with the current user's.
69 74
 	roomID := fmt.Sprintf("!%s:%s", *localpart, cfg.Matrix.ServerName)
70 75
 	userID := fmt.Sprintf("@%s:%s", cfg.Matrix.Localpart, cfg.Matrix.ServerName)
71 76
 
77
+	// Load the Matrix client from configuration data.
72 78
 	cli, err := gomatrix.NewClient(cfg.Matrix.HomeserverURL, userID, cfg.Matrix.AccessToken)
73 79
 	if err != nil {
74 80
 		logrus.Panic(err)
75 81
 	}
76 82
 
83
+	// Retrieve the list of joined members in the room.
77 84
 	membersResp, err := cli.JoinedMembers(roomID)
78 85
 	if err != nil {
79 86
 		logrus.Panic(err)
80 87
 	}
81 88
 
89
+	// Retrieve the current user's own display  name.
82 90
 	displayNameResp, err := cli.GetOwnDisplayName()
83 91
 	if err != nil {
84 92
 		logrus.Panic(err)
85 93
 	}
86 94
 
95
+	// Check if the number of joined members is three, as it should be with a
96
+	// 1:1 puppeted chat (the current user, their friend, and the AS bot).
87 97
 	if len(membersResp.Joined) != 3 {
88 98
 		logrus.Error(ErrInvalidRoomMembersNb)
89 99
 		os.Exit(1)
90 100
 	}
91 101
 
102
+	// Iterate over the slice of joined members.
92 103
 	var avatarURL, displayName string
93 104
 	for _, member := range membersResp.Joined {
105
+		// The friend should be the only joined member who has a display name set
106
+		// which isn't the same as the current user's.
94 107
 		if member.DisplayName != nil && *(member.DisplayName) != displayNameResp.DisplayName {
95 108
 			displayName = *(member.DisplayName)
109
+			// If there's also an avatar set for the friend, use it.
96 110
 			if member.AvatarURL != nil {
97 111
 				avatarURL = *(member.AvatarURL)
98 112
 			}
@@ -104,6 +118,8 @@ func main() {
104 118
 		"avatar_url":   avatarURL,
105 119
 	}).Info("Found the friend")
106 120
 
121
+	// If the avatar has been found, set it as the room's avatar using a
122
+	// m.room.avatar state event.
107 123
 	if len(avatarURL) > 0 {
108 124
 		if _, err := cli.SendStateEvent(
109 125
 			roomID,
@@ -117,9 +133,13 @@ func main() {
117 133
 		}
118 134
 		logrus.Info(InfoAvatarUpdated)
119 135
 	} else {
136
+		// Else print a warning so the user can see it clearly.
120 137
 		logrus.Warn(WarnNoAvatar)
121 138
 	}
122 139
 
140
+	// If the display name has been found, set it as the room's name using a
141
+	// m.room.name state event. This condition shouldn't be necessary, but heh,
142
+	// at least that might cover a potential regression from the bridge.
123 143
 	if len(displayName) > 0 {
124 144
 		if _, err := cli.SendStateEvent(
125 145
 			roomID,
@@ -133,8 +153,12 @@ func main() {
133 153
 		}
134 154
 		logrus.Info(InfoNameUpdated)
135 155
 	} else {
156
+		// Else print a warning so the user can see it clearly.
136 157
 		logrus.Warn(WarnNoDisplayName)
137 158
 	}
138 159
 
160
+	// Print a shiny message telling the user the process is over, but it's up
161
+	// to them to set the room as a direct chat and to update the room's push
162
+	// notification settings, since that's not supported by gomatrix.
139 163
 	logrus.Info(InfoProcessIsOver)
140 164
 }