Add option to hex encode the source IP of a client and use it as the ident, closes #24
This commit is contained in:
parent
e2c6cedc27
commit
c975c5d120
File diff suppressed because one or more lines are too long
@ -29,14 +29,20 @@ class Connect extends Component {
|
|||||||
this.setState({ showOptionals: !this.state.showOptionals });
|
this.setState({ showOptionals: !this.state.showOptionals });
|
||||||
};
|
};
|
||||||
|
|
||||||
renderOptionals = () => (
|
renderOptionals = () => {
|
||||||
|
const { hexIP } = this.props;
|
||||||
|
|
||||||
|
return (
|
||||||
<div>
|
<div>
|
||||||
<TextInput name="username" placeholder="Username" />
|
{!hexIP && [
|
||||||
{this.renderError('username')}
|
<TextInput name="username" placeholder="Username" />,
|
||||||
|
this.renderError('username')
|
||||||
|
]}
|
||||||
<TextInput type="password" name="password" placeholder="Password" />
|
<TextInput type="password" name="password" placeholder="Password" />
|
||||||
<TextInput name="realname" placeholder="Realname" />
|
<TextInput name="realname" placeholder="Realname" />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
};
|
||||||
|
|
||||||
renderError = name => {
|
renderError = name => {
|
||||||
const { touched, errors } = this.props;
|
const { touched, errors } = this.props;
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { createStructuredSelector } from 'reselect';
|
import { createStructuredSelector } from 'reselect';
|
||||||
import Connect from 'components/pages/Connect';
|
import Connect from 'components/pages/Connect';
|
||||||
import { getConnectDefaults } from 'state/app';
|
import { getConnectDefaults, getApp } from 'state/app';
|
||||||
import { join } from 'state/channels';
|
import { join } from 'state/channels';
|
||||||
import { connect as connectServer } from 'state/servers';
|
import { connect as connectServer } from 'state/servers';
|
||||||
import { select } from 'state/tab';
|
import { select } from 'state/tab';
|
||||||
|
|
||||||
const mapState = createStructuredSelector({
|
const mapState = createStructuredSelector({
|
||||||
defaults: getConnectDefaults
|
defaults: getConnectDefaults,
|
||||||
|
hexIP: state => getApp(state).hexIP
|
||||||
});
|
});
|
||||||
|
|
||||||
const mapDispatch = {
|
const mapDispatch = {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import Cookie from 'js-cookie';
|
import Cookie from 'js-cookie';
|
||||||
import { socket as socketActions } from 'state/actions';
|
import { socket as socketActions } from 'state/actions';
|
||||||
import { getWrapWidth, setConnectDefaults } from 'state/app';
|
import { getWrapWidth, setConnectDefaults, appSet } from 'state/app';
|
||||||
import { addMessages } from 'state/messages';
|
import { addMessages } from 'state/messages';
|
||||||
import { select, updateSelection } from 'state/tab';
|
import { select, updateSelection } from 'state/tab';
|
||||||
import { find } from 'utils';
|
import { find } from 'utils';
|
||||||
@ -11,6 +11,7 @@ export default function initialState({ store }) {
|
|||||||
const env = JSON.parse(document.getElementById('env').innerHTML);
|
const env = JSON.parse(document.getElementById('env').innerHTML);
|
||||||
|
|
||||||
store.dispatch(setConnectDefaults(env.defaults));
|
store.dispatch(setConnectDefaults(env.defaults));
|
||||||
|
store.dispatch(appSet('hexIP', env.hexIP));
|
||||||
|
|
||||||
if (env.servers) {
|
if (env.servers) {
|
||||||
store.dispatch({
|
store.dispatch({
|
||||||
|
@ -21,7 +21,8 @@ const initialState = {
|
|||||||
password: false,
|
password: false,
|
||||||
readonly: false,
|
readonly: false,
|
||||||
showDetails: false
|
showDetails: false
|
||||||
}
|
},
|
||||||
|
hexIP: false
|
||||||
};
|
};
|
||||||
|
|
||||||
export default createReducer(initialState, {
|
export default createReducer(initialState, {
|
||||||
|
@ -103,6 +103,7 @@ func init() {
|
|||||||
viper.BindPFlag("port", rootCmd.Flags().Lookup("port"))
|
viper.BindPFlag("port", rootCmd.Flags().Lookup("port"))
|
||||||
viper.BindPFlag("dev", rootCmd.Flags().Lookup("dev"))
|
viper.BindPFlag("dev", rootCmd.Flags().Lookup("dev"))
|
||||||
|
|
||||||
|
viper.SetDefault("hexIP", false)
|
||||||
viper.SetDefault("verify_client_certificates", true)
|
viper.SetDefault("verify_client_certificates", true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
port = 80
|
port = 80
|
||||||
|
# Hex encode the users IP and use it as the ident
|
||||||
|
hexIP = false
|
||||||
verify_certificates = true
|
verify_certificates = true
|
||||||
|
|
||||||
# Defaults for the client connect form
|
# Defaults for the client connect form
|
||||||
|
@ -25,6 +25,7 @@ type indexData struct {
|
|||||||
Defaults connectDefaults
|
Defaults connectDefaults
|
||||||
Servers []Server
|
Servers []Server
|
||||||
Channels []*storage.Channel
|
Channels []*storage.Channel
|
||||||
|
HexIP bool
|
||||||
|
|
||||||
// Users in the selected channel
|
// Users in the selected channel
|
||||||
Users *Userlist
|
Users *Userlist
|
||||||
@ -34,7 +35,9 @@ type indexData struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getIndexData(r *http.Request, state *State) *indexData {
|
func getIndexData(r *http.Request, state *State) *indexData {
|
||||||
data := indexData{}
|
data := indexData{
|
||||||
|
HexIP: viper.GetBool("hexIP"),
|
||||||
|
}
|
||||||
|
|
||||||
data.Defaults = connectDefaults{
|
data.Defaults = connectDefaults{
|
||||||
Name: viper.GetString("defaults.name"),
|
Name: viper.GetString("defaults.name"),
|
||||||
|
@ -97,6 +97,8 @@ func easyjson7e607aefDecodeGithubComKhliengDispatchServer(in *jlexer.Lexer, out
|
|||||||
}
|
}
|
||||||
in.Delim(']')
|
in.Delim(']')
|
||||||
}
|
}
|
||||||
|
case "hexIP":
|
||||||
|
out.HexIP = bool(in.Bool())
|
||||||
case "users":
|
case "users":
|
||||||
if in.IsNull() {
|
if in.IsNull() {
|
||||||
in.Skip()
|
in.Skip()
|
||||||
@ -187,6 +189,16 @@ func easyjson7e607aefEncodeGithubComKhliengDispatchServer(out *jwriter.Writer, i
|
|||||||
out.RawByte(']')
|
out.RawByte(']')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if in.HexIP {
|
||||||
|
const prefix string = ",\"hexIP\":"
|
||||||
|
if first {
|
||||||
|
first = false
|
||||||
|
out.RawString(prefix[1:])
|
||||||
|
} else {
|
||||||
|
out.RawString(prefix)
|
||||||
|
}
|
||||||
|
out.Bool(bool(in.HexIP))
|
||||||
|
}
|
||||||
if in.Users != nil {
|
if in.Users != nil {
|
||||||
const prefix string = ",\"users\":"
|
const prefix string = ",\"users\":"
|
||||||
if first {
|
if first {
|
||||||
|
13
server/ip.go
Normal file
13
server/ip.go
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
package server
|
||||||
|
|
||||||
|
import "net"
|
||||||
|
|
||||||
|
func addrToIPBytes(addr net.Addr) []byte {
|
||||||
|
ip := addr.(*net.TCPAddr).IP
|
||||||
|
|
||||||
|
if ipv4 := ip.To4(); ipv4 != nil {
|
||||||
|
return ipv4
|
||||||
|
}
|
||||||
|
|
||||||
|
return ip
|
||||||
|
}
|
@ -2,6 +2,7 @@ package server
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
|
"encoding/hex"
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
@ -26,7 +27,7 @@ func createNickInUseHandler(i *irc.Client, state *State) func(string) string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func connectIRC(server *storage.Server, state *State) *irc.Client {
|
func connectIRC(server *storage.Server, state *State, srcIP []byte) *irc.Client {
|
||||||
i := irc.NewClient(server.Nick, server.Username)
|
i := irc.NewClient(server.Nick, server.Username)
|
||||||
i.TLS = server.TLS
|
i.TLS = server.TLS
|
||||||
i.Realname = server.Realname
|
i.Realname = server.Realname
|
||||||
@ -37,9 +38,12 @@ func connectIRC(server *storage.Server, state *State) *irc.Client {
|
|||||||
address = net.JoinHostPort(server.Host, server.Port)
|
address = net.JoinHostPort(server.Host, server.Port)
|
||||||
}
|
}
|
||||||
|
|
||||||
if i.Username == "" {
|
if viper.GetBool("hexIP") {
|
||||||
|
i.Username = hex.EncodeToString(srcIP)
|
||||||
|
} else if i.Username == "" {
|
||||||
i.Username = server.Nick
|
i.Username = server.Nick
|
||||||
}
|
}
|
||||||
|
|
||||||
if i.Realname == "" {
|
if i.Realname == "" {
|
||||||
i.Realname = server.Nick
|
i.Realname = server.Nick
|
||||||
}
|
}
|
||||||
|
@ -93,7 +93,7 @@ func (d *Dispatch) loadUser(user *storage.User) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, server := range servers {
|
for _, server := range servers {
|
||||||
i := connectIRC(server, state)
|
i := connectIRC(server, state, user.GetLastIP())
|
||||||
|
|
||||||
var joining []string
|
var joining []string
|
||||||
for _, channel := range channels {
|
for _, channel := range channels {
|
||||||
|
@ -2,6 +2,7 @@ package server
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
"log"
|
||||||
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@ -12,24 +13,24 @@ import (
|
|||||||
type wsHandler struct {
|
type wsHandler struct {
|
||||||
ws *wsConn
|
ws *wsConn
|
||||||
state *State
|
state *State
|
||||||
addr string
|
addr net.Addr
|
||||||
handlers map[string]func([]byte)
|
handlers map[string]func([]byte)
|
||||||
}
|
}
|
||||||
|
|
||||||
func newWSHandler(conn *websocket.Conn, state *State, r *http.Request) *wsHandler {
|
func newWSHandler(conn *websocket.Conn, state *State, r *http.Request) *wsHandler {
|
||||||
var address string
|
|
||||||
|
|
||||||
if r.Header.Get("X-Forwarded-For") != "" {
|
|
||||||
address = r.Header.Get("X-Forwarded-For")
|
|
||||||
} else {
|
|
||||||
address = conn.RemoteAddr().String()
|
|
||||||
}
|
|
||||||
|
|
||||||
h := &wsHandler{
|
h := &wsHandler{
|
||||||
ws: newWSConn(conn),
|
ws: newWSConn(conn),
|
||||||
state: state,
|
state: state,
|
||||||
addr: address,
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
h.init(r)
|
h.init(r)
|
||||||
h.initHandlers()
|
h.initHandlers()
|
||||||
return h
|
return h
|
||||||
@ -44,7 +45,7 @@ func (h *wsHandler) run() {
|
|||||||
req, ok := <-h.ws.in
|
req, ok := <-h.ws.in
|
||||||
if !ok {
|
if !ok {
|
||||||
if h.state != nil {
|
if h.state != nil {
|
||||||
h.state.deleteWS(h.addr)
|
h.state.deleteWS(h.addr.String())
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -60,7 +61,8 @@ func (h *wsHandler) dispatchRequest(req WSRequest) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (h *wsHandler) init(r *http.Request) {
|
func (h *wsHandler) init(r *http.Request) {
|
||||||
h.state.setWS(h.addr, h.ws)
|
h.state.setWS(h.addr.String(), h.ws)
|
||||||
|
h.state.user.SetLastIP(addrToIPBytes(h.addr))
|
||||||
|
|
||||||
log.Println(h.addr, "[State] User ID:", h.state.user.ID, "|",
|
log.Println(h.addr, "[State] User ID:", h.state.user.ID, "|",
|
||||||
h.state.numIRC(), "IRC connections |",
|
h.state.numIRC(), "IRC connections |",
|
||||||
@ -98,7 +100,7 @@ func (h *wsHandler) connect(b []byte) {
|
|||||||
if _, ok := h.state.getIRC(data.Host); !ok {
|
if _, ok := h.state.getIRC(data.Host); !ok {
|
||||||
log.Println(h.addr, "[IRC] Add server", data.Host)
|
log.Println(h.addr, "[IRC] Add server", data.Host)
|
||||||
|
|
||||||
connectIRC(data.Server, h.state)
|
connectIRC(data.Server, h.state, addrToIPBytes(h.addr))
|
||||||
|
|
||||||
go h.state.user.AddServer(data.Server)
|
go h.state.user.AddServer(data.Server)
|
||||||
} else {
|
} else {
|
||||||
|
@ -54,13 +54,11 @@ func (s *BoltStore) GetUsers() ([]*storage.User, error) {
|
|||||||
s.db.View(func(tx *bolt.Tx) error {
|
s.db.View(func(tx *bolt.Tx) error {
|
||||||
b := tx.Bucket(bucketUsers)
|
b := tx.Bucket(bucketUsers)
|
||||||
|
|
||||||
return b.ForEach(func(k, _ []byte) error {
|
return b.ForEach(func(k, v []byte) error {
|
||||||
id := idFromBytes(k)
|
|
||||||
user := storage.User{
|
user := storage.User{
|
||||||
ID: id,
|
|
||||||
IDBytes: make([]byte, 8),
|
IDBytes: make([]byte, 8),
|
||||||
Username: strconv.FormatUint(id, 10),
|
|
||||||
}
|
}
|
||||||
|
user.Unmarshal(v)
|
||||||
copy(user.IDBytes, k)
|
copy(user.IDBytes, k)
|
||||||
|
|
||||||
users = append(users, &user)
|
users = append(users, &user)
|
||||||
@ -76,7 +74,10 @@ func (s *BoltStore) SaveUser(user *storage.User) error {
|
|||||||
return s.db.Batch(func(tx *bolt.Tx) error {
|
return s.db.Batch(func(tx *bolt.Tx) error {
|
||||||
b := tx.Bucket(bucketUsers)
|
b := tx.Bucket(bucketUsers)
|
||||||
|
|
||||||
|
if user.ID == 0 {
|
||||||
user.ID, _ = b.NextSequence()
|
user.ID, _ = b.NextSequence()
|
||||||
|
user.IDBytes = idToBytes(user.ID)
|
||||||
|
}
|
||||||
user.Username = strconv.FormatUint(user.ID, 10)
|
user.Username = strconv.FormatUint(user.ID, 10)
|
||||||
|
|
||||||
data, err := user.Marshal(nil)
|
data, err := user.Marshal(nil)
|
||||||
@ -84,7 +85,6 @@ func (s *BoltStore) SaveUser(user *storage.User) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
user.IDBytes = idToBytes(user.ID)
|
|
||||||
return b.Put(user.IDBytes, data)
|
return b.Put(user.IDBytes, data)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
struct User {
|
struct User {
|
||||||
ID uint64
|
ID uint64
|
||||||
Username string
|
Username string
|
||||||
|
lastIP []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Server {
|
struct Server {
|
||||||
|
@ -29,6 +29,21 @@ func (d *User) Size() (s uint64) {
|
|||||||
}
|
}
|
||||||
s += l
|
s += l
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
l := uint64(len(d.lastIP))
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
t := l
|
||||||
|
for t >= 0x80 {
|
||||||
|
t >>= 7
|
||||||
|
s++
|
||||||
|
}
|
||||||
|
s++
|
||||||
|
|
||||||
|
}
|
||||||
|
s += l
|
||||||
|
}
|
||||||
s += 8
|
s += 8
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -67,6 +82,25 @@ func (d *User) Marshal(buf []byte) ([]byte, error) {
|
|||||||
copy(buf[i+8:], d.Username)
|
copy(buf[i+8:], d.Username)
|
||||||
i += l
|
i += l
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
l := uint64(len(d.lastIP))
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
t := uint64(l)
|
||||||
|
|
||||||
|
for t >= 0x80 {
|
||||||
|
buf[i+8] = byte(t) | 0x80
|
||||||
|
t >>= 7
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
buf[i+8] = byte(t)
|
||||||
|
i++
|
||||||
|
|
||||||
|
}
|
||||||
|
copy(buf[i+8:], d.lastIP)
|
||||||
|
i += l
|
||||||
|
}
|
||||||
return buf[:i+8], nil
|
return buf[:i+8], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,6 +132,31 @@ func (d *User) Unmarshal(buf []byte) (uint64, error) {
|
|||||||
d.Username = string(buf[i+8 : i+8+l])
|
d.Username = string(buf[i+8 : i+8+l])
|
||||||
i += l
|
i += l
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
l := uint64(0)
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
bs := uint8(7)
|
||||||
|
t := uint64(buf[i+8] & 0x7F)
|
||||||
|
for buf[i+8]&0x80 == 0x80 {
|
||||||
|
i++
|
||||||
|
t |= uint64(buf[i+8]&0x7F) << bs
|
||||||
|
bs += 7
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
|
||||||
|
l = t
|
||||||
|
|
||||||
|
}
|
||||||
|
if uint64(cap(d.lastIP)) >= l {
|
||||||
|
d.lastIP = d.lastIP[:l]
|
||||||
|
} else {
|
||||||
|
d.lastIP = make([]byte, l)
|
||||||
|
}
|
||||||
|
copy(d.lastIP, buf[i+8:])
|
||||||
|
i += l
|
||||||
|
}
|
||||||
return i + 8, nil
|
return i + 8, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,6 +15,7 @@ type User struct {
|
|||||||
store Store
|
store Store
|
||||||
messageLog MessageStore
|
messageLog MessageStore
|
||||||
messageIndex MessageSearchProvider
|
messageIndex MessageSearchProvider
|
||||||
|
lastIP []byte
|
||||||
certificate *tls.Certificate
|
certificate *tls.Certificate
|
||||||
lock sync.Mutex
|
lock sync.Mutex
|
||||||
}
|
}
|
||||||
@ -68,6 +69,21 @@ func (u *User) Remove() {
|
|||||||
os.RemoveAll(Path.User(u.Username))
|
os.RemoveAll(Path.User(u.Username))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *User) GetLastIP() []byte {
|
||||||
|
u.lock.Lock()
|
||||||
|
ip := u.lastIP
|
||||||
|
u.lock.Unlock()
|
||||||
|
return ip
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *User) SetLastIP(ip []byte) error {
|
||||||
|
u.lock.Lock()
|
||||||
|
u.lastIP = ip
|
||||||
|
u.lock.Unlock()
|
||||||
|
|
||||||
|
return u.store.SaveUser(u)
|
||||||
|
}
|
||||||
|
|
||||||
type Server struct {
|
type Server struct {
|
||||||
Name string
|
Name string
|
||||||
Host string
|
Host string
|
||||||
|
Loading…
Reference in New Issue
Block a user