/
synchronisation.go
123 lines (105 loc) · 2.67 KB
/
synchronisation.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
// Synchronization management message handlers
package websockets
import (
"errors"
"meguca/auth"
"meguca/common"
"meguca/db"
"meguca/websockets/feeds"
"golang.org/x/crypto/bcrypt"
)
var (
errInvalidBoard = errors.New("invalid board")
errInvalidThread = errors.New("invalid thread")
errBanned = errors.New("you are banned from this board")
)
type syncRequest struct {
Thread uint64
Board string
}
type reclaimRequest struct {
ID uint64
Password string
}
// Synchronise the client to a certain thread, assign it's ID and prepare to
// receive update messages.
func (c *Client) synchronise(data []byte) error {
var msg syncRequest
err := decodeMessage(data, &msg)
switch {
case err != nil:
return err
case !auth.IsBoard(msg.Board):
return errInvalidBoard
case auth.IsBanned(msg.Board, c.ip):
return errBanned
case msg.Thread != 0:
valid, err := db.ValidateOP(msg.Thread, msg.Board)
switch {
case err != nil:
return err
case !valid:
return errInvalidThread
}
}
return c.registerSync(msg.Thread, msg.Board)
}
// Register fresh client sync or change from previous sync
func (c *Client) registerSync(id uint64, board string) (err error) {
// Don't close OP's, as navigating to the thread is a natural part of
// thread creation
if c.post.id != 0 && c.post.id != c.post.op {
err = c.closePreviousPost()
if err != nil {
return
}
}
c.feed, err = feeds.SyncClient(c, id, board)
if err != nil {
return
}
// Still sending something for consistency, but there is no actual syncing
// to board pages
if id == 0 {
return c.sendMessage(common.MessageSynchronise, nil)
}
return
}
// Reclaim an open post after connection loss or navigating away.
//
// TODO: Technically there is no locking performed so a single post may be open
// by multiple clients. This opens us up to some exploits, but nothing severe.
// Still need to think of a solution.
func (c *Client) reclaimPost(data []byte) error {
if err := c.closePreviousPost(); err != nil {
return err
}
var req reclaimRequest
if err := decodeMessage(data, &req); err != nil {
return err
}
hash, err := db.GetPostPassword(req.ID)
switch {
case err != nil:
return err
case hash == nil:
return c.sendMessage(common.MessageReclaim, 1)
}
switch err = auth.BcryptCompare(req.Password, hash); err {
case nil:
case bcrypt.ErrMismatchedHashAndPassword:
return c.sendMessage(common.MessageReclaim, 1)
default:
return err
}
post, err := db.GetPost(req.ID)
switch {
case err != nil:
return err
case !post.Editing:
return c.sendMessage(common.MessageReclaim, 1)
}
c.post.init(post)
c.feed.InsertPost(post, c.post.body, nil)
return c.sendMessage(common.MessageReclaim, 0)
}