21 Commits

Author SHA1 Message Date
James Mills
51f667b521 Added support for multi-layer channel privacy (Public, Private and Secret) 2017-11-27 00:10:28 -08:00
James Mills
9d93bca179 Added support for measuring secure vs. non-secure registerd clients (#34) 2017-11-26 17:31:11 -08:00
James Mills
ccae795335 Fixed graceful shutdown (#32) 2017-11-26 17:30:53 -08:00
James Mills
862eb429d4 Update README.md 2017-11-26 15:26:12 -08:00
James Mills
9e075dde67 Fixed send on closed channel bug (#29) 2017-11-26 13:25:21 -08:00
James Mills
20be29bcef Fixed bug with RPL_ENDOFWHOIS (/WHOIS) response missing nick component (#27) 2017-11-26 10:42:14 -08:00
James Mills
34c3be0a88 Update README.md 2017-11-26 10:10:18 -08:00
Mike Taylor
be246a3bc4 minor typo fixes (#25) 2017-11-25 20:21:54 -08:00
James Mills
4fb452b2c0 Release v1.6.2 2017-11-25 20:19:05 -08:00
James Mills
d707382a78 Added support for user hostmask(s) / Hostname/IP Cloacks (#24) 2017-11-25 19:36:38 -08:00
James Mills
7620a3c282 Update README.md 2017-11-25 18:50:42 -08:00
James Mills
18a3e2f2c3 Update README.md 2017-11-25 18:47:15 -08:00
James Mills
d046a9863f Fixed /VERSION response (#22) 2017-11-25 17:57:09 -08:00
James Mills
a1450a81d6 Updated vendor 3rd-party packages (#20) 2017-11-25 16:42:35 -08:00
James Mills
d594386658 Fixed scripts/release.sh to correctly produce linux binaries for both amd64 and arm64 (#18) 2017-11-25 16:04:09 -08:00
James Mills
89b512fc76 Update README.md 2017-11-25 15:37:30 -08:00
James Mills
d01bb4fe57 Added support for network name and RPL_WELCOME to display network name (#14) 2017-11-25 15:22:31 -08:00
James Mills
2fef0feb5a Added Travis CI config and fixed some broken tests (#12) 2017-11-24 22:48:16 -08:00
James Mills
735458ffed Update README.md 2017-11-24 22:34:58 -08:00
Mike Taylor
02427bcb3f Issue #3 - unless the WHOIS request is from a user with the SecureConn flag, hide the hostmask (#11) 2017-11-24 22:29:58 -08:00
James Mills
bdcb4c21a5 Added contributors guideline (CONTRIBUTING.md) (#9) 2017-11-24 16:47:01 -08:00
28 changed files with 356 additions and 59 deletions

6
.gitmodules vendored
View File

@@ -43,3 +43,9 @@
[submodule "vendor/github.com/prometheus/procfs"]
path = vendor/github.com/prometheus/procfs
url = https://github.com/prometheus/procfs
[submodule "vendor/github.com/sasha-s/go-deadlock"]
path = vendor/github.com/sasha-s/go-deadlock
url = https://github.com/sasha-s/go-deadlock
[submodule "vendor/github.com/petermattis/goid"]
path = vendor/github.com/petermattis/goid
url = https://github.com/petermattis/goid

8
.travis.yml Normal file
View File

@@ -0,0 +1,8 @@
language: go
sudo: false
go:
- tip
before_install:
- go get github.com/mattn/goveralls
script:
- $HOME/gopath/bin/goveralls -service=travis-ci

49
CONTRIBUTING.md Normal file
View File

@@ -0,0 +1,49 @@
# Welcome to the contributing guide for eris!
## Developers
- James Mills [@prologic](https://github.com/prologic) (*uthor / Maintainer*)
### Contributors
- [@bear](https://github.com/bear)
- [@DanielOaks](https://github.com/DanielOaks)
- [@kzisme](https://github.com/kzisme)
## New Features
* [Create an Issue](https://github.com/prologic/eris/issues/new)
* [Fork eris](https://github.com/prologic/eris#fork-destination-box)
```bash
$ git clone git@github.com:myuser/eris.git
```
* Create a new feature branch:
```bash
$ git checkout -b myfeature#issueN master
```
* Hack on your feature with your favorite editor
* Commit and Push your changes up:
```bash
$ git add -A
$ git commit -m "my fancy new feature"
$ git push -u origin my-feature
```
* Create a new [Pull Request](https://github.com/prologic/eris/compare/)
* Give the pull request an appropriate title possibly matching the issue
* In the pull request's description include the text `Closes #N` or `Fixes #N`
# Reporting Bugs
* File a new [Bug Report](https://github.com/prologic/eris/issues/new)
* Label it as a "Bug"
When describing your bug report; please be concise and as detailed as you can
so we can easily work out what the problem is. It's also very helpful if you
are able to provide a test case that repeatedly demonstrates the bug at hand.

View File

@@ -6,7 +6,7 @@ APP=eris
PACKAGE=irc
REPO?=prologic/$(APP)
TAG?=latest
BUILD?=-dev
BUILD?=dev
all: dev

View File

@@ -1,5 +1,11 @@
# eris - IRC Server / Daemon written in Go
[![Build Status](https://travis-ci.org/prologic/eris.svg)](https://travis-ci.org/prologic/eris)
[![Go Report Card](https://goreportcard.com/badge/github.com/prologic/eris)](https://goreportcard.com/report/github.com/prologic/eris)
[![Coverage](https://coveralls.io/repos/prologic/eris/badge.svg)](https://coveralls.io/r/prologic/eris)
[![GoDoc](https://godoc.org/github.com/prologic/eris?status.svg)](https://godoc.org/github.com/prologic/eris)
[![Wiki](https://img.shields.io/badge/docs-wiki-blue.svg)](https://github.com/prologic/eris/wiki)
> This project and repository is based off of [ergonomadic](https://github.com/edmund-huber/ergonomadic)
> and much of my original contributions were made in my [fork of ergonomadic](https://github.com/prologic/ergonomadic)
> but the upstream project was ultimately shutdown.
@@ -29,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
@@ -48,6 +54,41 @@ 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
```#!bash
$ go get github.com/prologic/eris
$ cat > ircd.yml <<EOF
network:
name: Test
server:
name: Test
listen:
- ":6667"
EOF
$ eris
```
If you want TLS (**recommended**) then:
```#!bash
$ go get github.com/prologic/mksslcert
$ mksslcert
```
This generates a self-signed cert `cert.pem` and `key.pem` into the `$PWD`.
Then add a `tlslisten` block to your config:
```#!yaml
server:
tlslisten:
":6697":
key: key.pem
cert: cert.pem
```
## Installation
@@ -67,6 +108,14 @@ $ go install github.com/prologic/mkpasswd
$ mkpasswd
```
Self-signed certificates can also be generated using the `mksslcert` tool
from [prologic/mksslcert](https://github.com/prologic/mksslcert):
```#!bash
$ go install github.com/prologic/mksslcert
$ mksslcert
```
## Deployment
To run simply run the `eris` binary (*assuming a `ircd.yml` in the current directory*):
@@ -87,14 +136,18 @@ You may want to customize the configuration however and create your own image ba
$ docker stack deploy -c docker-compose.yml eris
```
Which assumes a `ircd.yml` coniguration fiel int he current directory which Docker will use to distribute as the configuration. The `docker-compose.yml` (*Docker Stackfile*) is available at the root of this repository.
Which assumes a `ircd.yml` coniguration file in the current directory which Docker will use to distribute as the configuration. The `docker-compose.yml` (*Docker Stackfile*) is available at the root of this repository.
## Related Proejcts
## Related Projects
There are a number of supported accompanying services that are being developed alongside Eris:
* [Soter](https://github.com/prologic/soter) -- An IRC Bot that persists channel modes and topics.
* [Cadmus](https://github.com/prologic/cadmus) -- An IRC Bot that logs channels and provides an interface for viewing and searching logs (*Coming soon...*)
* [Cadmus](https://github.com/prologic/cadmus) -- An IRC Bot that logs channels and provides an interface for viewing and searching logs
## Recommended Mobile clients
* [Palaver (iOS)](https://palaverapp.com/) -- SASL, TLS, Server Password, Push Notifications, IRCv3 (*Also supports custom image upload service(s) for better privacy of shared photos/images over IRC*)
## License

View File

@@ -155,16 +155,16 @@ func (channel *Channel) Join(client *Client, key Text) {
return
}
isInvited := channel.lists[InviteMask].Match(client.UserHost())
isInvited := channel.lists[InviteMask].Match(client.UserHost(false))
if !isOperator && channel.flags.Has(InviteOnly) && !isInvited {
client.ErrInviteOnlyChan(channel)
return
}
if channel.lists[BanMask].Match(client.UserHost()) &&
if channel.lists[BanMask].Match(client.UserHost(false)) &&
!isInvited &&
!isOperator &&
!channel.lists[ExceptMask].Match(client.UserHost()) {
!channel.lists[ExceptMask].Match(client.UserHost(false)) {
client.ErrBannedFromChan(channel)
return
}
@@ -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:
@@ -508,7 +508,7 @@ func (channel *Channel) Invite(invitee *Client, inviter *Client) {
}
if channel.flags.Has(InviteOnly) {
channel.lists[InviteMask].Add(invitee.UserHost())
channel.lists[InviteMask].Add(invitee.UserHost(false))
}
inviter.RplInviting(invitee, channel.name)

View File

@@ -26,6 +26,7 @@ type Client struct {
hasQuit bool
hops uint
hostname Name
hostmask Name // Cloacked hostname (SHA256)
pingTime time.Time
idleTimer *time.Timer
nick Name
@@ -83,6 +84,7 @@ func (client *Client) readloop() {
// Set the hostname for this client.
client.hostname = AddrLookupHostname(client.socket.conn.RemoteAddr())
client.hostmask = NewName(SHA256(client.hostname.String()))
for err == nil {
if line, err = client.socket.Read(); err != nil {
@@ -220,6 +222,12 @@ func (client *Client) destroy() {
// clean up server
if _, ok := client.socket.conn.(*tls.Conn); ok {
client.server.metrics.GaugeVec("server", "clients").WithLabelValues("secure").Dec()
} else {
client.server.metrics.GaugeVec("server", "clients").WithLabelValues("insecure").Dec()
}
client.server.connections.Dec()
client.server.clients.Remove(client)
@@ -233,6 +241,7 @@ func (client *Client) destroy() {
}
close(client.replies)
client.replies = nil
client.socket.Close()
@@ -279,11 +288,14 @@ func (c *Client) ModeString() (str string) {
return
}
func (c *Client) UserHost() Name {
func (c *Client) UserHost(cloacked bool) Name {
username := "*"
if c.HasUsername() {
username = c.username.String()
}
if cloacked {
return Name(fmt.Sprintf("%s!%s@%s", c.Nick(), username, c.hostmask))
}
return Name(fmt.Sprintf("%s!%s@%s", c.Nick(), username, c.hostname))
}
@@ -303,7 +315,7 @@ func (c *Client) Nick() Name {
}
func (c *Client) Id() Name {
return c.UserHost()
return c.UserHost(true)
}
func (c *Client) String() string {
@@ -346,7 +358,9 @@ func (client *Client) ChangeNickname(nickname Name) {
}
func (client *Client) Reply(reply string) {
client.replies <- reply
if client.replies != nil {
client.replies <- reply
}
}
func (client *Client) Quit(message Text) {

View File

@@ -105,7 +105,7 @@ func (clients *ClientLookupSet) FindAll(userhost Name) *ClientSet {
var casemappedNickMask string
for _, client := range clients.nicks {
casemappedNickMask = client.UserHost().String()
casemappedNickMask = client.UserHost(false).String()
if matcher.Match(casemappedNickMask) {
set.Add(client)
}
@@ -123,7 +123,7 @@ func (clients *ClientLookupSet) Find(userhost Name) *Client {
var casemappedNickMask string
for _, client := range clients.nicks {
casemappedNickMask = client.UserHost().String()
casemappedNickMask = client.UserHost(false).String()
if matcher.Match(casemappedNickMask) {
return client
}

View File

@@ -33,6 +33,10 @@ type Config struct {
sync.Mutex
filename string
Network struct {
Name string
}
Server struct {
PassConfig `yaml:",inline"`
Listen []string
@@ -97,6 +101,10 @@ func LoadConfig(filename string) (config *Config, err error) {
config.filename = filename
if config.Network.Name == "" {
return nil, errors.New("Network name missing")
}
if config.Server.Name == "" {
return nil, errors.New("Server name missing")
}

View File

@@ -20,6 +20,7 @@ var DefObjectives = map[float64]float64{
type Metrics struct {
namespace string
metrics map[string]prometheus.Metric
gaugevecs map[string]*prometheus.GaugeVec
sumvecs map[string]*prometheus.SummaryVec
}
@@ -27,6 +28,7 @@ func NewMetrics(namespace string) *Metrics {
return &Metrics{
namespace: namespace,
metrics: make(map[string]prometheus.Metric),
gaugevecs: make(map[string]*prometheus.GaugeVec),
sumvecs: make(map[string]*prometheus.SummaryVec),
}
}
@@ -101,6 +103,24 @@ func (m *Metrics) NewGaugeFunc(subsystem, name, help string, f func() float64) p
return guage
}
func (m *Metrics) NewGaugeVec(subsystem, name, help string, labels []string) *prometheus.GaugeVec {
gauagevec := prometheus.NewGaugeVec(
prometheus.GaugeOpts{
Namespace: m.namespace,
Subsystem: subsystem,
Name: name,
Help: help,
},
labels,
)
key := fmt.Sprintf("%s_%s", subsystem, name)
m.gaugevecs[key] = gauagevec
prometheus.MustRegister(gauagevec)
return gauagevec
}
func (m *Metrics) NewSummary(subsystem, name, help string) prometheus.Summary {
summary := prometheus.NewSummary(
prometheus.SummaryOpts{
@@ -148,6 +168,11 @@ func (m *Metrics) Gauge(subsystem, name string) prometheus.Gauge {
return m.metrics[key].(prometheus.Gauge)
}
func (m *Metrics) GaugeVec(subsystem, name string) *prometheus.GaugeVec {
key := fmt.Sprintf("%s_%s", subsystem, name)
return m.gaugevecs[key]
}
func (m *Metrics) Summary(subsystem, name string) prometheus.Summary {
key := fmt.Sprintf("%s_%s", subsystem, name)
return m.metrics[key].(prometheus.Summary)

View File

@@ -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,
}
)

View File

@@ -68,7 +68,7 @@ func (store *MemoryPasswordStore) Verify(username, password string) error {
hash, ok := store.Get(username)
if !ok {
log.Debugf("username %s not found", username)
return fmt.Errorf("account not found: %S", username)
return fmt.Errorf("account not found: %s", username)
}
return store.hasher.Compare(hash, []byte(password))

22
irc/privacy.go Normal file
View 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
}

View File

@@ -173,8 +173,12 @@ func RplCap(client *Client, subCommand CapSubCommand, arg interface{}) string {
// numeric replies
func (target *Client) RplWelcome() {
target.NumericReply(RPL_WELCOME,
":Welcome to the Internet Relay Network %s", target.Id())
target.NumericReply(
RPL_WELCOME,
":Welcome to the %s Internet Relay Network %s",
target.server.Network(),
target.Id(),
)
}
func (target *Client) RplYourHost() {
@@ -256,13 +260,26 @@ func (target *Client) RplWhois(client *Client) {
}
target.RplWhoisServer(client)
target.RplWhoisLoggedIn(client)
target.RplEndOfWhois()
target.RplEndOfWhois(client)
}
func (target *Client) RplWhoisUser(client *Client) {
target.NumericReply(RPL_WHOISUSER,
"%s %s %s * :%s", client.Nick(), client.username, client.hostname,
client.realname)
var clientHost Name
if target.flags[Operator] {
clientHost = client.hostname
} else {
clientHost = client.hostmask
}
target.NumericReply(
RPL_WHOISUSER,
"%s %s %s * :%s",
client.Nick(),
client.username,
clientHost,
client.realname,
)
}
func (target *Client) RplWhoisOperator(client *Client) {
@@ -307,9 +324,12 @@ func (target *Client) RplWhoisServer(client *Client) {
)
}
func (target *Client) RplEndOfWhois() {
target.NumericReply(RPL_ENDOFWHOIS,
":End of WHOIS list")
func (target *Client) RplEndOfWhois(client *Client) {
target.NumericReply(
RPL_ENDOFWHOIS,
"%s :End of WHOIS list",
client.Nick(),
)
}
func (target *Client) RplChannelModeIs(channel *Channel) {
@@ -320,6 +340,14 @@ func (target *Client) RplChannelModeIs(channel *Channel) {
// <channel> <user> <host> <server> <nick> ( "H" / "G" ) ["*"] [ ( "@" / "+" ) ]
// :<hopcount> <real name>
func (target *Client) RplWhoReply(channel *Channel, client *Client) {
var clientHost Name
if target.flags[Operator] {
clientHost = client.hostname
} else {
clientHost = client.hostmask
}
channelName := "*"
flags := ""
@@ -349,9 +377,18 @@ func (target *Client) RplWhoReply(channel *Channel, client *Client) {
}
}
}
target.NumericReply(RPL_WHOREPLY,
"%s %s %s %s %s %s :%d %s", channelName, client.username, client.hostname,
client.server.name, client.Nick(), flags, client.hops, client.realname)
target.NumericReply(
RPL_WHOREPLY,
"%s %s %s %s %s %s :%d %s",
channelName,
client.username,
clientHost,
client.server.name,
client.Nick(),
flags,
client.hops,
client.realname,
)
}
// <name> :End of WHO list
@@ -452,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) {
@@ -467,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() {
@@ -562,9 +608,22 @@ func (target *Client) RplLUserMe() {
}
func (target *Client) RplWhoWasUser(whoWas *WhoWas) {
target.NumericReply(RPL_WHOWASUSER,
var whoWasHost Name
if target.flags[Operator] {
whoWasHost = whoWas.hostname
} else {
whoWasHost = whoWas.hostmask
}
target.NumericReply(
RPL_WHOWASUSER,
"%s %s %s * :%s",
whoWas.nickname, whoWas.username, whoWas.hostname, whoWas.realname)
whoWas.nickname,
whoWas.username,
whoWasHost,
whoWas.realname,
)
}
func (target *Client) RplEndOfWhoWas(nickname Name) {

View File

@@ -37,19 +37,23 @@ type Server struct {
idle chan *Client
motdFile string
name Name
network Name
description string
newConns chan net.Conn
operators map[Name][]byte
accounts PasswordStore
password []byte
signals chan os.Signal
done chan bool
whoWas *WhoWasList
ids map[string]*Identity
}
var (
SERVER_SIGNALS = []os.Signal{syscall.SIGINT, syscall.SIGHUP,
syscall.SIGTERM, syscall.SIGQUIT}
SERVER_SIGNALS = []os.Signal{
syscall.SIGINT, syscall.SIGHUP,
syscall.SIGTERM, syscall.SIGQUIT,
}
)
func NewServer(config *Config) *Server {
@@ -63,11 +67,13 @@ func NewServer(config *Config) *Server {
idle: make(chan *Client),
motdFile: config.Server.MOTD,
name: NewName(config.Server.Name),
network: NewName(config.Network.Name),
description: config.Server.Description,
newConns: make(chan net.Conn),
operators: config.Operators(),
accounts: NewMemoryPasswordStore(config.Accounts(), PasswordStoreOpts{}),
signals: make(chan os.Signal, len(SERVER_SIGNALS)),
done: make(chan bool),
whoWas: NewWhoWasList(100),
ids: make(map[string]*Identity),
}
@@ -121,15 +127,22 @@ func NewServer(config *Config) *Server {
},
)
// server clients gauge
// server registered (clients) gauge
server.metrics.NewGaugeFunc(
"server", "clients",
"server", "registered",
"Number of registered clients connected",
func() float64 {
return float64(server.clients.Count())
},
)
// server clients gauge (by secure/insecire)
server.metrics.NewGaugeVec(
"server", "clients",
"Number of registered clients connected (by secure/insecure)",
[]string{"secure"},
)
// server channels gauge
server.metrics.NewGaugeFunc(
"server", "channels",
@@ -190,12 +203,17 @@ func (server *Server) Shutdown() {
}
func (server *Server) Run() {
done := false
for !done {
for {
select {
case <-server.done:
return
case <-server.signals:
server.Shutdown()
done = true
// Give at least 1s for clients to see the shutdown
go func() {
time.Sleep(1 * time.Second)
server.done <- true
}()
case conn := <-server.newConns:
go NewClient(server, conn)
@@ -215,6 +233,12 @@ func (s *Server) acceptor(listener net.Listener) {
}
log.Debugf("%s accept: %s", s, conn.RemoteAddr())
if _, ok := conn.(*tls.Conn); ok {
s.metrics.GaugeVec("server", "clients").WithLabelValues("secure").Inc()
} else {
s.metrics.GaugeVec("server", "clients").WithLabelValues("insecure").Inc()
}
s.connections.Inc()
s.newConns <- conn
}
@@ -314,6 +338,7 @@ func (s *Server) Rehash() error {
s.motdFile = s.config.Server.MOTD
s.name = NewName(s.config.Server.Name)
s.network = NewName(s.config.Network.Name)
s.description = s.config.Server.Description
s.operators = s.config.Operators()
@@ -324,6 +349,10 @@ func (s *Server) Id() Name {
return s.name
}
func (s *Server) Network() Name {
return s.network
}
func (s *Server) String() string {
return s.name.String()
}
@@ -596,10 +625,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()
@@ -806,7 +839,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)
@@ -815,7 +848,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
}

11
irc/utils.go Normal file
View File

@@ -0,0 +1,11 @@
package irc
import (
"crypto/sha256"
"fmt"
)
func SHA256(data string) string {
hash := sha256.Sum256([]byte(data))
return fmt.Sprintf("%x", hash)
}

View File

@@ -1,14 +1,18 @@
package irc
import (
"fmt"
)
var (
//PackageName package name
Package = "eris"
// Version release version
Version = "1.6.0"
Version = "1.6.2"
// Build will be overwritten automatically by the build system
Build = "-dev"
Build = "dev"
// GitCommit will be overwritten automatically by the build system
GitCommit = "HEAD"
@@ -16,5 +20,5 @@ var (
// FullVersion display the full version and build
func FullVersion() string {
return Package + " v" + Version + Build + " (" + GitCommit + ")"
return fmt.Sprintf("%s-%s-%s@%s", Package, Version, Build, GitCommit)
}

View File

@@ -17,6 +17,7 @@ type WhoWas struct {
nickname Name
username Name
hostname Name
hostmask Name
realname Text
}
@@ -33,6 +34,7 @@ func (list *WhoWasList) Append(client *Client) {
nickname: client.Nick(),
username: client.username,
hostname: client.hostname,
hostmask: client.hostmask,
realname: client.realname,
}
list.end = (list.end + 1) % len(list.buffer)

View File

@@ -1,3 +1,7 @@
network:
# network name
name: Local
server:
# server name
name: localhost.localdomain

View File

@@ -21,7 +21,7 @@ fi
echo -n "Building binaries ... "
GOOS=linux GOARCH=amd64 go build -o ./bin/eris-Linux-x86_64 .
GOOS=linux GOARCH=arm64 go build -o ./bin/eris-Linux-x86_64 .
GOOS=linux GOARCH=arm64 go build -o ./bin/eris-Linux-arm_64 .
GOOS=darwin GOARCH=amd64 go build -o ./bin/eris-Darwin-x86_64 .
GOOS=windows GOARCH=amd64 go build -o ./bin/eris-Windows-x86_64.exe .

1
vendor/github.com/petermattis/goid generated vendored Submodule