Changeset 95 in code for trunk/upstream.go
- Timestamp:
- Mar 13, 2020, 2:12:44 PM (5 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/upstream.go
r93 r95 3 3 import ( 4 4 "crypto/tls" 5 "encoding/base64" 5 6 "fmt" 6 7 "io" … … 10 11 "time" 11 12 13 "github.com/emersion/go-sasl" 12 14 "gopkg.in/irc.v3" 13 15 ) … … 49 51 history map[string]uint64 50 52 caps map[string]string 53 54 saslClient sasl.Client 55 saslStarted bool 51 56 } 52 57 … … 170 175 uc.logger.Print(msg) 171 176 case "CAP": 172 if len(msg.Params) < 2 { 173 return newNeedMoreParamsError(msg.Command) 174 } 175 caps := strings.Fields(msg.Params[len(msg.Params)-1]) 176 more := msg.Params[len(msg.Params)-2] == "*" 177 178 for _, s := range caps { 179 kv := strings.SplitN(s, "=", 2) 180 k := strings.ToLower(kv[0]) 181 var v string 182 if len(kv) >= 2 { 183 v = kv[1] 184 } 185 uc.caps[k] = v 186 } 187 188 if !more { 177 var subCmd string 178 if err := parseMessageParams(msg, nil, &subCmd); err != nil { 179 return err 180 } 181 subCmd = strings.ToUpper(subCmd) 182 subParams := msg.Params[2:] 183 switch subCmd { 184 case "LS": 185 if len(subParams) < 1 { 186 return newNeedMoreParamsError(msg.Command) 187 } 188 caps := strings.Fields(subParams[len(subParams)-1]) 189 more := len(subParams) >= 2 && msg.Params[len(subParams)-2] == "*" 190 191 for _, s := range caps { 192 kv := strings.SplitN(s, "=", 2) 193 k := strings.ToLower(kv[0]) 194 var v string 195 if len(kv) == 2 { 196 v = kv[1] 197 } 198 uc.caps[k] = v 199 } 200 201 if more { 202 break // wait to receive all capabilities 203 } 204 205 if uc.requestSASL() { 206 uc.SendMessage(&irc.Message{ 207 Command: "CAP", 208 Params: []string{"REQ", "sasl"}, 209 }) 210 break // we'll send CAP END after authentication is completed 211 } 212 189 213 uc.SendMessage(&irc.Message{ 190 214 Command: "CAP", 191 215 Params: []string{"END"}, 192 216 }) 193 } 217 case "ACK", "NAK": 218 if len(subParams) < 1 { 219 return newNeedMoreParamsError(msg.Command) 220 } 221 caps := strings.Fields(subParams[0]) 222 223 for _, name := range caps { 224 if err := uc.handleCapAck(strings.ToLower(name), subCmd == "ACK"); err != nil { 225 return err 226 } 227 } 228 229 if uc.saslClient == nil { 230 uc.SendMessage(&irc.Message{ 231 Command: "CAP", 232 Params: []string{"END"}, 233 }) 234 } 235 default: 236 uc.logger.Printf("unhandled message: %v", msg) 237 } 238 case "AUTHENTICATE": 239 if uc.saslClient == nil { 240 return fmt.Errorf("received unexpected AUTHENTICATE message") 241 } 242 243 // TODO: if a challenge is 400 bytes long, buffer it 244 var challengeStr string 245 if err := parseMessageParams(msg, &challengeStr); err != nil { 246 uc.SendMessage(&irc.Message{ 247 Command: "AUTHENTICATE", 248 Params: []string{"*"}, 249 }) 250 return err 251 } 252 253 var challenge []byte 254 if challengeStr != "+" { 255 var err error 256 challenge, err = base64.StdEncoding.DecodeString(challengeStr) 257 if err != nil { 258 uc.SendMessage(&irc.Message{ 259 Command: "AUTHENTICATE", 260 Params: []string{"*"}, 261 }) 262 return err 263 } 264 } 265 266 var resp []byte 267 var err error 268 if !uc.saslStarted { 269 _, resp, err = uc.saslClient.Start() 270 uc.saslStarted = true 271 } else { 272 resp, err = uc.saslClient.Next(challenge) 273 } 274 if err != nil { 275 uc.SendMessage(&irc.Message{ 276 Command: "AUTHENTICATE", 277 Params: []string{"*"}, 278 }) 279 return err 280 } 281 282 // TODO: send response in multiple chunks if >= 400 bytes 283 var respStr = "+" 284 if resp != nil { 285 respStr = base64.StdEncoding.EncodeToString(resp) 286 } 287 288 uc.SendMessage(&irc.Message{ 289 Command: "AUTHENTICATE", 290 Params: []string{respStr}, 291 }) 292 case rpl_loggedin: 293 var account string 294 if err := parseMessageParams(msg, nil, nil, &account); err != nil { 295 return err 296 } 297 uc.logger.Printf("logged in with account %q", account) 298 case rpl_loggedout: 299 uc.logger.Printf("logged out") 300 case err_nicklocked, rpl_saslsuccess, err_saslfail, err_sasltoolong, err_saslaborted: 301 var info string 302 if err := parseMessageParams(msg, nil, &info); err != nil { 303 return err 304 } 305 switch msg.Command { 306 case err_nicklocked: 307 uc.logger.Printf("invalid nick used with SASL authentication: %v", info) 308 case err_saslfail: 309 uc.logger.Printf("SASL authentication failed: %v", info) 310 case err_sasltoolong: 311 uc.logger.Printf("SASL message too long: %v", info) 312 } 313 314 uc.saslClient = nil 315 uc.saslStarted = false 316 317 uc.SendMessage(&irc.Message{ 318 Command: "CAP", 319 Params: []string{"END"}, 320 }) 194 321 case irc.RPL_WELCOME: 195 322 uc.registered = true … … 440 567 // Ignore 441 568 default: 442 uc.logger.Printf("unhandled upstreammessage: %v", msg)569 uc.logger.Printf("unhandled message: %v", msg) 443 570 } 444 571 return nil … … 478 605 } 479 606 607 func (uc *upstreamConn) requestSASL() bool { 608 if uc.network.SASL.Mechanism == "" { 609 return false 610 } 611 612 v, ok := uc.caps["sasl"] 613 if !ok { 614 return false 615 } 616 if v != "" { 617 mechanisms := strings.Split(v, ",") 618 found := false 619 for _, mech := range mechanisms { 620 if strings.EqualFold(mech, uc.network.SASL.Mechanism) { 621 found = true 622 break 623 } 624 } 625 if !found { 626 return false 627 } 628 } 629 630 return true 631 } 632 633 func (uc *upstreamConn) handleCapAck(name string, ok bool) error { 634 auth := &uc.network.SASL 635 switch name { 636 case "sasl": 637 if !ok { 638 uc.logger.Printf("server refused to acknowledge the SASL capability") 639 return nil 640 } 641 642 switch auth.Mechanism { 643 case "PLAIN": 644 uc.logger.Printf("starting SASL PLAIN authentication with username %q", auth.Plain.Username) 645 uc.saslClient = sasl.NewPlainClient("", auth.Plain.Username, auth.Plain.Password) 646 default: 647 return fmt.Errorf("unsupported SASL mechanism %q", name) 648 } 649 650 uc.SendMessage(&irc.Message{ 651 Command: "AUTHENTICATE", 652 Params: []string{auth.Mechanism}, 653 }) 654 } 655 return nil 656 } 657 480 658 func (uc *upstreamConn) readMessages() error { 481 659 for {
Note:
See TracChangeset
for help on using the changeset viewer.