Skip to content

Instantly share code, notes, and snippets.

@henrik
Last active December 8, 2020 19:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save henrik/48e8bb74de9d887770dfb3cc6efaa9b2 to your computer and use it in GitHub Desktop.
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.
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
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
@henrik
Copy link
Author

henrik commented Dec 8, 2020

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).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment