diff --git a/src/infrastructure/util/PhabricatorSlug.php b/src/infrastructure/util/PhabricatorSlug.php --- a/src/infrastructure/util/PhabricatorSlug.php +++ b/src/infrastructure/util/PhabricatorSlug.php @@ -10,6 +10,24 @@ $slug = preg_replace('@_+@', '_', $slug); $slug = trim($slug, '_'); + // Specifically rewrite these slugs. It's OK to have a slug like "a..b", + // but not a slug which is only "..". + + // NOTE: These are explicitly not pht()'d, because they should be stable + // across languages. + + $replace = array( + '.' => 'dot', + '..' => 'dotdot', + ); + + foreach ($replace as $pattern => $replacement) { + $pattern = preg_quote($pattern, '@'); + $slug = preg_replace( + '@(^|/)'.$pattern.'(\z|/)@', + '\1'.$replacement.'\2', $slug); + } + return $slug.'/'; } diff --git a/src/infrastructure/util/__tests__/PhabricatorSlugTestCase.php b/src/infrastructure/util/__tests__/PhabricatorSlugTestCase.php --- a/src/infrastructure/util/__tests__/PhabricatorSlugTestCase.php +++ b/src/infrastructure/util/__tests__/PhabricatorSlugTestCase.php @@ -17,6 +17,16 @@ "T\x00O\x00D\x00O" => "t_o_d_o/", 'x#%&+=\\?<> y' => 'x_y/', "\xE2\x98\x83" => "\xE2\x98\x83/", + '..' => 'dotdot/', + '../' => 'dotdot/', + '/../' => 'dotdot/', + 'a/b' => 'a/b/', + 'a//b' => 'a/b/', + 'a/../b/' => 'a/dotdot/b/', + '/../a' => 'dotdot/a/', + '../a' => 'dotdot/a/', + 'a/..' => 'a/dotdot/', + 'a/../' => 'a/dotdot/', ); foreach ($slugs as $slug => $normal) {