2015-05-01 20:59:46 +00:00
|
|
|
package server
|
2015-01-17 01:37:21 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"log"
|
2018-08-10 18:24:29 +00:00
|
|
|
"net"
|
2017-04-19 23:51:55 +00:00
|
|
|
"net/http"
|
|
|
|
"strings"
|
2015-01-17 01:37:21 +00:00
|
|
|
|
2016-03-01 00:51:26 +00:00
|
|
|
"github.com/gorilla/websocket"
|
2020-06-03 01:04:38 +00:00
|
|
|
"github.com/khlieng/dispatch/storage"
|
2015-01-17 01:37:21 +00:00
|
|
|
)
|
|
|
|
|
2015-06-16 22:46:58 +00:00
|
|
|
type wsHandler struct {
|
2015-12-29 21:23:07 +00:00
|
|
|
ws *wsConn
|
2018-05-31 21:24:59 +00:00
|
|
|
state *State
|
2018-08-10 18:24:29 +00:00
|
|
|
addr net.Addr
|
2015-06-16 22:46:58 +00:00
|
|
|
handlers map[string]func([]byte)
|
|
|
|
}
|
2015-06-05 22:34:13 +00:00
|
|
|
|
2018-05-31 21:24:59 +00:00
|
|
|
func newWSHandler(conn *websocket.Conn, state *State, r *http.Request) *wsHandler {
|
2015-06-16 22:46:58 +00:00
|
|
|
h := &wsHandler{
|
2018-05-31 21:24:59 +00:00
|
|
|
ws: newWSConn(conn),
|
|
|
|
state: state,
|
2018-08-10 18:24:29 +00:00
|
|
|
addr: conn.RemoteAddr(),
|
|
|
|
}
|
|
|
|
|
|
|
|
if r.Header.Get("X-Forwarded-For") != "" {
|
|
|
|
ip := net.ParseIP(r.Header.Get("X-Forwarded-For"))
|
|
|
|
if ip != nil {
|
|
|
|
h.addr.(*net.TCPAddr).IP = ip
|
|
|
|
}
|
2015-06-16 22:46:58 +00:00
|
|
|
}
|
2018-08-10 18:24:29 +00:00
|
|
|
|
2017-04-19 23:51:55 +00:00
|
|
|
h.init(r)
|
2016-01-26 21:10:44 +00:00
|
|
|
h.initHandlers()
|
2015-06-16 22:46:58 +00:00
|
|
|
return h
|
|
|
|
}
|
2015-01-17 01:37:21 +00:00
|
|
|
|
2015-06-16 22:46:58 +00:00
|
|
|
func (h *wsHandler) run() {
|
|
|
|
defer h.ws.close()
|
|
|
|
go h.ws.send()
|
|
|
|
go h.ws.recv()
|
2015-01-17 01:37:21 +00:00
|
|
|
|
|
|
|
for {
|
2015-06-16 22:46:58 +00:00
|
|
|
req, ok := <-h.ws.in
|
2015-06-05 22:34:13 +00:00
|
|
|
if !ok {
|
2018-05-31 21:24:59 +00:00
|
|
|
if h.state != nil {
|
2018-08-10 18:24:29 +00:00
|
|
|
h.state.deleteWS(h.addr.String())
|
2015-01-17 01:37:21 +00:00
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2015-06-16 22:46:58 +00:00
|
|
|
h.dispatchRequest(req)
|
|
|
|
}
|
|
|
|
}
|
2015-01-17 01:37:21 +00:00
|
|
|
|
2015-06-16 22:46:58 +00:00
|
|
|
func (h *wsHandler) dispatchRequest(req WSRequest) {
|
|
|
|
if handler, ok := h.handlers[req.Type]; ok {
|
|
|
|
handler(req.Data)
|
|
|
|
}
|
|
|
|
}
|
2015-01-17 01:37:21 +00:00
|
|
|
|
2017-04-19 23:51:55 +00:00
|
|
|
func (h *wsHandler) init(r *http.Request) {
|
2018-08-10 18:24:29 +00:00
|
|
|
h.state.setWS(h.addr.String(), h.ws)
|
|
|
|
h.state.user.SetLastIP(addrToIPBytes(h.addr))
|
2020-05-17 01:55:46 +00:00
|
|
|
if r.TLS != nil {
|
|
|
|
h.state.Set("scheme", "https")
|
|
|
|
} else {
|
|
|
|
h.state.Set("scheme", "http")
|
|
|
|
}
|
|
|
|
h.state.Set("host", r.Host)
|
2015-01-17 01:37:21 +00:00
|
|
|
|
2018-05-31 21:24:59 +00:00
|
|
|
log.Println(h.addr, "[State] User ID:", h.state.user.ID, "|",
|
|
|
|
h.state.numIRC(), "IRC connections |",
|
|
|
|
h.state.numWS(), "WebSocket connections")
|
2015-01-17 01:37:21 +00:00
|
|
|
|
2020-05-06 02:19:55 +00:00
|
|
|
tab, err := tabFromRequest(r)
|
|
|
|
|
2018-05-31 21:24:59 +00:00
|
|
|
channels, err := h.state.user.GetChannels()
|
|
|
|
if err != nil {
|
|
|
|
log.Println(err)
|
|
|
|
}
|
2015-01-17 01:37:21 +00:00
|
|
|
|
2016-01-15 01:27:30 +00:00
|
|
|
for _, channel := range channels {
|
2020-05-06 02:19:55 +00:00
|
|
|
if channel.Server == tab.Server && channel.Name == tab.Name {
|
2018-05-31 21:24:59 +00:00
|
|
|
// Userlist and messages for this channel gets embedded in the index page
|
2017-04-19 23:51:55 +00:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2020-06-03 01:04:38 +00:00
|
|
|
if i, ok := h.state.getIRC(channel.Server); ok {
|
|
|
|
h.state.sendJSON("users", Userlist{
|
|
|
|
Server: channel.Server,
|
|
|
|
Channel: channel.Name,
|
|
|
|
Users: i.ChannelUsers(channel.Name),
|
|
|
|
})
|
|
|
|
}
|
2017-04-19 23:51:55 +00:00
|
|
|
|
2018-05-31 21:24:59 +00:00
|
|
|
h.state.sendLastMessages(channel.Server, channel.Name, 50)
|
2015-06-16 22:46:58 +00:00
|
|
|
}
|
2020-05-06 02:19:55 +00:00
|
|
|
|
|
|
|
openDMs, err := h.state.user.GetOpenDMs()
|
|
|
|
if err != nil {
|
|
|
|
log.Println(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, openDM := range openDMs {
|
|
|
|
if openDM.Server == tab.Server && openDM.Name == tab.Name {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
h.state.sendLastMessages(openDM.Server, openDM.Name, 50)
|
|
|
|
}
|
2015-06-16 22:46:58 +00:00
|
|
|
}
|
2015-01-17 01:37:21 +00:00
|
|
|
|
2015-06-16 22:46:58 +00:00
|
|
|
func (h *wsHandler) connect(b []byte) {
|
2017-07-02 01:31:00 +00:00
|
|
|
var data Server
|
2018-05-25 21:54:36 +00:00
|
|
|
data.UnmarshalJSON(b)
|
2015-01-17 01:37:21 +00:00
|
|
|
|
2019-01-23 06:34:39 +00:00
|
|
|
data.Host = strings.ToLower(data.Host)
|
|
|
|
|
2018-05-31 21:24:59 +00:00
|
|
|
if _, ok := h.state.getIRC(data.Host); !ok {
|
2018-05-16 03:02:48 +00:00
|
|
|
log.Println(h.addr, "[IRC] Add server", data.Host)
|
2015-01-17 01:37:21 +00:00
|
|
|
|
2018-08-10 18:24:29 +00:00
|
|
|
connectIRC(data.Server, h.state, addrToIPBytes(h.addr))
|
2016-01-27 17:08:20 +00:00
|
|
|
|
2018-06-01 02:16:38 +00:00
|
|
|
go h.state.user.AddServer(data.Server)
|
2015-06-16 22:46:58 +00:00
|
|
|
} else {
|
2017-07-02 01:31:00 +00:00
|
|
|
log.Println(h.addr, "[IRC]", data.Host, "already added")
|
2015-06-16 22:46:58 +00:00
|
|
|
}
|
|
|
|
}
|
2015-01-21 02:06:34 +00:00
|
|
|
|
2017-07-04 09:28:56 +00:00
|
|
|
func (h *wsHandler) reconnect(b []byte) {
|
|
|
|
var data ReconnectSettings
|
2018-05-25 21:54:36 +00:00
|
|
|
data.UnmarshalJSON(b)
|
2017-07-04 09:28:56 +00:00
|
|
|
|
2018-05-31 21:24:59 +00:00
|
|
|
if i, ok := h.state.getIRC(data.Server); ok && !i.Connected() {
|
2020-05-23 07:42:20 +00:00
|
|
|
if i.Config.TLS {
|
|
|
|
i.Config.TLSConfig.InsecureSkipVerify = data.SkipVerify
|
2017-07-04 09:28:56 +00:00
|
|
|
}
|
|
|
|
i.Reconnect()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-16 22:46:58 +00:00
|
|
|
func (h *wsHandler) join(b []byte) {
|
|
|
|
var data Join
|
2018-05-25 21:54:36 +00:00
|
|
|
data.UnmarshalJSON(b)
|
2015-01-17 01:37:21 +00:00
|
|
|
|
2018-05-31 21:24:59 +00:00
|
|
|
if i, ok := h.state.getIRC(data.Server); ok {
|
2015-06-16 22:46:58 +00:00
|
|
|
i.Join(data.Channels...)
|
|
|
|
}
|
|
|
|
}
|
2015-01-17 01:37:21 +00:00
|
|
|
|
2015-06-16 22:46:58 +00:00
|
|
|
func (h *wsHandler) part(b []byte) {
|
|
|
|
var data Part
|
2018-05-25 21:54:36 +00:00
|
|
|
data.UnmarshalJSON(b)
|
2015-02-04 01:43:49 +00:00
|
|
|
|
2018-05-31 21:24:59 +00:00
|
|
|
if i, ok := h.state.getIRC(data.Server); ok {
|
2015-06-16 22:46:58 +00:00
|
|
|
i.Part(data.Channels...)
|
|
|
|
}
|
|
|
|
}
|
2015-02-04 01:43:49 +00:00
|
|
|
|
2015-06-16 22:46:58 +00:00
|
|
|
func (h *wsHandler) quit(b []byte) {
|
|
|
|
var data Quit
|
2018-05-25 21:54:36 +00:00
|
|
|
data.UnmarshalJSON(b)
|
2015-02-04 01:43:49 +00:00
|
|
|
|
2017-07-03 05:35:38 +00:00
|
|
|
log.Println(h.addr, "[IRC] Remove server", data.Server)
|
2018-05-31 21:24:59 +00:00
|
|
|
if i, ok := h.state.getIRC(data.Server); ok {
|
|
|
|
h.state.deleteIRC(data.Server)
|
2017-07-03 05:35:38 +00:00
|
|
|
i.Quit()
|
2015-06-16 22:46:58 +00:00
|
|
|
}
|
2017-07-03 05:35:38 +00:00
|
|
|
|
2018-05-31 21:24:59 +00:00
|
|
|
go h.state.user.RemoveServer(data.Server)
|
2015-06-16 22:46:58 +00:00
|
|
|
}
|
2015-02-10 01:25:28 +00:00
|
|
|
|
2017-04-17 20:36:37 +00:00
|
|
|
func (h *wsHandler) message(b []byte) {
|
|
|
|
var data Message
|
2018-05-25 21:54:36 +00:00
|
|
|
data.UnmarshalJSON(b)
|
2015-02-10 01:25:28 +00:00
|
|
|
|
2018-05-31 21:24:59 +00:00
|
|
|
if i, ok := h.state.getIRC(data.Server); ok {
|
2017-04-17 20:36:37 +00:00
|
|
|
i.Privmsg(data.To, data.Content)
|
2017-04-20 03:32:22 +00:00
|
|
|
|
2020-06-03 01:04:38 +00:00
|
|
|
go h.state.user.LogMessage(&storage.Message{
|
|
|
|
Server: data.Server,
|
|
|
|
From: i.GetNick(),
|
|
|
|
To: data.To,
|
|
|
|
Content: data.Content,
|
|
|
|
})
|
2015-06-16 22:46:58 +00:00
|
|
|
}
|
|
|
|
}
|
2015-02-10 01:25:28 +00:00
|
|
|
|
2015-06-16 22:46:58 +00:00
|
|
|
func (h *wsHandler) nick(b []byte) {
|
|
|
|
var data Nick
|
2018-05-25 21:54:36 +00:00
|
|
|
data.UnmarshalJSON(b)
|
2015-02-10 01:25:28 +00:00
|
|
|
|
2018-05-31 21:24:59 +00:00
|
|
|
if i, ok := h.state.getIRC(data.Server); ok {
|
2015-06-16 22:46:58 +00:00
|
|
|
i.Nick(data.New)
|
|
|
|
}
|
|
|
|
}
|
2015-02-10 01:25:28 +00:00
|
|
|
|
2017-05-28 05:20:43 +00:00
|
|
|
func (h *wsHandler) topic(b []byte) {
|
|
|
|
var data Topic
|
2018-05-25 21:54:36 +00:00
|
|
|
data.UnmarshalJSON(b)
|
2017-05-28 05:20:43 +00:00
|
|
|
|
2018-05-31 21:24:59 +00:00
|
|
|
if i, ok := h.state.getIRC(data.Server); ok {
|
2017-05-28 05:20:43 +00:00
|
|
|
i.Topic(data.Channel, data.Topic)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-16 22:46:58 +00:00
|
|
|
func (h *wsHandler) invite(b []byte) {
|
|
|
|
var data Invite
|
2018-05-25 21:54:36 +00:00
|
|
|
data.UnmarshalJSON(b)
|
2015-02-10 01:25:28 +00:00
|
|
|
|
2018-05-31 21:24:59 +00:00
|
|
|
if i, ok := h.state.getIRC(data.Server); ok {
|
2015-06-16 22:46:58 +00:00
|
|
|
i.Invite(data.User, data.Channel)
|
|
|
|
}
|
|
|
|
}
|
2015-02-10 01:25:28 +00:00
|
|
|
|
2015-06-16 22:46:58 +00:00
|
|
|
func (h *wsHandler) kick(b []byte) {
|
|
|
|
var data Invite
|
2018-05-25 21:54:36 +00:00
|
|
|
data.UnmarshalJSON(b)
|
2015-02-10 01:25:28 +00:00
|
|
|
|
2018-05-31 21:24:59 +00:00
|
|
|
if i, ok := h.state.getIRC(data.Server); ok {
|
2015-06-16 22:46:58 +00:00
|
|
|
i.Kick(data.Channel, data.User)
|
|
|
|
}
|
|
|
|
}
|
2015-02-10 01:25:28 +00:00
|
|
|
|
2015-06-16 22:46:58 +00:00
|
|
|
func (h *wsHandler) whois(b []byte) {
|
|
|
|
var data Whois
|
2018-05-25 21:54:36 +00:00
|
|
|
data.UnmarshalJSON(b)
|
2015-02-21 12:06:05 +00:00
|
|
|
|
2018-05-31 21:24:59 +00:00
|
|
|
if i, ok := h.state.getIRC(data.Server); ok {
|
2015-06-16 22:46:58 +00:00
|
|
|
i.Whois(data.User)
|
|
|
|
}
|
|
|
|
}
|
2015-02-21 12:06:05 +00:00
|
|
|
|
2015-06-16 22:46:58 +00:00
|
|
|
func (h *wsHandler) away(b []byte) {
|
|
|
|
var data Away
|
2018-05-25 21:54:36 +00:00
|
|
|
data.UnmarshalJSON(b)
|
2015-02-21 12:06:05 +00:00
|
|
|
|
2018-05-31 21:24:59 +00:00
|
|
|
if i, ok := h.state.getIRC(data.Server); ok {
|
2015-06-16 22:46:58 +00:00
|
|
|
i.Away(data.Message)
|
|
|
|
}
|
|
|
|
}
|
2015-05-10 23:09:59 +00:00
|
|
|
|
2016-01-27 19:48:47 +00:00
|
|
|
func (h *wsHandler) raw(b []byte) {
|
|
|
|
var data Raw
|
2018-05-25 21:54:36 +00:00
|
|
|
data.UnmarshalJSON(b)
|
2016-01-27 19:48:47 +00:00
|
|
|
|
2018-05-31 21:24:59 +00:00
|
|
|
if i, ok := h.state.getIRC(data.Server); ok {
|
2016-01-27 19:48:47 +00:00
|
|
|
i.Write(data.Message)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-16 22:46:58 +00:00
|
|
|
func (h *wsHandler) search(b []byte) {
|
|
|
|
go func() {
|
|
|
|
var data SearchRequest
|
2018-05-25 21:54:36 +00:00
|
|
|
data.UnmarshalJSON(b)
|
2015-05-10 23:09:59 +00:00
|
|
|
|
2018-05-31 21:24:59 +00:00
|
|
|
results, err := h.state.user.SearchMessages(data.Server, data.Channel, data.Phrase)
|
2015-06-16 22:46:58 +00:00
|
|
|
if err != nil {
|
|
|
|
log.Println(err)
|
|
|
|
return
|
|
|
|
}
|
2015-05-10 23:09:59 +00:00
|
|
|
|
2018-05-31 21:24:59 +00:00
|
|
|
h.state.sendJSON("search", SearchResult{
|
2015-06-16 22:46:58 +00:00
|
|
|
Server: data.Server,
|
|
|
|
Channel: data.Channel,
|
|
|
|
Results: results,
|
|
|
|
})
|
|
|
|
}()
|
|
|
|
}
|
2015-05-10 23:09:59 +00:00
|
|
|
|
2016-01-11 20:04:57 +00:00
|
|
|
func (h *wsHandler) cert(b []byte) {
|
|
|
|
var data ClientCert
|
2018-05-25 21:54:36 +00:00
|
|
|
data.UnmarshalJSON(b)
|
2016-01-11 20:04:57 +00:00
|
|
|
|
2018-10-10 19:23:42 +00:00
|
|
|
err := h.state.user.SetCertificate([]byte(data.Cert), []byte(data.Key))
|
2016-01-11 20:04:57 +00:00
|
|
|
if err != nil {
|
2018-05-31 21:24:59 +00:00
|
|
|
h.state.sendJSON("cert_fail", Error{Message: err.Error()})
|
2016-01-11 20:04:57 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2018-05-31 21:24:59 +00:00
|
|
|
h.state.sendJSON("cert_success", nil)
|
2016-01-11 20:04:57 +00:00
|
|
|
}
|
|
|
|
|
2017-05-02 21:21:25 +00:00
|
|
|
func (h *wsHandler) fetchMessages(b []byte) {
|
|
|
|
var data FetchMessages
|
2018-05-25 21:54:36 +00:00
|
|
|
data.UnmarshalJSON(b)
|
2017-05-02 21:21:25 +00:00
|
|
|
|
2018-05-31 21:24:59 +00:00
|
|
|
h.state.sendMessages(data.Server, data.Channel, 200, data.Next)
|
2017-05-02 21:21:25 +00:00
|
|
|
}
|
|
|
|
|
2017-06-12 04:18:32 +00:00
|
|
|
func (h *wsHandler) setServerName(b []byte) {
|
2017-07-02 01:31:00 +00:00
|
|
|
var data ServerName
|
2018-05-25 21:54:36 +00:00
|
|
|
data.UnmarshalJSON(b)
|
2017-06-12 04:18:32 +00:00
|
|
|
|
|
|
|
if isValidServerName(data.Name) {
|
2018-05-31 21:24:59 +00:00
|
|
|
h.state.user.SetServerName(data.Name, data.Server)
|
2017-06-12 04:18:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-15 06:56:17 +00:00
|
|
|
func (h *wsHandler) setSettings(b []byte) {
|
|
|
|
err := h.state.user.UnmarshalClientSettingsJSON(b)
|
|
|
|
if err != nil {
|
|
|
|
log.Println(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-23 06:34:39 +00:00
|
|
|
func (h *wsHandler) channelSearch(b []byte) {
|
|
|
|
var data ChannelSearch
|
|
|
|
data.UnmarshalJSON(b)
|
|
|
|
|
|
|
|
index, needsUpdate := channelIndexes.Get(data.Server)
|
|
|
|
if index != nil {
|
|
|
|
n := 10
|
|
|
|
if data.Start > 0 {
|
|
|
|
n = 50
|
|
|
|
}
|
|
|
|
|
|
|
|
h.state.sendJSON("channel_search", ChannelSearchResult{
|
2020-05-03 07:05:16 +00:00
|
|
|
ChannelSearch: data,
|
|
|
|
Results: index.SearchN(data.Q, data.Start, n),
|
2019-01-23 06:34:39 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
if i, ok := h.state.getIRC(data.Server); ok && needsUpdate {
|
|
|
|
h.state.Set("update_chanlist_"+data.Server, true)
|
|
|
|
i.List()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-06 02:19:55 +00:00
|
|
|
func (h *wsHandler) openDM(b []byte) {
|
|
|
|
var data Tab
|
|
|
|
data.UnmarshalJSON(b)
|
|
|
|
|
|
|
|
h.state.sendLastMessages(data.Server, data.Name, 50)
|
|
|
|
h.state.user.AddOpenDM(data.Server, data.Name)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (h *wsHandler) closeDM(b []byte) {
|
|
|
|
var data Tab
|
|
|
|
data.UnmarshalJSON(b)
|
|
|
|
|
|
|
|
h.state.user.RemoveOpenDM(data.Server, data.Name)
|
|
|
|
}
|
|
|
|
|
2015-06-16 22:46:58 +00:00
|
|
|
func (h *wsHandler) initHandlers() {
|
|
|
|
h.handlers = map[string]func([]byte){
|
2017-06-12 04:18:32 +00:00
|
|
|
"connect": h.connect,
|
2017-07-04 09:28:56 +00:00
|
|
|
"reconnect": h.reconnect,
|
2017-06-12 04:18:32 +00:00
|
|
|
"join": h.join,
|
|
|
|
"part": h.part,
|
|
|
|
"quit": h.quit,
|
|
|
|
"message": h.message,
|
|
|
|
"nick": h.nick,
|
|
|
|
"topic": h.topic,
|
|
|
|
"invite": h.invite,
|
|
|
|
"kick": h.kick,
|
|
|
|
"whois": h.whois,
|
|
|
|
"away": h.away,
|
|
|
|
"raw": h.raw,
|
|
|
|
"search": h.search,
|
|
|
|
"cert": h.cert,
|
|
|
|
"fetch_messages": h.fetchMessages,
|
|
|
|
"set_server_name": h.setServerName,
|
2018-10-15 06:56:17 +00:00
|
|
|
"settings_set": h.setSettings,
|
2019-01-23 06:34:39 +00:00
|
|
|
"channel_search": h.channelSearch,
|
2020-05-06 02:19:55 +00:00
|
|
|
"open_dm": h.openDM,
|
|
|
|
"close_dm": h.closeDM,
|
2015-01-17 01:37:21 +00:00
|
|
|
}
|
|
|
|
}
|
2017-06-12 04:18:32 +00:00
|
|
|
|
|
|
|
func isValidServerName(name string) bool {
|
|
|
|
return strings.TrimSpace(name) != ""
|
|
|
|
}
|