Add SASL auth and CAP negotiation
This commit is contained in:
parent
be8b785813
commit
2f8dad2529
File diff suppressed because one or more lines are too long
@ -408,6 +408,17 @@ i[class*=' icon-']:before {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.connect-section {
|
||||||
|
border-bottom: 1px solid #ddd;
|
||||||
|
padding-bottom: 15px;
|
||||||
|
margin: 15px 0;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.connect-section h2 {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
input[type='number'] {
|
input[type='number'] {
|
||||||
appearance: textfield;
|
appearance: textfield;
|
||||||
}
|
}
|
||||||
@ -806,7 +817,6 @@ input.message-input-nick.invalid {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.settings h2 {
|
.settings h2 {
|
||||||
font-weight: 700;
|
|
||||||
color: #222;
|
color: #222;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import { createSelector } from 'reselect';
|
import { createSelector } from 'reselect';
|
||||||
import { Form, withFormik } from 'formik';
|
import { Form, withFormik } from 'formik';
|
||||||
|
import { FiMoreHorizontal } from 'react-icons/fi';
|
||||||
import Navicon from 'components/ui/Navicon';
|
import Navicon from 'components/ui/Navicon';
|
||||||
import Button from 'components/ui/Button';
|
import Button from 'components/ui/Button';
|
||||||
import Checkbox from 'components/ui/formik/Checkbox';
|
import Checkbox from 'components/ui/formik/Checkbox';
|
||||||
import TextInput from 'components/ui/TextInput';
|
import TextInput from 'components/ui/TextInput';
|
||||||
import Error from 'components/ui/formik/Error';
|
import Error from 'components/ui/formik/Error';
|
||||||
import { isValidNick, isValidChannel, isValidUsername, isInt } from 'utils';
|
import { isValidNick, isValidChannel, isValidUsername, isInt } from 'utils';
|
||||||
import { FiMoreHorizontal } from 'react-icons/fi';
|
|
||||||
|
|
||||||
const getSortedDefaultChannels = createSelector(
|
const getSortedDefaultChannels = createSelector(
|
||||||
defaults => defaults.channels,
|
defaults => defaults.channels,
|
||||||
@ -56,11 +56,21 @@ class Connect extends Component {
|
|||||||
const { hexIP } = this.props;
|
const { hexIP } = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<>
|
||||||
{!hexIP && <TextInput name="username" />}
|
<div className="connect-section">
|
||||||
<TextInput name="password" type="password" noTrim />
|
<h2>SASL</h2>
|
||||||
<TextInput name="realname" noTrim />
|
<TextInput name="account" />
|
||||||
|
<TextInput name="password" type="password" />
|
||||||
</div>
|
</div>
|
||||||
|
{!hexIP && <TextInput name="username" />}
|
||||||
|
<TextInput
|
||||||
|
name="serverPassword"
|
||||||
|
label="Server Password"
|
||||||
|
type="password"
|
||||||
|
noTrim
|
||||||
|
/>
|
||||||
|
<TextInput name="realname" noTrim />
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -170,8 +180,10 @@ export default withFormik({
|
|||||||
port,
|
port,
|
||||||
nick: query.nick || localStorage.lastNick || '',
|
nick: query.nick || localStorage.lastNick || '',
|
||||||
channels: channels || defaults.channels.join(','),
|
channels: channels || defaults.channels.join(','),
|
||||||
|
account: '',
|
||||||
|
password: '',
|
||||||
username: query.username || '',
|
username: query.username || '',
|
||||||
password: defaults.password ? ' ' : '',
|
serverPassword: defaults.serverPassword ? ' ' : '',
|
||||||
realname: query.realname || localStorage.lastRealname || '',
|
realname: query.realname || localStorage.lastRealname || '',
|
||||||
tls: ssl
|
tls: ssl
|
||||||
};
|
};
|
||||||
@ -219,7 +231,7 @@ export default withFormik({
|
|||||||
const channels = values.channels ? values.channels.split(',') : [];
|
const channels = values.channels ? values.channels.split(',') : [];
|
||||||
delete values.channels;
|
delete values.channels;
|
||||||
|
|
||||||
values.password = values.password.trim();
|
values.serverPassword = values.serverPassword.trim();
|
||||||
|
|
||||||
values.port = `${values.port}`;
|
values.port = `${values.port}`;
|
||||||
connect(values);
|
connect(values);
|
||||||
|
@ -13,7 +13,7 @@ port = 6697
|
|||||||
channels = [
|
channels = [
|
||||||
"#dispatch"
|
"#dispatch"
|
||||||
]
|
]
|
||||||
password = ""
|
server_password = ""
|
||||||
ssl = true
|
ssl = true
|
||||||
# Only allow a nick to be filled in
|
# Only allow a nick to be filled in
|
||||||
readonly = false
|
readonly = false
|
||||||
|
@ -27,7 +27,7 @@ type Defaults struct {
|
|||||||
Host string
|
Host string
|
||||||
Port string
|
Port string
|
||||||
Channels []string
|
Channels []string
|
||||||
Password string
|
ServerPassword string `mapstructure:"server_password"`
|
||||||
SSL bool
|
SSL bool
|
||||||
ReadOnly bool
|
ReadOnly bool
|
||||||
ShowDetails bool `mapstructure:"show_details"`
|
ShowDetails bool `mapstructure:"show_details"`
|
||||||
|
129
pkg/irc/cap.go
Normal file
129
pkg/irc/cap.go
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
package irc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (c *Client) HasCapability(name string, values ...string) bool {
|
||||||
|
if capValues, ok := c.enabledCapabilities[name]; ok {
|
||||||
|
if len(values) == 0 || capValues == nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, v := range values {
|
||||||
|
for _, vCap := range capValues {
|
||||||
|
if v == vCap {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
var clientWantedCaps = []string{}
|
||||||
|
|
||||||
|
func (c *Client) writeCAP() {
|
||||||
|
c.write("CAP LS 302")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) handleCAP(msg *Message) {
|
||||||
|
if len(msg.Params) < 3 {
|
||||||
|
c.write("CAP END")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
caps := parseCaps(msg.LastParam())
|
||||||
|
|
||||||
|
c.lock.Lock()
|
||||||
|
defer c.lock.Unlock()
|
||||||
|
|
||||||
|
switch msg.Params[1] {
|
||||||
|
case "LS":
|
||||||
|
for cap, values := range caps {
|
||||||
|
for _, wanted := range c.wantedCapabilities {
|
||||||
|
if cap == wanted {
|
||||||
|
c.requestedCapabilities[cap] = values
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(msg.Params) == 3 {
|
||||||
|
if len(c.requestedCapabilities) == 0 {
|
||||||
|
c.write("CAP END")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
reqCaps := []string{}
|
||||||
|
for cap := range c.requestedCapabilities {
|
||||||
|
reqCaps = append(reqCaps, cap)
|
||||||
|
}
|
||||||
|
|
||||||
|
c.write("CAP REQ :" + strings.Join(reqCaps, " "))
|
||||||
|
}
|
||||||
|
|
||||||
|
case "ACK":
|
||||||
|
for cap := range caps {
|
||||||
|
if v, ok := c.requestedCapabilities[cap]; ok {
|
||||||
|
c.enabledCapabilities[cap] = v
|
||||||
|
delete(c.requestedCapabilities, cap)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(c.requestedCapabilities) == 0 {
|
||||||
|
if c.SASL != nil && c.HasCapability("sasl", c.SASL.Name()) {
|
||||||
|
c.write("AUTHENTICATE " + c.SASL.Name())
|
||||||
|
} else {
|
||||||
|
c.write("CAP END")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case "NAK":
|
||||||
|
for cap := range caps {
|
||||||
|
delete(c.requestedCapabilities, cap)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(c.requestedCapabilities) == 0 {
|
||||||
|
c.write("CAP END")
|
||||||
|
}
|
||||||
|
|
||||||
|
case "NEW":
|
||||||
|
reqCaps := []string{}
|
||||||
|
for cap, values := range caps {
|
||||||
|
for _, wanted := range c.wantedCapabilities {
|
||||||
|
if cap == wanted && !c.HasCapability(cap) {
|
||||||
|
c.requestedCapabilities[cap] = values
|
||||||
|
reqCaps = append(reqCaps, cap)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(reqCaps) > 0 {
|
||||||
|
c.write("CAP REQ :" + strings.Join(reqCaps, " "))
|
||||||
|
}
|
||||||
|
|
||||||
|
case "DEL":
|
||||||
|
for cap := range caps {
|
||||||
|
delete(c.enabledCapabilities, cap)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseCaps(caps string) map[string][]string {
|
||||||
|
result := map[string][]string{}
|
||||||
|
|
||||||
|
parts := strings.Split(caps, " ")
|
||||||
|
for _, part := range parts {
|
||||||
|
capParts := strings.Split(part, "=")
|
||||||
|
name := capParts[0]
|
||||||
|
|
||||||
|
if len(capParts) > 1 {
|
||||||
|
result[name] = strings.Split(capParts[1], ",")
|
||||||
|
} else {
|
||||||
|
result[name] = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
58
pkg/irc/cap_test.go
Normal file
58
pkg/irc/cap_test.go
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
package irc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestParseCaps(t *testing.T) {
|
||||||
|
cases := []struct {
|
||||||
|
input string
|
||||||
|
expected map[string][]string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
"sasl",
|
||||||
|
map[string][]string{
|
||||||
|
"sasl": nil,
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
"sasl=PLAIN",
|
||||||
|
map[string][]string{
|
||||||
|
"sasl": {"PLAIN"},
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
"cake sasl=PLAIN",
|
||||||
|
map[string][]string{
|
||||||
|
"cake": nil,
|
||||||
|
"sasl": {"PLAIN"},
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
"cake sasl=PLAIN pie",
|
||||||
|
map[string][]string{
|
||||||
|
"cake": nil,
|
||||||
|
"sasl": {"PLAIN"},
|
||||||
|
"pie": nil,
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
"cake sasl=PLAIN pie=BLUEBERRY,RASPBERRY",
|
||||||
|
map[string][]string{
|
||||||
|
"cake": nil,
|
||||||
|
"sasl": {"PLAIN"},
|
||||||
|
"pie": {"BLUEBERRY", "RASPBERRY"},
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
"cake sasl=PLAIN pie=BLUEBERRY,RASPBERRY cheesecake",
|
||||||
|
map[string][]string{
|
||||||
|
"cake": nil,
|
||||||
|
"sasl": {"PLAIN"},
|
||||||
|
"pie": {"BLUEBERRY", "RASPBERRY"},
|
||||||
|
"cheesecake": nil,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range cases {
|
||||||
|
assert.Equal(t, tc.expected, parseCaps(tc.input))
|
||||||
|
}
|
||||||
|
}
|
@ -19,6 +19,7 @@ type Client struct {
|
|||||||
Password string
|
Password string
|
||||||
Username string
|
Username string
|
||||||
Realname string
|
Realname string
|
||||||
|
SASL SASL
|
||||||
HandleNickInUse func(string) string
|
HandleNickInUse func(string) string
|
||||||
|
|
||||||
// Version is the reply to VERSION and FINGER CTCP messages
|
// Version is the reply to VERSION and FINGER CTCP messages
|
||||||
@ -32,6 +33,10 @@ type Client struct {
|
|||||||
nick string
|
nick string
|
||||||
channels []string
|
channels []string
|
||||||
|
|
||||||
|
wantedCapabilities []string
|
||||||
|
requestedCapabilities map[string][]string
|
||||||
|
enabledCapabilities map[string][]string
|
||||||
|
|
||||||
conn net.Conn
|
conn net.Conn
|
||||||
connected bool
|
connected bool
|
||||||
registered bool
|
registered bool
|
||||||
@ -58,6 +63,9 @@ func NewClient(nick, username string) *Client {
|
|||||||
out: make(chan string, 32),
|
out: make(chan string, 32),
|
||||||
quit: make(chan struct{}),
|
quit: make(chan struct{}),
|
||||||
reconnect: make(chan struct{}),
|
reconnect: make(chan struct{}),
|
||||||
|
wantedCapabilities: clientWantedCaps,
|
||||||
|
enabledCapabilities: map[string][]string{},
|
||||||
|
requestedCapabilities: map[string][]string{},
|
||||||
dialer: &net.Dialer{Timeout: 10 * time.Second},
|
dialer: &net.Dialer{Timeout: 10 * time.Second},
|
||||||
recvBuf: make([]byte, 0, 4096),
|
recvBuf: make([]byte, 0, 4096),
|
||||||
backoff: &backoff.Backoff{
|
backoff: &backoff.Backoff{
|
||||||
@ -191,6 +199,11 @@ func (c *Client) writeUser(username, realname string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) register() {
|
func (c *Client) register() {
|
||||||
|
if c.SASL != nil {
|
||||||
|
c.wantedCapabilities = append(c.wantedCapabilities, "sasl")
|
||||||
|
}
|
||||||
|
|
||||||
|
c.writeCAP()
|
||||||
if c.Password != "" {
|
if c.Password != "" {
|
||||||
c.writePass(c.Password)
|
c.writePass(c.Password)
|
||||||
}
|
}
|
||||||
|
@ -152,11 +152,13 @@ func TestRegister(t *testing.T) {
|
|||||||
c.Username = "user"
|
c.Username = "user"
|
||||||
c.Realname = "rn"
|
c.Realname = "rn"
|
||||||
c.register()
|
c.register()
|
||||||
|
assert.Equal(t, "CAP LS 302\r\n", <-out)
|
||||||
assert.Equal(t, "NICK nick\r\n", <-out)
|
assert.Equal(t, "NICK nick\r\n", <-out)
|
||||||
assert.Equal(t, "USER user 0 * :rn\r\n", <-out)
|
assert.Equal(t, "USER user 0 * :rn\r\n", <-out)
|
||||||
|
|
||||||
c.Password = "pass"
|
c.Password = "pass"
|
||||||
c.register()
|
c.register()
|
||||||
|
assert.Equal(t, "CAP LS 302\r\n", <-out)
|
||||||
assert.Equal(t, "PASS pass\r\n", <-out)
|
assert.Equal(t, "PASS pass\r\n", <-out)
|
||||||
assert.Equal(t, "NICK nick\r\n", <-out)
|
assert.Equal(t, "NICK nick\r\n", <-out)
|
||||||
assert.Equal(t, "USER user 0 * :rn\r\n", <-out)
|
assert.Equal(t, "USER user 0 * :rn\r\n", <-out)
|
||||||
|
@ -226,6 +226,9 @@ func (c *Client) recv() {
|
|||||||
c.handleCTCP(ctcp, msg)
|
c.handleCTCP(ctcp, msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case CAP:
|
||||||
|
c.handleCAP(msg)
|
||||||
|
|
||||||
case RPL_WELCOME:
|
case RPL_WELCOME:
|
||||||
c.setNick(msg.Params[0])
|
c.setNick(msg.Params[0])
|
||||||
c.setRegistered(true)
|
c.setRegistered(true)
|
||||||
@ -251,6 +254,8 @@ func (c *Client) recv() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
c.handleSASL(msg)
|
||||||
|
|
||||||
c.Messages <- msg
|
c.Messages <- msg
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
64
pkg/irc/sasl.go
Normal file
64
pkg/irc/sasl.go
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
package irc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/base64"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SASL interface {
|
||||||
|
Name() string
|
||||||
|
Encode() string
|
||||||
|
}
|
||||||
|
|
||||||
|
type SASLPlain struct {
|
||||||
|
Username string
|
||||||
|
Password string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SASLPlain) Name() string {
|
||||||
|
return "PLAIN"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SASLPlain) Encode() string {
|
||||||
|
buf := bytes.Buffer{}
|
||||||
|
buf.WriteString(s.Username)
|
||||||
|
buf.WriteByte(0x0)
|
||||||
|
buf.WriteString(s.Username)
|
||||||
|
buf.WriteByte(0x0)
|
||||||
|
buf.WriteString(s.Password)
|
||||||
|
|
||||||
|
return base64.StdEncoding.EncodeToString(buf.Bytes())
|
||||||
|
}
|
||||||
|
|
||||||
|
type SASLExternal struct{}
|
||||||
|
|
||||||
|
func (s *SASLExternal) Name() string {
|
||||||
|
return "EXTERNAL"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SASLExternal) Encode() string {
|
||||||
|
return "+"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) handleSASL(msg *Message) {
|
||||||
|
switch msg.Command {
|
||||||
|
case AUTHENTICATE:
|
||||||
|
auth := c.SASL.Encode()
|
||||||
|
|
||||||
|
for len(auth) >= 400 {
|
||||||
|
c.write("AUTHENTICATE " + auth)
|
||||||
|
auth = auth[400:]
|
||||||
|
}
|
||||||
|
if len(auth) > 0 {
|
||||||
|
c.write("AUTHENTICATE " + auth)
|
||||||
|
} else {
|
||||||
|
c.write("AUTHENTICATE +")
|
||||||
|
}
|
||||||
|
|
||||||
|
case RPL_SASLSUCCESS:
|
||||||
|
c.write("CAP END")
|
||||||
|
|
||||||
|
case ERR_NICKLOCKED, ERR_SASLFAIL, ERR_SASLTOOLONG, ERR_SASLABORTED, RPL_SASLMECHS:
|
||||||
|
c.write("CAP END")
|
||||||
|
}
|
||||||
|
}
|
@ -12,7 +12,7 @@ import (
|
|||||||
|
|
||||||
type connectDefaults struct {
|
type connectDefaults struct {
|
||||||
*config.Defaults
|
*config.Defaults
|
||||||
Password bool
|
ServerPassword bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type dispatchVersion struct {
|
type dispatchVersion struct {
|
||||||
@ -51,7 +51,7 @@ func (d *Dispatch) getIndexData(r *http.Request, state *State) *indexData {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
data.Defaults.Password = cfg.Defaults.Password != ""
|
data.Defaults.ServerPassword = cfg.Defaults.ServerPassword != ""
|
||||||
|
|
||||||
if state == nil {
|
if state == nil {
|
||||||
data.Settings = storage.DefaultClientSettings()
|
data.Settings = storage.DefaultClientSettings()
|
||||||
|
@ -553,8 +553,8 @@ func easyjson7e607aefDecodeGithubComKhliengDispatchServer2(in *jlexer.Lexer, out
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
switch key {
|
switch key {
|
||||||
case "password":
|
case "serverPassword":
|
||||||
out.Password = bool(in.Bool())
|
out.ServerPassword = bool(in.Bool())
|
||||||
case "name":
|
case "name":
|
||||||
out.Name = string(in.String())
|
out.Name = string(in.String())
|
||||||
case "host":
|
case "host":
|
||||||
@ -604,11 +604,11 @@ func easyjson7e607aefEncodeGithubComKhliengDispatchServer2(out *jwriter.Writer,
|
|||||||
out.RawByte('{')
|
out.RawByte('{')
|
||||||
first := true
|
first := true
|
||||||
_ = first
|
_ = first
|
||||||
if in.Password {
|
if in.ServerPassword {
|
||||||
const prefix string = ",\"password\":"
|
const prefix string = ",\"serverPassword\":"
|
||||||
first = false
|
first = false
|
||||||
out.RawString(prefix[1:])
|
out.RawString(prefix[1:])
|
||||||
out.Bool(bool(in.Password))
|
out.Bool(bool(in.ServerPassword))
|
||||||
}
|
}
|
||||||
if in.Name != "" {
|
if in.Name != "" {
|
||||||
const prefix string = ",\"name\":"
|
const prefix string = ",\"name\":"
|
||||||
|
@ -55,12 +55,19 @@ func connectIRC(server *storage.Server, state *State, srcIP []byte) *irc.Client
|
|||||||
i.Realname = server.Nick
|
i.Realname = server.Nick
|
||||||
}
|
}
|
||||||
|
|
||||||
if server.Password == "" &&
|
if server.ServerPassword == "" &&
|
||||||
cfg.Defaults.Password != "" &&
|
cfg.Defaults.ServerPassword != "" &&
|
||||||
address == cfg.Defaults.Host {
|
address == cfg.Defaults.Host {
|
||||||
i.Password = cfg.Defaults.Password
|
i.Password = cfg.Defaults.ServerPassword
|
||||||
} else {
|
} else {
|
||||||
i.Password = server.Password
|
i.Password = server.ServerPassword
|
||||||
|
}
|
||||||
|
|
||||||
|
if server.Account != "" && server.Password != "" {
|
||||||
|
i.SASL = &irc.SASLPlain{
|
||||||
|
Username: server.Account,
|
||||||
|
Password: server.Password,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if i.TLS {
|
if i.TLS {
|
||||||
|
@ -866,14 +866,18 @@ func easyjson42239ddeDecodeGithubComKhliengDispatchServer8(in *jlexer.Lexer, out
|
|||||||
out.Port = string(in.String())
|
out.Port = string(in.String())
|
||||||
case "tls":
|
case "tls":
|
||||||
out.TLS = bool(in.Bool())
|
out.TLS = bool(in.Bool())
|
||||||
case "password":
|
case "serverPassword":
|
||||||
out.Password = string(in.String())
|
out.ServerPassword = string(in.String())
|
||||||
case "nick":
|
case "nick":
|
||||||
out.Nick = string(in.String())
|
out.Nick = string(in.String())
|
||||||
case "username":
|
case "username":
|
||||||
out.Username = string(in.String())
|
out.Username = string(in.String())
|
||||||
case "realname":
|
case "realname":
|
||||||
out.Realname = string(in.String())
|
out.Realname = string(in.String())
|
||||||
|
case "account":
|
||||||
|
out.Account = string(in.String())
|
||||||
|
case "password":
|
||||||
|
out.Password = string(in.String())
|
||||||
default:
|
default:
|
||||||
in.SkipRecursive()
|
in.SkipRecursive()
|
||||||
}
|
}
|
||||||
@ -964,15 +968,15 @@ func easyjson42239ddeEncodeGithubComKhliengDispatchServer8(out *jwriter.Writer,
|
|||||||
}
|
}
|
||||||
out.Bool(bool(in.TLS))
|
out.Bool(bool(in.TLS))
|
||||||
}
|
}
|
||||||
if in.Password != "" {
|
if in.ServerPassword != "" {
|
||||||
const prefix string = ",\"password\":"
|
const prefix string = ",\"serverPassword\":"
|
||||||
if first {
|
if first {
|
||||||
first = false
|
first = false
|
||||||
out.RawString(prefix[1:])
|
out.RawString(prefix[1:])
|
||||||
} else {
|
} else {
|
||||||
out.RawString(prefix)
|
out.RawString(prefix)
|
||||||
}
|
}
|
||||||
out.String(string(in.Password))
|
out.String(string(in.ServerPassword))
|
||||||
}
|
}
|
||||||
if in.Nick != "" {
|
if in.Nick != "" {
|
||||||
const prefix string = ",\"nick\":"
|
const prefix string = ",\"nick\":"
|
||||||
@ -1004,6 +1008,26 @@ func easyjson42239ddeEncodeGithubComKhliengDispatchServer8(out *jwriter.Writer,
|
|||||||
}
|
}
|
||||||
out.String(string(in.Realname))
|
out.String(string(in.Realname))
|
||||||
}
|
}
|
||||||
|
if in.Account != "" {
|
||||||
|
const prefix string = ",\"account\":"
|
||||||
|
if first {
|
||||||
|
first = false
|
||||||
|
out.RawString(prefix[1:])
|
||||||
|
} else {
|
||||||
|
out.RawString(prefix)
|
||||||
|
}
|
||||||
|
out.String(string(in.Account))
|
||||||
|
}
|
||||||
|
if in.Password != "" {
|
||||||
|
const prefix string = ",\"password\":"
|
||||||
|
if first {
|
||||||
|
first = false
|
||||||
|
out.RawString(prefix[1:])
|
||||||
|
} else {
|
||||||
|
out.RawString(prefix)
|
||||||
|
}
|
||||||
|
out.String(string(in.Password))
|
||||||
|
}
|
||||||
out.RawByte('}')
|
out.RawByte('}')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,10 +14,12 @@ struct Server {
|
|||||||
Host string
|
Host string
|
||||||
Port string
|
Port string
|
||||||
TLS bool
|
TLS bool
|
||||||
Password string
|
ServerPassword string
|
||||||
Nick string
|
Nick string
|
||||||
Username string
|
Username string
|
||||||
Realname string
|
Realname string
|
||||||
|
Account string
|
||||||
|
Password string
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Channel {
|
struct Channel {
|
||||||
|
@ -286,7 +286,7 @@ func (d *Server) Size() (s uint64) {
|
|||||||
s += l
|
s += l
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
l := uint64(len(d.Password))
|
l := uint64(len(d.ServerPassword))
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -345,6 +345,36 @@ func (d *Server) Size() (s uint64) {
|
|||||||
}
|
}
|
||||||
s += l
|
s += l
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
l := uint64(len(d.Account))
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
t := l
|
||||||
|
for t >= 0x80 {
|
||||||
|
t >>= 7
|
||||||
|
s++
|
||||||
|
}
|
||||||
|
s++
|
||||||
|
|
||||||
|
}
|
||||||
|
s += l
|
||||||
|
}
|
||||||
|
{
|
||||||
|
l := uint64(len(d.Password))
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
t := l
|
||||||
|
for t >= 0x80 {
|
||||||
|
t >>= 7
|
||||||
|
s++
|
||||||
|
}
|
||||||
|
s++
|
||||||
|
|
||||||
|
}
|
||||||
|
s += l
|
||||||
|
}
|
||||||
s += 1
|
s += 1
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -424,7 +454,7 @@ func (d *Server) Marshal(buf []byte) ([]byte, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
l := uint64(len(d.Password))
|
l := uint64(len(d.ServerPassword))
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -439,7 +469,7 @@ func (d *Server) Marshal(buf []byte) ([]byte, error) {
|
|||||||
i++
|
i++
|
||||||
|
|
||||||
}
|
}
|
||||||
copy(buf[i+1:], d.Password)
|
copy(buf[i+1:], d.ServerPassword)
|
||||||
i += l
|
i += l
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
@ -499,6 +529,44 @@ func (d *Server) Marshal(buf []byte) ([]byte, error) {
|
|||||||
copy(buf[i+1:], d.Realname)
|
copy(buf[i+1:], d.Realname)
|
||||||
i += l
|
i += l
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
l := uint64(len(d.Account))
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
t := uint64(l)
|
||||||
|
|
||||||
|
for t >= 0x80 {
|
||||||
|
buf[i+1] = byte(t) | 0x80
|
||||||
|
t >>= 7
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
buf[i+1] = byte(t)
|
||||||
|
i++
|
||||||
|
|
||||||
|
}
|
||||||
|
copy(buf[i+1:], d.Account)
|
||||||
|
i += l
|
||||||
|
}
|
||||||
|
{
|
||||||
|
l := uint64(len(d.Password))
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
t := uint64(l)
|
||||||
|
|
||||||
|
for t >= 0x80 {
|
||||||
|
buf[i+1] = byte(t) | 0x80
|
||||||
|
t >>= 7
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
buf[i+1] = byte(t)
|
||||||
|
i++
|
||||||
|
|
||||||
|
}
|
||||||
|
copy(buf[i+1:], d.Password)
|
||||||
|
i += l
|
||||||
|
}
|
||||||
return buf[:i+1], nil
|
return buf[:i+1], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -585,7 +653,7 @@ func (d *Server) Unmarshal(buf []byte) (uint64, error) {
|
|||||||
l = t
|
l = t
|
||||||
|
|
||||||
}
|
}
|
||||||
d.Password = string(buf[i+1 : i+1+l])
|
d.ServerPassword = string(buf[i+1 : i+1+l])
|
||||||
i += l
|
i += l
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
@ -648,6 +716,46 @@ func (d *Server) Unmarshal(buf []byte) (uint64, error) {
|
|||||||
d.Realname = string(buf[i+1 : i+1+l])
|
d.Realname = string(buf[i+1 : i+1+l])
|
||||||
i += l
|
i += l
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
l := uint64(0)
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
bs := uint8(7)
|
||||||
|
t := uint64(buf[i+1] & 0x7F)
|
||||||
|
for buf[i+1]&0x80 == 0x80 {
|
||||||
|
i++
|
||||||
|
t |= uint64(buf[i+1]&0x7F) << bs
|
||||||
|
bs += 7
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
|
||||||
|
l = t
|
||||||
|
|
||||||
|
}
|
||||||
|
d.Account = string(buf[i+1 : i+1+l])
|
||||||
|
i += l
|
||||||
|
}
|
||||||
|
{
|
||||||
|
l := uint64(0)
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
bs := uint8(7)
|
||||||
|
t := uint64(buf[i+1] & 0x7F)
|
||||||
|
for buf[i+1]&0x80 == 0x80 {
|
||||||
|
i++
|
||||||
|
t |= uint64(buf[i+1]&0x7F) << bs
|
||||||
|
bs += 7
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
|
||||||
|
l = t
|
||||||
|
|
||||||
|
}
|
||||||
|
d.Password = string(buf[i+1 : i+1+l])
|
||||||
|
i += l
|
||||||
|
}
|
||||||
return i + 1, nil
|
return i + 1, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,10 +136,12 @@ type Server struct {
|
|||||||
Host string
|
Host string
|
||||||
Port string
|
Port string
|
||||||
TLS bool
|
TLS bool
|
||||||
Password string
|
ServerPassword string
|
||||||
Nick string
|
Nick string
|
||||||
Username string
|
Username string
|
||||||
Realname string
|
Realname string
|
||||||
|
Account string
|
||||||
|
Password string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *User) GetServer(address string) (*Server, error) {
|
func (u *User) GetServer(address string) (*Server, error) {
|
||||||
|
Loading…
Reference in New Issue
Block a user