From 21175168ab4d87fe414844888275cff048928030 Mon Sep 17 00:00:00 2001 From: symys Date: Sun, 4 Aug 2024 23:59:09 -0500 Subject: [PATCH 1/5] Created timer functions. Untested. --- main.go | 46 +++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 41 insertions(+), 5 deletions(-) diff --git a/main.go b/main.go index a16a221..94ba962 100644 --- a/main.go +++ b/main.go @@ -38,11 +38,12 @@ type RecordCount struct { } type Item struct { - author string - date time.Time - number string - name string - path string + author string + date time.Time + number string + name string + path string + currentTimer *time.Timer } func (i Item) Status() string { @@ -300,6 +301,37 @@ important: let all items sit for awhile prior to closure return nil } +func createTriggerOneDayAutoDecide(item Item) func() { + return func() { + records := countRecords(item.path) + if records.approvals != 0 && records.concerns == 0 { + handleClose(item.number, "approved") + + } + if records.concerns > 0 { + handleClose(item.number, "cancelled") + } + if records.approvals == 0 && records.concerns == 0 { + msg := fmt.Sprintf("consensus item %s was created 7 days ago... but nobody has approved or concerned yet. Let's give it another week, shall we?") + sendMessage(msg) + notifFunc := createNotifFunc(item) + time.AfterFunc(time.ParseDuration("144h"), notifFunc) + } + } +} + +func createNotifFunc(item Item) func() { + return func() { + msg := fmt.Sprintf("consensus item %s is now 6 days old: %s\nThe item will auto-pass tomorrow if there is unanimous approval, and auto-fail otherwise! So, now is a good time to weigh in if you haven't yet and have an opinion!", item.number, item.name) + err = sendMessage(msg) + if err != nil { + return err + } + triggerOneDayAutoDecide := createTriggerOneDayAutoDecide(item) + time.AfterFunc(time.ParseDuration("24h"), triggerOneDayAutoDecide) + } +} + func handleNew(event *gomatrix.Event) error { body, ok := event.Body() if !ok { @@ -330,6 +362,10 @@ func handleNew(event *gomatrix.Event) error { if err != nil { return err } + //automatically check-in after 6 days, then close the item on the 7th day + notifFunc := createNotifFunc(item) + time.AfterFunc(time.ParseDuration("144h"), sendSixDayTriggerOneDay) + return nil } -- 2.45.2 From ff2f9d2735652be745ff8a38c8c026214c1ca2d0 Mon Sep 17 00:00:00 2001 From: symys Date: Mon, 5 Aug 2024 00:43:04 -0500 Subject: [PATCH 2/5] Fixed minor path traversal vuln and added some error logging to sendMessage calls that might've failed silently. --- main.go | 71 ++++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 60 insertions(+), 11 deletions(-) diff --git a/main.go b/main.go index 94ba962..5f3b5f3 100644 --- a/main.go +++ b/main.go @@ -10,6 +10,7 @@ import ( "path" "path/filepath" "reflect" + "strconv" "strings" "time" @@ -302,6 +303,7 @@ important: let all items sit for awhile prior to closure } func createTriggerOneDayAutoDecide(item Item) func() { + //TODO: add functions to extend the timer, and to cancel the timer if the item is closed before it fires return func() { records := countRecords(item.path) if records.approvals != 0 && records.concerns == 0 { @@ -313,22 +315,28 @@ func createTriggerOneDayAutoDecide(item Item) func() { } if records.approvals == 0 && records.concerns == 0 { msg := fmt.Sprintf("consensus item %s was created 7 days ago... but nobody has approved or concerned yet. Let's give it another week, shall we?") - sendMessage(msg) + err := sendMessage(msg) + if err != nil { + log.Println(fmt.Sprintf("Error (from notifFunc) sending message for item %s: %v", item.name, err)) + } notifFunc := createNotifFunc(item) - time.AfterFunc(time.ParseDuration("144h"), notifFunc) + sixDays, _ := time.ParseDuration("144h") + time.AfterFunc(sixDays, notifFunc) } } } func createNotifFunc(item Item) func() { + //TODO: add functions to extend the timer, and to cancel the timer if the item is closed before it fires return func() { msg := fmt.Sprintf("consensus item %s is now 6 days old: %s\nThe item will auto-pass tomorrow if there is unanimous approval, and auto-fail otherwise! So, now is a good time to weigh in if you haven't yet and have an opinion!", item.number, item.name) - err = sendMessage(msg) + err := sendMessage(msg) if err != nil { - return err + log.Println(fmt.Sprintf("Error (from notifFunc) sending message for item %s: %v", item.name, err)) } triggerOneDayAutoDecide := createTriggerOneDayAutoDecide(item) - time.AfterFunc(time.ParseDuration("24h"), triggerOneDayAutoDecide) + oneDay, _ := time.ParseDuration("24h") + time.AfterFunc(oneDay, triggerOneDayAutoDecide) } } @@ -364,7 +372,8 @@ func handleNew(event *gomatrix.Event) error { } //automatically check-in after 6 days, then close the item on the 7th day notifFunc := createNotifFunc(item) - time.AfterFunc(time.ParseDuration("144h"), sendSixDayTriggerOneDay) + sixDays, _ := time.ParseDuration("144h") + time.AfterFunc(sixDays, notifFunc) return nil } @@ -525,6 +534,11 @@ func handleClose(itemNumber string, status string) { sendMessage("please specify an item number. see !help") return } + + if !isValidItemNumber(itemNumber) { + return + } + itemPath := recordDir + "/" + itemNumber + ".txt" if !fileExists(itemPath) { @@ -559,12 +573,28 @@ func handleClose(itemNumber string, status string) { sendMessage(msg) } +func isValidItemNumber(itemNumberCandidate string) bool { + _, err := strconv.Atoi(itemNumberCandidate) + if err != nil { + err = sendMessage("hold yer horses there pard, that ain't no item number like I ever seen before...") + if err != nil { + log.Println(fmt.Sprintf("Error (from isValidItemNumber) sending message: %v", err)) + } + return false + } + return true +} + func handleShow(itemNumber string) { if strings.TrimSpace(itemNumber) == "" { sendMessage("please specify an item number. see !help") return } + if !isValidItemNumber(itemNumber) { + return + } + itemPath := recordDir + "/" + itemNumber + ".txt" if !fileExists(itemPath) { sendMessage("item specified does not exist") @@ -582,30 +612,49 @@ func handleShow(itemNumber string) { func handleComment(event *gomatrix.Event, itemNumber string, comment string, emoji string) { if strings.TrimSpace(itemNumber) == "" { - sendMessage("please specify an item number. see !help") + err := sendMessage("please specify an item number. see !help") + if err != nil { + log.Println(fmt.Sprintf("Error (from handleComment) sending messag: %v", err)) + } return } if strings.TrimSpace(comment) == "" { - sendMessage("please specify a comment. see !help") + err := sendMessage("please specify a comment. see !help") + if err != nil { + log.Println(fmt.Sprintf("Error (from handleComment) sending messag: %v", err)) + } + return + } + + if !isValidItemNumber(itemNumber) { return } itemPath := recordDir + "/" + itemNumber + ".txt" if !fileExists(itemPath) { - sendMessage("item specified does not exist") + err := sendMessage("item specified does not exist") + if err != nil { + log.Println(fmt.Sprintf("Error (from handleComment) sending messag: %v", err)) + } return } item, err := loadItemByPath(itemPath) if err != nil { - sendMessage("item not found: " + err.Error()) + err = sendMessage("item not found: " + err.Error()) + if err != nil { + log.Println(fmt.Sprintf("Error (from handleComment) sending messag: %v", err)) + } return } if !item.isActive() { - sendMessage(fmt.Sprintf("item %s (%s) is not active and may not be commented on", item.number, item.name)) + err = sendMessage(fmt.Sprintf("item %s (%s) is not active and may not be commented on", item.number, item.name)) + if err != nil { + log.Println(fmt.Sprintf("Error (from handleComment) sending messag: %v", err)) + } return } -- 2.45.2 From 105751fee2f0cd84e73d5e92d779aabfd36b71e2 Mon Sep 17 00:00:00 2001 From: symys Date: Mon, 5 Aug 2024 12:45:26 -0500 Subject: [PATCH 3/5] Config-variable-ized the timer settings (for time to warning and then time to activation of auto-decide consensus or not) --- main.go | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/main.go b/main.go index 5f3b5f3..497dd77 100644 --- a/main.go +++ b/main.go @@ -26,10 +26,12 @@ const ( var config Config type Config struct { - MatrixRoom string - MatrixURL string - MatrixUsername string - MatrixToken string + MatrixRoom string + MatrixURL string + MatrixUsername string + MatrixToken string + WarningTime string + ActivationTimeAfterWarning string } type RecordCount struct { @@ -320,8 +322,8 @@ func createTriggerOneDayAutoDecide(item Item) func() { log.Println(fmt.Sprintf("Error (from notifFunc) sending message for item %s: %v", item.name, err)) } notifFunc := createNotifFunc(item) - sixDays, _ := time.ParseDuration("144h") - time.AfterFunc(sixDays, notifFunc) + warningTime, _ := time.ParseDuration(config.WarningTime) + time.AfterFunc(warningTime, notifFunc) } } } @@ -335,8 +337,8 @@ func createNotifFunc(item Item) func() { log.Println(fmt.Sprintf("Error (from notifFunc) sending message for item %s: %v", item.name, err)) } triggerOneDayAutoDecide := createTriggerOneDayAutoDecide(item) - oneDay, _ := time.ParseDuration("24h") - time.AfterFunc(oneDay, triggerOneDayAutoDecide) + activationTime, _ := time.ParseDuration(config.ActivationTimeAfterWarning) + time.AfterFunc(activationTime, triggerOneDayAutoDecide) } } @@ -372,8 +374,8 @@ func handleNew(event *gomatrix.Event) error { } //automatically check-in after 6 days, then close the item on the 7th day notifFunc := createNotifFunc(item) - sixDays, _ := time.ParseDuration("144h") - time.AfterFunc(sixDays, notifFunc) + warningTime, _ := time.ParseDuration(config.WarningTime) + time.AfterFunc(warningTime, notifFunc) return nil } -- 2.45.2 From 0ef191b35b26b89a4694a590fa4792eec089d650 Mon Sep 17 00:00:00 2001 From: symys Date: Mon, 5 Aug 2024 21:41:44 -0500 Subject: [PATCH 4/5] Made the time til warning and time til auto-decide configuration-defined values. Did basic testing on matrix, and fixed various bugs. --- main.go | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/main.go b/main.go index 497dd77..8469cad 100644 --- a/main.go +++ b/main.go @@ -316,7 +316,9 @@ func createTriggerOneDayAutoDecide(item Item) func() { handleClose(item.number, "cancelled") } if records.approvals == 0 && records.concerns == 0 { - msg := fmt.Sprintf("consensus item %s was created 7 days ago... but nobody has approved or concerned yet. Let's give it another week, shall we?") + + openDays := time.Since(item.date).Hours() / 24 + msg := fmt.Sprintf("consensus item %s is %v days old... but nobody has approved or concerned yet. Let's give it another %s, shall we?", item.number, openDays, config.WarningTime) err := sendMessage(msg) if err != nil { log.Println(fmt.Sprintf("Error (from notifFunc) sending message for item %s: %v", item.name, err)) @@ -331,7 +333,8 @@ func createTriggerOneDayAutoDecide(item Item) func() { func createNotifFunc(item Item) func() { //TODO: add functions to extend the timer, and to cancel the timer if the item is closed before it fires return func() { - msg := fmt.Sprintf("consensus item %s is now 6 days old: %s\nThe item will auto-pass tomorrow if there is unanimous approval, and auto-fail otherwise! So, now is a good time to weigh in if you haven't yet and have an opinion!", item.number, item.name) + openDays := time.Since(item.date).Hours() / 24 + msg := fmt.Sprintf("consensus item %s is now %v days old: %s\nThe item will auto-pass after %s if there is unanimous approval, and auto-fail otherwise! So, now is a good time to weigh in if you haven't yet and have an opinion!", item.number, openDays, item.name, config.ActivationTimeAfterWarning) err := sendMessage(msg) if err != nil { log.Println(fmt.Sprintf("Error (from notifFunc) sending message for item %s: %v", item.name, err)) @@ -372,7 +375,8 @@ func handleNew(event *gomatrix.Event) error { if err != nil { return err } - //automatically check-in after 6 days, then close the item on the 7th day + //automatically check-in after time specified in configuration, then after the other time specified in configuration + //approve if it has unanimous approval or cancel if any concerns notifFunc := createNotifFunc(item) warningTime, _ := time.ParseDuration(config.WarningTime) time.AfterFunc(warningTime, notifFunc) -- 2.45.2 From a29a1584aae719c2458a6f4ba189a3ccebbf8bdd Mon Sep 17 00:00:00 2001 From: symys Date: Mon, 5 Aug 2024 21:47:54 -0500 Subject: [PATCH 5/5] Updated example config to include timer settings --- config.example.json | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/config.example.json b/config.example.json index c082509..a12cabd 100644 --- a/config.example.json +++ b/config.example.json @@ -2,5 +2,7 @@ "MatrixRoom": "!exampleEXAMPLEexample:cyberia.club", "MatrixToken": "syt_exampleEXAMPLE_exampleEXAMPLE_example", "MatrixUsername": "@consensus-bot:cyberia.club", - "MatrixURL": "https://matrix.cyberia.club" -} \ No newline at end of file + "MatrixURL": "https://matrix.cyberia.club", + "WarningTime": "144h", + "ActivationTimeAfterWarning":"24h" +} -- 2.45.2