Last active
December 8, 2020 19:48
-
-
Save henrik/48e8bb74de9d887770dfb3cc6efaa9b2 to your computer and use it in GitHub Desktop.
Ruby code to check if a pathname is contained within another pathname (e.g. "/foo/bar/baz" within "/foo/bar") without being tricked by "..". Written with @olleolleolle.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class PathnameExtras | |
def self.in_dir?(path, dir:) | |
path_parts = path.expand_path.each_filename.to_a | |
dir_parts = dir.expand_path.each_filename.to_a | |
return false if path_parts == dir_paths | |
dir_parts.zip(path_parts).all? { |x, y| x == y } | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require "spec_helper" | |
require "pathname_extras" | |
RSpec.describe PathnameExtras do | |
describe "in_dir?" do | |
it "is true when within the given dir" do | |
actual = PathnameExtras.in_dir?(Pathname("/foo/bar/baz"), dir: Pathname("/foo/bar")) | |
expect(actual).to be true | |
end | |
it "is true when within the given dir while using '..'" do | |
actual = PathnameExtras.in_dir?(Pathname("/foo/../foo/bar/../bar/baz"), dir: Pathname("/foo/bar")) | |
expect(actual).to be true | |
end | |
it "is true when within the given dir while the dir uses '..'" do | |
actual = PathnameExtras.in_dir?(Pathname("/foo/bar/baz"), dir: Pathname("/foo/../foo/bar/../bar")) | |
expect(actual).to be true | |
end | |
it "is false for an already-expanded path not within the given dir" do | |
actual = PathnameExtras.in_dir?(Pathname("/foo/bar/baz"), dir: Pathname("/boink")) | |
expect(actual).to be false | |
end | |
it "is false for a path using '..' that is not within the given dir" do | |
actual = PathnameExtras.in_dir?(Pathname("/foo/bar/../not_bar/baz"), dir: Pathname("/foo/bar")) | |
expect(actual).to be false | |
end | |
it "is false if only dir name prefixes match" do | |
actual = PathnameExtras.in_dir?(Pathname("/foo/bar/../bar_not/baz"), dir: Pathname("/foo/bar")) | |
expect(actual).to be false | |
end | |
it "is false if the path is a parent of the dir" do | |
actual = PathnameExtras.in_dir?(Pathname("/foo"), dir: Pathname("/foo/bar")) | |
expect(actual).to be false | |
end | |
it "is false with no overlap whatsoever" do | |
actual = PathnameExtras.in_dir?(Pathname("/foo"), dir: Pathname("/bar")) | |
expect(actual).to be false | |
end | |
it "is false for identical paths" do | |
actual = PathnameExtras.in_dir?(Pathname("/foo"), dir: Pathname("/foo")) | |
expect(actual).to be false | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
We considered just checking for the substring ".." but weren't confident this would protect against all forms of traversal. Perhaps there's some way to escape your way around it that would trick such a substring check, but not this Pathname check – not sure (we overdesigned for somewhere it wasn't strictly needed so haven't done deep research).