2021-04-22 17:08:24 -06:00
|
|
|
package chats
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"log"
|
|
|
|
"net/http"
|
2024-06-18 14:46:32 -06:00
|
|
|
"net/smtp"
|
2021-04-22 17:08:24 -06:00
|
|
|
"strings"
|
|
|
|
|
|
|
|
"golang.org/x/crypto/bcrypt"
|
|
|
|
"suah.dev/mcchunkie/plugins"
|
|
|
|
)
|
|
|
|
|
|
|
|
func smsCanSend(number string, numbers []string) bool {
|
|
|
|
for _, s := range numbers {
|
|
|
|
if number == s {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
// SMSListen listens for our incoming sms
|
|
|
|
func SMSListen(store ChatStore, plugins *plugins.Plugins) {
|
2024-06-18 14:46:32 -06:00
|
|
|
var (
|
|
|
|
smsPort, _ = store.Get("sms_listen")
|
|
|
|
smsAllowed, _ = store.Get("sms_users")
|
|
|
|
smtpUser, _ = store.Get("smtp_user")
|
|
|
|
smtpReceiver, _ = store.Get("smtp_receiver")
|
|
|
|
smsUsers = strings.Split(smsAllowed, ",")
|
|
|
|
)
|
2021-04-22 17:08:24 -06:00
|
|
|
|
|
|
|
if smsPort != "" {
|
|
|
|
var htpass, _ = store.Get("sms_htpass")
|
|
|
|
|
|
|
|
log.Printf("SMS: listening on %q\n", smsPort)
|
|
|
|
|
|
|
|
http.HandleFunc("/_sms", func(w http.ResponseWriter, r *http.Request) {
|
2024-06-18 15:12:43 -06:00
|
|
|
var msg, from, id string
|
2024-06-18 14:46:32 -06:00
|
|
|
emailSend := false
|
2021-04-22 17:08:24 -06:00
|
|
|
user, pass, ok := r.BasicAuth()
|
2024-05-28 15:35:05 -06:00
|
|
|
if !ok {
|
|
|
|
log.Println("SMS: basic auth no ok")
|
|
|
|
w.Header().Set("WWW-Authenticate", `Basic realm="sms notify"`)
|
|
|
|
http.Error(w, "auth error", http.StatusUnauthorized)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if user != "sms" {
|
|
|
|
log.Printf("SMS: failed auth for invalid user: %q, %q\n", user, pass)
|
|
|
|
w.Header().Set("WWW-Authenticate", `Basic realm="sms notify"`)
|
|
|
|
http.Error(w, "Unauthorized", http.StatusUnauthorized)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2021-04-22 17:08:24 -06:00
|
|
|
err := bcrypt.CompareHashAndPassword([]byte(htpass), []byte(pass))
|
2024-05-28 15:35:05 -06:00
|
|
|
if err != nil {
|
2021-04-22 17:08:24 -06:00
|
|
|
log.Printf("SMS: failed auth %q %q\n", user, pass)
|
|
|
|
w.Header().Set("WWW-Authenticate", `Basic realm="sms notify"`)
|
|
|
|
http.Error(w, "Unauthorized", http.StatusUnauthorized)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
switch r.Method {
|
|
|
|
case http.MethodPost:
|
2024-06-17 19:27:38 -06:00
|
|
|
err = r.ParseForm()
|
|
|
|
if err != nil {
|
|
|
|
http.Error(w, "invalid request", http.StatusBadRequest)
|
|
|
|
return
|
|
|
|
}
|
2021-04-22 17:08:24 -06:00
|
|
|
msg = r.Form.Get("Body")
|
|
|
|
from = r.Form.Get("From")
|
2024-06-17 19:27:38 -06:00
|
|
|
case http.MethodGet:
|
2024-06-18 14:46:32 -06:00
|
|
|
// to={TO}&from={FROM}&message={MESSAGE}&id={ID}&date={TIMESTAMP}
|
|
|
|
id = r.URL.Query().Get("id")
|
2024-06-17 19:27:38 -06:00
|
|
|
msg = r.URL.Query().Get("message")
|
|
|
|
from = r.URL.Query().Get("from")
|
2024-06-18 14:46:32 -06:00
|
|
|
|
|
|
|
emailSend = true
|
2021-04-22 17:08:24 -06:00
|
|
|
default:
|
|
|
|
http.Error(
|
|
|
|
w,
|
|
|
|
fmt.Sprintf("method %q not implemented", r.Method),
|
|
|
|
http.StatusMethodNotAllowed,
|
|
|
|
)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if smsCanSend(from, smsUsers) {
|
|
|
|
msg = strings.TrimSuffix(msg, "\n")
|
|
|
|
|
|
|
|
if msg == "" {
|
|
|
|
fmt.Fprintf(w, "empty message")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, p := range *plugins {
|
|
|
|
if p.Match(from, msg) {
|
|
|
|
log.Printf("%s: responding to '%s'", p.Name(), from)
|
|
|
|
p.SetStore(store)
|
|
|
|
|
|
|
|
resp := p.Process(from, msg)
|
2024-06-18 14:46:32 -06:00
|
|
|
|
|
|
|
if emailSend {
|
|
|
|
sc, err := smtp.Dial("localhost:25")
|
|
|
|
if err != nil {
|
|
|
|
log.Printf("SMS: smtp dial failed: %q\n", err)
|
|
|
|
http.Error(w, "internal server error", http.StatusInternalServerError)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := sc.Mail(smtpUser); err != nil {
|
|
|
|
log.Printf("SMS: smtp Mail failed: %q\n", err)
|
|
|
|
http.Error(w, "internal server error", http.StatusInternalServerError)
|
|
|
|
return
|
|
|
|
|
|
|
|
}
|
|
|
|
if err := sc.Rcpt(smtpReceiver); err != nil {
|
|
|
|
log.Printf("SMS: smtp Rcpt failed: %q\n", err)
|
|
|
|
http.Error(w, "internal server error", http.StatusInternalServerError)
|
|
|
|
return
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
wc, err := sc.Data()
|
|
|
|
if err != nil {
|
|
|
|
log.Printf("SMS: smtp Data failed: %q\n", err)
|
|
|
|
http.Error(w, "internal server error", http.StatusInternalServerError)
|
|
|
|
return
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
fmt.Fprintf(wc, fmt.Sprintf("To: %s\r\n", smtpReceiver))
|
|
|
|
fmt.Fprintf(wc, fmt.Sprintf("From: %s\r\n", smtpUser))
|
|
|
|
fmt.Fprintf(wc, fmt.Sprintf("Subject: Message received from number %s to number %s [%s]\r\n", from, from, id))
|
|
|
|
fmt.Fprintf(wc, resp)
|
|
|
|
|
2024-06-18 15:25:15 -06:00
|
|
|
err = wc.Close()
|
|
|
|
if err != nil {
|
|
|
|
log.Printf("SMS: smtp Close failed: %q\n", err)
|
|
|
|
http.Error(w, "internal server error", http.StatusInternalServerError)
|
|
|
|
return
|
|
|
|
}
|
2024-06-18 14:46:32 -06:00
|
|
|
|
|
|
|
err = sc.Quit()
|
|
|
|
if err != nil {
|
|
|
|
log.Printf("SMS: smtp Quit failed: %q\n", err)
|
|
|
|
http.Error(w, "internal server error", http.StatusInternalServerError)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
fmt.Fprint(w, resp)
|
|
|
|
}
|
2021-04-22 17:08:24 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
log.Printf("number not allowed (%q)", from)
|
|
|
|
http.Error(
|
|
|
|
w,
|
|
|
|
fmt.Sprintf("number not allowed (%q)", from),
|
|
|
|
http.StatusMethodNotAllowed,
|
|
|
|
)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
})
|
|
|
|
log.Fatal(http.ListenAndServe(smsPort, nil))
|
|
|
|
}
|
|
|
|
}
|