func (s *Session) processPresence(stanza *xmpp.ClientPresence) { gone := false switch stanza.Type { case "subscribe": // This is a subscription request jid := xmpp.RemoveResourceFromJid(stanza.From) info(s.term, jid+" wishes to see when you're online. Use '/confirm "+jid+"' to confirm (or likewise with /deny to decline)") s.pendingSubscribes[jid] = stanza.Id s.input.AddUser(jid) return case "unavailable": gone = true case "": break default: return } from := xmpp.RemoveResourceFromJid(stanza.From) if gone { if _, ok := s.knownStates[from]; !ok { // They've gone, but we never knew they were online. return } delete(s.knownStates, from) } else { if _, ok := s.knownStates[from]; !ok && isAwayStatus(stanza.Show) { // Skip people who are initially away. return } if lastState, ok := s.knownStates[from]; ok && lastState == stanza.Show { // No change. Ignore. return } s.knownStates[from] = stanza.Show } if !s.config.HideStatusUpdates { var line []byte line = append(line, s.term.Escape.Magenta...) line = append(line, []byte(from)...) line = append(line, ':') line = append(line, s.term.Escape.Reset...) line = append(line, ' ') if gone { line = append(line, []byte("offline")...) } else if len(stanza.Show) > 0 { line = append(line, []byte(stanza.Show)...) } else { line = append(line, []byte("online")...) } line = append(line, ' ') line = append(line, []byte(stanza.Status)...) line = append(line, '\n') s.term.Write(line) } }
func (s *Session) processClientMessage(stanza *xmpp.ClientMessage) { from := xmpp.RemoveResourceFromJid(stanza.From) conversation, ok := s.conversations[from] if !ok { conversation = new(otr.Conversation) conversation.PrivateKey = s.privateKey s.conversations[from] = conversation } out, encrypted, change, toSend, err := conversation.Process([]byte(stanza.Body)) if err != nil { alert(s.term, "While processing message from "+from+": "+err.Error()) } for _, msg := range toSend { s.conn.Send(stanza.From, string(msg)) } switch change { case otr.NewKeys: fpr := conversation.TheirPublicKey.Fingerprint() info(s.term, fmt.Sprintf("New OTR session with %s established", from)) info(s.term, fmt.Sprintf(" their fingerprint: %x", fpr)) info(s.term, fmt.Sprintf(" session id: %x", conversation.SSID)) knownUserId := s.config.UserIdForFingerprint(fpr) if len(knownUserId) == 0 { alert(s.term, "Fingerprint is unknown. You should use /auth or /authqa to verify their identity") } else { if knownUserId == from { info(s.term, "Fingerprint is verified") } else { alert(s.term, fmt.Sprintf("Fingerprint is known, but for %s", knownUserId)) } } case otr.ConversationEnded: info(s.term, fmt.Sprintf("%s has ended the secure conversation. You should do likewise with /endotr", from)) case otr.SMPSecretNeeded: info(s.term, fmt.Sprintf("%s is attempting to authenticate. Please supply mutual shared secret with /smp", from)) if question := conversation.SMPQuestion(); len(question) > 0 { info(s.term, fmt.Sprintf("%s asks: %s", from, question)) } case otr.SMPComplete: info(s.term, fmt.Sprintf("Authentication with %s successful", from)) fpr := conversation.TheirPublicKey.Fingerprint() if len(s.config.UserIdForFingerprint(fpr)) == 0 { s.config.KnownFingerprints = append(s.config.KnownFingerprints, KnownFingerprint{fingerprint: fpr, UserId: from}) } s.config.Save() } if len(out) == 0 { return } var line []byte if encrypted { line = append(line, s.term.Escape.Green...) } else { line = append(line, s.term.Escape.Red...) } if s.lastMessageFrom != from { line = append(line, []byte(from)...) s.lastMessageFrom = from } line = append(line, ':') line = append(line, s.term.Escape.Reset...) line = append(line, ' ') line = append(line, out...) line = append(line, '\n') s.term.Write(line) s.maybeNotify() }
func (s *Session) processClientMessage(stanza *xmpp.ClientMessage) { from := xmpp.RemoveResourceFromJid(stanza.From) if stanza.Type == "error" { alert(s.term, "Error reported from "+from+": "+stanza.Body) return } conversation, ok := s.conversations[from] if !ok { conversation = new(otr.Conversation) conversation.PrivateKey = s.privateKey s.conversations[from] = conversation } out, encrypted, change, toSend, err := conversation.Receive([]byte(stanza.Body)) if err != nil { alert(s.term, "While processing message from "+from+": "+err.Error()) s.conn.Send(stanza.From, otr.ErrorPrefix+"Error processing message") } for _, msg := range toSend { s.conn.Send(stanza.From, string(msg)) } switch change { case otr.NewKeys: info(s.term, fmt.Sprintf("New OTR session with %s established at %s", from, time.Now().Format(time.RubyDate))) printConversationInfo(*s, from, conversation) case otr.ConversationEnded: // This is probably unsafe without a policy that _forces_ crypto to // _everyone_ by default and refuses plaintext. Users might not notice // their buddy has ended a session, which they have also ended, and they // might send a plain text message. So we should ensure they _want_ this // feature and have set it as an explicit preference. if s.config.OTRAutoTearDown { if s.conversations[from] == nil { alert(s.term, fmt.Sprintf("No secure session established; unable to automatically tear down OTR conversation with %s.", from)) break } else { info(s.term, fmt.Sprintf("%s has ended the secure conversation.", from)) msgs := conversation.End() for _, msg := range msgs { s.conn.Send(from, string(msg)) } info(s.term, fmt.Sprintf("Secure session with %s has been automatically ended. Messages will be sent in the clear until another OTR session is established.", from)) } } else { info(s.term, fmt.Sprintf("%s has ended the secure conversation. You should do likewise with /otr-end %s", from, from)) } case otr.SMPSecretNeeded: info(s.term, fmt.Sprintf("%s is attempting to authenticate. Please supply mutual shared secret with /otr-auth user secret", from)) if question := conversation.SMPQuestion(); len(question) > 0 { info(s.term, fmt.Sprintf("%s asks: %s", from, question)) } case otr.SMPComplete: info(s.term, fmt.Sprintf("Authentication with %s successful", from)) fpr := conversation.TheirPublicKey.Fingerprint() if len(s.config.UserIdForFingerprint(fpr)) == 0 { s.config.KnownFingerprints = append(s.config.KnownFingerprints, KnownFingerprint{fingerprint: fpr, UserId: from}) } s.config.Save() case otr.SMPFailed: alert(s.term, fmt.Sprintf("Authentication with %s failed", from)) } if len(out) == 0 { return } detectedOTRVersion := 0 // We don't need to alert about tags encoded inside of messages that are // already encrypted with OTR whitespaceTagLength := len(OTRWhitespaceTagStart) + len(OTRWhiteSpaceTagV1) if !encrypted && len(out) >= whitespaceTagLength { whitespaceTag := out[len(out)-whitespaceTagLength:] if bytes.Equal(whitespaceTag[:len(OTRWhitespaceTagStart)], OTRWhitespaceTagStart) { if bytes.HasSuffix(whitespaceTag, OTRWhiteSpaceTagV1) { info(s.term, fmt.Sprintf("%s appears to support OTRv1. You should encourage them to upgrade their OTR client!", from)) detectedOTRVersion = 1 } if bytes.HasSuffix(whitespaceTag, OTRWhiteSpaceTagV2) { detectedOTRVersion = 2 } if bytes.HasSuffix(whitespaceTag, OTRWhiteSpaceTagV3) { detectedOTRVersion = 3 } } } if s.config.OTRAutoStartSession && detectedOTRVersion >= 2 { info(s.term, fmt.Sprintf("%s appears to support OTRv%d. We are attempting to start an OTR session with them.", from, detectedOTRVersion)) s.conn.Send(from, otr.QueryMessage) } else if s.config.OTRAutoStartSession && detectedOTRVersion == 1 { info(s.term, fmt.Sprintf("%s appears to support OTRv%d. You should encourage them to upgrade their OTR client!", from, detectedOTRVersion)) } var line []byte if encrypted { line = append(line, s.term.Escape.Green...) } else { line = append(line, s.term.Escape.Red...) } var timestamp string var messageTime time.Time if stanza.Delay != nil && len(stanza.Delay.Stamp) > 0 { // An XEP-0203 Delayed Delivery <delay/> element exists for // this message, meaning that someone sent it while we were // offline. Let's show the timestamp for when the message was // sent, rather than time.Now(). messageTime, err = time.Parse(time.RFC3339, stanza.Delay.Stamp) if err != nil { alert(s.term, "Can not parse Delayed Delivery timestamp, using quoted string instead.") timestamp = fmt.Sprintf("%q", stanza.Delay.Stamp) } } else { messageTime = time.Now() } if len(timestamp) == 0 { timestamp = messageTime.Format(time.RubyDate) } t := fmt.Sprintf("(%s) %s: ", timestamp, from) line = append(line, []byte(t)...) line = append(line, s.term.Escape.Reset...) line = appendTerminalEscaped(line, stripHTML(out)) line = append(line, '\n') if s.config.Bell { line = append(line, '\a') } s.term.Write(line) s.maybeNotify() }
func Echo(ws *websocket.Conn) { fmt.Println("socket open") var recMes message err := websocket.JSON.Receive(ws, &recMes) if err != nil { fmt.Println("Can't receive message") } if recMes.Type != "login" { fmt.Println("not login message") return } userName := strings.Split(recMes.Data["UserName"], "@") if len(userName) < 2 { userName = []string{userName[0], ""} } xmppConfig := xmpp.Config{nil, nil, nil, nil, false, false, false, []byte("")} talk, err := xmpp.Dial(recMes.Data["Server"], userName[0], userName[1], recMes.Data["Password"], &xmppConfig) if err != nil { fmt.Println("login error") return } senMes := message{"login", nil} if err := websocket.JSON.Send(ws, senMes); err != nil { fmt.Println("Can't send") return } fmt.Println("Ready") rosterReply, _, err := talk.RequestRoster() if err != nil { fmt.Println("Can't roster") } talk.SignalPresence("") ses := session{ talk: talk, ws: ws, } stanzaChan := make(chan xmpp.Stanza) go ses.receiveMessage(stanzaChan) webSocketChan := make(chan string) go ses.receiveWebSocket(webSocketChan) for { select { case rosterStanza, ok := <-rosterReply: var roster []xmpp.RosterEntry if !ok { fmt.Println("fail to read roaster") return } if roster, err = xmpp.ParseRoster(rosterStanza); err != nil { fmt.Println("fail to parse roaster") return } if err := websocket.JSON.Send(ws, rosterMessage{"roster", roster}); err != nil { fmt.Println("Can't send") return } fmt.Println("Roster information sent to the client") case rawStanza, ok := <-stanzaChan: if !ok { fmt.Println("stanzaChan receive failed") return } switch stanza := rawStanza.Value.(type) { case *xmpp.ClientMessage: fmt.Println("Message comming") if stanza.Body == "" { break } chatMes := message{"chat", map[string]string{"Remote": xmpp.RemoveResourceFromJid(stanza.From), "Text": stanza.Body}} if err := websocket.JSON.Send(ws, chatMes); err != nil { fmt.Println("Can't send") break } case *xmpp.ClientPresence: fmt.Println("ClientPresence comming") fmt.Println(stanza.From, stanza.Type) var status string if len(stanza.Show) > 0 { status = stanza.Show } else { status = "available" } preMes := message{"presence", map[string]string{"Remote": xmpp.RemoveResourceFromJid(stanza.From), "Mode": status}} if err := websocket.JSON.Send(ws, preMes); err != nil { fmt.Println("Can't send") return } } case receivedMessage, ok := <-webSocketChan: if !ok { fmt.Println("webSocketChan receive failed") return } var sendMes message if err = json.Unmarshal([]byte(receivedMessage), &sendMes); err != nil { fmt.Println("Can't receive") } else { if err = talk.Send(sendMes.Data["Remote"], sendMes.Data["Text"]); err != nil { fmt.Println("failed to send") } fmt.Println("Message sent" + sendMes.Data["Remote"] + sendMes.Data["Text"]) } } } fmt.Println("function ends") }