Skip to content

Commit

Permalink
restructure and add niro
Browse files Browse the repository at this point in the history
  • Loading branch information
joshspicer authored Feb 27, 2023
1 parent 20d3318 commit a77d156
Show file tree
Hide file tree
Showing 13 changed files with 254 additions and 128 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,5 @@
# Development artifacts
dev.env
jarvis
utilities
__debug_bin
50 changes: 0 additions & 50 deletions server/api.go

This file was deleted.

14 changes: 14 additions & 0 deletions server/august.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,28 @@ import (
"net/http"
"os"
"strings"

"github.com/gin-gonic/gin"
)

const AUGUST_HTTP_CONTEXT = `AUGUST_HTTP_CONTEXT`
const AUGUST_SESSION_URL = "https://api-production.august.com/session"

type AugustHttpClient struct {
*http.Client
}

func AugustHttpClientContext() gin.HandlerFunc {
return func(c *gin.Context) {

httpClient := &http.Client{}
augustHttpClient := &AugustHttpClient{httpClient}

c.Set(AUGUST_HTTP_CONTEXT, augustHttpClient)
c.Next()
}
}

type AugustSessionPayload struct {
ApiKey string `json:"apiKey"`
InstallId string `json:"installID"`
Expand Down
75 changes: 37 additions & 38 deletions server/routes.go → server/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,36 +12,55 @@ import (
"time"

"github.com/gin-gonic/gin"
"github.com/google/uuid"
)

func Hello(c *gin.Context) {
c.String(http.StatusOK, "hello")
}
func GenerateAuthHeaderForPrimaryActor() (string, string, error) {

trustedActors, err := GetTrustedActors()
if err != nil {
fmt.Printf("Failed to retrieve trusted actors: %s\n", err)
return "", "", err
}
var primaryActor = trustedActors[0]

timestamp := time.Now().Unix()
uuid, _ := uuid.NewRandom()
nonce := fmt.Sprintf("%d_%s", timestamp, uuid)

h := hmac.New(
sha256.New,
[]byte(primaryActor.secret))
h.Write([]byte(nonce))

auth := hex.EncodeToString(h.Sum(nil))

func Health(c *gin.Context) {
c.String(http.StatusOK, "healthy")
return auth, nonce, nil
}

func TrustedHmacAuthentication() gin.HandlerFunc {
func Auth() gin.HandlerFunc {
return func(c *gin.Context) {
authHeader := c.Request.Header.Get("Authorization")
nonce := c.Request.Header.Get("X-Jarvis-Timestamp")

if authHeader == "" || nonce == "" {
c.AbortWithStatus(401)
return
}

var timestamp time.Time

splitted := strings.Split(nonce, "_")
if len(splitted) != 2 {
c.AbortWithStatus(401)
return
}

timestampAsInt, err := strconv.ParseInt(splitted[0], 10, 64)
if err != nil {
fmt.Printf("Failed to parse timestamp from body: %s\n", strings.ReplaceAll(splitted[0], "\n", ""))
c.AbortWithStatus(401)
return
}

timestamp = time.Unix(timestampAsInt, 0)
Expand All @@ -65,7 +84,11 @@ func TrustedHmacAuthentication() gin.HandlerFunc {
return
}

bot := c.MustGet(BOT_CONTEXT).(*BotExtended)
fetchedBot, hasBot := c.Get(BOT_CONTEXT)
var bot *BotExtended = nil
if hasBot {
bot = fetchedBot.(*BotExtended)
}

// Retrieve list of trusted actors

Expand Down Expand Up @@ -94,9 +117,11 @@ func TrustedHmacAuthentication() gin.HandlerFunc {
if computedHash == authHeader {
matchStr := fmt.Sprintf("✅ Hash match: %s\n", actor.name)
fmt.Println(matchStr)
bot.SendMessageToPrimaryTelegramGroup(matchStr)
if hasBot {
bot.SendMessageToPrimaryTelegramGroup(matchStr)
}
c.Set("authenticatedUser", actor.name)
c.String(http.StatusAccepted, actor.name)
c.Next()

device := c.Request.Header.Get("X-Jarvis-Device")
fmt.Printf("Device: %s\n", strings.ReplaceAll(device, "\n", ""))
Expand All @@ -106,35 +131,9 @@ func TrustedHmacAuthentication() gin.HandlerFunc {
}

// Fallback
bot.SendMessageToPrimaryTelegramGroup("⚠️ Invalid authentication hash provided.")
if hasBot {
bot.SendMessageToPrimaryTelegramGroup("⚠️ Invalid authentication hash provided.")
}
c.AbortWithStatus(401)
}
}

func TrustedKnock(c *gin.Context) {
// Protected by 'TrustedHmacAuthentication' middleware
authenticatedUser := c.MustGet("authenticatedUser").(string)

august := c.MustGet(AUGUST_HTTP_CONTEXT).(*AugustHttpClient)

error := august.OperateLock("unlock")
if error != nil {
fmt.Println(fmt.Errorf("failed to unlock August: %s", error))
c.AbortWithStatus(http.StatusInternalServerError)
}

// Accept if we have not aborted.
if !c.IsAborted() {
c.String(http.StatusAccepted, fmt.Sprintf("Welcome, %s.", authenticatedUser))
}
}

func Welcome(c *gin.Context) {

bot := c.MustGet(BOT_CONTEXT).(*BotExtended)
invite_code := c.Param("invite_code")

// TODO
bot.SendMessageToPrimaryTelegramGroup(fmt.Sprintf("Welcome %s", invite_code))
c.String(http.StatusAccepted, "Welcome, "+invite_code)
}
48 changes: 19 additions & 29 deletions server/bot.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,26 @@ import (
"strconv"
"strings"

"github.com/gin-gonic/gin"
tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5"
)

const BOT_CONTEXT = "BOT_CONTEXT"

type BotExtended struct {
*tgbotapi.BotAPI
}

func BotContext(bot *tgbotapi.BotAPI) gin.HandlerFunc {
return func(c *gin.Context) {

botExtended := &BotExtended{bot}

c.Set(BOT_CONTEXT, botExtended)
c.Next()
}
}

func (b *BotExtended) SendMessageToPrimaryTelegramGroup(message string) {
// Get primary group, which is the first in the space-separated list.
validTelegramGroups := strings.Split(os.Getenv("VALID_TELEGRAM_GROUPS"), " ")
Expand Down Expand Up @@ -41,6 +54,9 @@ func SetupTelegram() *tgbotapi.BotAPI {
if err != nil {
panic(fmt.Sprintf("Error Creating new Telegram bot object: %s", err))
}

log.Printf("Bot authorized on account %s", bot.Self.UserName)

return bot
}

Expand All @@ -63,7 +79,7 @@ func validate(configEnvVariable string, valueToCheck string) bool {
return false
}

func SetupCommandHandler(bot *BotExtended, handlerMode string) {
func SetupTelegramCommandHandler(bot *BotExtended, handlerMode string) {

ginMode := os.Getenv("GIN_MODE")
if ginMode == "release" {
Expand Down Expand Up @@ -114,9 +130,9 @@ func SetupCommandHandler(bot *BotExtended, handlerMode string) {
args := update.Message.CommandArguments()
switch handlerMode {
case "jarvis":
msg.Text = jarvisCommandHandler(bot, command, args)
msg.Text = JarvisCommandHandler(bot, command, args)
case "narnia":
msg.Text = narniaCommandHandler(bot, command, args)
msg.Text = NarniaCommandHandler(bot, command, args)
default:
msg.Text = "[ERR] Invalid handler mode!"
log.Printf("Invalid handler mode %s", handlerMode)
Expand All @@ -129,29 +145,3 @@ func SetupCommandHandler(bot *BotExtended, handlerMode string) {
}
}
}

func jarvisCommandHandler(bot *BotExtended, command string, args string) string {
// Extract the command from the Message.
switch command {
case "help":
return ServerHelpCommand()
case "status":
return ServerStatusCommand()
case "invite":
return AugustInviteCommand(args)
default:
return "Try Again."
}
}

func narniaCommandHandler(bot *BotExtended, command string, args string) string {
// Extract the command from the Message.
switch command {
case "help":
return "narnia Help"
case "status":
return "narnia status"
default:
return "Try Again."
}
}
20 changes: 17 additions & 3 deletions server/serverCommands.go → server/jarvisBot.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,29 @@ import (
"github.com/google/uuid"
)

func ServerHelpCommand() string {
func JarvisCommandHandler(bot *BotExtended, command string, args string) string {
// Extract the command from the Message.
switch command {
case "help":
return jarvisHelpCommand()
case "status":
return jarvisStatusCommand()
case "invite":
return augustInviteCommand(args)
default:
return "Try Again."
}
}

func jarvisHelpCommand() string {
return ("- /status\n")
}

func ServerStatusCommand() string {
func jarvisStatusCommand() string {
return time.Now().Weekday().String()
}

func AugustInviteCommand(args string) string {
func augustInviteCommand(args string) string {
split := strings.Split(args, " ")
if len(split) > 2 {
return "Too many arguments. Usage: /invite <name> [count=1]"
Expand Down
58 changes: 58 additions & 0 deletions server/jarvisRouter.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package main

import (
"fmt"
"net/http"

"github.com/gin-gonic/gin"
tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5"
)

func JarvisRouter(bot *tgbotapi.BotAPI) *gin.Engine {
router := gin.Default()

router.Use(BotContext(bot))
router.Use(AugustHttpClientContext())

// Static
router.StaticFile("robots.txt", "./static/robots.txt")

router.GET("/health", health)
// Knocks
router.POST("/welcome/:invite_code", welcome)
router.POST("/trustedknock", Auth(), trustedKnock)

return router
}

func health(c *gin.Context) {
c.String(http.StatusOK, "healthy")
}

func trustedKnock(c *gin.Context) {
// Protected by 'TrustedHmacAuthentication' middleware
authenticatedUser := c.MustGet("authenticatedUser").(string)

august := c.MustGet(AUGUST_HTTP_CONTEXT).(*AugustHttpClient)

error := august.OperateLock("unlock")
if error != nil {
fmt.Println(fmt.Errorf("failed to unlock August: %s", error))
c.AbortWithStatus(http.StatusInternalServerError)
}

// Accept if we have not aborted.
if !c.IsAborted() {
c.String(http.StatusAccepted, fmt.Sprintf("Welcome, %s.", authenticatedUser))
}
}

func welcome(c *gin.Context) {

bot := c.MustGet(BOT_CONTEXT).(*BotExtended)
invite_code := c.Param("invite_code")

// TODO
bot.SendMessageToPrimaryTelegramGroup(fmt.Sprintf("Welcome %s", invite_code))
c.String(http.StatusAccepted, "Welcome, "+invite_code)
}
Loading

0 comments on commit a77d156

Please sign in to comment.