about summary refs log tree commit diff
diff options
context:
space:
mode:
authoreta <eta@theta.eu.org>2020-07-02T21·32+0100
committereta <eta@theta.eu.org>2020-07-02T21·46+0000
commit6fd3371e94fa529e39a9c047f2eef81f3b4ec43c (patch)
treecfddcdf56aff55482ca55fad5603ea00532b5383
parent1ecae26afa78371dcc77d487a17af4a658d71fd1 (diff)
feat(tvldb): prohibit infinite recursion r/1173
Change-Id: I63b54e937f4c4fdb823f2e2e91a5a5d8af071a42
Reviewed-on: https://cl.tvl.fyi/c/depot/+/855
Tested-by: BuildkiteCI
Reviewed-by: eta <eta@theta.eu.org>
Reviewed-by: isomer <isomer@tvl.fyi>
Reviewed-by: BuildkiteCI
-rw-r--r--fun/tvldb/src/keyword.rs21
1 files changed, 19 insertions, 2 deletions
diff --git a/fun/tvldb/src/keyword.rs b/fun/tvldb/src/keyword.rs
index fe296f03df..9c5ea47ea5 100644
--- a/fun/tvldb/src/keyword.rs
+++ b/fun/tvldb/src/keyword.rs
@@ -4,6 +4,9 @@ use diesel::prelude::*;
 use failure::Error;
 use std::borrow::Cow;
 
+/// Maximum number of times we'll follow a `see: ` pointer.
+const RECURSION_LIMIT: usize = 5;
+
 pub struct KeywordDetails {
     pub keyword: Keyword,
     pub entries: Vec<Entry>,
@@ -162,10 +165,11 @@ impl KeywordDetails {
         Ok(entries)
     }
 
-    pub fn get<'a, T: Into<Cow<'a, str>>>(
+    fn get_inner<'a, T: Into<Cow<'a, str>>>(
         word: T,
         c: &str,
         dbc: &PgConnection,
+        recursion_count: usize,
     ) -> Result<Option<Self>, Error> {
         let word = word.into();
         let keyword: Option<Keyword> = {
@@ -179,7 +183,12 @@ impl KeywordDetails {
             let entries = Self::get_entries(k.id, dbc)?;
             if let Some(e0) = entries.get(0) {
                 if e0.text.starts_with("see: ") {
-                    return Self::get(e0.text.replace("see: ", ""), c, dbc);
+                    if recursion_count > RECURSION_LIMIT {
+                        // Oh dear.
+                        Err(format_err!("Halt. You're having a bit too much fun."))?
+                    }
+                    let new_word = e0.text.replace("see: ", "");
+                    return Self::get_inner(new_word, c, dbc, recursion_count + 1);
                 }
             }
             Ok(Some(KeywordDetails {
@@ -190,4 +199,12 @@ impl KeywordDetails {
             Ok(None)
         }
     }
+
+    pub fn get<'a, T: Into<Cow<'a, str>>>(
+        word: T,
+        c: &str,
+        dbc: &PgConnection,
+    ) -> Result<Option<Self>, Error> {
+        Self::get_inner(word, c, dbc, 0)
+    }
 }