2025-01-03 04:47:07 -05:00
|
|
|
|
package chat
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"encoding/json"
|
2025-01-05 18:16:26 -05:00
|
|
|
|
"fmt"
|
2025-01-03 04:47:07 -05:00
|
|
|
|
"io"
|
|
|
|
|
"log"
|
|
|
|
|
"net/http"
|
|
|
|
|
"strings"
|
|
|
|
|
"time"
|
|
|
|
|
|
2025-01-05 18:16:26 -05:00
|
|
|
|
"github.com/golang-jwt/jwt/v5"
|
|
|
|
|
|
2025-01-03 04:47:07 -05:00
|
|
|
|
"git.simponic.xyz/simponic/phoneof/adapters/messaging"
|
|
|
|
|
"git.simponic.xyz/simponic/phoneof/api/types"
|
|
|
|
|
"git.simponic.xyz/simponic/phoneof/database"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
func ValidateFren(context *types.RequestContext, req *http.Request, resp http.ResponseWriter) types.ContinuationChain {
|
|
|
|
|
return func(success types.Continuation, failure types.Continuation) types.ContinuationChain {
|
|
|
|
|
fren_id := req.FormValue("fren_id")
|
|
|
|
|
fren, err := database.FindFren(context.DBConn, fren_id)
|
|
|
|
|
if err != nil || fren == nil {
|
|
|
|
|
log.Printf("err fetching friend %s %s", fren, err)
|
|
|
|
|
resp.WriteHeader(http.StatusUnauthorized)
|
|
|
|
|
return failure(context, req, resp)
|
|
|
|
|
}
|
|
|
|
|
context.User = fren
|
|
|
|
|
(*context.TemplateData)["User"] = fren
|
|
|
|
|
return success(context, req, resp)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func FetchMessagesContinuation(context *types.RequestContext, req *http.Request, resp http.ResponseWriter) types.ContinuationChain {
|
|
|
|
|
return func(success types.Continuation, failure types.Continuation) types.ContinuationChain {
|
|
|
|
|
before := time.Now().UTC()
|
|
|
|
|
var err error
|
|
|
|
|
if req.FormValue("before") != "" {
|
|
|
|
|
before, err = time.Parse(time.RFC3339, req.FormValue("before"))
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Printf("bad time: %s", err)
|
|
|
|
|
resp.WriteHeader(http.StatusBadRequest)
|
|
|
|
|
return failure(context, req, resp)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
query := database.ListMessageQuery{
|
|
|
|
|
FrenId: context.User.Id,
|
|
|
|
|
Before: before,
|
|
|
|
|
Limit: 25,
|
|
|
|
|
}
|
|
|
|
|
messages, err := database.ListMessages(context.DBConn, query)
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Printf("err listing messages %v %s", query, err)
|
|
|
|
|
resp.WriteHeader(http.StatusInternalServerError)
|
|
|
|
|
return failure(context, req, resp)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
(*context.TemplateData)["Messages"] = messages
|
|
|
|
|
return success(context, req, resp)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-05 18:16:26 -05:00
|
|
|
|
func SendMessageContinuation(messagingPipeline messaging.Continuation) func(context *types.RequestContext, req *http.Request, resp http.ResponseWriter) types.ContinuationChain {
|
2025-01-03 04:47:07 -05:00
|
|
|
|
return func(context *types.RequestContext, req *http.Request, resp http.ResponseWriter) types.ContinuationChain {
|
|
|
|
|
return func(success types.Continuation, failure types.Continuation) types.ContinuationChain {
|
|
|
|
|
rawMessage := req.FormValue("message")
|
|
|
|
|
now := time.Now().UTC()
|
2025-01-05 18:16:26 -05:00
|
|
|
|
|
|
|
|
|
persist := messaging.PersistMessageContinuation(context.DBConn, context.User.Id, context.Id, now, true)
|
|
|
|
|
var err error
|
|
|
|
|
messaging.LogContinuation(messaging.Message{
|
|
|
|
|
FrenName: context.User.Name,
|
|
|
|
|
Message: rawMessage,
|
|
|
|
|
})(messagingPipeline, messaging.FailurePassingContinuation)(persist, messaging.FailurePassingContinuation)(messaging.IdContinuation, func(message messaging.Message) messaging.ContinuationChain {
|
|
|
|
|
err = fmt.Errorf("err sending message from: %s %s", context.User, rawMessage)
|
|
|
|
|
return messaging.FailurePassingContinuation(message)
|
|
|
|
|
})
|
|
|
|
|
|
2025-01-03 04:47:07 -05:00
|
|
|
|
if err != nil {
|
|
|
|
|
// yeah this might be a 400 or whatever, i’ll fix it later
|
|
|
|
|
resp.WriteHeader(http.StatusInternalServerError)
|
|
|
|
|
return failure(context, req, resp)
|
|
|
|
|
}
|
|
|
|
|
return success(context, req, resp)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type Timestamp struct {
|
|
|
|
|
time.Time
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (p *Timestamp) UnmarshalJSON(bytes []byte) error {
|
|
|
|
|
var raw string
|
|
|
|
|
err := json.Unmarshal(bytes, &raw)
|
|
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Printf("error decoding timestamp: %s\n", err)
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
p.Time, err = time.Parse(time.RFC3339, raw)
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Printf("error decoding timestamp: %s\n", err)
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type HttpSmsEventData struct {
|
|
|
|
|
Contact string `json:"contact"`
|
|
|
|
|
Content string `json:"content"`
|
|
|
|
|
Owner string `json:"owner"`
|
|
|
|
|
Timestamp time.Time `json:"timestamp"`
|
|
|
|
|
}
|
|
|
|
|
type HttpSmsEvent struct {
|
|
|
|
|
Data HttpSmsEventData `json:"data"`
|
|
|
|
|
Type string `json:"type"`
|
|
|
|
|
Id string `json:"id"`
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-05 18:16:26 -05:00
|
|
|
|
func ChatEventProcessorContinuation(allowedFrom string, signingKey string, messagingPipeline messaging.Continuation) func(context *types.RequestContext, req *http.Request, resp http.ResponseWriter) types.ContinuationChain {
|
2025-01-03 04:47:07 -05:00
|
|
|
|
return func(context *types.RequestContext, req *http.Request, resp http.ResponseWriter) types.ContinuationChain {
|
|
|
|
|
return func(success types.Continuation, failure types.Continuation) types.ContinuationChain {
|
|
|
|
|
// check signing
|
|
|
|
|
joken := strings.Split(req.Header.Get("Authorization"), "Bearer ")
|
|
|
|
|
_, err := jwt.Parse(joken[1], func(token *jwt.Token) (interface{}, error) {
|
|
|
|
|
return []byte(signingKey), nil
|
|
|
|
|
})
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Printf("invalid jwt %s", err)
|
|
|
|
|
resp.WriteHeader(http.StatusBadRequest)
|
|
|
|
|
return failure(context, req, resp)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// decode the event
|
|
|
|
|
defer req.Body.Close()
|
|
|
|
|
body, err := io.ReadAll(req.Body)
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Printf("err reading body")
|
|
|
|
|
resp.WriteHeader(http.StatusInternalServerError)
|
|
|
|
|
return failure(context, req, resp)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var event HttpSmsEvent
|
|
|
|
|
err = json.Unmarshal(body, &event)
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Printf("err unmarshaling body")
|
|
|
|
|
resp.WriteHeader(http.StatusBadRequest)
|
|
|
|
|
return failure(context, req, resp)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// we only care about received messages
|
|
|
|
|
if event.Type != "message.phone.received" {
|
|
|
|
|
log.Printf("got non-receive event %s", event.Type)
|
|
|
|
|
return success(context, req, resp)
|
|
|
|
|
}
|
2025-01-05 18:16:26 -05:00
|
|
|
|
if event.Data.Contact != allowedFrom {
|
|
|
|
|
log.Printf("someone did something naughty %s", event.Data.Contact)
|
|
|
|
|
return success(context, req, resp)
|
|
|
|
|
}
|
2025-01-03 04:47:07 -05:00
|
|
|
|
|
2025-01-05 18:16:26 -05:00
|
|
|
|
message, err := messaging.Decode(event.Data.Content)
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Printf("err when decoding message %s", err)
|
2025-01-03 04:47:07 -05:00
|
|
|
|
resp.WriteHeader(http.StatusBadRequest)
|
|
|
|
|
return failure(context, req, resp)
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-05 18:16:26 -05:00
|
|
|
|
fren, err := database.FindFrenByName(context.DBConn, message.FrenName)
|
2025-01-03 04:47:07 -05:00
|
|
|
|
if err != nil {
|
2025-01-05 18:16:26 -05:00
|
|
|
|
log.Printf("err when getting fren %s %s", fren.Name, err)
|
2025-01-03 04:47:07 -05:00
|
|
|
|
resp.WriteHeader(http.StatusBadRequest)
|
|
|
|
|
return failure(context, req, resp)
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-05 18:16:26 -05:00
|
|
|
|
persist := messaging.PersistMessageContinuation(context.DBConn, fren.Id, context.Id, event.Data.Timestamp, false)
|
|
|
|
|
messaging.LogContinuation(*message)(messagingPipeline, messaging.FailurePassingContinuation)(persist, messaging.FailurePassingContinuation)(messaging.IdContinuation, func(message messaging.Message) messaging.ContinuationChain {
|
|
|
|
|
err = fmt.Errorf("err propagating stuff for message %s", message)
|
|
|
|
|
return messaging.FailurePassingContinuation(message)
|
2025-01-03 04:47:07 -05:00
|
|
|
|
})
|
|
|
|
|
if err != nil {
|
|
|
|
|
resp.WriteHeader(http.StatusInternalServerError)
|
|
|
|
|
return failure(context, req, resp)
|
|
|
|
|
}
|
|
|
|
|
return success(context, req, resp)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|