IR53C/peer/peer.go
2022-02-25 06:19:12 -08:00

178 lines
3.4 KiB
Go

package peer
import (
"crypto/rsa"
"fmt"
"strings"
"github.com/rs/zerolog/log"
"github.com/awnumar/memguard"
"git.tcp.direct/tcp.direct/IR5EC/chat"
"git.tcp.direct/tcp.direct/IR5EC/connection"
"git.tcp.direct/tcp.direct/IR5EC/crypto"
)
type Peer struct {
ID string
Name string
Conn *connection.Session
CleartextInbox []*chat.Msg
decryptionKey *memguard.Enclave
PublicKey *rsa.PublicKey
trusted bool
handshaking bool
}
func (p *Peer) DecryptionKey() []byte {
o, err := p.decryptionKey.Open()
if err != nil {
log.Warn().Str("caller", p.Name).Msg(err.Error())
return nil
}
o.RLock()
defer o.RUnlock()
return o.Bytes()
}
func (p *Peer) RSAEncrypt(buf string) string {
return crypto.RSAEncrypt(p.PublicKey, buf)
}
func (p *Peer) decryptPrivMSG(m *chat.Msg) {
msgIndex := m.Offset + 2
msg := strings.Join(m.Components[msgIndex:], " ")
trimmedComponents := m.Components[:msgIndex]
plaintext := true
// Extract Message
msg = msg[1 : len(msg)-2]
// Check if RSA Message
if strings.HasPrefix(msg, "RSA ") {
msg = p.Conn.rsaDecrypt(msg)
plaintext = false
}
// Check for non encrypted control command
if strings.HasPrefix(msg, "CTRL ") {
p.recieveControlCommand(msg)
return
}
// Determine if we can decrypt or if we have to request the decryption key
if !p.canDecrypt() {
p.beginHandshake()
p.CleartextInbox = append(p.CleartextInbox, m)
return
}
// Decrypt Message
decMsg := p.aesDecryptString(msg)
if decMsg != msg {
plaintext = false
}
msg = decMsg
// Check for encrypted control command
if strings.HasPrefix(msg, "CTRL ") {
p.recieveControlCommand(msg)
return
}
// Properly Name Sender
m.senderComponents[0] = p.Name
sender := strings.Join(m.senderComponents, "!~")
trimmedComponents[0] = ":" + sender
// Add cleartext warning
if plaintext {
msg += " [SENT AS CLEARTEXT]"
}
// Rebuild Message string
result := strings.Join(trimmedComponents, " ") + " :" + msg + "\n"
p.Conn.writeClient([]byte(result))
}
func (p *Peer) canDecrypt() bool {
return p.decryptionKey != nil
}
//
// Handshakes
//
func (p *Peer) beginHandshake() {
p.sendControlCommand("HANDSHAKE", p.Conn.publicKeyBase64())
p.handshaking = true
}
//
// Control Commands
//
// Basics
func (p *Peer) sendControlCommand(command string, payload string) {
msg := "CTRL " + command
if payload != "" {
msg += " " + payload
}
p.sendPrivateMessage(msg)
}
func (p *Peer) sendControlCommandRSA(command string, payload string) {
msg := "CTRL " + command
if payload != "" {
msg += " " + payload
}
msg = p.rsaEncrypt(msg)
p.sendPrivateMessage(msg)
}
func (p *Peer) sendPrivateMessage(message string) {
msg := "PRIVMSG " + p.ID + " :" + message
p.Conn.writeServer([]byte(msg + "\n"))
}
//
// After the handshake, decrypt the messages that were sent previously
//
func (p *Peer) decryptUnencryptedMessages() {
if p.canDecrypt() {
for _, message := range p.CleartextInbox {
message.decrypt()
}
p.CleartextInbox = []*message{}
}
}
func (p *Peer) displayName() string {
fingerprintHex := p.publicKeyFingerprintSha1()
fingerprintChunks := make([]string, len(fingerprintHex)/2)
for i := range fingerprintChunks {
fingerprintChunks[i] = string(fingerprintHex[(i*2)]) + string(fingerprintHex[(i*2)+1])
}
fingerprint := strings.Join(fingerprintChunks, ":")
fmt.Println(fingerprint, fingerprintHex)
return p.Name + " (" + fingerprint + ")"
}