diff --git a/src/routes/timeline.nim b/src/routes/timeline.nim index 49c7ce2..0894d83 100644 --- a/src/routes/timeline.nim +++ b/src/routes/timeline.nim @@ -114,6 +114,7 @@ proc createTimelineRouter*(cfg: Config) = get "/@name/?@tab?/?": cond '.' notin @"name" cond @"name" notin ["pic", "gif", "video", "search", "settings", "login", "intent", "i"] + cond @"name".allCharsInSet({'a'..'z', 'A'..'Z', '0'..'9', '_'}) cond @"tab" in ["with_replies", "media", "search", ""] let prefs = cookiePrefs() diff --git a/tests/test_profile.py b/tests/test_profile.py index ea05add..cbf0256 100644 --- a/tests/test_profile.py +++ b/tests/test_profile.py @@ -15,7 +15,19 @@ protected = [ ['Poop', 'Randy', 'Social media fanatic.'] ] -invalid = [['thisprofiledoesntexist'], ['%']] +invalid = [['thisprofiledoesntexist']] + +malformed = [ + ['${userId}'], + ['$%7BuserId%7D'], # URL encoded version + ['%'], # Percent sign is invalid + ['user@name'], + ['user.name'], + ['user-name'], + ['user$name'], + ['user{name}'], + ['user name'], # space +] banner_image = [ ['mobile_test', 'profile_banners%2F82135242%2F1384108037%2F1500x500'] @@ -65,6 +77,13 @@ class ProfileTest(BaseTestCase): self.open_nitter(username) self.assert_text(f'User "{username}" not found') + @parameterized.expand(malformed) + def test_malformed_username(self, username): + """Test that malformed usernames (with invalid characters) return 404""" + self.open_nitter(username) + # Malformed usernames should return 404 page not found, not try to fetch from Twitter + self.assert_text('Page not found') + def test_suspended(self): self.open_nitter('suspendme') self.assert_text('User "suspendme" has been suspended')