Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 72 additions & 0 deletions backend/cmd/cmd_email.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package cmd

import (
"fmt"
"io"
"slices"

"github.com/RoundRobinHood/cogniflight-cloud/backend/email"
"github.com/RoundRobinHood/cogniflight-cloud/backend/types"
"github.com/RoundRobinHood/cogniflight-cloud/backend/util"
"github.com/RoundRobinHood/sh"
)

type CmdEmail struct {
EmailConfig email.EmailConfig
}

func (c CmdEmail) Identifier() string {
return "email"
}

func (c CmdEmail) Run(ctx sh.CommandContext) int {
tags := util.GetTags(ctx.Ctx)
if !slices.Contains(tags, "sysadmin") && !slices.Contains(tags, "atc") {
fmt.Fprint(ctx.Stderr, "access denied")
return 1
}

if len(ctx.Args) == 1 {
fmt.Fprint(ctx.Stderr, "usage: email [-s <subject>] [-c <content-type>] <target-address>")
return 1
}

opts, email, err := util.ParseArgs([]types.OptionDescriptor{
{
Identifier: "subject",
Aliases: []string{"s", "subject"},
Default: "",
},
{
Identifier: "content_type",
Aliases: []string{"c", "content-type"},
Default: "text/plain",
},
}, ctx.Args[1:])

if err != nil {
fmt.Fprint(ctx.Stderr, err)
return 1
}

if len(email) != 1 {
fmt.Fprint(ctx.Stderr, "usage: email [-s <subject>] [-c <content-type>] <target-address>")
return 1
}

subject := opts["subject"].(string)
contentType := opts["content_type"].(string)

email_bytes, err := io.ReadAll(ctx.Stdin)
if err != nil {
fmt.Fprint(ctx.Stderr, "error getting input: ", err)
return 1
}

if err := c.EmailConfig.SendEmail(email[0], subject, contentType, string(email_bytes)); err != nil {
fmt.Fprint(ctx.Stderr, err)
return 1
}

return 0
}
76 changes: 76 additions & 0 deletions backend/cmd/cmd_send-text.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package cmd

import (
"fmt"
"io"
"slices"

"github.com/RoundRobinHood/cogniflight-cloud/backend/types"
"github.com/RoundRobinHood/cogniflight-cloud/backend/uazapi"
"github.com/RoundRobinHood/cogniflight-cloud/backend/util"
"github.com/RoundRobinHood/sh"
)

type CmdSendText struct {
UazapiConfig uazapi.UazapiConfig
}

func (c *CmdSendText) Identifier() string {
return "send-text"
}

func (c *CmdSendText) Run(ctx sh.CommandContext) int {
tags := util.GetTags(ctx.Ctx)
if !slices.Contains(tags, "sysadmin") && !slices.Contains(tags, "atc") {
fmt.Fprint(ctx.Stderr, "access denied")
return 1
}

if len(ctx.Args) == 1 {
fmt.Fprint(ctx.Stderr, "usage: send-text [-p] <numbers...>")
return 1
}

opts, numbers, err := util.ParseArgs([]types.OptionDescriptor{
{
Identifier: "preview_links",
Aliases: []string{"p", "preview", "preview-links"},
Default: false,
},
}, ctx.Args[1:])
if err != nil {
fmt.Fprint(ctx.Stderr, err)
return 1
}

if len(numbers) == 0 {
fmt.Fprint(ctx.Stderr, "usage: send-text [-p] <numbers...>")
return 1
}

preview_links := opts["preview_links"].(bool)

message_bytes, err := io.ReadAll(ctx.Stdin)
if err != nil {
fmt.Fprint(ctx.Stderr, "failed to read input: ", err)
return 1
}

if len(message_bytes) == 0 {
fmt.Fprint(ctx.Stderr, "error: can't send an empty text message")
}

message_text := string(message_bytes)
for _, number := range numbers {
if err := c.UazapiConfig.SendTextMessage(uazapi.TxtMessage{
Number: number,
Text: message_text,
LinkPreview: preview_links,
}); err != nil {
fmt.Fprintf(ctx.Stderr, "failed to send message to %q: %v", number, err)
return 1
}
}

return 0
}
32 changes: 27 additions & 5 deletions backend/cmd/endpoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@ import (
"sync"

"github.com/RoundRobinHood/cogniflight-cloud/backend/chatbot"
"github.com/RoundRobinHood/cogniflight-cloud/backend/email"
"github.com/RoundRobinHood/cogniflight-cloud/backend/filesystem"
"github.com/RoundRobinHood/cogniflight-cloud/backend/influx"
"github.com/RoundRobinHood/cogniflight-cloud/backend/types"
"github.com/RoundRobinHood/cogniflight-cloud/backend/uazapi"
"github.com/RoundRobinHood/cogniflight-cloud/backend/util"
"github.com/gin-gonic/gin"
"github.com/gorilla/websocket"
Expand All @@ -24,7 +26,16 @@ var upgrader = websocket.Upgrader{
},
}

