Compare commits
6 Commits
channel_pr
...
v1.6.4
Author | SHA1 | Date | |
---|---|---|---|
![]() |
caab002d51 | ||
![]() |
7ff892bba9 | ||
![]() |
233238b709 | ||
![]() |
59e0792db1 | ||
![]() |
962b6645c1 | ||
![]() |
cee8bf9957 |
@@ -6,9 +6,15 @@ pipeline:
|
||||
build:
|
||||
image: golang
|
||||
commands:
|
||||
- go get -d
|
||||
- go get -d ./...
|
||||
- go build .
|
||||
|
||||
test:
|
||||
image: golang
|
||||
commands:
|
||||
- go get -d ./...
|
||||
- go test ./...
|
||||
|
||||
docker:
|
||||
image: plugins/docker
|
||||
repo: r.mills.io/prologic/eris
|
||||
|
6
.gitmodules
vendored
6
.gitmodules
vendored
@@ -49,3 +49,9 @@
|
||||
[submodule "vendor/github.com/petermattis/goid"]
|
||||
path = vendor/github.com/petermattis/goid
|
||||
url = https://github.com/petermattis/goid
|
||||
[submodule "vendor/github.com/thoj/go-ircevent"]
|
||||
path = vendor/github.com/thoj/go-ircevent
|
||||
url = https://github.com/thoj/go-ircevent
|
||||
[submodule "vendor/github.com/stretchr/testify"]
|
||||
path = vendor/github.com/stretchr/testify
|
||||
url = https://github.com/stretchr/testify
|
||||
|
@@ -35,9 +35,9 @@ Discussion at:
|
||||
* /server irc.mills.io +6697 (*use TLS/SSL*)
|
||||
* /join #lobby
|
||||
|
||||
Or (*not recommended*)P
|
||||
Or (**not recommended**):
|
||||
|
||||
* /server irc.mills.io (*default port 6667, non-TLS)
|
||||
* /server irc.mills.io (*default port 6667, non-TLS*)
|
||||
* /join #lobby
|
||||
|
||||
## Features
|
||||
@@ -54,6 +54,7 @@ Or (*not recommended*)P
|
||||
* Simple IRC operator privileges (*overrides most things*)
|
||||
* Secure connection tracking (+z) and SecureOnly user mode (+Z)
|
||||
* Secure channels (+Z)
|
||||
* Three layers of channel privacy, Public, Private (+p) and Secret (s)
|
||||
|
||||
## Quick Start
|
||||
|
||||
|
@@ -374,7 +374,7 @@ func (channel *Channel) applyMode(client *Client, change *ChannelModeChange) boo
|
||||
return channel.applyModeMask(client, change.mode, change.op,
|
||||
NewName(change.arg))
|
||||
|
||||
case InviteOnly, Moderated, NoOutside, OpOnlyTopic, Private, SecureChan:
|
||||
case InviteOnly, Moderated, NoOutside, OpOnlyTopic, Private, Secret, SecureChan:
|
||||
return channel.applyModeFlag(client, change.mode, change.op)
|
||||
|
||||
case Key:
|
||||
|
@@ -119,13 +119,6 @@ func (client *Client) readloop() {
|
||||
}
|
||||
|
||||
func (client *Client) processCommand(cmd Command) {
|
||||
client.server.metrics.Counter("client", "commands").Inc()
|
||||
|
||||
defer func(t time.Time) {
|
||||
v := client.server.metrics.SummaryVec("client", "command_duration_seconds")
|
||||
v.WithLabelValues(cmd.Code().String()).Observe(time.Now().Sub(t).Seconds())
|
||||
}(time.Now())
|
||||
|
||||
cmd.SetClient(client)
|
||||
|
||||
if !client.registered {
|
||||
@@ -144,6 +137,13 @@ func (client *Client) processCommand(cmd Command) {
|
||||
return
|
||||
}
|
||||
|
||||
client.server.metrics.Counter("client", "commands").Inc()
|
||||
|
||||
defer func(t time.Time) {
|
||||
v := client.server.metrics.SummaryVec("client", "command_duration_seconds")
|
||||
v.WithLabelValues(cmd.Code().String()).Observe(time.Now().Sub(t).Seconds())
|
||||
}(time.Now())
|
||||
|
||||
switch srvCmd.(type) {
|
||||
case *PingCommand, *PongCommand:
|
||||
client.Touch()
|
||||
|
@@ -70,7 +70,6 @@ var (
|
||||
)
|
||||
|
||||
const (
|
||||
Anonymous ChannelMode = 'a' // flag
|
||||
BanMask ChannelMode = 'b' // arg
|
||||
ChannelCreator ChannelMode = 'O' // flag
|
||||
ChannelOperator ChannelMode = 'o' // arg
|
||||
@@ -82,8 +81,6 @@ const (
|
||||
NoOutside ChannelMode = 'n' // flag
|
||||
OpOnlyTopic ChannelMode = 't' // flag
|
||||
Private ChannelMode = 'p' // flag
|
||||
Quiet ChannelMode = 'q' // flag
|
||||
ReOp ChannelMode = 'r' // flag
|
||||
Secret ChannelMode = 's' // flag, deprecated
|
||||
UserLimit ChannelMode = 'l' // flag arg
|
||||
Voice ChannelMode = 'v' // arg
|
||||
@@ -93,7 +90,7 @@ const (
|
||||
var (
|
||||
SupportedChannelModes = ChannelModes{
|
||||
BanMask, ExceptMask, InviteMask, InviteOnly, Key, NoOutside,
|
||||
OpOnlyTopic, Private, UserLimit, SecureChan,
|
||||
OpOnlyTopic, Private, UserLimit, Secret, SecureChan,
|
||||
}
|
||||
)
|
||||
|
||||
|
22
irc/privacy.go
Normal file
22
irc/privacy.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package irc
|
||||
|
||||
func CanSeeChannel(client *Client, channel *Channel) bool {
|
||||
isPrivate := channel.flags.Has(Private)
|
||||
isSecret := channel.flags.Has(Secret)
|
||||
|
||||
isMember := channel.members.Has(client)
|
||||
isOperator := client.flags[Operator]
|
||||
isRegistered := client.flags[Registered]
|
||||
isSecure := client.flags[SecureConn]
|
||||
|
||||
if !(isSecret || isPrivate) {
|
||||
return true
|
||||
}
|
||||
if isSecret && (isMember || isOperator) {
|
||||
return true
|
||||
}
|
||||
if isPrivate && (isMember || isOperator || (isRegistered && isSecure)) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
17
irc/reply.go
17
irc/reply.go
@@ -489,8 +489,13 @@ func (target *Client) RplMOTDEnd() {
|
||||
}
|
||||
|
||||
func (target *Client) RplList(channel *Channel) {
|
||||
target.NumericReply(RPL_LIST,
|
||||
"%s %d :%s", channel, channel.members.Count(), channel.topic)
|
||||
target.NumericReply(
|
||||
RPL_LIST,
|
||||
"%s %d :%s",
|
||||
channel,
|
||||
channel.members.Count(),
|
||||
channel.topic,
|
||||
)
|
||||
}
|
||||
|
||||
func (target *Client) RplListEnd(server *Server) {
|
||||
@@ -504,8 +509,12 @@ func (target *Client) RplNamReply(channel *Channel) {
|
||||
}
|
||||
|
||||
func (target *Client) RplWhoisChannels(client *Client) {
|
||||
target.MultilineReply(client.WhoisChannelsNames(), RPL_WHOISCHANNELS,
|
||||
"%s :%s", client.Nick())
|
||||
target.MultilineReply(
|
||||
client.WhoisChannelsNames(target),
|
||||
RPL_WHOISCHANNELS,
|
||||
"%s :%s",
|
||||
client.Nick(),
|
||||
)
|
||||
}
|
||||
|
||||
func (target *Client) RplVersion() {
|
||||
|
@@ -202,6 +202,10 @@ func (server *Server) Shutdown() {
|
||||
server.Global("shutting down...")
|
||||
}
|
||||
|
||||
func (server *Server) Stop() {
|
||||
server.done <- true
|
||||
}
|
||||
|
||||
func (server *Server) Run() {
|
||||
for {
|
||||
select {
|
||||
@@ -212,7 +216,7 @@ func (server *Server) Run() {
|
||||
// Give at least 1s for clients to see the shutdown
|
||||
go func() {
|
||||
time.Sleep(1 * time.Second)
|
||||
server.done <- true
|
||||
server.Stop()
|
||||
}()
|
||||
|
||||
case conn := <-server.newConns:
|
||||
@@ -625,10 +629,14 @@ func (msg *PrivMsgCommand) HandleServer(server *Server) {
|
||||
}
|
||||
}
|
||||
|
||||
func (client *Client) WhoisChannelsNames() []string {
|
||||
func (client *Client) WhoisChannelsNames(target *Client) []string {
|
||||
chstrs := make([]string, client.channels.Count())
|
||||
index := 0
|
||||
client.channels.Range(func(channel *Channel) bool {
|
||||
if !CanSeeChannel(target, channel) {
|
||||
return true
|
||||
}
|
||||
|
||||
switch {
|
||||
case channel.members.Get(client).Has(ChannelOperator):
|
||||
chstrs[index] = "@" + channel.name.String()
|
||||
@@ -835,7 +843,7 @@ func (msg *ListCommand) HandleServer(server *Server) {
|
||||
|
||||
if len(msg.channels) == 0 {
|
||||
server.channels.Range(func(name Name, channel *Channel) bool {
|
||||
if !client.flags[Operator] && channel.flags.Has(Private) {
|
||||
if !CanSeeChannel(client, channel) {
|
||||
return true
|
||||
}
|
||||
client.RplList(channel)
|
||||
@@ -844,7 +852,7 @@ func (msg *ListCommand) HandleServer(server *Server) {
|
||||
} else {
|
||||
for _, chname := range msg.channels {
|
||||
channel := server.channels.Get(chname)
|
||||
if channel == nil || (!client.flags[Operator] && channel.flags.Has(Private)) {
|
||||
if channel == nil || !CanSeeChannel(client, channel) {
|
||||
client.ErrNoSuchChannel(chname)
|
||||
continue
|
||||
}
|
||||
|
@@ -9,7 +9,7 @@ var (
|
||||
Package = "eris"
|
||||
|
||||
// Version release version
|
||||
Version = "1.6.2"
|
||||
Version = "1.6.4"
|
||||
|
||||
// Build will be overwritten automatically by the build system
|
||||
Build = "dev"
|
||||
|
185
main_test.go
Normal file
185
main_test.go
Normal file
@@ -0,0 +1,185 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"log"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/thoj/go-ircevent"
|
||||
|
||||
eris "github.com/prologic/eris/irc"
|
||||
)
|
||||
|
||||
var (
|
||||
done chan bool
|
||||
server *eris.Server
|
||||
|
||||
client *irc.Connection
|
||||
clients map[string]*irc.Connection
|
||||
|
||||
tls = flag.Bool("tls", false, "run tests with TLS")
|
||||
)
|
||||
|
||||
func setupServer() *eris.Server {
|
||||
config := &eris.Config{}
|
||||
|
||||
config.Network.Name = "Test"
|
||||
config.Server.Name = "test"
|
||||
config.Server.Description = "Test"
|
||||
config.Server.Listen = []string{":6667"}
|
||||
|
||||
server := eris.NewServer(config)
|
||||
|
||||
go server.Run()
|
||||
|
||||
return server
|
||||
}
|
||||
|
||||
func newClient(nick, user, name string, start bool) *irc.Connection {
|
||||
client := irc.IRC(nick, user)
|
||||
client.RealName = name
|
||||
|
||||
err := client.Connect("localhost:6667")
|
||||
if err != nil {
|
||||
log.Fatalf("error setting up test client: %s", err)
|
||||
}
|
||||
|
||||
if start {
|
||||
go client.Loop()
|
||||
}
|
||||
|
||||
return client
|
||||
}
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
flag.Parse()
|
||||
|
||||
done = make(chan bool)
|
||||
|
||||
server = setupServer()
|
||||
|
||||
client = newClient("test", "test", "Test", true)
|
||||
clients = make(map[string]*irc.Connection)
|
||||
clients["test1"] = newClient("test1", "test", "Test 1", true)
|
||||
clients["test2"] = newClient("test2", "test", "Test 2", true)
|
||||
|
||||
result := m.Run()
|
||||
|
||||
for _, client := range clients {
|
||||
client.Quit()
|
||||
}
|
||||
|
||||
server.Stop()
|
||||
|
||||
os.Exit(result)
|
||||
}
|
||||
|
||||
func TestConnection(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
var (
|
||||
expected bool
|
||||
actual chan bool
|
||||
)
|
||||
|
||||
expected = true
|
||||
actual = make(chan bool)
|
||||
|
||||
client := newClient("connect", "connect", "Connect", false)
|
||||
|
||||
client.AddCallback("001", func(e *irc.Event) {
|
||||
defer func() { done <- true }()
|
||||
|
||||
actual <- true
|
||||
})
|
||||
|
||||
time.AfterFunc(1*time.Second, func() { done <- true })
|
||||
defer client.Quit()
|
||||
go client.Loop()
|
||||
<-done
|
||||
|
||||
assert.Equal(expected, <-actual)
|
||||
}
|
||||
|
||||
func TestRplWelcome(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
var (
|
||||
expected string
|
||||
actual chan string
|
||||
)
|
||||
|
||||
expected = "Welcome to the .* Internet Relay Network .*!.*@.*"
|
||||
actual = make(chan string)
|
||||
|
||||
client := newClient("connect", "connect", "Connect", false)
|
||||
|
||||
client.AddCallback("001", func(e *irc.Event) {
|
||||
defer func() { done <- true }()
|
||||
|
||||
actual <- e.Message()
|
||||
})
|
||||
|
||||
time.AfterFunc(1*time.Second, func() { done <- true })
|
||||
defer client.Quit()
|
||||
go client.Loop()
|
||||
<-done
|
||||
|
||||
assert.Regexp(expected, <-actual)
|
||||
}
|
||||
|
||||
func TestUser_JOIN(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
var (
|
||||
expected []string
|
||||
actual chan string
|
||||
)
|
||||
|
||||
expected = []string{"test", "=", "#test", "@test"}
|
||||
actual = make(chan string)
|
||||
|
||||
client.AddCallback("353", func(e *irc.Event) {
|
||||
defer func() { done <- true }()
|
||||
|
||||
for i := range e.Arguments {
|
||||
actual <- e.Arguments[i]
|
||||
}
|
||||
})
|
||||
|
||||
time.AfterFunc(1*time.Second, func() { done <- true })
|
||||
client.Join("#test")
|
||||
client.SendRaw("NAMES #test")
|
||||
<-done
|
||||
|
||||
for i := range expected {
|
||||
assert.Equal(expected[i], <-actual)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUser_PRIVMSG(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
var (
|
||||
expected string
|
||||
actual chan string
|
||||
)
|
||||
|
||||
expected = "Hello World!"
|
||||
actual = make(chan string)
|
||||
|
||||
clients["test1"].AddCallback("PRIVMSG", func(e *irc.Event) {
|
||||
defer func() { done <- true }()
|
||||
|
||||
actual <- e.Message()
|
||||
})
|
||||
|
||||
time.AfterFunc(1*time.Second, func() { done <- true })
|
||||
client.Privmsg("test1", expected)
|
||||
<-done
|
||||
|
||||
assert.Equal(expected, <-actual)
|
||||
}
|
1
vendor/github.com/stretchr/testify
generated
vendored
Submodule
1
vendor/github.com/stretchr/testify
generated
vendored
Submodule
Submodule vendor/github.com/stretchr/testify added at 2aa2c176b9
1
vendor/github.com/thoj/go-ircevent
generated
vendored
Submodule
1
vendor/github.com/thoj/go-ircevent
generated
vendored
Submodule
Submodule vendor/github.com/thoj/go-ircevent added at db5bd176f7
2
vendor/golang.org/x/crypto
generated
vendored
2
vendor/golang.org/x/crypto
generated
vendored
Submodule vendor/golang.org/x/crypto updated: b080dc9a8c...365904b0f3
2
vendor/golang.org/x/sys
generated
vendored
2
vendor/golang.org/x/sys
generated
vendored
Submodule vendor/golang.org/x/sys updated: 4ff8c001ce...a204229cd8
2
vendor/golang.org/x/text
generated
vendored
2
vendor/golang.org/x/text
generated
vendored
Submodule vendor/golang.org/x/text updated: 88f656faf3...a352c5cd19
Reference in New Issue
Block a user