Compare commits

...

2 Commits

Author SHA1 Message Date
Sebastian Crane b099d6bfe1 Release version 1.0.1
Signed-off-by: Sebastian Crane <seabass-labrax@gmx.com>
2022-04-01 15:52:51 +01:00
Sebastian Crane 6a594c5ad3 Use strings instead of keywords for game names
This commit changes the internal representation of game names in the
state data to be strings instead of keywords. This fixes a potential
memory leak relating to games that no longer have any players, since
strings, unlike keywords, are garbage collected when no longer in use.

Resolves issue LibreGaming/matchbot#2

Signed-off-by: Sebastian Crane <seabass-labrax@gmx.com>
2022-03-30 12:11:10 +01:00
5 changed files with 38 additions and 27 deletions

View File

@ -5,8 +5,17 @@
`matchbot` uses [version 2.0.0 of the Semantic Versioning](https://semver.org/spec/v2.0.0.html) scheme. `matchbot` uses [version 2.0.0 of the Semantic Versioning](https://semver.org/spec/v2.0.0.html) scheme.
## [1.0.1] - 2022-04-01
* Fix vulnerability that causes serialised data to be deleted when it contains certain user input
* Change internal representation of game names, fixing a potential memory leak for long-running instances
* Improve reliability and code quality of the startup and shutdown sequences
## [1.0.0] - 2022-03-03 ## [1.0.0] - 2022-03-03
* Initial release * Initial release
[1.0.1]: https://git.libregaming.org/LibreGaming/matchbot/releases/tag/1.0.1
[1.0.0]: https://git.libregaming.org/LibreGaming/matchbot/releases/tag/1.0.0 [1.0.0]: https://git.libregaming.org/LibreGaming/matchbot/releases/tag/1.0.0

View File

@ -6,15 +6,15 @@
[game] [game]
[irclj.core])) [irclj.core]))
(defn keywordise-game [game] (defn lower-case-game [game]
(when (string? game) (when (string? game)
(keyword (str/lower-case game)))) (str/lower-case game)))
(defn sort-case-insensitive [coll] (defn sort-case-insensitive [coll]
(sort #(apply compare (map str/lower-case %&)) coll)) (sort #(apply compare (map str/lower-case %&)) coll))
(defn match-string [& {:keys [state game player]}] (defn match-string [& {:keys [state game player]}]
(as-> (keywordise-game game) x (as-> (lower-case-game game) x
(game/get-players-of-game state x) (game/get-players-of-game state x)
(disj x player) (disj x player)
(sort-case-insensitive x) (sort-case-insensitive x)
@ -22,7 +22,7 @@
(str "Anyone ready for " game "? " x))) (str "Anyone ready for " game "? " x)))
(defn list-players-string [& {:keys [state game]}] (defn list-players-string [& {:keys [state game]}]
(as-> (keywordise-game game) x (as-> (lower-case-game game) x
(game/get-players-of-game state x) (game/get-players-of-game state x)
(sort-case-insensitive x) (sort-case-insensitive x)
(map #(str " _" % "_") x) (map #(str " _" % "_") x)
@ -46,7 +46,7 @@
(str "Games with a list of players: " (str "Games with a list of players: "
(str/join (str/join
", " ", "
(sort-case-insensitive (map name (game/get-games state)))))) (sort-case-insensitive (game/get-games state)))))
(defn help-string [& {:keys []}] (defn help-string [& {:keys []}]
" !list - show all the games that have a list of players " !list - show all the games that have a list of players
@ -59,7 +59,7 @@
(let [message-parts (str/split message #"\s") (let [message-parts (str/split message #"\s")
command (if-let [x (first message-parts)] (str/lower-case x) "") command (if-let [x (first message-parts)] (str/lower-case x) "")
game (second message-parts) game (second message-parts)
game-keyword (keywordise-game game)] game-keyword (lower-case-game game)]
{:command command {:command command
:game game :game game
:game-keyword game-keyword})) :game-keyword game-keyword}))

View File

@ -4,6 +4,7 @@
(ns system (ns system
(:require [irc] (:require [irc]
[clojure.data.json :as json] [clojure.data.json :as json]
[clojure.set :as set]
[clj-yaml.core :as yaml])) [clj-yaml.core :as yaml]))
(defn setify-vals [x] (defn setify-vals [x]
@ -13,13 +14,14 @@
{} x)) {} x))
(defn process-json [x] (defn process-json [x]
(update x :games setify-vals)) (-> (set/rename-keys x {"games" :games})
(update :games setify-vals)))
(defn load-state [f] (defn load-state [f]
(process-json (process-json
(try (try
(with-open [datafile (clojure.java.io/reader f)] (with-open [datafile (clojure.java.io/reader f)]
(json/read datafile :key-fn keyword)) (json/read datafile))
(catch Exception e nil)))) (catch Exception e nil))))
(defn save-state [f data] (defn save-state [f data]

View File

@ -5,13 +5,13 @@
(:require [clojure.test :refer :all] (:require [clojure.test :refer :all]
[bot :refer :all])) [bot :refer :all]))
(def test-state '{:games {:hypothetical-shooter #{"abc" "xyz" "123"} (def test-state '{:games {"hypothetical-shooter" #{"abc" "xyz" "123"}
:quasi-rts #{"abc" "123"} "quasi-rts" #{"abc" "123"}
:imaginary-rpg #{"xyz" "abc"}}}) "imaginary-rpg" #{"xyz" "abc"}}})
(deftest keywordise-game-test (deftest lower-case-game-test
(is (= :quasi-rts (is (= "quasi-rts"
(keywordise-game "Quasi-RTS")))) (lower-case-game "Quasi-RTS"))))
(deftest sort-case-insensitive-test (deftest sort-case-insensitive-test
(is (= ["A" "b" "C"] (is (= ["A" "b" "C"]
@ -38,7 +38,7 @@
(list-games-string :state test-state)))) (list-games-string :state test-state))))
(deftest split-message-test (deftest split-message-test
(is (= {:command "!match" :game "Quasi-Rts" :game-keyword :quasi-rts} (is (= {:command "!match" :game "Quasi-Rts" :game-keyword "quasi-rts"}
(split-message "!match Quasi-Rts ")))) (split-message "!match Quasi-Rts "))))
(deftest dispatch-command-test (deftest dispatch-command-test
@ -46,7 +46,7 @@
(is (and (is (and
(= "Added 123 to the list of players for Imaginary-RPG!" (= "Added 123 to the list of players for Imaginary-RPG!"
(dispatch-command state-atom "123" "!add Imaginary-RPG")) (dispatch-command state-atom "123" "!add Imaginary-RPG"))
(= {:games {:hypothetical-shooter #{"abc" "xyz" "123"} (= {:games {"hypothetical-shooter" #{"abc" "xyz" "123"}
:quasi-rts #{"abc" "123"} "quasi-rts" #{"abc" "123"}
:imaginary-rpg #{"xyz" "abc" "123"}}} "imaginary-rpg" #{"xyz" "abc" "123"}}}
@state-atom))))) @state-atom)))))

View File

@ -5,31 +5,31 @@
(:require [clojure.test :refer :all] (:require [clojure.test :refer :all]
[game :refer :all])) [game :refer :all]))
(def test-state '{:games {:hypothetical-shooter #{"player-one" "player-two" "player-three"} (def test-state '{:games {"hypothetical-shooter" #{"player-one" "player-two" "player-three"}
:quasi-rts #{"player-two" "player-four"} "quasi-rts" #{"player-two" "player-four"}
:imaginary-rpg #{"player-one" "player-three" "player-four"}}}) "imaginary-rpg" #{"player-one" "player-three" "player-four"}}})
(deftest get-players-of-game-test (deftest get-players-of-game-test
(is (= (is (=
'#{"player-two" "player-four"} '#{"player-two" "player-four"}
(get-players-of-game test-state :quasi-rts)))) (get-players-of-game test-state "quasi-rts"))))
(deftest add-player-of-game-test (deftest add-player-of-game-test
(is (= (is (=
'#{"player-one" "player-two" "player-four"} '#{"player-one" "player-two" "player-four"}
(get-in (add-player-of-game test-state :quasi-rts "player-one") [:games :quasi-rts])))) (get-in (add-player-of-game test-state "quasi-rts" "player-one") [:games "quasi-rts"]))))
(deftest remove-player-of-game-test (deftest remove-player-of-game-test
(is (= (is (=
'#{"player-one" "player-three"} '#{"player-one" "player-three"}
(get-in (remove-player-of-game test-state :imaginary-rpg "player-four") [:games :imaginary-rpg])))) (get-in (remove-player-of-game test-state "imaginary-rpg" "player-four") [:games "imaginary-rpg"]))))
(deftest get-games-test (deftest get-games-test
(is (= (is (=
'#{:hypothetical-shooter :quasi-rts :imaginary-rpg} '#{"hypothetical-shooter" "quasi-rts" "imaginary-rpg"}
(set (get-games test-state))))) (set (get-games test-state)))))
(deftest remove-game-test (deftest remove-game-test
(is (= (is (=
'#{:hypothetical-shooter :imaginary-rpg} '#{"hypothetical-shooter" "imaginary-rpg"}
(set (keys (:games (remove-game test-state :quasi-rts))))))) (set (keys (:games (remove-game test-state "quasi-rts")))))))