func CmdWebhook(filestore filesystem.Store, sessionStore *types.SessionStore, apiKey chatbot.APIKey, jsonConn *jsonrpc2.Conn, mqttEvents *util.EventHandler[types.MQTTMessage], flux_cfg *influx.InfluxDBConfig) gin.HandlerFunc {
func CmdWebhook(
filestore filesystem.Store,
sessionStore *types.SessionStore,
apiKey chatbot.APIKey,
jsonConn *jsonrpc2.Conn,
mqttEvents *util.EventHandler[types.MQTTMessage],
flux_cfg *influx.InfluxDBConfig,
uazapi_cfg uazapi.UazapiConfig,
email_cfg email.EmailConfig,
) gin.HandlerFunc {
return func(c *gin.Context) {
auth_get, ok := c.Get("auth")
if !ok {
Expand All @@ -35,10 +46,21 @@ func CmdWebhook(filestore filesystem.Store, sessionStore *types.SessionStore, ap
auth_status := auth_get.(types.AuthorizationStatus)
socketID := util.RandHex(20)
session := sessionStore.AttachSession(socketID, auth_status)
available_commands := InitCommands(filestore, filesystem.FSContext{
Store: filestore,
UserTags: auth_status.Tags,
}, session, sessionStore, apiKey, jsonConn, mqttEvents, flux_cfg)
available_commands := InitCommands(
filestore,
filesystem.FSContext{
Store: filestore,
UserTags: auth_status.Tags,
},
session,
sessionStore,
apiKey,
jsonConn,
mqttEvents,
flux_cfg,
uazapi_cfg,
email_cfg,
)

clients := map[string]types.ClientInfo{}
client_cancels := map[string]context.CancelFunc{}
Expand Down
18 changes: 17 additions & 1 deletion backend/cmd/init_commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,28 @@ package cmd

import (
"github.com/RoundRobinHood/cogniflight-cloud/backend/chatbot"
"github.com/RoundRobinHood/cogniflight-cloud/backend/email"
"github.com/RoundRobinHood/cogniflight-cloud/backend/filesystem"
"github.com/RoundRobinHood/cogniflight-cloud/backend/influx"
"github.com/RoundRobinHood/cogniflight-cloud/backend/types"
"github.com/RoundRobinHood/cogniflight-cloud/backend/uazapi"
"github.com/RoundRobinHood/cogniflight-cloud/backend/util"
"github.com/RoundRobinHood/sh"
"github.com/sourcegraph/jsonrpc2"
)

func InitCommands(filestore filesystem.Store, fsctx filesystem.FSContext, socketSession *types.SocketSession, sessionStore *types.SessionStore, apiKey chatbot.APIKey, jsonConn *jsonrpc2.Conn, mqttEvents *util.EventHandler[types.MQTTMessage], flux_cfg *influx.InfluxDBConfig) []sh.Command {
func InitCommands(
filestore filesystem.Store,
fsctx filesystem.FSContext,
socketSession *types.SocketSession,
sessionStore *types.SessionStore,
apiKey chatbot.APIKey,
jsonConn *jsonrpc2.Conn,
mqttEvents *util.EventHandler[types.MQTTMessage],
flux_cfg *influx.InfluxDBConfig,
uazapi_cfg uazapi.UazapiConfig,
email_cfg email.EmailConfig,
) []sh.Command {
commands := []sh.Command{
&CmdWhoami{FileStore: filestore, Session: socketSession},
CmdHelp{},
Expand Down Expand Up @@ -46,6 +59,9 @@ func InitCommands(filestore filesystem.Store, fsctx filesystem.FSContext, socket

CmdB64{},
CmdHex{},

&CmdSendText{UazapiConfig: uazapi_cfg},
CmdEmail{EmailConfig: email_cfg},
}

activate_cmd := &CmdActivate{
Expand Down
22 changes: 22 additions & 0 deletions backend/email/send_email.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package email

import "gopkg.in/gomail.v2"

type EmailConfig struct {
Username, Password, Host string
Port int
}

func (c EmailConfig) SendEmail(receiver, subject, contentType, content string) error {
m := gomail.NewMessage()
m.SetHeader("From", c.Username)
m.SetHeader("To", receiver)
if subject != "" {
m.SetHeader("Subject", subject)
}
m.SetBody(contentType, content)

d := gomail.NewDialer(c.Host, c.Port, c.Username, c.Password)

return d.DialAndSend(m)
}
2 changes: 2 additions & 0 deletions backend/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -50,5 +50,7 @@ require (
golang.org/x/sys v0.36.0 // indirect
golang.org/x/text v0.29.0 // indirect
google.golang.org/protobuf v1.36.6 // indirect
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
4 changes: 4 additions & 0 deletions backend/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -145,8 +145,12 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk=
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df h1:n7WqCuqOuCbNr617RXOY0AWRXxgwEyPp2z+p0+hgMuE=
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
Expand Down
63 changes: 58 additions & 5 deletions backend/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,11 @@ import (
"github.com/RoundRobinHood/cogniflight-cloud/backend/auth"
"github.com/RoundRobinHood/cogniflight-cloud/backend/chatbot"
"github.com/RoundRobinHood/cogniflight-cloud/backend/cmd"
"github.com/RoundRobinHood/cogniflight-cloud/backend/email"
"github.com/RoundRobinHood/cogniflight-cloud/backend/filesystem"
"github.com/RoundRobinHood/cogniflight-cloud/backend/influx"
"github.com/RoundRobinHood/cogniflight-cloud/backend/types"
"github.com/RoundRobinHood/cogniflight-cloud/backend/uazapi"
"github.com/RoundRobinHood/jlogging"
"github.com/gin-gonic/gin"
"github.com/sourcegraph/jsonrpc2"
Expand All @@ -41,6 +43,38 @@ func main() {
log.Fatal("Missing OpenAI key")
}

uazapi_url := os.Getenv("UAZAPI_URL")
if uazapi_url == "" {
log.Fatal("Missing UAZAPI URL")
}

uazapi_key := os.Getenv("UAZAPI_API_KEY")
if uazapi_key == "" {
log.Fatal("Missing UAZAPI API Key")
}

email_username := os.Getenv("EMAIL_USERNAME")
if email_username == "" {
log.Fatal("Missing email username")
}

email_password := os.Getenv("EMAIL_PASSWORD")
if email_password == "" {
log.Fatal("Missing email password")
}

email_host := os.Getenv("EMAIL_HOST")
if email_host == "" {
log.Fatal("Missing email host")
}

email_port := 465
if port_str := os.Getenv("EMAIL_PORT"); port_str != "" {
if _, err := fmt.Sscan(port_str, &email_port); err != nil {
log.Fatal("invalid email port: ", err)
}
}

database := client.Database("cogniflight")
bucket, err := gridfs.NewBucket(database)
if err != nil {
Expand Down Expand Up @@ -121,11 +155,30 @@ func main() {
r.GET("/signup/check-username/:username", auth.SignupCheckUsername(fileStore))
r.POST("/signup", auth.Signup(fileStore))
r.POST("/login", auth.Login(fileStore))
r.GET("/cmd-socket", auth.AuthMiddleware(fileStore), cmd.CmdWebhook(fileStore, sessionStore, chatbot.APIKey(openAIKey), jsonConn, mqttEvents, &influx.InfluxDBConfig{
URL: os.Getenv("INFLUX_URL"),
Token: os.Getenv("INFLUX_TOKEN"),
Org: os.Getenv("INFLUX_ORG"),
}))
r.GET("/cmd-socket", auth.AuthMiddleware(fileStore),
cmd.CmdWebhook(
fileStore,
sessionStore,
chatbot.APIKey(openAIKey),
jsonConn,
mqttEvents,
&influx.InfluxDBConfig{
URL: os.Getenv("INFLUX_URL"),
Token: os.Getenv("INFLUX_TOKEN"),
Org: os.Getenv("INFLUX_ORG"),
},
uazapi.UazapiConfig{
BaseURL: uazapi_url,
APIKey: uazapi_key,
HTTPClient: &http.Client{},
},
email.EmailConfig{
Username: email_username,
Password: email_password,
Host: email_host,
Port: email_port,
},
))

server := &http.Server{
Addr: ":8080",
Expand Down
Loading
Loading